fix #58 add TypeScript to delos!

pull/76/head
Bosn 7 years ago
parent 8dcdfb03dc
commit 90314eba58

3
.gitignore vendored

@ -1,6 +1,7 @@
/dist
.DS_Store .DS_Store
node_modules node_modules
bower_components bower_components
coverage coverage
npm-debug.log npm-debug.log
tmp tmp

@ -0,0 +1,16 @@
{
// 使 IntelliSense Node.js
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach by Process ID",
"processId": "${command:PickProcess}",
"protocol": "inspector"
}
]
}

@ -1,5 +0,0 @@
// local or development or production
module.exports =
(process.env.NODE_ENV === 'local' && require('./config.local')) ||
(process.env.NODE_ENV === 'development' && require('./config.dev')) ||
require('./config.prod')

@ -2,24 +2,21 @@
"name": "rap2-delos", "name": "rap2-delos",
"version": "1.0.0", "version": "1.0.0",
"repository": { "repository": {
"url": "" "url": "https://github.com/thx/rap2-delos"
}, },
"description": "", "description": "",
"main": "dispatch.js", "main": "dist/dispatch.js",
"scripts": { "scripts": {
"create-db": "node scripts/init", "init": "node dist/scripts/init/index.js",
"dev": "NODE_ENV=development nodemon --watch scripts --watch src scripts/dev.js", "dev": "cross-env NODE_ENV=development nodemon --watch scripts --watch dist dist/scripts/dev.js",
"dev-local": "NODE_ENV=local nodemon --watch scripts --watch src scripts/dev.js", "start": "cross-env NODE_ENV=production node dist/dispatch.js"
"start": "NODE_ENV=production node dispatch.js",
"check": "npm run linter;npm run test;",
"test": "NODE_ENV=development TEST_MODE=true mocha --exit --reporter nyan",
"linter": "standard --fix",
"watch-test": "NODE_ENV=development nodemon --watch scripts --watch src --watch test ./node_modules/.bin/mocha --timeout 5000",
"watch-test-local": "NODE_ENV=local nodemon --watch scripts --watch src --watch test ./node_modules/.bin/mocha --timeout 5000"
}, },
"author": "mozhi.gyy@alibaba-inc.com, bosn@outlook.com", "author": "bosn, nuysoft",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@types/koa": "^2.0.43",
"cross-env": "^5.1.1",
"@types/koa-router": "^7.0.27",
"chalk": "^1.1.3", "chalk": "^1.1.3",
"graceful": "^1.0.1", "graceful": "^1.0.1",
"js-beautify": "^1.6.9", "js-beautify": "^1.6.9",
@ -34,33 +31,34 @@
"mockjs": "^1.0.1-beta3", "mockjs": "^1.0.1-beta3",
"moment": "^2.17.1", "moment": "^2.17.1",
"mysql": "^2.11.1", "mysql": "^2.11.1",
"mysql2": "^1.5.1",
"node-fetch": "^1.7.1", "node-fetch": "^1.7.1",
"node-print": "0.0.4", "node-print": "0.0.4",
"path-to-regexp": "^2.1.0", "path-to-regexp": "^2.1.0",
"sequelize": "^3.30.4", "reflect-metadata": "^0.1.10",
"sequelize-cli": "^3.1.0", "sequelize": "^4.28.6",
"sequelize-typescript": "^0.6.2",
"svg-captcha": "^1.3.11",
"underscore": "^1.8.3", "underscore": "^1.8.3",
"urllib": "^2.22.0" "urllib": "^2.22.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^8.5.2",
"babel-eslint": "^7.2.3", "babel-eslint": "^7.2.3",
"chai": "^3.5.0", "chai": "^3.5.0",
"mocha": "^4.0.1", "mocha": "^4.0.1",
"nodemon": "^1.11.0", "nodemon": "^1.11.0",
"npm-run-all": "^4.0.2", "npm-run-all": "^4.0.2",
"pre-commit": "^1.2.2",
"standard": "^10.0.2", "standard": "^10.0.2",
"supertest": "^3.0.0" "supertest": "^3.0.0",
"tslint": "^5.8.0"
}, },
"standard": { "standard": {
"parser": "babel-eslint", "parser": "babel-eslint",
"globals": [], "globals": [],
"ignore": [] "ignore": []
}, },
"pre-commit": [
"linter"
],
"engines": { "engines": {
"install-node": "9.2.0" "install-node": "8.9.3"
} }
} }

@ -7,6 +7,7 @@
<title>RAP2 Delos</title> <title>RAP2 Delos</title>
</head> </head>
<body> <body>
<a href="https://rap2.alibaba-inc.com">https://rap2.alibaba-inc.com</a> RAP2后端服务已启动请从前端服务(rap2-dolores)访问。
RAP2 back-end server is started, please visit via front-end service (rap2-dolores).
</body> </body>
</html> </html>

@ -1,6 +0,0 @@
# 1. 你可以直接编辑本文件的内容或者通过工具来帮你校验合法性和自动生成请点击http://aliwing.alibaba-inc.com/apprelease/home.htm
# 2. 更多关于Release文件的规范和约定请点击: http://docs.alibaba-inc.com/pages/viewpage.action?pageId=252891532
# 构建源码语言类型
code.language=nodejs

