合并主分支

pull/513/head
irving.zhao 6 years ago
commit 53c1606fc2

1
.gitignore vendored

@ -10,3 +10,4 @@ tmp
package-lock.json package-lock.json
dump.rdb dump.rdb
/docker/mysql/volume /docker/mysql/volume
.idea

@ -0,0 +1,2 @@
ALTER TABLE `Properties`
MODIFY COLUMN `type` enum('String','Number','Boolean','Object','Array','Function','RegExp','Null') NOT NULL;

@ -8,7 +8,8 @@ services:
# build from ./Dockerfile # build from ./Dockerfile
# build: . # build: .
# build from images # build from images
image: blackdog1987/rap2-delos:1.0.0 # you can find last tag from https://hub.docker.com/r/blackdog1987/rap2-delos
image: blackdog1987/rap2-delos:2.6.aa3be03
environment: environment:
# if you have your own mysql, config it here, and disable the 'mysql' config blow # if you have your own mysql, config it here, and disable the 'mysql' config blow
- MYSQL_URL=rap2-mysql # links will maintain /etc/hosts, just use 'container_name' - MYSQL_URL=rap2-mysql # links will maintain /etc/hosts, just use 'container_name'

@ -9,87 +9,84 @@
"scripts": { "scripts": {
"build": "rimraf -rf dist/ && tsc", "build": "rimraf -rf dist/ && tsc",
"test": "cross-env NODE_ENV=development cross-env TEST_MODE=true nyc mocha --exit", "test": "cross-env NODE_ENV=development cross-env TEST_MODE=true nyc mocha --exit",
"check": "echo \"Checking...\" && tsc && npm run tslint", "check": "echo \"Checking...\" && tsc && npm run lint",
"dev": "cross-env NODE_ENV=development nodemon --watch scripts --watch dist dist/scripts/dev.js", "dev": "cross-env NODE_ENV=development nodemon --watch scripts --watch dist dist/scripts/dev.js",
"create-db": "cross-env NODE_ENV=development node dist/scripts/init", "create-db": "cross-env NODE_ENV=development node dist/scripts/init",
"tslint": "tslint -c tslint.json -p tsconfig.json",
"start": "cross-env NODE_ENV=production pm2 start dist/dispatch.js --name=rap-server-delos", "start": "cross-env NODE_ENV=production pm2 start dist/dispatch.js --name=rap-server-delos",
"lint": "echo \"TSLint checking...\" && tslint -c tslint.json 'src/**/*.ts' 'src/**/*.tsx'",
"start:redis": "pm2 start redis-server --name redis-server", "start:redis": "pm2 start redis-server --name redis-server",
"clean": "pm2 delete all" "clean": "pm2 delete all"
}, },
"author": "bosn, nuysoft", "author": "bosn, nuysoft",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"chalk": "^2.4.1", "chalk": "^2.4.2",
"cluster": "^0.7.7", "cross-env": "^5.2.0",
"cross-env": "^5.1.1", "graceful": "^1.0.2",
"graceful": "^1.0.1",
"ioredis": "^3.2.2",
"is-md5": "^0.0.2", "is-md5": "^0.0.2",
"js-beautify": "^1.6.9", "js-beautify": "^1.10.0",
"kcors": "^2.2.1", "kcors": "^2.2.2",
"koa": "^2.2.0", "koa": "^2.7.0",
"koa-body": "^4.0.1", "koa-body": "^4.1.0",
"koa-generic-session": "^2.0.1", "koa-generic-session": "^2.0.1",
"koa-logger": "^3.2.0", "koa-logger": "^3.2.0",
"koa-redis": "^3.1.2", "koa-redis": "^4.0.0",
"koa-router": "^7.1.1", "koa-router": "^7.4.0",
"koa-send": "^4.0.0", "koa-send": "^5.0.0",
"koa-static": "^4.0.2", "koa-static": "^5.0.0",
"md5": "^2.2.1",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"md5": "^2.2.1",
"mockjs": "^1.0.1-beta3", "mockjs": "^1.0.1-beta3",
"moment": "^2.17.1", "moment": "^2.24.0",
"mysql": "^2.11.1", "mysql": "^2.17.1",
"mysql2": "^1.5.1", "mysql2": "^1.6.5",
"node-fetch": "^2.1.2", "node-fetch": "^2.6.0",
"node-print": "0.0.4", "node-print": "0.0.4",
"nodemailer": "^4.6.8", "nodemailer": "^6.2.1",
"notevil": "^1.1.0", "notevil": "^1.3.1",
"path-to-regexp": "^2.2.1", "path-to-regexp": "^3.0.0",
"redis": "^2.8.0", "redis": "^2.8.0",
"reflect-metadata": "^0.1.10", "reflect-metadata": "^0.1.13",
"request": "^2.85.0", "request": "^2.88.0",
"request-promise": "^4.2.2", "request-promise": "^4.2.4",
"sequelize": "^4.28.6", "sequelize": "^5.8.7",
"sequelize-typescript": "^0.6.4", "sequelize-typescript": "^1.0.0-beta.3",
"svg-captcha": "^1.3.11", "svg-captcha": "^1.4.0",
"underscore": "^1.8.3", "underscore": "^1.9.1",
"urllib": "^2.28.1" "urllib": "^2.34.0"
}, },
"devDependencies": { "devDependencies": {
"@types/chai": "^4.0.10", "@types/chai": "^4.1.7",
"@types/kcors": "^2.2.2", "@types/kcors": "^2.2.3",
"@types/koa": "^2.0.43", "@types/koa": "^2.0.48",
"@types/koa-generic-session": "^1.0.2", "@types/koa-generic-session": "^1.0.2",
"@types/koa-logger": "^3.1.0", "@types/koa-logger": "^3.1.1",
"@types/koa-redis": "^3.0.2", "@types/koa-redis": "^3.0.2",
"@types/koa-router": "^7.0.27", "@types/koa-router": "^7.0.40",
"@types/koa-static": "^4.0.0", "@types/koa-static": "^4.0.1",
"@types/lodash": "^4.14.106", "@types/lodash": "^4.14.132",
"@types/md5": "^2.1.32", "@types/md5": "^2.1.33",
"@types/mocha": "^5.2.0", "@types/mocha": "^5.2.6",
"@types/mockjs": "^1.0.0", "@types/mockjs": "^1.0.2",
"@types/node": "^10.1.0", "@types/node": "^12.0.3",
"@types/nodemailer": "^4.6.5", "@types/nodemailer": "^6.2.0",
"@types/redis": "^2.8.6", "@types/redis": "^2.8.13",
"@types/request": "^2.47.0", "@types/request": "^2.48.1",
"@types/request-promise": "^4.1.41", "@types/request-promise": "^4.1.44",
"@types/sequelize": "^4.27.12", "@types/underscore": "^1.8.18",
"@types/underscore": "^1.8.8", "babel-eslint": "^10.0.1",
"babel-eslint": "^8.2.3", "chai": "^4.2.0",
"chai": "^4.1.2", "mocha": "^6.1.4",
"mocha": "^5.1.1", "nodemon": "^1.19.1",
"nodemon": "^1.11.0", "npm-run-all": "^4.1.5",
"npm-run-all": "^4.0.2", "nyc": "^14.1.1",
"nyc": "^12.0.2",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"rimraf": "^2.6.2", "rimraf": "^2.6.3",
"source-map-support": "^0.5.0", "source-map-support": "^0.5.12",
"standard": "^11.0.1", "standard": "^12.0.1",
"supertest": "^3.0.0", "supertest": "^4.0.2",
"tslint": "^5.8.0", "tslint": "^5.16.0",
"typescript": "^2.9.2" "typescript": "^3.5.1"
}, },
"pre-commit": [ "pre-commit": [
"check" "check"

@ -1,4 +1,4 @@
import { IConfigOptions } from "../types"; import { IConfigOptions } from "../types"
let config: IConfigOptions = { let config: IConfigOptions = {
version: '2.3', version: '2.3',

@ -1,4 +1,4 @@
import { IConfigOptions } from "../types"; import { IConfigOptions } from "../types"
let config: IConfigOptions = { let config: IConfigOptions = {
version: '2.3', version: '2.3',

@ -1,4 +1,4 @@
import { IConfigOptions } from "../types"; import { IConfigOptions } from "../types"
// 先从环境变量取配置 // 先从环境变量取配置
let config: IConfigOptions = { let config: IConfigOptions = {

@ -1,4 +1,4 @@
import { IConfigOptions } from "../types"; import { IConfigOptions } from "../types"
// local or development or production // local or development or production
let configObj: IConfigOptions = let configObj: IConfigOptions =

@ -1,5 +1,5 @@
import { Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey, BeforeBulkDelete, BeforeBulkCreate, BeforeBulkUpdate, BeforeCreate, BeforeUpdate, BeforeDelete } from 'sequelize-typescript' import { Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey, BeforeBulkDestroy, BeforeBulkCreate, BeforeBulkUpdate, BeforeCreate, BeforeUpdate, BeforeDestroy } from 'sequelize-typescript'
import { User, Module, Repository, Property } from '../'; import { User, Module, Repository, Property } from '../'
import RedisService, { CACHE_KEY } from '../../service/redis' import RedisService, { CACHE_KEY } from '../../service/redis'
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
@ -13,16 +13,16 @@ export default class Interface extends Model<Interface> {
/** hooks */ /** hooks */
@BeforeCreate @BeforeCreate
@BeforeUpdate @BeforeUpdate
@BeforeDelete @BeforeDestroy
static async deleteCache(instance: Interface) { static async deleteCache(instance: Interface) {
await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, instance.repositoryId) await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, instance.repositoryId)
} }
@BeforeBulkCreate @BeforeBulkCreate
@BeforeBulkUpdate @BeforeBulkUpdate
@BeforeBulkDelete @BeforeBulkDestroy
static async bulkDeleteCache(options: any) { static async bulkDeleteCache(options: any) {
let id: number = +(options && options.attributes && options.attributes.id) let id: number = options && options.attributes && options.attributes.id
if (!id) { if (!id) {
id = options.where && +options.where.id id = options.where && +options.where.id
} }
@ -32,9 +32,11 @@ export default class Interface extends Model<Interface> {
id = arr[1].id id = arr[1].id
} }
} }
if (+id) { if ((id as any) instanceof Array) {
id = +id id = (id as any)[0]
const itf = await Interface.findById(id) }
if (id) {
const itf = await Interface.findByPk(id)
await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, itf.repositoryId) await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, itf.repositoryId)
} }
} }
@ -66,7 +68,7 @@ export default class Interface extends Model<Interface> {
@AllowNull(false) @AllowNull(false)
@Default(1) @Default(1)
@Column(DataType.BIGINT(11)) @Column(DataType.BIGINT())
priority: number priority: number
@Default(200) @Default(200)

@ -1,27 +1,27 @@
import { Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey, BeforeCreate, BeforeUpdate, BeforeDelete, BeforeBulkCreate, BeforeBulkDelete, BeforeBulkUpdate } from 'sequelize-typescript' import { Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey, BeforeCreate, BeforeUpdate, BeforeDestroy, BeforeBulkCreate, BeforeBulkDestroy, BeforeBulkUpdate } from 'sequelize-typescript'
import { User, Repository, Interface } from '../' import { User, Repository, Interface } from '../'
import RedisService, { CACHE_KEY } from '../../service/redis'; import RedisService, { CACHE_KEY } from '../../service/redis'
@Table({ paranoid: true, freezeTableName: false, timestamps: true }) @Table({ paranoid: true, freezeTableName: false, timestamps: true })
export default class Module extends Model<Module> { export default class Module extends Model<Module> {
/** hooks */ /** hooks */
@BeforeCreate @BeforeCreate
@BeforeUpdate @BeforeUpdate
@BeforeDelete @BeforeDestroy
static async deleteCache(instance: Interface) { static async deleteCache(instance: Interface) {
await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, instance.repositoryId) await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, instance.repositoryId)
} }
@BeforeBulkCreate @BeforeBulkCreate
@BeforeBulkUpdate @BeforeBulkUpdate
@BeforeBulkDelete @BeforeBulkDestroy
static async bulkDeleteCache(options: any) { static async bulkDeleteCache(options: any) {
let id: number = options && options.attributes && options.attributes.id let id: number = options && options.attributes && options.attributes.id
if (!id) { if (!id) {
id = options.where && +options.where.id id = options.where && +options.where.id
} }
if (id) { if (id) {
const mod = await Module.findById(id) const mod = await Module.findByPk(id)
await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, mod.repositoryId) await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, mod.repositoryId)
} }
} }
@ -42,7 +42,7 @@ export default class Module extends Model<Module> {
@AllowNull(false) @AllowNull(false)
@Default(1) @Default(1)
@Column(DataType.BIGINT(11)) @Column(DataType.BIGINT())
priority: number priority: number
@ForeignKey(() => User) @ForeignKey(() => User)

@ -2,7 +2,7 @@ import { Table, Column, Model, AutoIncrement, PrimaryKey, AllowNull, DataType, D
import { User, Interface, Module, Repository } from '../' import { User, Interface, Module, Repository } from '../'
export enum SCOPES { REQUEST = 'request', RESPONSE = 'response' } export enum SCOPES { REQUEST = 'request', RESPONSE = 'response' }
export enum TYPES { STRING = 'String', NUMBER = 'Number', BOOLEAN = 'Boolean', OBJECT = 'Object', ARRAY = 'Array', FUNCTION = 'Function', REGEXP = 'RegExp' } export enum TYPES { STRING = 'String', NUMBER = 'Number', BOOLEAN = 'Boolean', OBJECT = 'Object', ARRAY = 'Array', FUNCTION = 'Function', REGEXP = 'RegExp', Null = 'Null' }
export enum REQUEST_PARAMS_TYPE { export enum REQUEST_PARAMS_TYPE {
HEADERS = 1, HEADERS = 1,
@ -20,7 +20,7 @@ export default class Property extends Model<Property> {
@Column @Column
id: number id: number
static attributes: any; static attributes: any
@AllowNull(false) @AllowNull(false)
@ -65,7 +65,7 @@ export default class Property extends Model<Property> {
@AllowNull(false) @AllowNull(false)
@Default(1) @Default(1)
@Column(DataType.BIGINT(11)) @Column(DataType.BIGINT())
priority: number priority: number
@ForeignKey(() => Interface) @ForeignKey(() => Interface)

@ -1,4 +1,4 @@
import { Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, BelongsToMany, ForeignKey, BeforeUpdate, BeforeCreate, BeforeDelete, BeforeBulkCreate, BeforeBulkUpdate, BeforeBulkDelete } from 'sequelize-typescript' import { Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, BelongsToMany, ForeignKey, BeforeUpdate, BeforeCreate, BeforeDestroy, BeforeBulkCreate, BeforeBulkUpdate, BeforeBulkDestroy } from 'sequelize-typescript'
import { User, Organization, Module, Interface, RepositoriesCollaborators } from '../' import { User, Organization, Module, Interface, RepositoriesCollaborators } from '../'
import RedisService, { CACHE_KEY } from '../../service/redis' import RedisService, { CACHE_KEY } from '../../service/redis'
@ -8,14 +8,14 @@ export default class Repository extends Model<Repository> {
/** hooks */ /** hooks */
@BeforeCreate @BeforeCreate
@BeforeUpdate @BeforeUpdate
@BeforeDelete @BeforeDestroy
static async cleanCache(instance: Repository) { static async cleanCache(instance: Repository) {
await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, instance.id) await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, instance.id)
} }
@BeforeBulkCreate @BeforeBulkCreate
@BeforeBulkUpdate @BeforeBulkUpdate
@BeforeBulkDelete @BeforeBulkDestroy
static async bulkDeleteCache(options: any) { static async bulkDeleteCache(options: any) {
const id = options && options.attributes && options.attributes.id const id = options && options.attributes && options.attributes.id
if (id) { if (id) {

@ -1,22 +0,0 @@
import { Table, Column, Model, AutoIncrement, PrimaryKey, DataType, ForeignKey } from 'sequelize-typescript'
import { Repository } from '../'
@Table({ paranoid: true, freezeTableName: false, timestamps: false, tableName: 'foreign_room'})
export default class Room extends Model<Room> {
@AutoIncrement
@PrimaryKey
@Column
id: number
@ForeignKey(() => Repository)
@Column({type: DataType.BIGINT, comment: 'rap中的项目id'})
repositoryId: number
@Column({type: DataType.BIGINT, comment: 'room中的项目id'})
roomProjectId: number
@Column({comment: '项目域名'})
hostname: string
}

@ -10,4 +10,3 @@ export { default as User } from './bo/user'
export { default as OrganizationsMembers } from './bo/organizationsMembers' export { default as OrganizationsMembers } from './bo/organizationsMembers'
export { default as RepositoriesCollaborators } from './bo/repositoriesCollaborators' export { default as RepositoriesCollaborators } from './bo/repositoriesCollaborators'
export { default as RepositoriesMembers } from './bo/repositoriesMembers' export { default as RepositoriesMembers } from './bo/repositoriesMembers'
export { default as Room } from './bo/room'

@ -1,15 +1,15 @@
// TODO 2.2 如何缓存重复查询https://github.com/rfink/sequelize-redis-cache // TODO 2.2 如何缓存重复查询https://github.com/rfink/sequelize-redis-cache
import { Helper } from './helper' import { Helper } from './helper'
import User from '../bo/user'; import User from '../bo/user'
import Repository from '../bo/repository'; import Repository from '../bo/repository'
import Module from '../bo/module'; import Module from '../bo/module'
import Organization from '../bo/organization'; import Organization from '../bo/organization'
import Interface from '../bo/interface'; import Interface from '../bo/interface'
import Property from '../bo/property'; import Property from '../bo/property'
import { Model, IIncludeOptions } from 'sequelize-typescript'; import { IncludeOptions } from 'sequelize'
declare interface IQueryInclude { declare interface IQueryInclude {
[key: string]: typeof Model | IIncludeOptions [key: string]: IncludeOptions
} }
const QueryInclude: IQueryInclude = { const QueryInclude: IQueryInclude = {

@ -1,12 +1,15 @@
import * as svgCaptcha from 'svg-captcha' import * as svgCaptcha from 'svg-captcha'
import { User, Notification, Logger, Organization, Repository } from '../models' import { User, Notification, Logger, Organization, Repository } from '../models'
import router from './router' import router from './router'
import { Model, Sequelize } from 'sequelize-typescript'; import { Model } from 'sequelize-typescript'
import Pagination from './utils/pagination' import Pagination from './utils/pagination'
import { QueryInclude } from '../models' import { QueryInclude } from '../models'
import * as md5 from 'md5' import { Op } from 'sequelize'
import MailService from '../service/mail' import MailService from '../service/mail'
const Op = Sequelize.Op import * as md5 from 'md5'
router.get('/app/get', async (ctx, next) => { router.get('/app/get', async (ctx, next) => {
let data: any = {} let data: any = {}
@ -16,8 +19,8 @@ router.get('/app/get', async (ctx, next) => {
} }
for (let name in hooks) { for (let name in hooks) {
if (!query[name]) continue if (!query[name]) continue
data[name] = await hooks[name].findById(query[name], { data[name] = await hooks[name].findByPk(query[name], {
attributes: { exclude: [] }, attributes: { exclude: [] }
}) })
} }
ctx.body = { ctx.body = {
@ -38,9 +41,11 @@ router.get('/account/list', async (ctx) => {
let { name } = ctx.query let { name } = ctx.query
if (name) { if (name) {
Object.assign(where, { Object.assign(where, {
[Op.or]: [ [Op.or]: [{
{ fullname: { $like: `%${name}%` } }, fullname: {
], [Op.like]: `%${name}%`
},
}],
}) })
} }
let options = { where } let options = { where }
@ -61,9 +66,9 @@ router.get('/account/list', async (ctx) => {
router.get('/account/info', async (ctx) => { router.get('/account/info', async (ctx) => {
ctx.body = { ctx.body = {
data: ctx.session.id ? await User.findById(ctx.session.id, { data: ctx.session.id ? await User.findByPk(ctx.session.id, {
attributes: QueryInclude.User.attributes, attributes: QueryInclude.User.attributes
}) : undefined, }) : undefined
} }
}) })
@ -154,7 +159,7 @@ router.post('/account/update', async (ctx) => {
} else if (password.length < 6) { } else if (password.length < 6) {
errMsg = '密码长度过短' errMsg = '密码长度过短'
} else { } else {
const user = await User.findById(ctx.session.id) const user = await User.findByPk(ctx.session.id)
user.password = md5(md5(password)) user.password = md5(md5(password))
await user.save() await user.save()
isOk = true isOk = true
@ -244,7 +249,7 @@ router.get('/account/logger', async (ctx) => {
} }
return return
} }
let auth = await User.findById(ctx.session.id) let auth = await User.findByPk(ctx.session.id)
let repositories: Model<Repository>[] = [...(<Model<Repository>[]>await auth.$get('ownedRepositories')), ...(<Model<Repository>[]>await auth.$get('joinedRepositories'))] let repositories: Model<Repository>[] = [...(<Model<Repository>[]>await auth.$get('ownedRepositories')), ...(<Model<Repository>[]>await auth.$get('joinedRepositories'))]
let organizations: Model<Organization>[] = [...(<Model<Organization>[]>await auth.$get('ownedOrganizations')), ...(<Model<Organization>[]>await auth.$get('joinedOrganizations'))] let organizations: Model<Organization>[] = [...(<Model<Organization>[]>await auth.$get('ownedOrganizations')), ...(<Model<Organization>[]>await auth.$get('joinedOrganizations'))]

@ -1,7 +1,7 @@
import router from './router' import router from './router'
import Repository from "../models/bo/repository"; import Repository from "../models/bo/repository"
import Logger from "../models/bo/logger"; import Logger from "../models/bo/logger"
import User from "../models/bo/user"; import User from "../models/bo/user"
const moment = require('moment') const moment = require('moment')
const Sequelize = require('sequelize') const Sequelize = require('sequelize')
const SELECT = { type: Sequelize.QueryTypes.SELECT } const SELECT = { type: Sequelize.QueryTypes.SELECT }
@ -23,7 +23,7 @@ router.get('/app/analytics/repositories/created', async (ctx) => {
GROUP BY label GROUP BY label
ORDER BY label ASC; ORDER BY label ASC;
` `
let result = await sequelize.query(sql, SELECT) let result: any = await sequelize.query(sql, SELECT)
result = result.map((item: any) => ({ result = result.map((item: any) => ({
label: moment(item.label).format(YYYY_MM_DD), label: moment(item.label).format(YYYY_MM_DD),
value: item.value, value: item.value,
@ -48,7 +48,7 @@ router.get('/app/analytics/repositories/updated', async (ctx) => {
GROUP BY label GROUP BY label
ORDER BY label ASC; ORDER BY label ASC;
` `
let result = await sequelize.query(sql, SELECT) let result: any = await sequelize.query(sql, SELECT)
result = result.map((item: any) => ({ result = result.map((item: any) => ({
label: moment(item.label).format(YYYY_MM_DD), label: moment(item.label).format(YYYY_MM_DD),
value: item.value, value: item.value,

@ -1,170 +0,0 @@
import { Interface, QueryInclude, Room } from '../models'
import router from './router'
import Tree from './utils/tree'
import * as _ from 'underscore'
import { URL } from 'url'
import Helper from '../helpers/roomHelper'
const { mock } = require('mockjs')
router.get('/foreign/room', async (ctx, next) => {
let { repositoryId, roomProjectId } = ctx.query
if (!repositoryId && !roomProjectId) {
ctx.body = {
error: 'Need repositoryId or roomProjectId',
data: {},
}
return next()
}
let interfaceQuery = { roomProjectId, repositoryId }
!roomProjectId && delete interfaceQuery.roomProjectId
!repositoryId && delete interfaceQuery.repositoryId
let roomResult = await Room.findOne({
where: interfaceQuery,
})
let ret = {}
ctx.body = {
error: undefined,
data: ret,
}
if (!roomResult) {
ctx.body.error = 'Not found'
return next()
}
let interfaceResult = await Interface.findAll({
where: { repositoryId: roomResult.repositoryId },
})
// let {name, description} = repoResult;
Object.assign(ret, {
roomProjectId: roomResult.roomProjectId,
repositoryId: roomResult.repositoryId,
hostname: roomResult.hostname,
interfaces: interfaceResult.map(item => ({
url: item.url,
id: item.id,
})),
})
return next()
})
router.get('/foreign/room/params', async (ctx, next) => {
let {repositoryId, interfaceId, name} = ctx.query
if (!name || ['普通', '边界'].indexOf(name) === -1) {
name = '普通'
}
if (!ctx.session.empId) {
ctx.body = {
error: 'Need to login',
data: {},
}
}
if (!repositoryId) {
ctx.body = {
error: 'Need repositoryId',
data: {},
}
return next()
}
let [roomResult, theInterface] = await Promise.all([
Room.findOne({
where: { repositoryId },
}),
Interface.findOne({
where: { repositoryId, id: interfaceId },
include: [
QueryInclude.Properties,
],
} as any),
])
if (!theInterface) {
ctx.body.error = 'Cannot find interface corresponding to ' + interfaceId
return next()
}
let requestProperties = theInterface.properties.filter((item: any) => item.scope === 'request')
let responseProperties = theInterface.properties.filter((item: any) => item.scope === 'response')
let ret: any = {}
ctx.body = {
error: undefined,
data: ret,
}
if (!roomResult || !requestProperties.length) {
ctx.body.error = 'Not found'
return next()
}
let { roomProjectId, hostname } = roomResult
let cases = []
let standard = mock(Tree.ArrayToTreeToTemplate(requestProperties))
if (name === '普通') {
cases.push(standard)
} else if (name === '边界') {
for (let prop of requestProperties) {
let rules = Helper.generateRules(prop)
if (!rules) {
continue
}
// cases.push(standard)
for (let rule of rules) {
let obj = _.clone(standard)
obj[prop.name] = rule
Object.defineProperty(obj, '$type', {
value: rule['$type'],
})
cases.push(obj)
}
}
}
let moduleName = theInterface.name + '-自动' + name + '验证'
let path = new URL(theInterface.url, hostname).toString()
ret.module = {
moduleName: moduleName,
projectId: roomProjectId,
}
ret.cases = cases.map(function (theCase) {
let obj: any = {
caseDesc: theInterface.name + (theCase['$type'] || ''),
path: path + '?' + Helper.formatKV(theCase),
keyValue: JSON.stringify(theCase),
method: theInterface.method,
mode: 1, // 固定参数
moduleName: moduleName, // 冗余参数
// moduleId: moduleId,
projectId: roomProjectId,
rawData: '', // 天然为空
setUp: '', // 天然为空
tearDown: '', // 天然为空
userId: !ctx.session.empId ? '122033' : ctx.session.empId, // todo use empId
}
if (name === '普通') {
obj.expectResult = 'true_json'
obj.expectMessage = JSON.stringify(mock(Tree.ArrayToTreeToTemplate(responseProperties)))
} else if (name === '边界') {
obj.expectResult = 'false'
obj.expectMessage = 'error'
}
return obj
})
return next()
})
module.exports = router

@ -6,7 +6,7 @@ require('./organization')
require('./repository') require('./repository')
require('./mock') require('./mock')
require('./analytics') require('./analytics')
require('./foreign') // require('./foreign')
require('./postman') require('./postman')
export default router export default router

@ -1,16 +1,15 @@
import router from './router' import router from './router'
import { Repository, Interface, Property } from '../models' import { Repository, Interface, Property } from '../models'
import { QueryInclude } from '../models'; import { QueryInclude } from '../models'
import Tree from './utils/tree' import Tree from './utils/tree'
import urlUtils from './utils/url' import urlUtils from './utils/url'
import * as querystring from 'querystring' import * as querystring from 'querystring'
import { Sequelize } from 'sequelize-typescript';
import * as urlPkg from 'url' import * as urlPkg from 'url'
import { Op } from 'sequelize'
const attributes: any = { exclude: [] } const attributes: any = { exclude: [] }
const pt = require('node-print').pt const pt = require('node-print').pt
const beautify = require('js-beautify').js_beautify const beautify = require('js-beautify').js_beautify
const Op = Sequelize.Op
// 检测是否存在重复接口,会在返回的插件 JS 中提示。同时也会在编辑器中提示。 // 检测是否存在重复接口,会在返回的插件 JS 中提示。同时也会在编辑器中提示。
const parseDuplicatedInterfaces = (repository: Repository) => { const parseDuplicatedInterfaces = (repository: Repository) => {
@ -44,10 +43,10 @@ const generatePlugin = (protocol: any, host: any, repository: Repository) => {
let repositoryId = ${repository.id} let repositoryId = ${repository.id}
let interfaces = [ let interfaces = [
${repository.interfaces.map((itf: Interface) => ${repository.interfaces.map((itf: Interface) =>
`{ id: ${itf.id}, name: '${itf.name}', method: '${itf.method}', url: '${itf.url}', `{ id: ${itf.id}, name: '${itf.name}', method: '${itf.method}', url: '${itf.url}',
request: ${JSON.stringify(itf.request)}, request: ${JSON.stringify(itf.request)},
response: ${JSON.stringify(itf.response)} }`, response: ${JSON.stringify(itf.response)} }`
).join(',\n ')} ).join(',\n ')}
] ]
${duplicated.length ? `console.warn('检测到重复接口,请访问 ${editor} 修复警告!')\n` : ''} ${duplicated.length ? `console.warn('检测到重复接口,请访问 ${editor} 修复警告!')\n` : ''}
let RAP = window.RAP || { let RAP = window.RAP || {
@ -65,7 +64,7 @@ router.get('/app/plugin/:repositories', async (ctx) => {
let repositoryIds = new Set<number>(ctx.params.repositories.split(',').map((item: string) => +item).filter((item: any) => item)) // _.uniq() => Set let repositoryIds = new Set<number>(ctx.params.repositories.split(',').map((item: string) => +item).filter((item: any) => item)) // _.uniq() => Set
let result = [] let result = []
for (let id of repositoryIds) { for (let id of repositoryIds) {
let repository = await Repository.findById(id, { let repository = await Repository.findByPk(id, {
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [ include: [
QueryInclude.Creator, QueryInclude.Creator,
@ -136,7 +135,7 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => {
// KISSY 1.3.2 会把路径中的 // 替换为 /。在浏览器端拦截跨域请求时,需要 encodeURIComponent(url) 以防止 http:// 被替换为 http:/。但是同时也会把参数一起编码,导致 route 的 url 部分包含了参数。 // KISSY 1.3.2 会把路径中的 // 替换为 /。在浏览器端拦截跨域请求时,需要 encodeURIComponent(url) 以防止 http:// 被替换为 http:/。但是同时也会把参数一起编码,导致 route 的 url 部分包含了参数。
// 所以这里重新解析一遍!!! // 所以这里重新解析一遍!!!
let repository = await Repository.findById(repositoryId) let repository = await Repository.findByPk(repositoryId)
let collaborators: Repository[] = (await repository.$get('collaborators')) as Repository[] let collaborators: Repository[] = (await repository.$get('collaborators')) as Repository[]
let itf: Interface let itf: Interface
@ -180,8 +179,8 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => {
if (matchedItfList.length > 1) { if (matchedItfList.length > 1) {
matchedItfList = matchedItfList.filter(x => { matchedItfList = matchedItfList.filter(x => {
const params = { const params = {
... ctx.request.query, ...ctx.request.query,
...ctx.request.body, ...ctx.request.body,
} }
const parsedUrl = urlPkg.parse(x.url) const parsedUrl = urlPkg.parse(x.url)
const pairs = parsedUrl.query.split('&').map(x => x.split('=')) const pairs = parsedUrl.query.split('&').map(x => x.split('='))
@ -219,44 +218,44 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => {
} }
}) })
let listMatched = []; let listMatched = []
let relativeUrl = urlUtils.getRelative(url); let relativeUrl = urlUtils.getRelative(url)
for (let item of list) { for (let item of list) {
let regExp = urlUtils.getUrlPattern(item.url); // 获取地址匹配正则 let regExp = urlUtils.getUrlPattern(item.url) // 获取地址匹配正则
if (regExp.test(relativeUrl)) { // 检查地址是否匹配 if (regExp.test(relativeUrl)) { // 检查地址是否匹配
let regMatchLength = regExp.exec(relativeUrl).length; // 执行地址匹配 let regMatchLength = regExp.exec(relativeUrl).length // 执行地址匹配
if (listMatched[regMatchLength]) { // 检查匹配地址中是否具有同group数量的数据 if (listMatched[regMatchLength]) { // 检查匹配地址中是否具有同group数量的数据
ctx.body = { ctx.body = {
isOk: false, isOk: false,
errMsg: "匹配到多个同级别接口,请修改规则确保接口规则唯一性。" errMsg: "匹配到多个同级别接口,请修改规则确保接口规则唯一性。"
}; }
return; return
} }
listMatched[regMatchLength] = item; // 写入数据 listMatched[regMatchLength] = item // 写入数据
} }
} }
let loadDataId = 0; let loadDataId = 0
if (listMatched.length > 1) { if (listMatched.length > 1) {
for (let matchedItem of listMatched) { // 循环匹配内的数据 for (let matchedItem of listMatched) { // 循环匹配内的数据
if (matchedItem) { // 忽略为空的数据 if (matchedItem) { // 忽略为空的数据
loadDataId = matchedItem.id; // 设置需查询的id loadDataId = matchedItem.id // 设置需查询的id
break; break
} }
} }
} else if (listMatched.length === 0) { } else if (listMatched.length === 0) {
ctx.body = {isOk: false, errMsg: '未匹配到任何接口 No matched interface'} ctx.body = {isOk: false, errMsg: '未匹配到任何接口 No matched interface'}
return return
} else { } else {
loadDataId = listMatched[0].id; loadDataId = listMatched[0].id
} }
itf = itf = await Interface.findById(loadDataId); itf = itf = await Interface.findByPk(loadDataId)
} }
let interfaceId = itf.id let interfaceId = itf.id
let properties = await Property.findAll({ let properties: any = await Property.findAll({
attributes, attributes,
where: { interfaceId, scope: 'response' }, where: { interfaceId, scope: 'response' },
}) })
@ -269,6 +268,8 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => {
let passed = true let passed = true
let pFailed: Property | undefined let pFailed: Property | undefined
let params = method === 'GET' ? ctx.request.query : ctx.request.body let params = method === 'GET' ? ctx.request.query : ctx.request.body
// http request中head的参数未添加会造成head中的参数必填勾选后即使header中有值也会检查不通过
params = Object.assign(params, ctx.request.headers)
for (const p of requiredProperties) { for (const p of requiredProperties) {
if (typeof params[p.name] === 'undefined') { if (typeof params[p.name] === 'undefined') {
passed = false passed = false
@ -286,18 +287,19 @@ router.all('/app/mock/:repositoryId(\\d+)/:url(.+)', async (ctx) => {
} }
} }
properties = properties.map(item => item.toJSON()) properties = properties.map((item: any) => item.toJSON())
// DONE 2.2 支持引用请求参数 // DONE 2.2 支持引用请求参数
let requestProperties = await Property.findAll({ let requestProperties: any = await Property.findAll({
attributes, attributes,
where: { interfaceId, scope: 'request' }, where: { interfaceId, scope: 'request' },
}) })
requestProperties = requestProperties.map(item => item.toJSON()) requestProperties = requestProperties.map((item: any) => item.toJSON())
let requestData = Tree.ArrayToTreeToTemplateToData(requestProperties) let requestData = Tree.ArrayToTreeToTemplateToData(requestProperties)
Object.assign(requestData, ctx.query) Object.assign(requestData, ctx.query)
const data = Tree.ArrayToTreeToTemplateToData(properties, requestData) const data = Tree.ArrayToTreeToTemplateToData(properties, requestData)
ctx.type = 'json' ctx.type = 'json'
ctx.status = itf.status
ctx.body = JSON.stringify(data, undefined, 2) ctx.body = JSON.stringify(data, undefined, 2)
if (itf && itf.url.indexOf('[callback]=') > -1) { if (itf && itf.url.indexOf('[callback]=') > -1) {
const query = querystring.parse(itf.url.substring(itf.url.indexOf('?') + 1)) const query = querystring.parse(itf.url.substring(itf.url.indexOf('?') + 1))
@ -334,19 +336,19 @@ router.get('/app/mock/data/:interfaceId', async (ctx) => {
app.counter.mock++ app.counter.mock++
let { interfaceId } = ctx.params let { interfaceId } = ctx.params
let { scope = 'response' } = ctx.query let { scope = 'response' } = ctx.query
let properties = await Property.findAll({ let properties: any = await Property.findAll({
attributes, attributes,
where: { interfaceId, scope }, where: { interfaceId, scope },
}) })
properties = properties.map(item => item.toJSON()) properties = properties.map((item: any) => item.toJSON())
// pt(properties) // pt(properties)
// DONE 2.2 支持引用请求参数 // DONE 2.2 支持引用请求参数
let requestProperties = await Property.findAll({ let requestProperties: any = await Property.findAll({
attributes, attributes,
where: { interfaceId, scope: 'request' }, where: { interfaceId, scope: 'request' },
}) })
requestProperties = requestProperties.map(item => item.toJSON()) requestProperties = requestProperties.map((item: any) => item.toJSON())
let requestData = Tree.ArrayToTreeToTemplateToData(requestProperties) let requestData = Tree.ArrayToTreeToTemplateToData(requestProperties)
Object.assign(requestData, ctx.query) Object.assign(requestData, ctx.query)
@ -363,12 +365,12 @@ router.get('/app/mock/schema/:interfaceId', async (ctx) => {
app.counter.mock++ app.counter.mock++
let { interfaceId } = ctx.params let { interfaceId } = ctx.params
let { scope = 'response' } = ctx.query let { scope = 'response' } = ctx.query
let properties = await Property.findAll({ let properties: any = await Property.findAll({
attributes, attributes,
where: { interfaceId, scope }, where: { interfaceId, scope },
}) })
pt(properties.map(item => item.toJSON())) pt(properties.map((item: any) => item.toJSON()))
properties = properties.map(item => item.toJSON()) properties = properties.map((item: any) => item.toJSON())
let schema = Tree.ArrayToTreeToTemplateToJSONSchema(properties) let schema = Tree.ArrayToTreeToTemplateToJSONSchema(properties)
ctx.type = 'json' ctx.type = 'json'
ctx.body = Tree.stringifyWithFunctonAndRegExp(schema) ctx.body = Tree.stringifyWithFunctonAndRegExp(schema)
@ -379,12 +381,12 @@ router.get('/app/mock/tree/:interfaceId', async (ctx) => {
app.counter.mock++ app.counter.mock++
let { interfaceId } = ctx.params let { interfaceId } = ctx.params
let { scope = 'response' } = ctx.query let { scope = 'response' } = ctx.query
let properties = await Property.findAll({ let properties: any = await Property.findAll({
attributes, attributes,
where: { interfaceId, scope }, where: { interfaceId, scope },
}) })
pt(properties.map(item => item.toJSON())) pt(properties.map((item: any) => item.toJSON()))
properties = properties.map(item => item.toJSON()) properties = properties.map((item: any) => item.toJSON())
let tree = Tree.ArrayToTree(properties) let tree = Tree.ArrayToTree(properties)
ctx.type = 'json' ctx.type = 'json'
ctx.body = Tree.stringifyWithFunctonAndRegExp(tree) ctx.body = Tree.stringifyWithFunctonAndRegExp(tree)

@ -1,11 +1,10 @@
import router from './router' import router from './router'
import { Organization, User, Logger, Repository, Module, Interface, Property } from '../models' import { Organization, User, Logger, Repository, Module, Interface, Property } from '../models'
import { QueryInclude } from '../models'; import { QueryInclude } from '../models'
import * as _ from 'lodash' import * as _ from 'lodash'
import Pagination from './utils/pagination' import Pagination from './utils/pagination'
import { Op } from 'sequelize';
import OrganizationService from '../service/organization' import OrganizationService from '../service/organization'
import { IFindOptions } from 'sequelize-typescript'; import { Op, FindOptions } from 'sequelize'
router.get('/app/get', async (ctx, next) => { router.get('/app/get', async (ctx, next) => {
let data: any = {} let data: any = {}
@ -15,8 +14,8 @@ router.get('/app/get', async (ctx, next) => {
} }
for (let name in hooks) { for (let name in hooks) {
if (!query[name]) continue if (!query[name]) continue
data[name] = await hooks[name].findById(query[name], { data[name] = await hooks[name].findByPk(query[name], {
attributes: { exclude: [] }, attributes: { exclude: [] }
}) })
} }
ctx.body = { ctx.body = {
@ -38,8 +37,12 @@ router.get('/organization/list', async (ctx) => {
const total = await OrganizationService.getAllOrganizationIdListNum(curUserId) const total = await OrganizationService.getAllOrganizationIdListNum(curUserId)
const pagination = new Pagination(total, ctx.query.cursor || 1, ctx.query.limit || 100) const pagination = new Pagination(total, ctx.query.cursor || 1, ctx.query.limit || 100)
const organizationIds = await OrganizationService.getAllOrganizationIdList(curUserId, pagination, name) const organizationIds = await OrganizationService.getAllOrganizationIdList(curUserId, pagination, name)
const options: IFindOptions<Organization> = { const options: FindOptions = {
where: { id: { [Op.in]: organizationIds } }, where: {
id: {
[Op.in]: organizationIds,
},
},
include: [ include: [
QueryInclude.Creator, QueryInclude.Creator,
QueryInclude.Owner, QueryInclude.Owner,
@ -74,7 +77,7 @@ router.get('/organization/owned', async (ctx) => {
}) })
} }
let auth = await User.findById(ctx.session.id) let auth = await User.findByPk(ctx.session.id)
let options: any = { let options: any = {
where, where,
attributes: { exclude: [] }, attributes: { exclude: [] },
@ -108,7 +111,7 @@ router.get('/organization/joined', async (ctx) => {
}) })
} }
let auth = await User.findById(ctx.session.id) let auth = await User.findByPk(ctx.session.id)
let options: object = { let options: object = {
where, where,
attributes: { exclude: [] }, attributes: { exclude: [] },
@ -124,7 +127,7 @@ router.get('/organization/joined', async (ctx) => {
} }
}) })
router.get('/organization/get', async (ctx) => { router.get('/organization/get', async (ctx) => {
let organization = await Organization.findById(ctx.query.id, { let organization = await Organization.findByPk(ctx.query.id, {
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members], include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members],
} as any) } as any)
@ -140,7 +143,7 @@ router.post('/organization/create', async (ctx) => {
let members = await User.findAll({ where: { id: body.memberIds } }) let members = await User.findAll({ where: { id: body.memberIds } })
await created.$set('members', members) await created.$set('members', members)
} }
let filled = await Organization.findById(created.id, { let filled = await Organization.findByPk(created.id, {
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members], include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members],
} as any) } as any)
@ -155,7 +158,7 @@ router.post('/organization/update', async (ctx, next) => {
// delete body.ownerId // delete body.ownerId
let updated = await Organization.update(body, { where: { id: body.id } }) let updated = await Organization.update(body, { where: { id: body.id } })
if (body.memberIds) { if (body.memberIds) {
let reloaded = await Organization.findById(body.id) let reloaded = await Organization.findByPk(body.id)
let members = await User.findAll({ where: { id: body.memberIds } }) let members = await User.findAll({ where: { id: body.memberIds } })
ctx.prevAssociations = await reloaded.$get('members') ctx.prevAssociations = await reloaded.$get('members')
await reloaded.$set('members', members) await reloaded.$set('members', members)

@ -3,15 +3,14 @@ import router from './router'
import * as _ from 'underscore' import * as _ from 'underscore'
import Pagination from './utils/pagination' import Pagination from './utils/pagination'
import { User, Organization, Repository, Module, Interface, Property, QueryInclude, Logger } from '../models' import { User, Organization, Repository, Module, Interface, Property, QueryInclude, Logger } from '../models'
import { Sequelize } from 'sequelize-typescript'
import Tree from './utils/tree' import Tree from './utils/tree'
import { AccessUtils, ACCESS_TYPE } from './utils/access' import { AccessUtils, ACCESS_TYPE } from './utils/access'
import * as Consts from './utils/const' import * as Consts from './utils/const'
import RedisService, { CACHE_KEY } from '../service/redis' import RedisService, { CACHE_KEY } from '../service/redis'
import MigrateService from '../service/migrate'; import MigrateService from '../service/migrate'
import { Op } from 'sequelize'
const { initRepository, initModule } = require('./utils/helper') const { initRepository, initModule } = require('./utils/helper')
const Op = Sequelize.Op
router.get('/app/get', async (ctx, next) => { router.get('/app/get', async (ctx, next) => {
let data: any = {} let data: any = {}
@ -24,7 +23,7 @@ router.get('/app/get', async (ctx, next) => {
} }
for (let name in hooks) { for (let name in hooks) {
if (!query[name]) continue if (!query[name]) continue
data[name] = await hooks[name].findById(query[name]) data[name] = await hooks[name].findByPk(query[name])
} }
ctx.body = { ctx.body = {
data: Object.assign({}, ctx.body && ctx.body.data, data), data: Object.assign({}, ctx.body && ctx.body.data, data),
@ -109,13 +108,7 @@ router.get('/repository/owned', async (ctx) => {
}) })
} }
let auth: User = await User.findById(ctx.query.user || ctx.session.id) let auth: User = await User.findByPk(ctx.query.user || ctx.session.id)
if (!auth) {
ctx.body = {
isOk: false,
errMsg: '登陆过期了,请重新登陆。',
}
}
// let total = await auth.countOwnedRepositories({ where }) // let total = await auth.countOwnedRepositories({ where })
// let pagination = new Pagination(total, ctx.query.cursor || 1, ctx.query.limit || 100) // let pagination = new Pagination(total, ctx.query.cursor || 1, ctx.query.limit || 100)
let repositories = await auth.$get('ownedRepositories', { let repositories = await auth.$get('ownedRepositories', {
@ -149,7 +142,7 @@ router.get('/repository/joined', async (ctx) => {
}) })
} }
let auth = await User.findById(ctx.query.user || ctx.session.id) let auth = await User.findByPk(ctx.query.user || ctx.session.id)
// let total = await auth.countJoinedRepositories({ where }) // let total = await auth.countJoinedRepositories({ where })
// let pagination = new Pagination(total, ctx.query.cursor || 1, ctx.query.limit || 100) // let pagination = new Pagination(total, ctx.query.cursor || 1, ctx.query.limit || 100)
let repositories = await auth.$get('joinedRepositories', { let repositories = await auth.$get('joinedRepositories', {
@ -185,11 +178,9 @@ router.get('/repository/get', async (ctx) => {
const tryCache = await RedisService.getCache(CACHE_KEY.REPOSITORY_GET, ctx.query.id) const tryCache = await RedisService.getCache(CACHE_KEY.REPOSITORY_GET, ctx.query.id)
let repository: Repository let repository: Repository
if (tryCache) { if (tryCache) {
console.log(`from cache`)
repository = JSON.parse(tryCache) repository = JSON.parse(tryCache)
} else { } else {
console.log(`from db`) repository = await Repository.findByPk(ctx.query.id, {
repository = await Repository.findById(ctx.query.id, {
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [ include: [
QueryInclude.Creator, QueryInclude.Creator,
@ -203,7 +194,7 @@ router.get('/repository/get', async (ctx) => {
order: [ order: [
[{ model: Module, as: 'modules' }, 'priority', 'asc'], [{ model: Module, as: 'modules' }, 'priority', 'asc'],
[{ model: Module, as: 'modules' }, { model: Interface, as: 'interfaces' }, 'priority', 'asc'] [{ model: Module, as: 'modules' }, { model: Interface, as: 'interfaces' }, 'priority', 'asc']
] ] as any
}) })
await RedisService.setCache(CACHE_KEY.REPOSITORY_GET, JSON.stringify(repository), ctx.query.id) await RedisService.setCache(CACHE_KEY.REPOSITORY_GET, JSON.stringify(repository), ctx.query.id)
} }
@ -226,7 +217,7 @@ router.post('/repository/create', async (ctx, next) => {
} }
await initRepository(created) await initRepository(created)
ctx.body = { ctx.body = {
data: await Repository.findById(created.id, { data: await Repository.findByPk(created.id, {
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [ include: [
QueryInclude.Creator, QueryInclude.Creator,
@ -255,7 +246,7 @@ router.post('/repository/update', async (ctx, next) => {
delete body.organizationId delete body.organizationId
let result = await Repository.update(body, { where: { id: body.id } }) let result = await Repository.update(body, { where: { id: body.id } })
if (body.memberIds) { if (body.memberIds) {
let reloaded = await Repository.findById(body.id, { let reloaded = await Repository.findByPk(body.id, {
include: [{ include: [{
model: User, model: User,
as: 'members', as: 'members',
@ -274,7 +265,7 @@ router.post('/repository/update', async (ctx, next) => {
ctx.nextAssociations = reloaded.members ctx.nextAssociations = reloaded.members
} }
if (body.collaboratorIds) { if (body.collaboratorIds) {
let reloaded = await Repository.findById(body.id) let reloaded = await Repository.findByPk(body.id)
let collaborators = await Repository.findAll({ let collaborators = await Repository.findAll({
where: { where: {
id: { id: {
@ -316,7 +307,7 @@ router.post('/repository/transfer', async (ctx) => {
if (ownerId) body.ownerId = ownerId // 转移给其他用户 if (ownerId) body.ownerId = ownerId // 转移给其他用户
if (organizationId) { if (organizationId) {
body.organizationId = organizationId // 转移给其他团队,同时转移给该团队拥有者 body.organizationId = organizationId // 转移给其他团队,同时转移给该团队拥有者
body.ownerId = (await Organization.findById(organizationId)).ownerId body.ownerId = (await Organization.findByPk(organizationId)).ownerId
} }
let result = await Repository.update(body, { where: { id } }) let result = await Repository.update(body, { where: { id } })
ctx.body = { ctx.body = {
@ -389,9 +380,9 @@ router.get('/module/list', async (ctx) => {
}) })
router.get('/module/get', async (ctx) => { router.get('/module/get', async (ctx) => {
ctx.body = { ctx.body = {
data: await Module.findById(ctx.query.id, { data: await Module.findByPk(ctx.query.id, {
attributes: { exclude: [] }, attributes: { exclude: [] }
}), })
} }
}) })
router.post('/module/create', async (ctx, next) => { router.post('/module/create', async (ctx, next) => {
@ -401,7 +392,7 @@ router.post('/module/create', async (ctx, next) => {
let created = await Module.create(body) let created = await Module.create(body)
await initModule(created) await initModule(created)
ctx.body = { ctx.body = {
data: await Module.findById(created.id), data: await Module.findByPk(created.id)
} }
return next() return next()
}, async (ctx) => { }, async (ctx) => {
@ -447,7 +438,7 @@ router.get('/module/remove', async (ctx, next) => {
}, async (ctx) => { }, async (ctx) => {
if (ctx.body.data === 0) return if (ctx.body.data === 0) return
let { id } = ctx.query let { id } = ctx.query
let mod = await Module.findById(id, { paranoid: false }) let mod = await Module.findByPk(id, { paranoid: false })
await Logger.create({ await Logger.create({
userId: ctx.session.id, userId: ctx.session.id,
type: 'delete', type: 'delete',
@ -464,7 +455,7 @@ router.post('/module/sort', async (ctx) => {
}) })
} }
if (ids && ids.length) { if (ids && ids.length) {
const mod = await Module.findById(ids[0]) const mod = await Module.findByPk(ids[0])
await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, mod.repositoryId) await RedisService.delCache(CACHE_KEY.REPOSITORY_GET, mod.repositoryId)
} }
ctx.body = { ctx.body = {
@ -494,15 +485,15 @@ router.get('/interface/list', async (ctx) => {
router.get('/interface/get', async (ctx) => { router.get('/interface/get', async (ctx) => {
let { id, repositoryId, method, url } = ctx.query let { id, repositoryId, method, url } = ctx.query
let itf let itf: any
if (id) { if (id) {
itf = await Interface.findById(id, { itf = await Interface.findByPk(id, {
attributes: { exclude: [] }, attributes: { exclude: [] }
}) })
} else if (repositoryId && method && url) { } else if (repositoryId && method && url) {
// 同 /app/mock/:repository/:method/:url // 同 /app/mock/:repository/:method/:url
let urlWithoutPrefixSlash = /(\/)?(.*)/.exec(url)[2] let urlWithoutPrefixSlash = /(\/)?(.*)/.exec(url)[2]
let repository = await Repository.findById(repositoryId) let repository = await Repository.findByPk(repositoryId)
let collaborators = await repository.$get('collaborators') let collaborators = await repository.$get('collaborators')
itf = await Interface.findOne({ itf = await Interface.findOne({
@ -518,11 +509,11 @@ router.get('/interface/get', async (ctx) => {
let scopes = ['request', 'response'] let scopes = ['request', 'response']
for (let i = 0; i < scopes.length; i++) { for (let i = 0; i < scopes.length; i++) {
let properties = await Property.findAll({ let properties: any = await Property.findAll({
attributes: { exclude: [] }, attributes: { exclude: [] },
where: { interfaceId: itf.id, scope: scopes[i] }, where: { interfaceId: itf.id, scope: scopes[i] },
}) })
properties = properties.map(item => item.toJSON()) properties = properties.map((item: any) => item.toJSON())
itf[scopes[i] + 'Properties'] = Tree.ArrayToTree(properties).children itf[scopes[i] + 'Properties'] = Tree.ArrayToTree(properties).children
} }
@ -537,7 +528,7 @@ router.post('/interface/create', async (ctx, next) => {
// await initInterface(created) // await initInterface(created)
ctx.body = { ctx.body = {
data: { data: {
itf: await Interface.findById(created.id), itf: await Interface.findByPk(created.id),
} }
} }
return next() return next()
@ -559,7 +550,7 @@ router.post('/interface/update', async (ctx, next) => {
}) })
ctx.body = { ctx.body = {
data: { data: {
itf: await Interface.findById(body.id), itf: await Interface.findByPk(body.id),
} }
} }
return next() return next()
@ -579,19 +570,19 @@ router.post('/interface/move', async (ctx) => {
const OP_MOVE = 1 const OP_MOVE = 1
const OP_COPY = 2 const OP_COPY = 2
const { modId, itfId, op } = ctx.request.body const { modId, itfId, op } = ctx.request.body
const itf = await Interface.findById(itfId) const itf = await Interface.findByPk(itfId)
if (op === OP_MOVE) { if (op === OP_MOVE) {
itf.moduleId = modId itf.moduleId = modId
await Property.update({ await Property.update({
moduleId: modId, moduleId: modId,
}, { }, {
where: { where: {
interfaceId: itf.id, interfaceId: itf.id,
} }
}) })
await itf.save() await itf.save()
} else if (op === OP_COPY) { } else if (op === OP_COPY) {
const { id, name, ...otherProps } = itf.dataValues const { id, name, ...otherProps } = itf.toJSON() as Interface
const newItf = await Interface.create({ const newItf = await Interface.create({
name: name + '副本', name: name + '副本',
...otherProps, ...otherProps,
@ -601,16 +592,26 @@ router.post('/interface/move', async (ctx) => {
const properties = await Property.findAll({ const properties = await Property.findAll({
where: { where: {
interfaceId: itf.id, interfaceId: itf.id,
} },
order: [['parentId', 'asc']],
}) })
// 解决parentId丢失的问题
let idMap = {}
for (const property of properties) { for (const property of properties) {
const { id, ...props } = property.dataValues const { id, parentId, ...props } = property.toJSON() as Property
await Property.create({ // @ts-ignore
const newParentId = idMap[parentId + ''] ? idMap[parentId + ''] : -1
const newProperty = await Property.create({
...props, ...props,
interfaceId: newItf.id, interfaceId: newItf.id,
parentId: newParentId,
moduleId: modId, moduleId: modId,
}) })
// @ts-ignore
idMap[id + ''] = newProperty.id
} }
} }
ctx.body = { ctx.body = {
data: { data: {
@ -630,7 +631,7 @@ router.get('/interface/remove', async (ctx, next) => {
}, async (ctx) => { }, async (ctx) => {
if (ctx.body.data === 0) return if (ctx.body.data === 0) return
let { id } = ctx.query let { id } = ctx.query
let itf = await Interface.findById(id, { paranoid: false }) let itf = await Interface.findByPk(id, { paranoid: false })
await Logger.create({ await Logger.create({
userId: ctx.session.id, userId: ctx.session.id,
type: 'delete', type: 'delete',
@ -641,7 +642,7 @@ router.get('/interface/remove', async (ctx, next) => {
}) })
router.get('/__test__', async (ctx) => { router.get('/__test__', async (ctx) => {
const itf = await Interface.findById(5331) const itf = await Interface.findByPk(5331)
itf.name = itf.name + '+' itf.name = itf.name + '+'
await itf.save() await itf.save()
ctx.body = { ctx.body = {
@ -656,7 +657,7 @@ router.post('/interface/lock', async (ctx, next) => {
} }
let { id } = ctx.request.body let { id } = ctx.request.body
let itf = await Interface.findById(id, { let itf = await Interface.findByPk(id, {
attributes: ['lockerId'], attributes: ['lockerId'],
include: [ include: [
QueryInclude.Locker, QueryInclude.Locker,
@ -670,7 +671,7 @@ router.post('/interface/lock', async (ctx, next) => {
} }
await Interface.update({ lockerId: ctx.session.id }, { where: { id } }) await Interface.update({ lockerId: ctx.session.id }, { where: { id } })
itf = await Interface.findById(id, { itf = await Interface.findByPk(id, {
attributes: ['lockerId'], attributes: ['lockerId'],
include: [ include: [
QueryInclude.Locker, QueryInclude.Locker,
@ -689,7 +690,7 @@ router.post('/interface/unlock', async (ctx) => {
} }
let { id } = ctx.request.body let { id } = ctx.request.body
let itf = await Interface.findById(id, { attributes: ['lockerId'] }) let itf = await Interface.findByPk(id, { attributes: ['lockerId'] })
if (itf.lockerId !== ctx.session.id) { // DONE 2.3 BUG 接口可能被其他人解锁。如果不是同一个用户,则忽略。 if (itf.lockerId !== ctx.session.id) { // DONE 2.3 BUG 接口可能被其他人解锁。如果不是同一个用户,则忽略。
ctx.body = { ctx.body = {
isOk: false, isOk: false,
@ -745,9 +746,9 @@ router.get('/property/list', async (ctx) => {
router.get('/property/get', async (ctx) => { router.get('/property/get', async (ctx) => {
let { id } = ctx.query let { id } = ctx.query
ctx.body = { ctx.body = {
data: await Property.findById(id, { data: await Property.findByPk(id, {
attributes: { exclude: [] }, attributes: { exclude: [] }
}), })
} }
}) })
@ -756,9 +757,9 @@ router.post('/property/create', async (ctx) => {
let body = Object.assign(ctx.request.body, { creatorId }) let body = Object.assign(ctx.request.body, { creatorId })
let created = await Property.create(body) let created = await Property.create(body)
ctx.body = { ctx.body = {
data: await Property.findById(created.id, { data: await Property.findByPk(created.id, {
attributes: { exclude: [] }, attributes: { exclude: [] }
}), })
} }
}) })
@ -767,7 +768,7 @@ router.post('/property/update', async (ctx) => {
properties = Array.isArray(properties) ? properties : [properties] properties = Array.isArray(properties) ? properties : [properties]
let result = 0 let result = 0
for (let item of properties) { for (let item of properties) {
let property = _.pick(item, Object.keys(Property.attributes)) let property = _.pick(item, Object.keys(Property.rawAttributes))
let affected = await Property.update(property, { let affected = await Property.update(property, {
where: { id: property.id }, where: { id: property.id },
}) })
@ -783,7 +784,7 @@ router.post('/properties/update', async (ctx, next) => {
let { properties, summary } = ctx.request.body // JSON.parse(ctx.request.body) let { properties, summary } = ctx.request.body // JSON.parse(ctx.request.body)
properties = Array.isArray(properties) ? properties : [properties] properties = Array.isArray(properties) ? properties : [properties]
let itf = await Interface.findById(itfId) let itf = await Interface.findByPk(itfId)
if (summary.name) { if (summary.name) {
itf.name = summary.name itf.name = summary.name
@ -848,7 +849,7 @@ router.post('/properties/update', async (ctx, next) => {
where: { id: item.id }, where: { id: item.id },
}) })
} }
itf = await Interface.findById(itfId, { itf = await Interface.findByPk(itfId, {
include: (QueryInclude.RepositoryHierarchy as any).include[0].include, include: (QueryInclude.RepositoryHierarchy as any).include[0].include,
}) })
ctx.body = { ctx.body = {
@ -860,8 +861,8 @@ router.post('/properties/update', async (ctx, next) => {
return next() return next()
}, async (ctx) => { }, async (ctx) => {
if (ctx.body.data === 0) return if (ctx.body.data === 0) return
let itf = await Interface.findById(ctx.query.itf, { let itf = await Interface.findByPk(ctx.query.itf, {
attributes: { exclude: [] }, attributes: { exclude: [] }
}) })
await Logger.create({ await Logger.create({
userId: ctx.session.id, userId: ctx.session.id,

@ -1,4 +1,4 @@
import { Property } from "../../models"; import { Property } from "../../models"
import * as _ from 'underscore' import * as _ from 'underscore'
const vm = require('vm') const vm = require('vm')
import * as Mock from 'mockjs' import * as Mock from 'mockjs'

@ -20,7 +20,7 @@ app.use(session({
if (process.env.NODE_ENV === 'development' && process.env.TEST_MODE !== 'true') app.use(logger()) if (process.env.NODE_ENV === 'development' && process.env.TEST_MODE !== 'true') app.use(logger())
app.use(async (ctx, next) => { app.use(async (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', '*'); ctx.set('Access-Control-Allow-Origin', '*')
ctx.set('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS') ctx.set('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS')
ctx.set('Access-Control-Allow-Credentials', 'true') ctx.set('Access-Control-Allow-Credentials', 'true')
await next() await next()

@ -1,5 +1,5 @@
import sequelize from '../../models/sequelize' import sequelize from '../../models/sequelize'
import { User, Organization, Repository, Module, Interface, Property, Room } from '../../models/index' import { User, Organization, Repository, Module, Interface, Property } from '../../models/index'
import { BO_ADMIN, BO_MOZHI } from './bo' import { BO_ADMIN, BO_MOZHI } from './bo'
import { BO_USER_FN, BO_ORGANIZATION_FN, BO_REPOSITORY_FN, BO_MODULE_FN, BO_INTERFACE_FN, BO_PROPERTY_FN } from './bo' import { BO_USER_FN, BO_ORGANIZATION_FN, BO_REPOSITORY_FN, BO_MODULE_FN, BO_INTERFACE_FN, BO_PROPERTY_FN } from './bo'
import { BO_USER_COUNT, BO_ORGANIZATION_COUNT, BO_REPOSITORY_COUNT, BO_MODULE_COUNT, BO_INTERFACE_COUNT, BO_PROPERTY_COUNT } from './bo' import { BO_USER_COUNT, BO_ORGANIZATION_COUNT, BO_REPOSITORY_COUNT, BO_MODULE_COUNT, BO_INTERFACE_COUNT, BO_PROPERTY_COUNT } from './bo'
@ -12,7 +12,6 @@ export async function init () {
force: true, force: true,
logging: console.log, logging: console.log,
}) })
await Room.destroy(EMPTY_WHERE)
await User.destroy(EMPTY_WHERE) await User.destroy(EMPTY_WHERE)
await Organization.destroy(EMPTY_WHERE) await Organization.destroy(EMPTY_WHERE)
await Repository.destroy(EMPTY_WHERE) await Repository.destroy(EMPTY_WHERE)
@ -134,12 +133,12 @@ export async function after () {
// console.log(JSON.stringify(repositories, null, 2)) // console.log(JSON.stringify(repositories, null, 2))
console.log(repositories.map(item => item.toJSON())) console.log(repositories.map(item => item.toJSON()))
let admin = await User.findById(BO_ADMIN.id) let admin = await User.findByPk(BO_ADMIN.id)
// for (let k in admin) console.log(k) // for (let k in admin) console.log(k)
let owned: any = await admin.$get('ownedOrganizations') let owned: any = await admin.$get('ownedOrganizations')
console.log(owned.map((item: any) => item.toJSON())) console.log(owned.map((item: any) => item.toJSON()))
let mozhi = await User.findById(BO_MOZHI.id) let mozhi = await User.findByPk(BO_MOZHI.id)
for (let k in mozhi) console.log(k) for (let k in mozhi) console.log(k)
let joined: any = await mozhi.$get('joinedOrganizations') let joined: any = await mozhi.$get('joinedOrganizations')
console.log(joined.map((item: any) => item.toJSON())) console.log(joined.map((item: any) => item.toJSON()))

@ -293,22 +293,6 @@ CREATE TABLE `users` (
) COMMENT='用户'; ) COMMENT='用户';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
--
-- Table structure for table `foreign_room`
--
DROP TABLE IF EXISTS `foreign_room`;
CREATE TABLE `foreign_room` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`repositoryId` bigint(11) unsigned DEFAULT NULL COMMENT '-',
`roomProjectId` bigint(11) unsigned DEFAULT NULL COMMENT '-',
PRIMARY KEY (`id`),
KEY `idx_repositoryId` (`repositoryId`),
KEY `idx_roomProjectId` (`roomProjectId`),
CONSTRAINT `interfaces_1` FOREIGN KEY (`repositoryId`) REFERENCES `repositories` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;

@ -6,7 +6,7 @@ export default class MailService {
public static send(to: string, subject: string, html: string) { public static send(to: string, subject: string, html: string) {
nodemailer.createTestAccount((_err, _account) => { nodemailer.createTestAccount((_err, _account) => {
const transporter = nodemailer.createTransport(config.mail); const transporter = nodemailer.createTransport(config.mail)
// setup email data with unicode symbols // setup email data with unicode symbols
const mailOptions = { const mailOptions = {
@ -14,7 +14,7 @@ export default class MailService {
to, to,
subject, subject,
html, html,
}; }
// send mail with defined transport object // send mail with defined transport object
transporter.sendMail(mailOptions) transporter.sendMail(mailOptions)

@ -1,5 +1,5 @@
import { Repository, Module, Interface, Property, User } from "../models"; import { Repository, Module, Interface, Property, User } from "../models"
import { SCOPES } from "../models/bo/property"; import { SCOPES } from "../models/bo/property"
import * as md5 from 'md5' import * as md5 from 'md5'
import * as querystring from 'querystring' import * as querystring from 'querystring'
import * as rp from 'request-promise' import * as rp from 'request-promise'

@ -1,7 +1,6 @@
import seq from '../models/sequelize' import seq from '../models/sequelize'
import Pagination from '../routes/utils/pagination' import Pagination from '../routes/utils/pagination'
import Utils from './utils'; import Utils from './utils'
export default class OrganizationService { export default class OrganizationService {
public static canUserAccessOrganization(userId: number, organizationId: number): Promise<boolean> { public static canUserAccessOrganization(userId: number, organizationId: number): Promise<boolean> {
const sql = ` const sql = `

@ -1,14 +1,14 @@
import { PostmanCollection, Folder, Item } from "../types/postman" import { PostmanCollection, Folder, Item } from "../types/postman"
import { Repository, Interface, Module, Property } from "../models" import { Repository, Interface, Module, Property } from "../models"
import * as url from 'url' import * as url from 'url'
import { REQUEST_PARAMS_TYPE } from "../models/bo/property"; import { REQUEST_PARAMS_TYPE } from "../models/bo/property"
import UrlUtils from "../routes/utils/url" import UrlUtils from "../routes/utils/url"
const SCHEMA_V_2_1_0 = 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json' const SCHEMA_V_2_1_0 = 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
export default class PostmanService { export default class PostmanService {
public static async export(repositoryId: number): Promise<PostmanCollection> { public static async export(repositoryId: number): Promise<PostmanCollection> {
const repo = await Repository.findById(repositoryId, { const repo = await Repository.findByPk(repositoryId, {
include: [{ include: [{
model: Module, model: Module,
as: 'modules', as: 'modules',

@ -1,9 +1,9 @@
import { Repository, RepositoriesMembers } from "../models" import { Repository, RepositoriesMembers } from "../models"
import OrganizationService from "./organization"; import OrganizationService from "./organization"
export default class RepositoryService { export default class RepositoryService {
public static async canUserAccessRepository(userId: number, repositoryId: number): Promise<boolean> { public static async canUserAccessRepository(userId: number, repositoryId: number): Promise<boolean> {
const repo = await Repository.findById(repositoryId) const repo = await Repository.findByPk(repositoryId)
if (!repo) return false if (!repo) return false
if (repo.creatorId === userId || repo.ownerId === userId) return true if (repo.creatorId === userId || repo.ownerId === userId) return true
const memberExistsNum = await RepositoriesMembers.count({ const memberExistsNum = await RepositoriesMembers.count({

@ -1 +1 @@
declare module 'ioredis'; declare module 'ioredis'

@ -1,26 +1,27 @@
/// <reference path="custom-typings.d.ts" /> /// <reference path="custom-typings.d.ts" />
import { PoolOptions } from "sequelize"; import { PoolOptions } from "sequelize"
import { ISequelizeConfig } from "sequelize-typescript"; import { ISequelizeConfig } from "sequelize-typescript"
import { RedisOptions } from "koa-redis"; import { RedisOptions } from "koa-redis"
import { PoolOptions } from "sequelize"
declare interface RedisAndClusterOptions extends RedisOptions { declare interface RedisAndClusterOptions extends RedisOptions {
isRedisCluster?: boolean; isRedisCluster?: boolean
nodes?: object[]; nodes?: object[]
redisOptions?: any; redisOptions?: any
} }
declare interface IConfigOptions { declare interface IConfigOptions {
version: string, version: string
serve: { serve: {
port: number port: number
}, },
keys: string[], keys: string[]
session: { session: {
key: string key: string
}, },
keycenter?: string | boolean, keycenter?: string | boolean
db: ISequelizeConfig, db: ISequelizeConfig
redis: RedisAndClusterOptions redis: RedisAndClusterOptions
mail: SMTPTransport mail: SMTPTransport
mailSender: string mailSender: string

@ -7,11 +7,11 @@
/** /**
* A collection's friendly name is defined by this field. You would want to set this field to a value that would allow you to easily identify this collection among a bunch of other collections, as such outlining its usage or content. * A collection's friendly name is defined by this field. You would want to set this field to a value that would allow you to easily identify this collection among a bunch of other collections, as such outlining its usage or content.
*/ */
export type NameOfTheCollection = string; export type NameOfTheCollection = string
/** /**
* A Description can be a raw text, or be an object, which holds the description along with its format. * A Description can be a raw text, or be an object, which holds the description along with its format.
*/ */
export type DefinitionsDescription = Description | string | null; export type DefinitionsDescription = Description | string | null
/** /**
* Postman allows you to version your collections as they grow, and this field holds the version number. While optional, it is recommended that you use this field to its fullest extent! * Postman allows you to version your collections as they grow, and this field holds the version number. While optional, it is recommended that you use this field to its fullest extent!
*/ */
@ -20,42 +20,42 @@ export type CollectionVersion =
/** /**
* Increment this number if you make changes to the collection that changes its behaviour. E.g: Removing or adding new test scripts. (partly or completely). * Increment this number if you make changes to the collection that changes its behaviour. E.g: Removing or adding new test scripts. (partly or completely).
*/ */
major: number; major: number
/** /**
* You should increment this number if you make changes that will not break anything that uses the collection. E.g: removing a folder. * You should increment this number if you make changes that will not break anything that uses the collection. E.g: removing a folder.
*/ */
minor: number; minor: number
/** /**
* Ideally, minor changes to a collection should result in the increment of this number. * Ideally, minor changes to a collection should result in the increment of this number.
*/ */
patch: number; patch: number
/** /**
* A human friendly identifier to make sense of the version numbers. E.g: 'beta-3' * A human friendly identifier to make sense of the version numbers. E.g: 'beta-3'
*/ */
identifier?: string; identifier?: string
meta?: any; meta?: any
[k: string]: any; [k: string]: any
} }
| string; | string
export type Items1 = Item | Folder; export type Items1 = Item | Folder
/** /**
* Using variables in your Postman requests eliminates the need to duplicate requests, which can save a lot of time. Variables can be defined, and referenced to from any part of a request. * Using variables in your Postman requests eliminates the need to duplicate requests, which can save a lot of time. Variables can be defined, and referenced to from any part of a request.
*/ */
export type Variable = export type Variable =
| { | {
[k: string]: any; [k: string]: any
} }
| { | {
[k: string]: any; [k: string]: any
} }
| { | {
[k: string]: any; [k: string]: any
}; }
/** /**
* Collection variables allow you to define a set of variables, that are a *part of the collection*, as opposed to environments, which are separate entities. * Collection variables allow you to define a set of variables, that are a *part of the collection*, as opposed to environments, which are separate entities.
* *Note: Collection variables must not contain any sensitive information.* * *Note: Collection variables must not contain any sensitive information.*
*/ */
export type VariableList = Variable[]; export type VariableList = Variable[]
/** /**
* If object, contains the complete broken-down URL for this request. If string, contains the literal request URL. * If object, contains the complete broken-down URL for this request. If string, contains the literal request URL.
*/ */
@ -64,170 +64,170 @@ export type Url =
/** /**
* The string representation of the request URL, including the protocol, host, path, hash, query parameter(s) and path variable(s). * The string representation of the request URL, including the protocol, host, path, hash, query parameter(s) and path variable(s).
*/ */
raw?: string; raw?: string
/** /**
* The protocol associated with the request, E.g: 'http' * The protocol associated with the request, E.g: 'http'
*/ */
protocol?: string; protocol?: string
host?: Host; host?: Host
path?: path?:
| string | string
| ( | (
| string | string
| { | {
type?: string; type?: string
value?: string; value?: string
[k: string]: any; [k: string]: any
})[]; })[]
/** /**
* The port number present in this URL. An empty value implies 80/443 depending on whether the protocol field contains http/https. * The port number present in this URL. An empty value implies 80/443 depending on whether the protocol field contains http/https.
*/ */
port?: string; port?: string
/** /**
* An array of QueryParams, which is basically the query string part of the URL, parsed into separate variables * An array of QueryParams, which is basically the query string part of the URL, parsed into separate variables
*/ */
query?: QueryParam[]; query?: QueryParam[]
/** /**
* Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases. * Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.
*/ */
hash?: string; hash?: string
/** /**
* Postman supports path variables with the syntax `/path/:variableName/to/somewhere`. These variables are stored in this field. * Postman supports path variables with the syntax `/path/:variableName/to/somewhere`. These variables are stored in this field.
*/ */
variable?: Variable[]; variable?: Variable[]
[k: string]: any; [k: string]: any
} }
| string; | string
/** /**
* The host for the URL, E.g: api.yourdomain.com. Can be stored as a string or as an array of strings. * The host for the URL, E.g: api.yourdomain.com. Can be stored as a string or as an array of strings.
*/ */
export type Host = string | string[]; export type Host = string | string[]
/** /**
* Postman allows you to configure scripts to run when specific events occur. These scripts are stored here, and can be referenced in the collection by their ID. * Postman allows you to configure scripts to run when specific events occur. These scripts are stored here, and can be referenced in the collection by their ID.
*/ */
export type EventList = Event[]; export type EventList = Event[]
/** /**
* A request represents an HTTP request. If a string, the string is assumed to be the request URL and the method is assumed to be 'GET'. * A request represents an HTTP request. If a string, the string is assumed to be the request URL and the method is assumed to be 'GET'.
*/ */
export type Request1 = Request | string; export type Request1 = Request | string
/** /**
* The attributes for [AWS Auth](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html). * The attributes for [AWS Auth](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html).
*/ */
export type AwsSignatureV4 = Auth1[]; export type AwsSignatureV4 = Auth1[]
/** /**
* The attributes for [Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). * The attributes for [Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication).
*/ */
export type BasicAuthentication = Auth1[]; export type BasicAuthentication = Auth1[]
/** /**
* The helper attributes for [Bearer Token Authentication](https://tools.ietf.org/html/rfc6750) * The helper attributes for [Bearer Token Authentication](https://tools.ietf.org/html/rfc6750)
*/ */
export type BearerTokenAuthentication = Auth1[]; export type BearerTokenAuthentication = Auth1[]
/** /**
* The attributes for [Digest Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication). * The attributes for [Digest Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication).
*/ */
export type DigestAuthentication = Auth1[]; export type DigestAuthentication = Auth1[]
/** /**
* The attributes for [Hawk Authentication](https://github.com/hueniverse/hawk) * The attributes for [Hawk Authentication](https://github.com/hueniverse/hawk)
*/ */
export type HawkAuthentication = Auth1[]; export type HawkAuthentication = Auth1[]
/** /**
* The attributes for [NTLM Authentication](https://msdn.microsoft.com/en-us/library/cc237488.aspx) * The attributes for [NTLM Authentication](https://msdn.microsoft.com/en-us/library/cc237488.aspx)
*/ */
export type NtlmAuthentication = Auth1[]; export type NtlmAuthentication = Auth1[]
/** /**
* The attributes for [OAuth2](https://oauth.net/1/) * The attributes for [OAuth2](https://oauth.net/1/)
*/ */
export type OAuth1 = Auth1[]; export type OAuth1 = Auth1[]
/** /**
* Helper attributes for [OAuth2](https://oauth.net/2/) * Helper attributes for [OAuth2](https://oauth.net/2/)
*/ */
export type OAuth2 = Auth1[]; export type OAuth2 = Auth1[]
/** /**
* A representation for a list of headers * A representation for a list of headers
*/ */
export type HeaderList = Header[]; export type HeaderList = Header[]
export type FormParameter = export type FormParameter =
| { | {
key: string; key: string
value?: string; value?: string
/** /**
* When set to true, prevents this form data entity from being sent. * When set to true, prevents this form data entity from being sent.
*/ */
disabled?: boolean; disabled?: boolean
type?: "text"; type?: "text"
description?: DefinitionsDescription; description?: DefinitionsDescription
[k: string]: any; [k: string]: any
} }
| { | {
key: string; key: string
src?: string; src?: string
/** /**
* When set to true, prevents this form data entity from being sent. * When set to true, prevents this form data entity from being sent.
*/ */
disabled?: boolean; disabled?: boolean
type?: "file"; type?: "file"
description?: DefinitionsDescription; description?: DefinitionsDescription
[k: string]: any; [k: string]: any
}; }
/** /**
* The time taken by the request to complete. If a number, the unit is milliseconds. If the response is manually created, this can be set to `null`. * The time taken by the request to complete. If a number, the unit is milliseconds. If the response is manually created, this can be set to `null`.
*/ */
export type ResponseTime = null | string | number; export type ResponseTime = null | string | number
export type Headers = Header2 | string; export type Headers = Header2 | string
export type Header1 = string; export type Header1 = string
/** /**
* No HTTP request is complete without its headers, and the same is true for a Postman request. This field is an array containing all the headers. * No HTTP request is complete without its headers, and the same is true for a Postman request. This field is an array containing all the headers.
*/ */
export type Header2 = (Header | Header1)[]; export type Header2 = (Header | Header1)[]
export type Responses = Response[]; export type Responses = Response[]
export type Items = Item | Folder; export type Items = Item | Folder
export interface PostmanCollection { export interface PostmanCollection {
info: Information; info: Information
/** /**
* Items are the basic unit for a Postman collection. You can think of them as corresponding to a single API endpoint. Each Item has one request and may have multiple API responses associated with it. * Items are the basic unit for a Postman collection. You can think of them as corresponding to a single API endpoint. Each Item has one request and may have multiple API responses associated with it.
*/ */
item: Items1[]; item: Items1[]
event?: EventList; event?: EventList
variable?: VariableList; variable?: VariableList
auth?: null | Auth; auth?: null | Auth
[k: string]: any; [k: string]: any
} }
/** /**
* Detailed description of the info block * Detailed description of the info block
*/ */
export interface Information { export interface Information {
name: NameOfTheCollection; name: NameOfTheCollection
/** /**
* Every collection is identified by the unique value of this field. The value of this field is usually easiest to generate using a UID generator function. If you already have a collection, it is recommended that you maintain the same id since changing the id usually implies that is a different collection than it was originally. * Every collection is identified by the unique value of this field. The value of this field is usually easiest to generate using a UID generator function. If you already have a collection, it is recommended that you maintain the same id since changing the id usually implies that is a different collection than it was originally.
* *Note: This field exists for compatibility reasons with Collection Format V1.* * *Note: This field exists for compatibility reasons with Collection Format V1.*
*/ */
_postman_id?: string; _postman_id?: string
description?: DefinitionsDescription; description?: DefinitionsDescription
version?: CollectionVersion; version?: CollectionVersion
/** /**
* This should ideally hold a link to the Postman schema that is used to validate this collection. E.g: https://schema.getpostman.com/collection/v1 * This should ideally hold a link to the Postman schema that is used to validate this collection. E.g: https://schema.getpostman.com/collection/v1
*/ */
schema: string; schema: string
[k: string]: any; [k: string]: any
} }
export interface Description { export interface Description {
/** /**
* The content of the description goes here, as a raw string. * The content of the description goes here, as a raw string.
*/ */
content?: string; content?: string
/** /**
* Holds the mime type of the raw description content. E.g: 'text/markdown' or 'text/html'. * Holds the mime type of the raw description content. E.g: 'text/markdown' or 'text/html'.
* The type is used to correctly render the description when generating documentation, or in the Postman app. * The type is used to correctly render the description when generating documentation, or in the Postman app.
*/ */
type?: string; type?: string
/** /**
* Description can have versions associated with it, which should be put in this property. * Description can have versions associated with it, which should be put in this property.
*/ */
version?: { version?: {
[k: string]: any; [k: string]: any
}; }
[k: string]: any; [k: string]: any
} }
/** /**
* Items are entities which contain an actual HTTP request, and sample responses attached to it. * Items are entities which contain an actual HTTP request, and sample responses attached to it.
@ -236,17 +236,17 @@ export interface Item {
/** /**
* A unique ID that is used to identify collections internally * A unique ID that is used to identify collections internally
*/ */
id?: string; id?: string
/** /**
* A human readable identifier for the current item. * A human readable identifier for the current item.
*/ */
name?: string; name?: string
description?: DefinitionsDescription; description?: DefinitionsDescription
variable?: VariableList; variable?: VariableList
event?: EventList; event?: EventList
request: Request1; request: Request1
response?: Responses; response?: Responses
[k: string]: any; [k: string]: any
} }
/** /**
* Defines a script associated with an associated event name * Defines a script associated with an associated event name
@ -255,17 +255,17 @@ export interface Event {
/** /**
* A unique identifier for the enclosing event. * A unique identifier for the enclosing event.
*/ */
id?: string; id?: string
/** /**
* Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively. * Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.
*/ */
listen: string; listen: string
script?: Script; script?: Script
/** /**
* Indicates whether the event is disabled. If absent, the event is assumed to be enabled. * Indicates whether the event is disabled. If absent, the event is assumed to be enabled.
*/ */
disabled?: boolean; disabled?: boolean
[k: string]: any; [k: string]: any
} }
/** /**
* A script is a snippet of Javascript code that can be used to to perform setup or teardown operations on a particular response. * A script is a snippet of Javascript code that can be used to to perform setup or teardown operations on a particular response.
@ -274,34 +274,34 @@ export interface Script {
/** /**
* A unique, user defined identifier that can be used to refer to this script from requests. * A unique, user defined identifier that can be used to refer to this script from requests.
*/ */
id?: string; id?: string
/** /**
* Type of the script. E.g: 'text/javascript' * Type of the script. E.g: 'text/javascript'
*/ */
type?: string; type?: string
exec?: string[] | string; exec?: string[] | string
src?: Url; src?: Url
/** /**
* Script name * Script name
*/ */
name?: string; name?: string
[k: string]: any; [k: string]: any
} }
export interface QueryParam { export interface QueryParam {
key?: string | null; key?: string | null
value?: string | null; value?: string | null
/** /**
* If set to true, the current query parameter will not be sent with the request. * If set to true, the current query parameter will not be sent with the request.
*/ */
disabled?: boolean; disabled?: boolean
description?: DefinitionsDescription; description?: DefinitionsDescription
[k: string]: any; [k: string]: any
} }
export interface Request { export interface Request {
url?: Url; url?: Url
auth?: null | Auth; auth?: null | Auth
proxy?: ProxyConfig; proxy?: ProxyConfig
certificate?: Certificate; certificate?: Certificate
/** /**
* The HTTP method associated with this request. * The HTTP method associated with this request.
*/ */
@ -320,9 +320,9 @@ export interface Request {
| "LOCK" | "LOCK"
| "UNLOCK" | "UNLOCK"
| "PROPFIND" | "PROPFIND"
| "VIEW"; | "VIEW"
description?: DefinitionsDescription; description?: DefinitionsDescription
header?: HeaderList | string; header?: HeaderList | string
/** /**
* This field contains the data usually contained in the request body. * This field contains the data usually contained in the request body.
*/ */
@ -330,46 +330,46 @@ export interface Request {
/** /**
* Postman stores the type of data associated with this request in this field. * Postman stores the type of data associated with this request in this field.
*/ */
mode?: "raw" | "urlencoded" | "formdata" | "file"; mode?: "raw" | "urlencoded" | "formdata" | "file"
raw?: string; raw?: string
urlencoded?: UrlEncodedParameter[]; urlencoded?: UrlEncodedParameter[]
formdata?: FormParameter[]; formdata?: FormParameter[]
file?: { file?: {
/** /**
* Contains the name of the file to upload. _Not the path_. * Contains the name of the file to upload. _Not the path_.
*/ */
src?: string; src?: string
content?: string; content?: string
[k: string]: any; [k: string]: any
}; }
[k: string]: any; [k: string]: any
}; }
[k: string]: any; [k: string]: any
} }
/** /**
* Represents authentication helpers provided by Postman * Represents authentication helpers provided by Postman
*/ */
export interface Auth { export interface Auth {
type: "awsv4" | "basic" | "bearer" | "digest" | "hawk" | "noauth" | "oauth1" | "oauth2" | "ntlm"; type: "awsv4" | "basic" | "bearer" | "digest" | "hawk" | "noauth" | "oauth1" | "oauth2" | "ntlm"
noauth?: any; noauth?: any
awsv4?: AwsSignatureV4; awsv4?: AwsSignatureV4
basic?: BasicAuthentication; basic?: BasicAuthentication
bearer?: BearerTokenAuthentication; bearer?: BearerTokenAuthentication
digest?: DigestAuthentication; digest?: DigestAuthentication
hawk?: HawkAuthentication; hawk?: HawkAuthentication
ntlm?: NtlmAuthentication; ntlm?: NtlmAuthentication
oauth1?: OAuth1; oauth1?: OAuth1
oauth2?: OAuth2; oauth2?: OAuth2
[k: string]: any; [k: string]: any
} }
/** /**
* Represents an attribute for any authorization method provided by Postman. For example `username` and `password` are set as auth attributes for Basic Authentication method. * Represents an attribute for any authorization method provided by Postman. For example `username` and `password` are set as auth attributes for Basic Authentication method.
*/ */
export interface Auth1 { export interface Auth1 {
key: string; key: string
value?: any; value?: any
type?: string; type?: string
[k: string]: any; [k: string]: any
} }
/** /**
* Using the Proxy, you can configure your custom proxy into the postman for particular url match * Using the Proxy, you can configure your custom proxy into the postman for particular url match
@ -378,24 +378,24 @@ export interface ProxyConfig {
/** /**
* The Url match for which the proxy config is defined * The Url match for which the proxy config is defined
*/ */
match?: string; match?: string
/** /**
* The proxy server host * The proxy server host
*/ */
host?: string; host?: string
/** /**
* The proxy server port * The proxy server port
*/ */
port?: number; port?: number
/** /**
* The tunneling details for the proxy config * The tunneling details for the proxy config
*/ */
tunnel?: boolean; tunnel?: boolean
/** /**
* When set to true, ignores this proxy configuration entity * When set to true, ignores this proxy configuration entity
*/ */
disabled?: boolean; disabled?: boolean
[k: string]: any; [k: string]: any
} }
/** /**
* A representation of an ssl certificate * A representation of an ssl certificate
@ -404,11 +404,11 @@ export interface Certificate {
/** /**
* A name for the certificate for user reference * A name for the certificate for user reference
*/ */
name?: string; name?: string
/** /**
* A list of Url match pattern strings, to identify Urls this certificate can be used for. * A list of Url match pattern strings, to identify Urls this certificate can be used for.
*/ */
matches?: any[]; matches?: any[]
/** /**
* An object containing path to file containing private key, on the file system * An object containing path to file containing private key, on the file system
*/ */
@ -417,10 +417,10 @@ export interface Certificate {
* The path to file containing key for certificate, on the file system * The path to file containing key for certificate, on the file system
*/ */
src?: { src?: {
[k: string]: any; [k: string]: any
}; }
[k: string]: any; [k: string]: any
}; }
/** /**
* An object containing path to file certificate, on the file system * An object containing path to file certificate, on the file system
*/ */
@ -429,15 +429,15 @@ export interface Certificate {
* The path to file containing key for certificate, on the file system * The path to file containing key for certificate, on the file system
*/ */
src?: { src?: {
[k: string]: any; [k: string]: any
}; }
[k: string]: any; [k: string]: any
}; }
/** /**
* The passphrase for the certificate * The passphrase for the certificate
*/ */
passphrase?: string; passphrase?: string
[k: string]: any; [k: string]: any
} }
/** /**
* Represents a single HTTP Header * Represents a single HTTP Header
@ -446,24 +446,24 @@ export interface Header {
/** /**
* This holds the LHS of the HTTP Header, e.g ``Content-Type`` or ``X-Custom-Header`` * This holds the LHS of the HTTP Header, e.g ``Content-Type`` or ``X-Custom-Header``
*/ */
key: string; key: string
/** /**
* The value (or the RHS) of the Header is stored in this field. * The value (or the RHS) of the Header is stored in this field.
*/ */
value: string; value: string
/** /**
* If set to true, the current header will not be sent with requests. * If set to true, the current header will not be sent with requests.
*/ */
disabled?: boolean; disabled?: boolean
description?: DefinitionsDescription; description?: DefinitionsDescription
[k: string]: any; [k: string]: any
} }
export interface UrlEncodedParameter { export interface UrlEncodedParameter {
key: string; key: string
value?: string; value?: string
disabled?: boolean; disabled?: boolean
description?: DefinitionsDescription; description?: DefinitionsDescription
[k: string]: any; [k: string]: any
} }
/** /**
* A response represents an HTTP response. * A response represents an HTTP response.
@ -472,24 +472,24 @@ export interface Response {
/** /**
* A unique, user defined identifier that can be used to refer to this response from requests. * A unique, user defined identifier that can be used to refer to this response from requests.
*/ */
id?: string; id?: string
originalRequest?: Request1; originalRequest?: Request1
responseTime?: ResponseTime; responseTime?: ResponseTime
header?: Headers; header?: Headers
cookie?: Cookie[]; cookie?: Cookie[]
/** /**
* The raw text of the response. * The raw text of the response.
*/ */
body?: string; body?: string
/** /**
* The response status, e.g: '200 OK' * The response status, e.g: '200 OK'
*/ */
status?: string; status?: string
/** /**
* The numerical response code, example: 200, 201, 404, etc. * The numerical response code, example: 200, 201, 404, etc.
*/ */
code?: number; code?: number
[k: string]: any; [k: string]: any
} }
/** /**
* A Cookie, that follows the [Google Chrome format](https://developer.chrome.com/extensions/cookies) * A Cookie, that follows the [Google Chrome format](https://developer.chrome.com/extensions/cookies)
@ -498,45 +498,45 @@ export interface Cookie {
/** /**
* The domain for which this cookie is valid. * The domain for which this cookie is valid.
*/ */
domain: string; domain: string
/** /**
* When the cookie expires. * When the cookie expires.
*/ */
expires?: string | number; expires?: string | number
maxAge?: string; maxAge?: string
/** /**
* True if the cookie is a host-only cookie. (i.e. a request's URL domain must exactly match the domain of the cookie). * True if the cookie is a host-only cookie. (i.e. a request's URL domain must exactly match the domain of the cookie).
*/ */
hostOnly?: boolean; hostOnly?: boolean
/** /**
* Indicates if this cookie is HTTP Only. (if True, the cookie is inaccessible to client-side scripts) * Indicates if this cookie is HTTP Only. (if True, the cookie is inaccessible to client-side scripts)
*/ */
httpOnly?: boolean; httpOnly?: boolean
/** /**
* This is the name of the Cookie. * This is the name of the Cookie.
*/ */
name?: string; name?: string
/** /**
* The path associated with the Cookie. * The path associated with the Cookie.
*/ */
path: string; path: string
/** /**
* Indicates if the 'secure' flag is set on the Cookie, meaning that it is transmitted over secure connections only. (typically HTTPS) * Indicates if the 'secure' flag is set on the Cookie, meaning that it is transmitted over secure connections only. (typically HTTPS)
*/ */
secure?: boolean; secure?: boolean
/** /**
* True if the cookie is a session cookie. * True if the cookie is a session cookie.
*/ */
session?: boolean; session?: boolean
/** /**
* The value of the Cookie. * The value of the Cookie.
*/ */
value?: string; value?: string
/** /**
* Custom attributes for a cookie go here, such as the [Priority Field](https://code.google.com/p/chromium/issues/detail?id=232693) * Custom attributes for a cookie go here, such as the [Priority Field](https://code.google.com/p/chromium/issues/detail?id=232693)
*/ */
extensions?: any[]; extensions?: any[]
[k: string]: any; [k: string]: any
} }
/** /**
* One of the primary goals of Postman is to organize the development of APIs. To this end, it is necessary to be able to group requests together. This can be achived using 'Folders'. A folder just is an ordered set of requests. * One of the primary goals of Postman is to organize the development of APIs. To this end, it is necessary to be able to group requests together. This can be achived using 'Folders'. A folder just is an ordered set of requests.
@ -545,14 +545,14 @@ export interface Folder {
/** /**
* A folder's friendly name is defined by this field. You would want to set this field to a value that would allow you to easily identify this folder. * A folder's friendly name is defined by this field. You would want to set this field to a value that would allow you to easily identify this folder.
*/ */
name?: string; name?: string
description?: DefinitionsDescription; description?: DefinitionsDescription
variable?: VariableList; variable?: VariableList
/** /**
* Items are entities which contain an actual HTTP request, and sample responses attached to it. Folders may contain many items. * Items are entities which contain an actual HTTP request, and sample responses attached to it. Folders may contain many items.
*/ */
item: Items[]; item: Items[]
event?: EventList; event?: EventList
auth?: null | Auth; auth?: null | Auth
[k: string]: any; [k: string]: any
} }

@ -1,6 +1,6 @@
--allow-uncaught --allow-uncaught
--exit --exit
--timeout 5000 --timeout 15000
--slow 200 --slow 200
test/**/*.js test/**/*.js

@ -27,7 +27,7 @@ describe('Interface', () => {
}) })
let validInterface = (itf, extras = []) => { let validInterface = (itf, extras = []) => {
itf.should.be.a('object').have.all.keys( itf.should.be.a('object').have.all.keys(
Object.keys(Interface.attributes).concat(extras) Object.keys(Interface.rawAttributes).concat(extras)
) )
itf.creatorId.should.be.a('number') itf.creatorId.should.be.a('number')
itf.repositoryId.should.be.a('number') itf.repositoryId.should.be.a('number')

@ -22,7 +22,7 @@ describe('Module', () => {
}) })
let validModule = (mod) => { let validModule = (mod) => {
mod.should.be.a('object').have.all.keys( mod.should.be.a('object').have.all.keys(
Object.keys(Module.attributes) Object.keys(Module.rawAttributes)
) )
mod.creatorId.should.be.a('number') mod.creatorId.should.be.a('number')
mod.repositoryId.should.be.a('number') mod.repositoryId.should.be.a('number')

@ -23,7 +23,7 @@ describe('Organization', () => {
}) })
let validOrganization = (organization) => { let validOrganization = (organization) => {
organization.should.be.a('object').have.all.keys( organization.should.be.a('object').have.all.keys(
[...Object.keys(Organization.attributes), 'creator', 'owner', 'members'] [...Object.keys(Organization.rawAttributes), 'creator', 'owner', 'members']
) )
let { creator, owner, members } = organization let { creator, owner, members } = organization
creator.should.be.a('object').have.all.keys(['id', 'fullname', 'email']) creator.should.be.a('object').have.all.keys(['id', 'fullname', 'email'])

@ -33,7 +33,7 @@ describe('Property', () => {
}) })
let validProperty = (property) => { let validProperty = (property) => {
property.should.be.a('object').have.all.keys( property.should.be.a('object').have.all.keys(
Object.keys(Property.attributes) Object.keys(Property.rawAttributes)
) )
property.creatorId.should.be.a('number') property.creatorId.should.be.a('number')
property.repositoryId.should.be.a('number') property.repositoryId.should.be.a('number')

@ -23,7 +23,7 @@ describe('Repository', () => {
}) })
let validRepository = (repository, deep) => { let validRepository = (repository, deep) => {
repository.should.be.a('object').have.all.keys( repository.should.be.a('object').have.all.keys(
[...Object.keys(Repository.attributes), 'creator', 'owner', 'members', 'locker', 'organization', 'collaborators'] [...Object.keys(Repository.rawAttributes), 'creator', 'owner', 'members', 'locker', 'organization', 'collaborators']
.concat(deep ? ['modules'] : []) .concat(deep ? ['modules'] : [])
) )
let { creator, owner, members } = repository let { creator, owner, members } = repository

@ -1,11 +1,11 @@
{ {
"compilerOptions": { "compilerOptions": {
"outDir": "dist", "outDir": "./dist",
"module": "commonjs", "module": "commonjs",
"moduleResolution": "node", "moduleResolution": "node",
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"target": "es6", "target": "esnext",
"removeComments": true, "removeComments": true,
"sourceMap": true, "sourceMap": true,
"watch": false, "watch": false,

@ -1,69 +1,69 @@
{ {
"tslint.enable": true, "tslint.enable": true,
"rules": { "rules": {
"class-name": true, "class-name": true,
"comment-format": [ "comment-format": [
true, true,
"check-space" "check-space"
], ],
"indent": [ "indent": [
true, true,
"spaces", "spaces",
2 2
], ],
"one-line": [ "one-line": [
true, true,
"check-open-brace", "check-open-brace",
"check-whitespace" "check-whitespace"
], ],
"no-var-keyword": true, "no-var-keyword": true,
"quotemark": [ "quotemark": [
false, false,
"double", "double",
"avoid-escape" "avoid-escape"
], ],
"semicolon": [ "semicolon": [
false, true,
"always", "never",
"ignore-bound-class-methods" "ignore-bound-class-methods"
], ],
"whitespace": [ "whitespace": [
true, true,
"check-branch", "check-branch",
"check-decl", "check-decl",
"check-operator", "check-operator",
"check-module", "check-module",
"check-separator", "check-separator",
"check-type" "check-type"
], ],
"trailing-comma": [ "trailing-comma": [
false, false,
{ {
"multiline": "always", "multiline": "always",
"singleline": "never" "singleline": "never"
} }
], ],
"typedef-whitespace": [ "typedef-whitespace": [
true, true,
{ {
"call-signature": "nospace", "call-signature": "nospace",
"index-signature": "nospace", "index-signature": "nospace",
"parameter": "nospace", "parameter": "nospace",
"property-declaration": "nospace", "property-declaration": "nospace",
"variable-declaration": "nospace" "variable-declaration": "nospace"
}, },
{ {
"call-signature": "onespace", "call-signature": "onespace",
"index-signature": "onespace", "index-signature": "onespace",
"parameter": "onespace", "parameter": "onespace",
"property-declaration": "onespace", "property-declaration": "onespace",
"variable-declaration": "onespace" "variable-declaration": "onespace"
} }
], ],
"no-internal-module": true, "no-internal-module": true,
"no-trailing-whitespace": true, "no-trailing-whitespace": true,
"no-null-keyword": true, "no-null-keyword": true,
"prefer-const": false, "prefer-const": false,
"jsdoc-format": true "jsdoc-format": true
} }
} }
Loading…
Cancel
Save