@ -1,4 +1,6 @@
module.exports = { import { IConfigOptions } from "../types";
let config:IConfigOptions = {
version: '2.3', version: '2.3',
serve: { serve: {
port: 8080 port: 8080
@ -10,9 +12,9 @@ module.exports = {
db: { db: {
dialect: 'mysql', dialect: 'mysql',
host: 'localhost', host: 'localhost',
port: '3306', port: 3306,
username: 'root', username: 'root',
password: '', // KeyCenter 配置项密文 password: '',
database: 'RAP2_DELOS_APP', database: 'RAP2_DELOS_APP',
pool: { pool: {
max: 5, max: 5,
@ -22,3 +24,5 @@ module.exports = {
logging: false logging: false
} }
} }
export default config

@ -1,4 +1,6 @@
module.exports = { import { IConfigOptions } from "../types";
let config:IConfigOptions = {
version: '2.3', version: '2.3',
serve: { serve: {
port: 8080 port: 8080
@ -10,7 +12,7 @@ module.exports = {
db: { db: {
dialect: 'mysql', dialect: 'mysql',
host: 'localhost', host: 'localhost',
port: '3306', port: 3306,
username: 'root', username: 'root',
password: '', password: '',
database: 'RAP2_DELOS_APP_LOCAL', database: 'RAP2_DELOS_APP_LOCAL',
@ -22,3 +24,5 @@ module.exports = {
logging: true logging: true
} }
} }
export default config

@ -1,4 +1,5 @@
module.exports = { import { IConfigOptions } from "../types";
let config:IConfigOptions = {
version: '2.3', version: '2.3',
serve: { serve: {
port: 8080 port: 8080
@ -10,7 +11,7 @@ module.exports = {
db: { db: {
dialect: 'mysql', dialect: 'mysql',
host: 'localhost', host: 'localhost',
port: '3306', port: 3306,
username: 'root', username: 'root',
password: '', password: '',
database: 'RAP2_DELOS_APP', database: 'RAP2_DELOS_APP',
@ -22,3 +23,5 @@ module.exports = {
logging: true logging: true
} }
} }
export default config

@ -0,0 +1,9 @@
import { IConfigOptions } from "../types";
// local or development or production
let configObj:IConfigOptions =
(process.env.NODE_ENV === 'local' && require('./config.local')).default ||
(process.env.NODE_ENV === 'development' && require('./config.dev')).default ||
require('./config.prod').default
export default configObj

@ -1,12 +1,6 @@
// process.env.NODE_ENV = 'production' import * as cluster from 'cluster'
import * as path from 'path'
// http://gitlab.alibaba-inc.com/thx/rap2-dolores/commit/2fd70fdcaa9d179e9cf95e530e37f31f8488f432
// https://nodejs.org/api/cluster.html
// https://github.com/node-modules/graceful/blob/master/example/express_with_cluster/dispatch.js
// http://gitlab.alibaba-inc.com/mm/fb/blob/master/dispatch.js
let cluster = require('cluster')
let path = require('path')
let now = () => new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') let now = () => new Date().toISOString().replace(/T/, ' ').replace(/Z/, '')
cluster.setupMaster({ cluster.setupMaster({

@ -1,5 +1,5 @@
const Sequelize = require('sequelize') const Sequelize = require('sequelize')
module.exports = { export let Helper = {
id: { type: Sequelize.BIGINT(11).UNSIGNED, primaryKey: true, allowNull: false, autoIncrement: true, comment: '唯一标识' }, id: { type: Sequelize.BIGINT(11).UNSIGNED, primaryKey: true, allowNull: false, autoIncrement: true, comment: '唯一标识' },
include: [], include: [],
exclude: { exclude: {

@ -1,111 +0,0 @@
// TODO 2.2 如何缓存重复查询https://github.com/rfink/sequelize-redis-cache
const Helper = require('./helper')
const User = require('./user')
const Organization = require('./organization')
const Repository = require('./repository')
const Module = require('./module')
const Interface = require('./interface')
const Property = require('./property')
const Logger = require('./logger')
const Notification = require('./notification')
// http://docs.sequelizejs.com/manual/tutorial/associations.html
User.OwnedOrganizations = User.hasMany(Organization, { foreignKey: 'ownerId', constraints: false, as: 'ownedOrganizations' })
User.JoinedOrganizations = User.belongsToMany(Organization, { through: 'organizations_members', as: 'joinedOrganizations' })
User.OwnedRepositories = User.hasMany(Repository, { foreignKey: 'ownerId', constraints: false, as: 'ownedRepositories' })
User.JoinedRepositories = User.belongsToMany(Repository, { through: 'repositories_members', as: 'joinedRepositories' })
Organization.Creator = Organization.belongsTo(User, { foreignKey: 'creatorId', as: 'creator' }) // 创建者
Organization.Owner = Organization.belongsTo(User, { foreignKey: 'ownerId', constraints: false, as: 'owner' }) // 所有者
Organization.Members = Organization.belongsToMany(User, { through: 'organizations_members', as: 'members' }) // 团队成员
Organization.Repositories = Organization.hasMany(Repository, { foreignKey: 'organizationId', constraints: false, as: 'repositories' })
Repository.Creator = Repository.belongsTo(User, { foreignKey: 'creatorId', constraints: false, as: 'creator' }) // 创建者
Repository.Owner = Repository.belongsTo(User, { foreignKey: 'ownerId', constraints: false, as: 'owner' }) // 所有者
Repository.Organization = Repository.belongsTo(Organization, { foreignKey: 'organizationId', constraints: false, as: 'organization' }) // 所属团队
Repository.Locker = Repository.belongsTo(User, { foreignKey: 'lockerId', constraints: false, as: 'locker' }) // 锁定者
Repository.Members = Repository.belongsToMany(User, { through: 'repositories_members', as: 'members' }) // 仓库成员
Repository.Modules = Repository.hasMany(Module, { foreignKey: 'repositoryId', constraints: false, as: 'modules' })
Repository.Interfaces = Repository.hasMany(Interface, { foreignKey: 'repositoryId', constraints: false, as: 'interfaces' })
Repository.Collaborators = Repository.belongsToMany(Repository, { through: 'repositories_collaborators', as: 'collaborators' }) // 仓库共享
Module.Creator = Module.belongsTo(User, { foreignKey: 'creatorId', as: 'creator' }) // 创建者
Module.Repository = Module.belongsTo(Repository, { foreignKey: 'repositoryId', as: 'repository' })
Module.Interfaces = Module.hasMany(Interface, { foreignKey: 'moduleId', constraints: false, as: 'interfaces' })
Interface.Creator = Interface.belongsTo(User, { foreignKey: 'creatorId', as: 'creator' }) // 创建者
Interface.Locker = Interface.belongsTo(User, { foreignKey: 'lockerId', as: 'locker' }) // 锁定者
Interface.Module = Interface.belongsTo(Module, { foreignKey: 'moduleId', as: 'module' })
Interface.Repository = Interface.belongsTo(Repository, { foreignKey: 'repositoryId', as: 'repository' })
Interface.Properties = Interface.hasMany(Property, { foreignKey: 'interfaceId', constraints: false, as: 'properties' })
Property.Creator = Property.belongsTo(User, { foreignKey: 'creatorId', as: 'creator' }) // 创建者
Property.Interface = Property.belongsTo(Interface, { foreignKey: 'interfaceId', as: 'interface' })
Property.Module = Property.belongsTo(Module, { foreignKey: 'moduleId', as: 'module' })
Property.Repository = Property.belongsTo(Repository, { foreignKey: 'repositoryId', as: 'repository' })
Logger.Creator = Logger.belongsTo(User, { foreignKey: 'creatorId', as: 'creator' })
Logger.User = Logger.belongsTo(User, { foreignKey: 'userId', as: 'user' })
Logger.Repository = Logger.belongsTo(Repository, { foreignKey: 'repositoryId', as: 'repository' })
Logger.Organization = Logger.belongsTo(Organization, { foreignKey: 'organizationId', as: 'organization' })
Logger.Module = Logger.belongsTo(Module, { foreignKey: 'moduleId', as: 'module' })
Logger.Interface = Logger.belongsTo(Interface, { foreignKey: 'interfaceId', as: 'interface' })
const QueryInclude = {
User: { model: User, as: 'user', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: true },
UserForSearch: { model: User, as: 'user', attributes: { include: ['id', 'fullname'] }, required: true },
Creator: { model: User, as: 'creator', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: true },
Owner: { model: User, as: 'owner', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: true },
Locker: { model: User, as: 'locker', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: false },
Members: { model: User, as: 'members', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, through: { attributes: [] }, required: false },
Repository: { model: Repository, as: 'repository', attributes: { exclude: [] }, paranoid: false, required: false },
Organization: { model: Organization, as: 'organization', attributes: { exclude: [] }, paranoid: false, required: false },
Module: { model: Module, as: 'module', attributes: { exclude: [] }, paranoid: false, required: false },
Interface: { model: Interface, as: 'interface', attributes: { exclude: [] }, paranoid: false, required: false },
Collaborators: { model: Repository, as: 'collaborators', attributes: { exclude: [] }, through: { attributes: [] }, required: false },
RepositoryHierarchy: {
model: Module,
as: 'modules',
attributes: { exclude: [] },
required: false,
separate: true,
order: [
['priority', 'ASC']
],
include: [{
model: Interface,
as: 'interfaces',
attributes: { exclude: [] },
required: false,
separate: true,
order: [
['priority', 'ASC']
],
include: [{
model: User,
as: 'locker',
attributes: { exclude: ['password', ...Helper.exclude.generalities] },
required: false
}, {
model: Property,
as: 'properties',
attributes: { exclude: [] },
required: false,
separate: true
}]
}]
},
Properties: {
model: Property,
as: 'properties',
attributes: { exclude: [] },
required: false
}
}
module.exports = {
User, Organization, Repository, Module, Interface, Property, Logger, Notification, Helper, QueryInclude
}

@ -0,0 +1,11 @@
import { User } from '.';
export { QueryInclude } from './queryInclude'
export { Interface } from './interface'
export { Logger } from './logger'
export { Module } from './module'
export { Notification } from './notification'
export { Organization } from './organization'
export { Property } from './property'
export { Repository } from './repository'
export { User } from './user'

@ -1,16 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
const methods = ['GET', 'POST', 'PUT', 'DELETE']
module.exports = sequelize.define('interface', {
id,
name: { type: Sequelize.STRING(256), allowNull: false, comment: '接口名称' },
url: { type: Sequelize.STRING(256), allowNull: false, comment: '接口地址' },
method: { type: Sequelize.ENUM(...methods), allowNull: false, comment: '接口类型' },
description: { type: Sequelize.TEXT, allowNull: true, comment: '接口描述' },
// DONE 2.2 支持接口排序
priority: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: false, defaultValue: 1, comment: '接口优先级' }
}, {
paranoid: true,
comment: '接口'
})

@ -0,0 +1,70 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey } from 'sequelize-typescript'
import { User, Module, Repository, Property } from './index';
enum methods { GET= 'GET', POST= 'POST', PUT= 'PUT', DELETE= 'DELETE' }
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Interface extends Model<Interface> {
public static METHODS= methods
public request?:object
public response?:object
@AutoIncrement
@PrimaryKey
@Column
id: number
@AllowNull(false)
@Column(DataType.STRING(256))
name: string
@AllowNull(false)
@Column(DataType.STRING(256))
url: string
@AllowNull(false)
@Column({ type: DataType.ENUM(methods.GET, methods.POST, methods.PUT, methods.DELETE), comment: 'API method' })
method: string
@Column(DataType.TEXT)
description
@AllowNull(false)
@Default(1)
@Column({ type: DataType.BIGINT(11).UNSIGNED, comment: 'Priority used for ordering' })
priority: number
@ForeignKey(() => User)
@Column
creatorId: number
@ForeignKey(() => User)
@Column
lockerId: number
@ForeignKey(() => Module)
@Column
moduleId: number
@ForeignKey(() => Repository)
@Column
repositoryId: number
@BelongsTo(() => User, 'creatorId')
creator: User
@BelongsTo(() => User, 'lockerId')
locker: User
@BelongsTo(() => Module, 'moduleId')
module: Module
@BelongsTo(() => Repository, 'repositoryId')
repository: Repository
@HasMany(() => Property, 'interfaceId')
properties: Property[]
}

@ -1,18 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
const types = ['create', 'update', 'delete', 'lock', 'unlock', 'join', 'exit']
// DONE 2.3 需要加 creator 吗Xxx 把 Xxx 加入了 仓库Xxx 或 团队Xxx。
module.exports = sequelize.define('logger', {
id,
type: { type: Sequelize.ENUM(...types), allowNull: false, comment: '操作类型' },
creatorId: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: true, comment: '创建者' },
userId: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: false, comment: '涉及用户' },
organizationId: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: true, comment: '涉及组织' },
repositoryId: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: true, comment: '涉及仓库' },
moduleId: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: true, comment: '涉及模块' },
interfaceId: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: true, comment: '涉及接口' }
}, {
paranoid: true,
comment: '操作日志'
})

@ -0,0 +1,68 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey } from 'sequelize-typescript'
import { User, Repository, Organization, Module, Interface } from './index'
enum types {
CREATE = 'create', UPDATE = 'update', DELETE = 'delete',
LOCK = 'lock', UNLOCK = 'unlock', JOIN = 'join', EXIT = 'exit'
}
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Logger extends Model<Logger> {
public static TYPES = types
@AutoIncrement
@PrimaryKey
@Column
id: number
@AllowNull(false)
@Column({
type: DataType.ENUM(types.CREATE, types.UPDATE, types.DELETE, types.LOCK, types.UNLOCK, types.JOIN, types.EXIT),
comment: 'operation type'
})
type: string
@ForeignKey(() => User)
@Column(DataType.BIGINT(11).UNSIGNED)
creatorId: number
@AllowNull(false)
@ForeignKey(() => User)
@Column(DataType.BIGINT(11).UNSIGNED)
userId: number
@ForeignKey(() => Organization)
@Column(DataType.BIGINT(11).UNSIGNED)
organizationId: number
@ForeignKey(() => Repository)
@Column(DataType.BIGINT(11).UNSIGNED)
repositoryId: number
@ForeignKey(() => Module)
@Column(DataType.BIGINT(11).UNSIGNED)
moduleId: number
@ForeignKey(() => Interface)
@Column(DataType.BIGINT(11).UNSIGNED)
interfaceId: number
@BelongsTo(() => User, 'creatorId')
creator: User
@BelongsTo(() => User, 'userId')
user: User
@BelongsTo(() => Repository, 'repositoryId')
repository: Repository
@BelongsTo(() => Organization, 'organizationId')
organization: Organization
@BelongsTo(() => Module, 'moduleId')
module: Module
@BelongsTo(() => Interface, 'interfaceId')
interface: Interface
}

@ -1,12 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
module.exports = sequelize.define('module', {
id,
name: { type: Sequelize.STRING(256), allowNull: false, comment: '模块名称' },
description: { type: Sequelize.TEXT, comment: '模块描述' },
priority: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: false, defaultValue: 1, comment: '接口优先级' }
}, {
paranoid: true,
comment: '模块'
})

@ -0,0 +1,42 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey } from 'sequelize-typescript'
import {User, Repository, Interface} from './index'
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Module extends Model<Module> {
@AutoIncrement
@PrimaryKey
@Column
id: number
@AllowNull(false)
@Column(DataType.STRING(256))
name: string
@AllowNull(false)
@Column(DataType.TEXT)
description: string
@AllowNull(false)
@Default(1)
@Column(DataType.BIGINT(11).UNSIGNED)
priority: number
@ForeignKey(() => User)
@Column
creatorId: number
@ForeignKey(() => Repository)
@Column
repositoryId: number
@BelongsTo(() => User, 'creatorId')
creator: User
@BelongsTo(() => Repository, 'repositoryId')
repository: Repository
@HasMany(() => Interface, 'moduleId')
interfaces: Interface[]
}

@ -1,16 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
module.exports = sequelize.define('notification', {
id,
fromId: { type: Sequelize.BIGINT(11), allowNull: true, comment: '发送者' },
toId: { type: Sequelize.BIGINT(11), allowNull: false, comment: '接受者' },
type: { type: Sequelize.STRING(128), allowNull: false, comment: '消息类型' },
param1: { type: Sequelize.STRING(128), allowNull: true, comment: '参数1' },
param2: { type: Sequelize.STRING(128), allowNull: true, comment: '参数2' },
param3: { type: Sequelize.STRING(128), allowNull: true, comment: '参数3' },
readed: { type: Sequelize.BOOLEAN, allowNull: false, defautValue: false, comment: '是否已读' }
}, {
paranoid: true,
comment: '消息'
})

@ -0,0 +1,35 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default } from 'sequelize-typescript'
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Notification extends Model<Notification> {
@AutoIncrement
@PrimaryKey
@Column
id: number
@Column({ type: DataType.BIGINT(11).UNSIGNED, comment: 'sender' })
fromId: number
@AllowNull(false)
@Column({ type: DataType.BIGINT(11).UNSIGNED, comment: 'receiver' })
toId: number
@AllowNull(false)
@Column({ type: DataType.STRING(128), comment: 'msg type' })
type: string
@Column(DataType.STRING(128))
param1: string
@Column(DataType.STRING(128))
param2: string
@Column(DataType.STRING(128))
param3: string
@AllowNull(false)
@Default(false)
@Column
readed: boolean
}

@ -1,13 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
module.exports = sequelize.define('organization', {
id,
name: { type: Sequelize.STRING(256), allowNull: false, comment: '团队名称' },
description: { type: Sequelize.TEXT, allowNull: true, comment: '团队描述' },
logo: { type: Sequelize.STRING(256), allowNull: true, comment: '团队标志' },
visibility: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true, comment: '是否公开' }
}, {
paranoid: true,
comment: '团队'
})

@ -0,0 +1,46 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, BelongsToMany, ForeignKey } from 'sequelize-typescript'
import { User, Repository } from './index'
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Organization extends Model<Organization> {
@AutoIncrement
@PrimaryKey
@Column
id: number
@AllowNull(false)
@Column(DataType.STRING(256))
name: string
@Column(DataType.TEXT)
description: string
@Column(DataType.STRING(256))
logo: string
@AllowNull(false)
@Default(true)
@Column({ comment: 'true:public, false:private' })
visibility: boolean
@ForeignKey(() => User)
@Column
creatorId: number
@ForeignKey(() => User)
@Column
ownerId: number
@BelongsTo(() => User, 'creatorId')
creator: User
@BelongsTo(() => User, 'ownerId')
owner: User
@BelongsToMany(() => User, 'organizations_members', 'organizationId', 'userId')
members: User[]
@HasMany(() => Repository, 'organizationId')
repositories: Repository[]
}

@ -1,19 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
const SCOPES = ['request', 'response']
const TYPES = ['String', 'Number', 'Boolean', 'Object', 'Array', 'Function', 'RegExp']
module.exports = sequelize.define('property', {
id,
scope: { type: Sequelize.ENUM(...SCOPES), allowNull: false, defaultValue: 'response', comment: '属性归属' },
name: { type: Sequelize.STRING(256), allowNull: false, comment: '属性名称' },
type: { type: Sequelize.ENUM(...TYPES), allowNull: false, comment: '属性值类型' },
rule: { type: Sequelize.STRING(128), allowNull: true, comment: '属性值生成规则' },
value: { type: Sequelize.TEXT, allowNull: true, comment: '属性值' },
description: { type: Sequelize.TEXT, allowNull: true, comment: '属性描述' },
parentId: { type: Sequelize.BIGINT(11), allowNull: false, defaultValue: -1, comment: '父属性' },
priority: { type: Sequelize.BIGINT(11).UNSIGNED, allowNull: false, defaultValue: 1, comment: '接口优先级' }
}, {
paranoid: true,
comment: '属性'
})

@ -0,0 +1,86 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, ForeignKey } from 'sequelize-TYPEScript'
import { User, Interface, Module, Repository } from './index'
enum SCOPES { REQUEST = 'request', RESPONSE = 'response' }
enum TYPES { STRING = 'String', NUMBER = 'Number', BOOLEAN = 'Boolean', OBJECT = 'Object', ARRAY = 'Array', FUNCTION = 'Function', REGEXP = 'RegExp' }
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Property extends Model<Property> {
public static TYPES = TYPES
public static SCOPES = SCOPES
@AutoIncrement
@PrimaryKey
@Column
id: number
static attributes: any;
@AllowNull(false)
@Default(SCOPES.RESPONSE)
@Column({
type: DataType.ENUM(SCOPES.REQUEST, SCOPES.RESPONSE),
comment: 'property owner'
})
scope: string
@AllowNull(false)
@Column({
type: DataType.ENUM(TYPES.STRING, TYPES.NUMBER, TYPES.BOOLEAN, TYPES.OBJECT, TYPES.ARRAY, TYPES.FUNCTION, TYPES.REGEXP),
comment: 'property type'
})
type: string
@AllowNull(false)
@Column(DataType.STRING(256))
name: string
@Column({ type: DataType.STRING(128), comment: 'property generation rules' })
rule: string
@Column({ type: DataType.TEXT, comment: 'value of this property'})
value: string
@Column(DataType.TEXT)
description: string
@AllowNull(false)
@Default(-1)
@Column({ type: DataType.BIGINT(11), comment: 'parent property ID' })
parentId: number
@AllowNull(false)
@Default(1)
@Column(DataType.BIGINT(11).UNSIGNED)
priority: number
@ForeignKey(() => Interface)
@Column
interfaceId: number
@ForeignKey(() => User)
@Column
creatorId: number
@ForeignKey(() => Module)
@Column
moduleId: number
@ForeignKey(() => Repository)
@Column
repositoryId: number
@BelongsTo(() => User, 'creatorId')
creator: User
@BelongsTo(() => Interface, 'interfaceId')
interface: Interface
@BelongsTo(() => Module, 'moduleId')
module: Module
@BelongsTo(() => Repository, 'repositoryId')
repository: Repository
}

@ -0,0 +1,60 @@
// TODO 2.2 如何缓存重复查询https://github.com/rfink/sequelize-redis-cache
import { Helper } from './helper'
import { User } from './user'
import { Repository } from './repository';
import { Organization } from './organization'
import { Module } from './module'
import { Interface } from './interface'
import { Property } from './property'
export const QueryInclude = {
User: { model: User, as: 'user', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: true },
UserForSearch: { model: User, as: 'user', attributes: { include: ['id', 'fullname'] }, required: true },
Creator: { model: User, as: 'creator', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: true },
Owner: { model: User, as: 'owner', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: true },
Locker: { model: User, as: 'locker', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, required: false },
Members: { model: User, as: 'members', attributes: { exclude: ['password', ...Helper.exclude.generalities] }, through: { attributes: [] }, required: false },
Repository: { model: Repository, as: 'repository', attributes: { exclude: [] }, paranoid: false, required: false },
Organization: { model: Organization, as: 'organization', attributes: { exclude: [] }, paranoid: false, required: false },
Module: { model: Module, as: 'module', attributes: { exclude: [] }, paranoid: false, required: false },
Interface: { model: Interface, as: 'interface', attributes: { exclude: [] }, paranoid: false, required: false },
Collaborators: { model: Repository, as: 'collaborators', attributes: { exclude: [] }, through: { attributes: [] }, required: false },
RepositoryHierarchy: {
model: Module,
as: 'modules',
attributes: { exclude: [] },
required: false,
separate: true,
order: [
['priority', 'ASC']
],
include: [{
model: Interface,
as: 'interfaces',
attributes: { exclude: [] },
required: false,
separate: true,
order: [
['priority', 'ASC']
],
include: [{
model: User,
as: 'locker',
attributes: { exclude: ['password', ...Helper.exclude.generalities] },
required: false
}, {
model: Property,
as: 'properties',
attributes: { exclude: [] },
required: false,
separate: true
}]
}]
},
Properties: {
model: Property,
as: 'properties',
attributes: { exclude: [] },
required: false
}
}

@ -1,13 +0,0 @@
const Sequelize = require('sequelize')
const sequelize = require('./sequelize')
const { id } = require('./helper')
module.exports = sequelize.define('repository', {
id,
name: { type: Sequelize.STRING(256), allowNull: false, comment: '仓库名称' },
description: { type: Sequelize.TEXT, allowNull: true, comment: '仓库描述' },
logo: { type: Sequelize.STRING(256), allowNull: true, comment: '仓库标志' },
visibility: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true, comment: '是否公开' }
}, {
paranoid: true,
comment: '仓库'
})

@ -0,0 +1,67 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, BelongsTo, BelongsToMany, ForeignKey } from 'sequelize-typescript'
import { User, Organization, Module, Interface } from './index'
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class Repository extends Model<Repository> {
@AutoIncrement
@PrimaryKey
@Column
id: number
@AllowNull(false)
@Column(DataType.STRING(256))
name: string
@Column(DataType.TEXT)
description: string
@Column(DataType.STRING(256))
logo: string
@AllowNull(false)
@Default(true)
@Column({ comment: 'true:public, false:private' })
visibility: boolean
@ForeignKey(() => User)
@Column
ownerId: number
@ForeignKey(() => Organization)
@Column
organizationId: number
@ForeignKey(() => User)
@Column
creatorId: number
@ForeignKey(() => User)
@Column
lockerId: number
@BelongsTo(() => User, 'creatorId')
creator: User
@BelongsTo(() => User, 'ownerId')
owner: User
@BelongsTo(() => Organization, 'organizationId')
organization: Organization
@BelongsTo(() => User, 'lockerId')
locker: User
@BelongsToMany(() => User, 'repositories_members', 'repositoryId', 'userId')
members: User[]
@HasMany(() => Module, 'repositoryId')
modules: Module[]
@HasMany(() => Module, 'repositoryId')
interfaces: Interface[]
@BelongsToMany(() => Repository, 'repositories_collaborators', 'repositoryId', 'collaboratorId')
collaborators: Repository[]
}

@ -0,0 +1,48 @@
import { Sequelize } from 'sequelize-typescript'
import { Interface, Logger, Module, Notification, Organization, Property, User, Repository } from './index'
import config from '../config'
const chalk = require('chalk')
const now = () => new Date().toISOString().replace(/T/, ' ').replace(/Z/, '')
const logging = process.env.NODE_ENV === 'development'
? (sql) => {
sql = sql.replace('Executing (default): ', '')
console.log(`${chalk.bold('SQL')} ${now()} ${chalk.gray(sql)}`)
}
: console.log
const sequelize = new Sequelize({
database: config.db.database,
dialect: config.db.dialect,
username: config.db.username,
password: config.db.password,
host: config.db.host,
port: config.db.port,
pool: config.db.pool,
logging: config.db.logging ? logging : false
})
sequelize.addModels([Interface, Logger, Module, Notification, Organization, Property, Repository, User])
sequelize.authenticate()
.then((/* err */) => {
// initialize hooks
Organization.hook('afterCreate', async(instance, options) => {
await Logger.create({
userId: instance.creatorId,
type: 'create',
organizationId: instance.id
})
})
console.log('----------------------------------------')
console.log('DATABASE √')
console.log(' HOST %s', config.db.host)
console.log(' PORT %s', config.db.port)
console.log(' DATABASE %s', config.db.database)
console.log('----------------------------------------')
})
.catch(err => {
console.log('Unable to connect to the database:', err)
})
module.exports = sequelize

@ -0,0 +1,36 @@
import { Sequelize, Table, Column, Model, HasMany, AutoIncrement, PrimaryKey, AllowNull, DataType, Default, Unique, ForeignKey, BelongsToMany } from 'sequelize-typescript'
import { Organization, Repository } from './index'
@Table({ paranoid: true, freezeTableName: false, timestamps: true })
export class User extends Model<User> {
@AutoIncrement
@PrimaryKey
@Column
id: number
@AllowNull(false)
@Column(DataType.STRING(32))
fullname: string
@Column(DataType.STRING(32))
password: string
@AllowNull(false)
@Unique
@Column(DataType.STRING(128))
email: string
@HasMany(() => Organization, 'ownerId')
ownedOrganizations: Organization[]
@BelongsToMany(() => Organization, 'organizations_members', 'organizationId', 'userId')
joinedOrganizations: Organization[]
@HasMany(() => Repository, 'ownerId')
ownedRepositories: Repository[]
@BelongsToMany(() => Repository, 'repositories_members', 'userId', 'repositoryId')
joinedRepositories: Repository[]
}

@ -1,6 +1,14 @@
let router = require('./router') import * as svgCaptcha from 'svg-captcha'
let Pagination = require('./utils/pagination') import { User, Notification, Logger, Organization, Repository } from '../models'
let { User, Notification, Logger, QueryInclude } = require('../models') import router from './router'
import { Model } from 'sequelize-typescript';
import { WhereOptions } from 'sequelize';
import { Pagination } from './utils/pagination'
import { QueryInclude } from '../models'
interface Application {
counter: any
}
router.get('/app/get', async (ctx, next) => { router.get('/app/get', async (ctx, next) => {
let data = {} let data = {}
@ -60,9 +68,15 @@ router.get('/account/info', async(ctx, next) => {
}) : null }) : null
} }
}) })
router.post('/account/login', async(ctx, next) => { router.post('/account/login', async(ctx, next) => {
let { email, password } = ctx.request.body let { email, password, captcha } = ctx.request.body
let result = await User.findOne({ let result, errMsg
if (!captcha || !ctx.session.captcha || captcha.trim().toLowerCase() !== ctx.session.captcha.toLowerCase()) {
errMsg = '错误的验证码'
}
result = await User.findOne({
attributes: QueryInclude.User.attributes, attributes: QueryInclude.User.attributes,
where: { email, password } where: { email, password }
}) })
@ -87,7 +101,6 @@ router.get('/account/logout', async(ctx, next) => {
}) })
router.post('/account/register', async(ctx, next) => { router.post('/account/register', async(ctx, next) => {
// TODO 2.4 empId 可能为空,需要重新梳理用户注册流程
let { fullname, email, password } = ctx.request.body let { fullname, email, password } = ctx.request.body
let exists = await User.findAll({ let exists = await User.findAll({
where: { email } where: { email }
@ -144,6 +157,7 @@ router.get('/account/setting', async(ctx, next) => {
data: {} data: {}
} }
}) })
router.post('/account/setting', async(ctx, next) => { router.post('/account/setting', async(ctx, next) => {
ctx.body = { ctx.body = {
data: {} data: {}
@ -167,16 +181,19 @@ router.get('/account/notification/list', async(ctx, next) => {
pagination: pagination pagination: pagination
} }
}) })
router.get('/account/notification/unreaded', async(ctx, next) => { router.get('/account/notification/unreaded', async(ctx, next) => {
ctx.body = { ctx.body = {
data: [] data: []
} }
}) })
router.post('/account/notification/unreaded', async(ctx, next) => { router.post('/account/notification/unreaded', async(ctx, next) => {
ctx.body = { ctx.body = {
data: 0 data: 0
} }
}) })
router.post('/account/notification/read', async(ctx, next) => { router.post('/account/notification/read', async(ctx, next) => {
ctx.body = { ctx.body = {
data: 0 data: 0
@ -186,10 +203,10 @@ router.post('/account/notification/read', async(ctx, next) => {
// TODO 2.3 账户日志 // TODO 2.3 账户日志
router.get('/account/logger', async(ctx, next) => { router.get('/account/logger', async(ctx, next) => {
let auth = await User.findById(ctx.session.id) let auth = await User.findById(ctx.session.id)
let repositories = [...await auth.getOwnedRepositories({}), ...await auth.getJoinedRepositories({})] let repositories:Model<Repository>[] = [...(<Model<Repository>[]>await auth.$get('ownedRepositories')), ...(<Model<Repository>[]> await auth.$get('joinedRepositories'))]
let organizations = [...await auth.getOwnedOrganizations({}), ...await auth.getJoinedOrganizations({})] let organizations:Model<Organization>[] = [...(<Model<Organization>[]>await auth.$get('ownedOrganizations')), ...(<Model<Organization>[]> await auth.$get('joinedOrganizations'))]
let where = { let where:any = {
$or: [ $or: [
{ userId: ctx.session.id }, { userId: ctx.session.id },
{ repositoryId: repositories.map(item => item.id) }, { repositoryId: repositories.map(item => item.id) },
@ -198,6 +215,7 @@ router.get('/account/logger', async(ctx, next) => {
} }
let total = await Logger.count({ where }) let total = await Logger.count({ 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)
console.log(QueryInclude.User)
let logs = await Logger.findAll({ let logs = await Logger.findAll({
where, where,
attributes: {}, attributes: {},
@ -216,10 +234,16 @@ router.get('/account/logger', async(ctx, next) => {
], ],
paranoid: false paranoid: false
}) })
ctx.body = { ctx.body = {
data: logs, data: logs,
pagination: pagination pagination
} }
}) })
module.exports = router router.get('/captcha', async(ctx, next) => {
var captcha = svgCaptcha.create()
ctx.session.captcha = captcha.text
ctx.set('Content-Type', 'image/svg+xml')
ctx.body = captcha.data
})

@ -1,4 +1,4 @@
const router = require('./router') import router from './router'
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 }
@ -62,7 +62,6 @@ router.get('/app/analytics/users/activation', async (ctx, next) => {
let sql = ` let sql = `
SELECT SELECT
loggers.userId AS userId, loggers.userId AS userId,
users.empId AS empId,
users.fullname AS fullname, users.fullname AS fullname,
COUNT(*) AS value COUNT(*) AS value
FROM FROM
@ -108,4 +107,4 @@ router.get('/app/analytics/repositories/activation', async (ctx, next) => {
} }
}) })
// TODO 2.3 支持 start、end // TODO 2.3 支持 start、end

@ -1,5 +1,5 @@
const router = require('./router') import router from './router'
const config = require('../../config') const config = require('../config')
router.get('/app/counter', async(ctx, next) => { router.get('/app/counter', async(ctx, next) => {
ctx.body = { ctx.body = {
@ -9,6 +9,4 @@ router.get('/app/counter', async(ctx, next) => {
mock: ctx.app.counter.mock mock: ctx.app.counter.mock
} }
} }
}) })
module.exports = router

@ -1,4 +1,4 @@
let router = require('./router') import router from './router'
require('./counter') require('./counter')
require('./account') require('./account')
@ -7,4 +7,4 @@ require('./repository')
require('./mock') require('./mock')
require('./analytics') require('./analytics')
module.exports = router export default router

@ -1,8 +1,8 @@
const { URL } = require('url') import router from './router'
const router = require('./router') import { Repository, Interface, Property } from '../models'
const { Repository, Interface, Property, QueryInclude } = require('../models') import { QueryInclude } from '../models';
import Tree from './utils/tree'
const attributes = { exclude: [] } const attributes = { exclude: [] }
const Tree = require('./utils/tree')
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 urlUtils = require('./utils/url') const urlUtils = require('./utils/url')
@ -25,7 +25,7 @@ const parseDuplicatedInterfaces = (repository) => {
const generatePlugin = (protocol, host, repository) => { const generatePlugin = (protocol, host, repository) => {
// DONE 2.3 protocol 错误,应该是 https // DONE 2.3 protocol 错误,应该是 https
let duplicated = parseDuplicatedInterfaces(repository) let duplicated = parseDuplicatedInterfaces(repository)
let editor = `${protocol}://rap2.alibaba-inc.com/repository/editor?id=${repository.id}` let editor = `${protocol}://rap2.taobao.org/repository/editor?id=${repository.id}` // [TODO] replaced by cur domain
let result = ` let result = `
/** /**
* #${repository.id} ${repository.name} * #${repository.id} ${repository.name}
@ -57,7 +57,7 @@ const generatePlugin = (protocol, host, repository) => {
} }
router.get('/app/plugin/:repositories', async (ctx, next) => { router.get('/app/plugin/:repositories', async (ctx, next) => {
let repositoryIds = new Set(ctx.params.repositories.split(',').map(item => +item).filter(item => item)) // _.uniq() => Set let repositoryIds = new Set<number>(ctx.params.repositories.split(',').map(item => +item).filter(item => 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.findById(id, {
@ -78,7 +78,7 @@ router.get('/app/plugin/:repositories', async (ctx, next) => {
}) })
} }
// console.log(repositoryIds) // console.log(repositoryIds)
repository.interfaces = await Interface.findAll({ repository.interfaces = await Interface.findAll<Interface>({
attributes: { exclude: [] }, attributes: { exclude: [] },
where: { where: {
repositoryId: repository.id repositoryId: repository.id
@ -105,10 +105,10 @@ router.get('/app/plugin/:repositories', async (ctx, next) => {
// X DONE 2.2 支持 GET POST PUT DELETE 请求 // X DONE 2.2 支持 GET POST PUT DELETE 请求
// DONE 2.2 忽略请求地址中的前缀斜杠 // DONE 2.2 忽略请求地址中的前缀斜杠
// DONE 2.3 支持所有类型的请求,这样从浏览器中发送跨越请求时不需要修改 method // DONE 2.3 支持所有类型的请求,这样从浏览器中发送跨越请求时不需要修改 method
router.all('/app/mock/(\\d+)/(\\w+)/(.+)', async (ctx, next) => { router.all('/app/mock/(\\d+)/(.+)', async (ctx, next) => {
ctx.app.counter.mock++ ctx.app.counter.mock++
let [ repositoryId, method, url ] = [ctx.params[0], ctx.params[1], ctx.params[2]] let [ repositoryId, method, url ] = [ctx.params[0], ctx.request.method, ctx.params[1]]
let urlWithoutPrefixSlash = /(\/)?(.*)/.exec(url)[2] let urlWithoutPrefixSlash = /(\/)?(.*)/.exec(url)[2]
let urlWithoutSearch let urlWithoutSearch
@ -124,7 +124,7 @@ router.all('/app/mock/(\\d+)/(\\w+)/(.+)', async (ctx, next) => {
// 所以这里重新解析一遍!!! // 所以这里重新解析一遍!!!
let repository = await Repository.findById(repositoryId) let repository = await Repository.findById(repositoryId)
let collaborators = await repository.getCollaborators() let collaborators = await repository.collaborators
let itf let itf
itf = await Interface.findOne({ itf = await Interface.findOne({

@ -1,15 +1,8 @@
let _ = require('underscore') import router from './router'
let router = require('./router') import { Organization, User, Logger, Repository, Module, Interface, Property } from '../models'
let Pagination = require('./utils/pagination') import { QueryInclude } from '../models';
let { User, Organization, Repository, Module, Interface, Property, QueryInclude, Logger } = require('../models') import * as _ from 'lodash'
import { Pagination } from './utils/pagination'
Organization.hook('afterCreate', async(instance, options) => {
await Logger.create({
userId: instance.creatorId,
type: 'create',
organizationId: instance.id
})
})
router.get('/app/get', async (ctx, next) => { router.get('/app/get', async (ctx, next) => {
let data = {} let data = {}
@ -84,13 +77,13 @@ router.get('/organization/owned', async(ctx, next) => {
} }
let auth = await User.findById(ctx.session.id) let auth = await User.findById(ctx.session.id)
let options = { let options:any = {
where, where,
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members], include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members],
order: [['updatedAt', 'DESC']] order: [['updatedAt', 'DESC']]
} }
let owned = await auth.getOwnedOrganizations(options) let owned = await auth.$get('ownedOrganizations', options)
ctx.body = { ctx.body = {
data: owned, data: owned,
pagination: null pagination: null
@ -109,13 +102,13 @@ router.get('/organization/joined', async(ctx, next) => {
} }
let auth = await User.findById(ctx.session.id) let auth = await User.findById(ctx.session.id)
let options = { let options:object = {
where, where,
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members], include: [QueryInclude.Creator, QueryInclude.Owner, QueryInclude.Members],
order: [['updatedAt', 'DESC']] order: [['updatedAt', 'DESC']]
} }
let joined = await auth.getJoinedOrganizations(options) let joined = await auth.$get('joinedOrganizations', options)
// await auth.getOwnedOrganizations() // await auth.getOwnedOrganizations()
// await auth.getJoinedOrganizations() // await auth.getJoinedOrganizations()
ctx.body = { ctx.body = {
@ -138,7 +131,7 @@ router.post('/organization/create', async(ctx, next) => {
let created = await Organization.create(body) let created = await Organization.create(body)
if (body.memberIds) { if (body.memberIds) {
let members = await User.findAll({ where: { id: body.memberIds } }) let members = await User.findAll({ where: { id: body.memberIds } })
await created.setMembers(members) await created.$set('members', members)
} }
let filled = await Organization.findById(created.id, { let filled = await Organization.findById(created.id, {
attributes: { exclude: [] }, attributes: { exclude: [] },
@ -157,9 +150,9 @@ router.post('/organization/update', async(ctx, next) => {
if (body.memberIds) { if (body.memberIds) {
let reloaded = await Organization.findById(body.id) let reloaded = await Organization.findById(body.id)
let members = await User.findAll({ where: { id: body.memberIds } }) let members = await User.findAll({ where: { id: body.memberIds } })
ctx.prevAssociations = await reloaded.getMembers() ctx.prevAssociations = await reloaded.$get('members')
await reloaded.setMembers(members) await reloaded.$set('members', members)
ctx.nextAssociations = await reloaded.getMembers() ctx.nextAssociations = await reloaded.$get('members')
} }
ctx.body = { ctx.body = {
data: updated[0] data: updated[0]
@ -220,6 +213,4 @@ router.get('/organization/remove', async(ctx, next) => {
type: 'delete', type: 'delete',
organizationId: id organizationId: id
}) })
}) })
module.exports = router

@ -1,8 +1,8 @@
// TODO 2.1 大数据测试,含有大量模块、接口、属性的仓库 // TODO 2.1 大数据测试,含有大量模块、接口、属性的仓库
const router = require('./router') import router from './router'
const _ = require('underscore') const _ = require('underscore')
const Pagination = require('./utils/pagination') const Pagination = require('./utils/pagination')
const { User, Organization, Repository, Module, Interface, Property, QueryInclude, Logger } = require('../models') import { User, Organization, Repository, Module, Interface, Property, QueryInclude, Logger } from '../models'
const Tree = require('./utils/tree') const Tree = require('./utils/tree')
const { initRepository, initModule } = require('./utils/helper') const { initRepository, initModule } = require('./utils/helper')
@ -75,7 +75,7 @@ router.get('/repository/list', async(ctx, next) => {
} }
}) })
router.get('/repository/owned', async(ctx, next) => { router.get('/repository/owned', async(ctx, next) => {
let where = {} // { organizationId: null } // 彻底废弃个人仓库&团队仓库概念,一个仓库必须属于某个用户,可选属于某个团队 let where = {}
let { name } = ctx.query let { name } = ctx.query
if (name) { if (name) {
Object.assign(where, { Object.assign(where, {
@ -86,12 +86,11 @@ router.get('/repository/owned', async(ctx, next) => {
}) })
} }
let auth = await User.findById(ctx.query.user || ctx.session.id) let auth: User = await User.findById(ctx.query.user || ctx.session.id)
// 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.getOwnedRepositories({ let repositories = await auth.$get('ownedRepositories', {
where, where,
attributes: { exclude: [] },
include: [ include: [
QueryInclude.Creator, QueryInclude.Creator,
QueryInclude.Owner, QueryInclude.Owner,
@ -110,7 +109,7 @@ router.get('/repository/owned', async(ctx, next) => {
} }
}) })
router.get('/repository/joined', async(ctx, next) => { router.get('/repository/joined', async(ctx, next) => {
let where = {} let where:any = {}
let { name } = ctx.query let { name } = ctx.query
if (name) { if (name) {
Object.assign(where, { Object.assign(where, {
@ -124,7 +123,7 @@ router.get('/repository/joined', async(ctx, next) => {
let auth = await User.findById(ctx.query.user || ctx.session.id) let auth = await User.findById(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.getJoinedRepositories({ let repositories = await auth.$get('joinedRepositories', {
where, where,
attributes: { exclude: [] }, attributes: { exclude: [] },
include: [ include: [
@ -167,11 +166,11 @@ router.post('/repository/create', async(ctx, next) => {
let created = await Repository.create(body) let created = await Repository.create(body)
if (body.memberIds) { if (body.memberIds) {
let members = await User.findAll({ where: { id: body.memberIds } }) let members = await User.findAll({ where: { id: body.memberIds } })
await created.setMembers(members) await created.$set('members', members)
} }
if (body.collaboratorIds) { if (body.collaboratorIds) {
let collaborators = await Repository.findAll({ where: { id: body.collaboratorIds } }) let collaborators = await Repository.findAll({ where: { id: body.collaboratorIds } })
await created.setCollaborators(collaborators) await created.$set('collaborators', collaborators)
} }
await initRepository(created) await initRepository(created)
ctx.body = { ctx.body = {
@ -206,14 +205,14 @@ router.post('/repository/update', async(ctx, next) => {
if (body.memberIds) { if (body.memberIds) {
let reloaded = await Repository.findById(body.id) let reloaded = await Repository.findById(body.id)
let members = await User.findAll({ where: { id: body.memberIds } }) let members = await User.findAll({ where: { id: body.memberIds } })
ctx.prevAssociations = await reloaded.getMembers() ctx.prevAssociations = await reloaded.$get('members')
await reloaded.setMembers(members) await reloaded.$set('members', members)
ctx.nextAssociations = await reloaded.getMembers() ctx.nextAssociations = await reloaded.$get('members')
} }
if (body.collaboratorIds) { if (body.collaboratorIds) {
let reloaded = await Repository.findById(body.id) let reloaded = await Repository.findById(body.id)
let collaborators = await Repository.findAll({ where: { id: body.collaboratorIds } }) let collaborators = await Repository.findAll({ where: { id: body.collaboratorIds } })
await reloaded.setCollaborators(collaborators) await reloaded.$set('collaborators', collaborators)
} }
ctx.body = { ctx.body = {
data: result[0] data: result[0]
@ -242,7 +241,7 @@ router.post('/repository/update', async(ctx, next) => {
}) })
router.post('/repository/transfer', async(ctx, next) => { router.post('/repository/transfer', async(ctx, next) => {
let { id, ownerId, organizationId } = ctx.request.body let { id, ownerId, organizationId } = ctx.request.body
let body = {} let body:any = {}
if (ownerId) body.ownerId = ownerId // 转移给其他用户 if (ownerId) body.ownerId = ownerId // 转移给其他用户
if (organizationId) { if (organizationId) {
body.organizationId = organizationId // 转移给其他团队,同时转移给该团队拥有者 body.organizationId = organizationId // 转移给其他团队,同时转移给该团队拥有者
@ -305,7 +304,7 @@ router.get('/module/count', async (ctx, next) => {
} }
}) })
router.get('/module/list', async (ctx, next) => { router.get('/module/list', async (ctx, next) => {
let where = {} let where:any = {}
let { repositoryId, name } = ctx.query let { repositoryId, name } = ctx.query
if (repositoryId) where.repositoryId = repositoryId if (repositoryId) where.repositoryId = repositoryId
if (name) where.name = { $like: `%${name}%` } if (name) where.name = { $like: `%${name}%` }
@ -400,7 +399,7 @@ router.get('/interface/count', async (ctx, next) => {
} }
}) })
router.get('/interface/list', async (ctx, next) => { router.get('/interface/list', async (ctx, next) => {
let where = {} let where:any = {}
let { repositoryId, moduleId, name } = ctx.query let { repositoryId, moduleId, name } = ctx.query
if (repositoryId) where.repositoryId = repositoryId if (repositoryId) where.repositoryId = repositoryId
if (moduleId) where.moduleId = moduleId if (moduleId) where.moduleId = moduleId
@ -424,12 +423,12 @@ router.get('/interface/get', async (ctx, next) => {
// 同 /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.findById(repositoryId)
let collaborators = await repository.getCollaborators() let collaborators = await repository.$get('collaborators')
itf = await Interface.findOne({ itf = await Interface.findOne({
attributes: { exclude: [] }, attributes: { exclude: [] },
where: { where: {
repositoryId: [repositoryId, ...collaborators.map(item => item.id)], repositoryId: [repositoryId, ...(<Repository[]>collaborators).map(item => item.id)],
method, method,
url: [urlWithoutPrefixSlash, '/' + urlWithoutPrefixSlash] url: [urlWithoutPrefixSlash, '/' + urlWithoutPrefixSlash]
} }
@ -575,7 +574,7 @@ router.get('/property/count', async (ctx, next) => {
} }
}) })
router.get('/property/list', async (ctx, next) => { router.get('/property/list', async (ctx, next) => {
let where = {} let where:any = {}
let { repositoryId, moduleId, interfaceId, name } = ctx.query let { repositoryId, moduleId, interfaceId, name } = ctx.query
if (repositoryId) where.repositoryId = repositoryId if (repositoryId) where.repositoryId = repositoryId
if (moduleId) where.moduleId = moduleId if (moduleId) where.moduleId = moduleId
@ -695,6 +694,4 @@ router.get('/property/remove', async (ctx, next) => {
where: { id } where: { id }
}) })
} }
}) })
module.exports = router

@ -1,5 +1,5 @@
let Router = require('koa-router') import * as Router from 'koa-router'
const fetch = require('node-fetch') import fetch from 'node-fetch'
let router = new Router() let router = new Router()
// index // index
@ -32,4 +32,4 @@ router.get('/proxy', async(ctx, next) => {
ctx.body = json ctx.body = json
}) })
module.exports = router export default router

@ -44,15 +44,34 @@
new Pagination( data, cursor, limit ) new Pagination( data, cursor, limit )
new Pagination( total, cursor, limit ) new Pagination( total, cursor, limit )
*/ */
function Pagination (data, cursor, limit) {
this.data = (typeof data === 'number' || typeof data === 'string') ? undefined : data export class Pagination {
this.total = this.data ? this.data.length : parseInt(data, 10) public data: any
this.cursor = parseInt(cursor, 10) public total: any
this.limit = parseInt(limit, 10) public cursor: number
this.calc() public limit: number
} public focus: number
Pagination.prototype = { public pages
calc: function () { public start
public end
public hasPrev
public hasNext
public hasFirst
public hasLast
public prev
public next
public first
public last
constructor(data, cursor, limit) {
this.data = (typeof data === 'number' || typeof data === 'string') ? undefined : data
this.total = this.data ? this.data.length : parseInt(data, 10)
this.cursor = parseInt(cursor, 10)
this.limit = parseInt(limit, 10)
this.calc()
}
public calc() {
if (this.total && parseInt(this.total, 10) > 0) { if (this.total && parseInt(this.total, 10) > 0) {
this.limit = this.limit < 1 ? 1 : this.limit this.limit = this.limit < 1 ? 1 : this.limit
@ -87,62 +106,74 @@ Pagination.prototype = {
} }
return this return this
}, }
moveTo: function (cursor) {
public moveTo(cursor) {
this.cursor = parseInt(cursor, 10) this.cursor = parseInt(cursor, 10)
return this.calc() return this.calc()
}, }
moveToPrev: function () {
public moveToPrev() {
return this.moveTo(this.cursor - 1) return this.moveTo(this.cursor - 1)
}, }
moveToNext: function () {
public moveToNext() {
return this.moveTo(this.cursor + 1) return this.moveTo(this.cursor + 1)
}, }
moveToFirst: function () {
public moveToFirst() {
return this.moveTo(1) return this.moveTo(1)
}, }
moveToLast: function () {
public moveToLast() {
return this.moveTo(this.pages) return this.moveTo(this.pages)
}, }
fetch: function (arr) {
public fetch(arr) {
return (arr || this.data).slice(this.start, this.end) return (arr || this.data).slice(this.start, this.end)
}, }
setData: function (data) {
public setData(data) {
this.data = data this.data = data
this.total = data.length this.total = data.length
return this.calc() return this.calc()
}, }
setTotal: function (total) {
public setTotal(total) {
this.total = parseInt(total, 10) this.total = parseInt(total, 10)
return this.calc() return this.calc()
}, }
setCursor: function (cursor) {
public setCursor(cursor) {
this.cursor = parseInt(cursor, 10) this.cursor = parseInt(cursor, 10)
return this.calc() return this.calc()
}, }
setFocus: function (focus) {
public setFocus(focus) {
this.focus = parseInt(focus, 10) this.focus = parseInt(focus, 10)
if (this.focus < 0) this.focus += this.total if (this.focus < 0) this.focus += this.total
if (this.focus >= this.total) this.focus -= this.total if (this.focus >= this.total) this.focus -= this.total
this.cursor = parseInt(this.focus / this.limit, 10) + 1 this.cursor = parseInt(String(this.focus / this.limit), 10) + 1
return this.calc() return this.calc()
}, }
setLimit: function (limit) {
public setLimit(limit) {
this.limit = parseInt(limit, 10) this.limit = parseInt(limit, 10)
return this.calc() return this.calc()
}, }
get: function (focus) {
public get(focus) {
if (focus !== undefined) return this.data[focus % this.data.length] if (focus !== undefined) return this.data[focus % this.data.length]
else return this.data[this.focus] else return this.data[this.focus]
}, }
toString: function () {
public toString() {
return JSON.stringify(this, null, 4) return JSON.stringify(this, null, 4)
} }
}
Pagination.prototype.to = Pagination.prototype.moveTo public to = this.moveTo
Pagination.prototype.toPrev = Pagination.prototype.moveToPrev public toPrev = this.moveToPrev
Pagination.prototype.toNext = Pagination.prototype.moveToNext public toNext = this.moveToNext
Pagination.prototype.toFirst = Pagination.prototype.moveToFirst public toFirst = this.moveToFirst
Pagination.prototype.toLast = Pagination.prototype.moveToLast public toLast = this.moveToLast
}
module.exports = Pagination

@ -1,173 +0,0 @@
const vm = require('vm')
const _ = require('underscore')
const Mock = require('mockjs')
const { RE_KEY } = require('mockjs/src/mock/constant')
const Tree = {}
Tree.ArrayToTree = (list) => {
let result = {
name: 'root',
children: [],
depth: 0
}
let mapped = {}
list.forEach(item => { mapped[item.id] = item })
function _parseChildren (parentId, children, depth) {
for (let id in mapped) {
let item = mapped[id]
if (typeof parentId === 'function' ? parentId(item.parentId) : item.parentId === parentId) {
children.push(item)
item.depth = depth + 1
item.children = _parseChildren(item.id, [], item.depth)
}
}
return children
}
_parseChildren(
(parentId) => {
// 忽略 parentId 为 0 的根属性(历史遗留),现为 -1
if (parentId === -1) return true
},
result.children,
result.depth
)
return result
}
// TODO 2.x 和前端重复了
Tree.TreeToTemplate = (tree) => {
function parse (item, result) {
let rule = item.rule ? ('|' + item.rule) : ''
let value = item.value
switch (item.type) {
case 'String':
result[item.name + rule] = item.value
break
case 'Number':
if (value === '') value = 1
let parsed = parseFloat(value)
if (!isNaN(parsed)) value = parsed
result[item.name + rule] = value
break
case 'Boolean':
if (value === 'true') value = true
if (value === 'false') value = false
if (value === '0') value = false
value = !!value
result[item.name + rule] = value
break
case 'Function':
case 'RegExp':
try {
result[item.name + rule] = eval('(' + item.value + ')') // eslint-disable-line no-eval
} catch (e) {
console.warn(`TreeToTemplate ${e.message}: ${item.type} { ${item.name}${rule}: ${item.value} }`) // TODO 2.2 怎么消除异常值?
result[item.name + rule] = item.value
}
break
case 'Object':
if (item.value) {
try {
result[item.name + rule] = eval(`(${item.value})`) // eslint-disable-line no-eval
} catch (e) {
result[item.name + rule] = item.value
}
} else {
result[item.name + rule] = {}
item.children.forEach((child) => {
parse(child, result[item.name + rule])
})
}
break
case 'Array':
if (item.value) {
try {
result[item.name + rule] = eval(`(${item.value})`) // eslint-disable-line no-eval
} catch (e) {
result[item.name + rule] = item.value
}
} else {
result[item.name + rule] = item.children.length ? [{}] : []
item.children.forEach((child) => {
parse(child, result[item.name + rule][0])
})
}
break
}
}
let result = {}
tree.children.forEach((child) => {
parse(child, result)
})
return result
}
Tree.TemplateToData = (template) => {
// 数据模板 template 中可能含有攻击代码,例如死循环,所以在沙箱中生成最终数据
// https://nodejs.org/dist/latest-v7.x/docs/api/vm.html
const sandbox = { Mock, template, data: {} }
const script = new vm.Script('data = Mock.mock(template)')
const context = new vm.createContext(sandbox) // eslint-disable-line new-cap
try {
script.runInContext(context, { timeout: 1000 }) // 每次 Mock.mock() 最多执行 1s
// DONE 2.1 __root__
let data = sandbox.data
let keys = Object.keys(data)
if (keys.length === 1 && keys[0] === '__root__') data = data.__root__
return data
} catch (err) {
console.error(err)
return {}
}
}
Tree.ArrayToTreeToTemplate = (list) => {
let tree = Tree.ArrayToTree(list)
let template = Tree.TreeToTemplate(tree)
return template
}
Tree.ArrayToTreeToTemplateToData = (list, extra) => {
let tree = Tree.ArrayToTree(list)
let template = Tree.TreeToTemplate(tree)
let data
if (extra) {
// DONE 2.2 支持引用请求参数
let keys = Object.keys(template).map(item => item.replace(RE_KEY, '$1'))
let extraKeys = _.difference(Object.keys(extra), keys)
let scopedData = Tree.TemplateToData(
Object.assign({}, _.pick(extra, extraKeys), template)
)
data = _.pick(scopedData, keys)
} else {
data = Tree.TemplateToData(template)
}
return data
}
Tree.ArrayToTreeToTemplateToJSONSchema = (list) => {
let tree = Tree.ArrayToTree(list)
let template = Tree.TreeToTemplate(tree)
let schema = Mock.toJSONSchema(template)
return schema
}
// TODO 2.2 执行 JSON.stringify() 序列化时会丢失正则和函数。需要转为字符串或者函数。
// X Function.protytype.toJSON = Function.protytype.toString
// X RegExp.protytype.toJSON = RegExp.protytype.toString
Tree.stringifyWithFunctonAndRegExp = (json) => {
return JSON.stringify(json, (k, v) => {
if (typeof v === 'function') return v.toString()
if (v !== undefined && v !== null && v.exec) return v.toString()
else return v
}, 2)
}
module.exports = Tree

@ -0,0 +1,174 @@
const vm = require('vm')
const _ = require('underscore')
const Mock = require('mockjs')
const { RE_KEY } = require('mockjs/src/mock/constant')
export default class Tree {
public static ArrayToTree (list) {
let result = {
name: 'root',
children: [],
depth: 0
}
let mapped = {}
list.forEach(item => { mapped[item.id] = item })
function _parseChildren (parentId, children, depth) {
for (let id in mapped) {
let item = mapped[id]
if (typeof parentId === 'function' ? parentId(item.parentId) : item.parentId === parentId) {
children.push(item)
item.depth = depth + 1
item.children = _parseChildren(item.id, [], item.depth)
}
}
return children
}
_parseChildren(
(parentId) => {
// 忽略 parentId 为 0 的根属性(历史遗留),现为 -1
if (parentId === -1) return true
},
result.children,
result.depth
)
return result
}
// TODO 2.x 和前端重复了
public static TreeToTemplate (tree) {
function parse (item, result) {
let rule = item.rule ? ('|' + item.rule) : ''
let value = item.value
switch (item.type) {
case 'String':
result[item.name + rule] = item.value
break
case 'Number':
if (value === '') value = 1
let parsed = parseFloat(value)
if (!isNaN(parsed)) value = parsed
result[item.name + rule] = value
break
case 'Boolean':
if (value === 'true') value = true
if (value === 'false') value = false
if (value === '0') value = false
value = !!value
result[item.name + rule] = value
break
case 'Function':
case 'RegExp':
try {
result[item.name + rule] = eval('(' + item.value + ')') // eslint-disable-line no-eval
} catch (e) {
console.warn(`TreeToTemplate ${e.message}: ${item.type} { ${item.name}${rule}: ${item.value} }`) // TODO 2.2 怎么消除异常值?
result[item.name + rule] = item.value
}
break
case 'Object':
if (item.value) {
try {
result[item.name + rule] = eval(`(${item.value})`) // eslint-disable-line no-eval
} catch (e) {
result[item.name + rule] = item.value
}
} else {
result[item.name + rule] = {}
item.children.forEach((child) => {
parse(child, result[item.name + rule])
})
}
break
case 'Array':
if (item.value) {
try {
result[item.name + rule] = eval(`(${item.value})`) // eslint-disable-line no-eval
} catch (e) {
result[item.name + rule] = item.value
}
} else {
result[item.name + rule] = item.children.length ? [{}] : []
item.children.forEach((child) => {
parse(child, result[item.name + rule][0])
})
}
break
}
}
let result = {}
tree.children.forEach((child) => {
parse(child, result)
})
return result
}
public static TemplateToData (template) {
// 数据模板 template 中可能含有攻击代码,例如死循环,所以在沙箱中生成最终数据
// https://nodejs.org/dist/latest-v7.x/docs/api/vm.html
const sandbox = { Mock, template, data: {} }
const script = new vm.Script('data = Mock.mock(template)')
const context = new vm.createContext(sandbox) // eslint-disable-line new-cap
try {
script.runInContext(context, { timeout: 1000 }) // 每次 Mock.mock() 最多执行 1s
// DONE 2.1 __root__
let data:any = sandbox.data
let keys = Object.keys(data)
if (keys.length === 1 && keys[0] === '__root__') data = data.__root__
return data
} catch (err) {
console.error(err)
return {}
}
}
public static ArrayToTreeToTemplate(list) {
let tree = Tree.ArrayToTree(list)
let template = Tree.TreeToTemplate(tree)
return template
}
public static ArrayToTreeToTemplateToData(list, extra?:any) {
let tree = Tree.ArrayToTree(list)
let template = Tree.TreeToTemplate(tree)
let data
if (extra) {
// DONE 2.2 支持引用请求参数
let keys = Object.keys(template).map(item => item.replace(RE_KEY, '$1'))
let extraKeys = _.difference(Object.keys(extra), keys)
let scopedData = Tree.TemplateToData(
Object.assign({}, _.pick(extra, extraKeys), template)
)
data = _.pick(scopedData, keys)
} else {
data = Tree.TemplateToData(template)
}
return data
}
public static ArrayToTreeToTemplateToJSONSchema(list) {
let tree = Tree.ArrayToTree(list)
let template = Tree.TreeToTemplate(tree)
let schema = Mock.toJSONSchema(template)
return schema
}
// TODO 2.2 执行 JSON.stringify() 序列化时会丢失正则和函数。需要转为字符串或者函数。
// X Function.protytype.toJSON = Function.protytype.toString
// X RegExp.protytype.toJSON = RegExp.protytype.toString
public static stringifyWithFunctonAndRegExp(json) {
return JSON.stringify(json, (k, v) => {
if (typeof v === 'function') return v.toString()
if (v !== undefined && v !== null && v.exec) return v.toString()
else return v
}, 2)
}
}

@ -1,33 +0,0 @@
let pathToRegexp = require('path-to-regexp')
const pkg = {}
pkg.getRelative = url => {
if (!url || typeof url !== 'string') return null
url = url.toLowerCase()
const prefixes = ['https://', 'http://']
for (let item of prefixes) {
if (url.indexOf(item) > -1) {
url = url.substring(item.length)
if (url.indexOf('/') > -1) {
url = url.substring(url.indexOf('/'))
} else {
url = '/'
}
break
}
}
if (url.indexOf('?') > -1) {
url = url.substring(0, url.indexOf('?'))
}
return url
}
pkg.urlMatchesPattern = (url, pattern) => {
url = pkg.getRelative(url)
pattern = pkg.getRelative(pattern)
let re = pathToRegexp(pattern)
return re.test(url)
}
module.exports = pkg

@ -0,0 +1,33 @@
let pathToRegexp = require('path-to-regexp')
export default class pkg {
public static getRelative = url => {
if (!url || typeof url !== 'string') return null
url = url.toLowerCase()
const prefixes = ['https://', 'http://']
for (let item of prefixes) {
if (url.indexOf(item) > -1) {
url = url.substring(item.length)
if (url.indexOf('/') > -1) {
url = url.substring(url.indexOf('/'))
} else {
url = '/'
}
break
}
}
if (url.indexOf('?') > -1) {
url = url.substring(0, url.indexOf('?'))
}
return url
}
public static urlMatchesPattern = (url, pattern) => {
url = pkg.getRelative(url)
pattern = pkg.getRelative(pattern)
let re = pathToRegexp(pattern)
return re.test(url)
}
}

@ -1,12 +1,12 @@
const debug = true const debug = true
const Koa = require('koa') import * as Koa from 'koa'
const session = require('koa-session') import * as session from 'koa-session'
const logger = require('koa-logger') import * as logger from 'koa-logger'
const serve = require('koa-static') import * as serve from 'koa-static'
const body = require('koa-body') import * as body from 'koa-body'
const cors = require('kcors') import * as cors from 'kcors'
const router = require('../src/routes') import router from '../routes'
const config = require('../config') import config from '../config'
const app = new Koa() const app = new Koa()
app.counter = { users: {}, mock: 0 } app.counter = { users: {}, mock: 0 }
@ -45,4 +45,4 @@ app.use(serve('test'))
app.use(body()) app.use(body())
app.use(router.routes()) app.use(router.routes())
module.exports = app export default app

@ -1,7 +1,8 @@
import config from '../config'
import app from './app'
const start = () => { const start = () => {
let execSync = require('child_process').execSync let execSync = require('child_process').execSync
let app = require('./app')
const config = require('../config')
let port = config.serve.port let port = config.serve.port
let url = `http://localhost:${port}` // /api.html let url = `http://localhost:${port}` // /api.html
let open = false let open = false
@ -18,3 +19,4 @@ const start = () => {
} }
start() start()
export {}

@ -19,7 +19,6 @@ module.exports = {
BO_USER_COUNT: 10, BO_USER_COUNT: 10,
BO_USER_FN: () => mock({ BO_USER_FN: () => mock({
id: USER_ID++, id: USER_ID++,
empId: 'bo@natural',
fullname: '@cname', fullname: '@cname',
email: '@email', email: '@email',
password: '@word(6)' password: '@word(6)'

@ -19,3 +19,5 @@ const start = () => {
} }
start() start()
export {}

@ -0,0 +1,15 @@
import { PoolOptions } from "sequelize";
import { ISequelizeConfig } from "sequelize-typescript";
declare interface IConfigOptions {
version: string,
serve: {
port: number
},
keys: string[],
session: {
key: string
},
keycenter?: string | boolean,
db: ISequelizeConfig
}

@ -0,0 +1,25 @@
{
"compilerOptions": {
"outDir": "dist",
"module": "commonjs",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowJs": true,
"target": "es6",
"removeComments": true,
"sourceMap": true,
"watch": false,
"baseUrl": "./src",
"rootDir": "./src",
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
}
},
"include": [
"src/**/*"
]
}

@ -0,0 +1,104 @@
{
"rules": {
"no-eval": true,
"forin": true,
"no-any": true,
"no-arg": true,
"no-bitwise": true,
"no-conditional-assignment": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-for-in-array": false,
"no-invalid-this": true,
"no-string-literal": true,
"no-string-throw": true,
"no-unsafe-finally": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"radix": true,
"switch-default": true,
"triple-equals": [true, "allow-null-check"],
"adjacent-overload-signatures": true,
"array-type": [true, "array"],
"arrow-parens": false,
"callable-types": true,
"class-name": true,
"comment-format": [true, "check-space", "check-uppercase"],
"interface-name": [true, "always-prefix"],
"jsdoc-format": true,
"max-classes-per-file": [true, 3],
"max-file-line-count": [true, 500],
"max-line-length": [true, 140],
"member-access": true,
"member-ordering": [true, { "order": "fields-first" }],
"new-parens": true,
"no-construct": true,
"no-default-export": true,
"no-inferrable-types": false,
"no-null-keyword": false,
"no-parameter-properties": true,
"no-require-imports": true,
"no-shadowed-variable": true,
"no-var-keyword": true,
"no-var-requires": true,
"object-literal-sort-keys": false,
"one-variable-per-declaration": [true, "ignore-for-loop"],
"only-arrow-functions": false,
"ordered-imports": [true, "case-insensitive"],
"prefer-const": false,
"prefer-for-of": true,
"typedef": [true, "call-signature", "parameter", "property-declaration", "variable-declaration", "member-variable-declaration"],
"unified-signatures": true,
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"],
"align": [true, "parameters", "statements"],
"curly": true,
"eofline": true,
"import-spacing": true,
"indent": [true, "spaces"],
"linebreak-style": true,
"no-consecutive-blank-lines": true,
"no-trailing-whitespace": true,
"object-literal-key-quotes": [true, "as-needed"],
"one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"],
"quotemark": [true, "single"],
"semicolon": [true, "always"],
"trailing-comma": [true, {"singleline": "never", "multiline": "always"}],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
],
"whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"],
"ban": false,
"cyclomatic-complexity": false,
"file-header": false,
"import-blacklist": false,
"interface-over-type-literal": false,
"no-angle-bracket-type-assertion": false,
"no-empty-interface": false,
"no-inferred-empty-object-type": false,
"no-internal-module": false,
"no-magic-numbers": false,
"no-mergeable-namespace": false,
"no-namespace": false,
"no-reference": true,
"object-literal-shorthand": false,
"space-before-function-paren": false
}
}
Loading…
Cancel
Save