├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .node-inspectorrc ├── README.md ├── app.js ├── bin ├── start.sh └── www ├── client ├── README.md ├── gulpfile.js └── package.json ├── config ├── cacert │ └── easemob.pem ├── db.sql ├── development.js ├── easemob.js ├── error_code.js ├── mongodb.js ├── nginx.conf ├── orm.js ├── pm2-gui.ini ├── pm2.config.js ├── production.js ├── rabbitmq.js ├── redis.js ├── secret.js ├── simulation.js └── testing.js ├── gulpfile.js ├── package.json ├── public ├── favicon.ico ├── robots.txt ├── static │ └── libs │ │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap-theme.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ │ ├── html5shiv.min.js │ │ ├── jQuery │ │ └── jquery-2.2.3.min.js │ │ └── respond.min.js └── swagger │ ├── api.json │ ├── css │ ├── print.css │ ├── reset.css │ ├── screen.css │ ├── style.css │ └── typography.css │ ├── fonts │ ├── DroidSans-Bold.ttf │ └── DroidSans.ttf │ ├── images │ ├── collapse.gif │ ├── expand.gif │ ├── explorer_icons.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── logo_small.png │ ├── pet_store_api.png │ ├── throbber.gif │ └── wordnik_api.png │ ├── index.html │ ├── lang │ ├── ca.js │ ├── el.js │ ├── en.js │ ├── es.js │ ├── fr.js │ ├── geo.js │ ├── it.js │ ├── ja.js │ ├── ko-kr.js │ ├── pl.js │ ├── pt.js │ ├── ru.js │ ├── tr.js │ ├── translator.js │ └── zh-cn.js │ ├── lib │ ├── backbone-min.js │ ├── es5-shim.js │ ├── handlebars-4.0.5.js │ ├── highlight.9.1.0.pack.js │ ├── highlight.9.1.0.pack_extended.js │ ├── jquery-1.8.0.min.js │ ├── jquery.ba-bbq.min.js │ ├── jquery.slideto.min.js │ ├── jquery.wiggle.min.js │ ├── js-yaml.min.js │ ├── jsoneditor.min.js │ ├── lodash.min.js │ ├── marked.js │ ├── object-assign-pollyfill.js │ ├── sanitize-html.min.js │ └── swagger-oauth.js │ ├── o2c.html │ ├── swagger-ui.js │ └── swagger-ui.min.js ├── server ├── controllers │ └── user.js ├── middlewares │ ├── api.js │ ├── auth.js │ ├── compress.js │ ├── interceptor.js │ └── logger.js ├── models │ ├── User.js │ └── UserORM.js ├── routes │ ├── index.js │ ├── login.js │ └── rest │ │ ├── token.js │ │ └── user.js ├── services │ ├── thrift │ │ ├── shared.thrift │ │ └── tutorial │ │ │ ├── gen │ │ │ ├── Calculator.js │ │ │ └── tutorial_types.js │ │ │ ├── tutorial.js │ │ │ └── tutorial.thrift │ └── users.js ├── utils │ ├── aes.js │ ├── easemob │ │ ├── ChatHistory.js │ │ ├── ChatRoom.js │ │ ├── Files.js │ │ ├── Group.js │ │ ├── SendMessage.js │ │ ├── Token.js │ │ ├── User.js │ │ ├── client.js │ │ └── request.js │ ├── hbs.js │ ├── http.js │ ├── md5.js │ ├── mongodb.js │ ├── orm.js │ ├── rabbitmq.js │ ├── redis.js │ ├── sql.js │ ├── token.js │ └── util.js └── views │ ├── error.hbs │ ├── index.hbs │ ├── layout.hbs │ ├── login.hbs │ └── partials │ ├── header.hbs │ └── sidebar.hbs └── test ├── api └── login.js └── unit └── sql.js /.eslintignore: -------------------------------------------------------------------------------- 1 | # /node_modules ignored by default 2 | 3 | public/* 4 | config/* 5 | test/* 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 3 | "extends": "standard", 4 | "plugins": [ 5 | "standard", 6 | "promise" 7 | ] 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | logs/ 4 | npm-debug.log 5 | selenium-debug.log 6 | -------------------------------------------------------------------------------- /.node-inspectorrc: -------------------------------------------------------------------------------- 1 | { 2 | "web-port": 8080, 3 | "web-host": "0.0.0.0", 4 | "debug-port": 5858, 5 | "debug-brk": false, 6 | "save-live-edit": false, 7 | "preload": true, 8 | "hidden": ["test/", "node_modules/", "client/", "public/", "config/", "logs/"], 9 | "nodejs": [], 10 | "stack-trace-limit": 50 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-server-project 2 | > 基于 node.js + express 技术栈,采用MVC结构设计、JWT + RESTful API、PM2服务监控的Node Web项目框架。 3 | 4 | 技术栈 5 | 6 | - node.js(>7.0,已原生支持绝大部分ES6/ES7语法) 7 | - express(成熟稳定的Web框架) 8 | - hbs(handlebars后端模版引擎,语法简洁高效、实现模版继承和内嵌功能等) 9 | - RESTful(API架构风格,并提供统一的接口输出结构) 10 | - JWT(Json Web Token 认证协议,用于页面和API的验证,包括token续期方案等) 11 | - ORM(数据库对象关系映射) 12 | - TEST(集成在线API文档生成和测试工具[Swagger-ui](https://github.com/swagger-api/swagger-ui),public/swagger目录下) 13 | - RabbitMQ & Thrift & 环信服务端 集成等 14 | - PM2(Node服务自动部署和监控) 15 | 16 | 关于API接口文档管理及线上线下测试,推荐:[SosoApi](http://www.sosoapi.com/) 17 | 18 | ## Build Setup @see package.json#scripts 19 | 20 | ### Install dependencies, use cnpm: 21 | npm install -g cnpm --registry=https://registry.npm.taobao.org 22 | ``` 23 | cnpm install 24 | ``` 25 | 26 | ### Start server for development or production (pm2) 27 | 28 | ``` 29 | npm start 30 | ``` 31 | 32 | ### Auto restarting server and reloading browsers for development 33 | 34 | ``` 35 | npm run live:client // 客户端源码变动实时监测 36 | npm run live:server // 服务端源码变动实时监测 37 | ``` 38 | 39 | ### For unit test, such as: 40 | 41 | ``` 42 | npm test ./test/api/login.js 43 | ``` 44 | 45 | ### Debug node code 46 | 47 | Please install 'npm install -g node-inspector' at first 48 | 49 | ``` 50 | npm run debug 51 | ``` 52 | 53 | ### Check update for npm packages 54 | 55 | Please install 'npm install npm-check-updates -g' at first 56 | 57 | ``` 58 | npm run update 59 | ``` 60 | 61 | ### PM2 operations and deploy(基于Git) 62 | 63 | First of all, please install node.js and git on the server and set $PATH env in ~/.bashrc 64 | ``` 65 | export NODE_HOME=/data/node-v7.7.4-linux-x64 66 | export PATH=$NODE_HOME/bin:$PATH 67 | ``` 68 | 69 | Host key verification after you execute ssh-keygen on server, and set ssh-key to gitlab. 70 | ``` 71 | ssh-keyscan -t rsa yourGitServer >> ~/.ssh/known_hosts 72 | ``` 73 | 74 | For client ssh password-less logon 75 | ``` 76 | ssh-keygen -t rsa 77 | ssh-copy-id -i ~/.ssh/id_rsa.pub node@192.168.1.10 78 | ``` 79 | 80 | then, use ·npm run setup:test· for the first time, other deployment use ·npm run deploy:test· 81 | ``` 82 | npm run setup:test // 测试环境远程部署(第一次安装) 83 | npm run setup:simu // 仿真环境远程部署(第一次安装) 84 | npm run setup:prod // 生产环境远程部署(第一次安装) 85 | npm run deploy:test // 测试环境远程部署(后期更新) 86 | npm run deploy:simu // 仿真环境远程部署(后期更新) 87 | npm run deploy:prod // 生产环境远程部署(后期更新) 88 | npm run stop 89 | npm run reload 90 | npm run list 91 | npm run monit 92 | npm run logs 93 | ``` 94 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 主入口程序 3 | */ 4 | 5 | var express = require('express') 6 | var favicon = require('serve-favicon') 7 | var cookieParser = require('cookie-parser') 8 | var bodyParser = require('body-parser') 9 | var mountRoutes = require('mount-routes') 10 | var cors = require('cors') 11 | var path = require('path') 12 | 13 | var config = require('./package.json') 14 | 15 | var logger = require('./server/middlewares/logger') 16 | var authorization = require('./server/middlewares/auth') 17 | var compression = require('./server/middlewares/compress') 18 | var resApi = require('./server/middlewares/api') 19 | var interceptor = require('./server/middlewares/interceptor') 20 | 21 | // require('./server/utils/mongodb') // init mongodb 22 | // require('./server/utils/orm') // init orm 23 | require('./server/utils/hbs') // init hbs 24 | 25 | var app = express() 26 | 27 | // view engine setup 28 | app.set('views', path.join(__dirname, 'server', 'views')) 29 | app.set('view engine', 'hbs') 30 | 31 | app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) 32 | app.use(bodyParser.json()) // application/json, any Unicode, gzip/deflate 33 | app.use(bodyParser.urlencoded({ extended: false })) // application/x-www-form-urlencoded, UTF-8, gzip/deflate 34 | app.use(cookieParser()) 35 | app.use(express.static(path.join(__dirname, 'public'))) 36 | 37 | // set resouces root url 38 | app.locals.resoucePath = '/static' 39 | // set resouces version 40 | app.locals.resouceVersion = config.version 41 | 42 | // log middleware 43 | app.use(logger) 44 | 45 | // api output middleware 46 | app.use(resApi) 47 | 48 | // authorization middleware 49 | app.use(authorization) 50 | 51 | // interceptor middleware 52 | app.use(interceptor) 53 | 54 | // compression middleware 55 | app.use(compression) 56 | 57 | // This is CORS-enabled for all origins; For a single route: app.get('/api', cors(), rooter) 58 | // var corsOptions = { 59 | // origin: '*', 60 | // optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204 61 | // } 62 | // app.use(cors()) 63 | 64 | // auto mount routes with routes_folder_path, 'false': dont dump list 65 | mountRoutes(app, path.join(__dirname, 'server', 'routes'), false) 66 | 67 | // catch 404 and forward to error handler 68 | app.use(function (req, res, next) { 69 | if (req.path.startsWith('/rest/')) { // for api 70 | return res.api_error({ 71 | message: 'Not Found' 72 | }) 73 | } else { // for page 74 | var err = new Error('Not Found') 75 | err.status = 404 76 | next(err) 77 | } 78 | }) 79 | 80 | // error handler 81 | // catch unauthorized error and other forward to error handler 82 | app.use(function (err, req, res, next) { 83 | if (err.name === 'UnauthorizedError') { 84 | if (req.path.startsWith('/rest/')) { // for api 85 | return res.api_error({ 86 | message: 'Invalid Token', 87 | error: err.message 88 | }) 89 | } else { // for page 90 | res.redirect('/login') 91 | } 92 | } else { 93 | next(err) 94 | } 95 | }) 96 | 97 | // error handler 98 | // no stacktraces leaked to user for production, 99 | // and will print stacktrace for development 100 | app.use(function (err, req, res, next) { 101 | if (req.path.startsWith('/rest/')) { // for api 102 | return res.api_error({ 103 | message: err.message, 104 | error: app.get('env') === 'development' ? err : {} 105 | }) 106 | } else { // for page 107 | res.status(err.status || 500) 108 | res.render('error', { 109 | layout: false, 110 | message: err.message, 111 | error: app.get('env') === 'development' ? err : {} 112 | }) 113 | } 114 | }) 115 | 116 | // Node全局异常捕获 117 | process.on('uncaughtException', function (err) { 118 | console.error('An uncaught error occurred!') 119 | console.error(err.stack) 120 | // Recommend: restart the server 121 | }); 122 | 123 | module.exports = app 124 | -------------------------------------------------------------------------------- /bin/start.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 启动脚本,用于设置开机启动,可跟参数:prod(产品-默认) simu(仿真) testing(测试) 3 | # 也可使用 pm2 设置开机启动: 4 | # pm2 save 5 | # pm2 startup centos 6 | 7 | cd `dirname $0` 8 | 9 | if [ "$1" == "" ]; then 10 | npm run prod 11 | else 12 | npm run $1 13 | fi -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app') 8 | var http = require('http') 9 | 10 | var config = require('../config/' + app.get('env')) 11 | 12 | /** 13 | * Get port from environment and store in Express. 14 | */ 15 | 16 | var port = normalizePort(process.env.PORT || config.port) 17 | app.set('port', port) 18 | 19 | /** 20 | * Create HTTP server. 21 | */ 22 | 23 | var server = http.createServer(app) 24 | 25 | /** 26 | * Listen on provided port, on all network interfaces. 27 | */ 28 | 29 | server.listen(port) 30 | server.on('error', onError) 31 | server.on('listening', onListening) 32 | 33 | console.log('env: ' + config.NODE_ENV) 34 | 35 | /** 36 | * Normalize a port into a number, string, or false. 37 | */ 38 | 39 | function normalizePort(val) { 40 | var port = parseInt(val, 10) 41 | 42 | if (isNaN(port)) { 43 | // named pipe 44 | return val 45 | } 46 | 47 | if (port >= 0) { 48 | // port number 49 | return port 50 | } 51 | 52 | return false 53 | } 54 | 55 | /** 56 | * Event listener for HTTP server "error" event. 57 | */ 58 | 59 | function onError(error) { 60 | if (error.syscall !== 'listen') { 61 | throw error 62 | } 63 | 64 | var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port 65 | 66 | // handle specific listen errors with friendly messages 67 | switch (error.code) { 68 | case 'EACCES': 69 | console.error(bind + ' requires elevated privileges') 70 | process.exit(1) 71 | break 72 | case 'EADDRINUSE': 73 | console.error(bind + ' is already in use') 74 | process.exit(1) 75 | break 76 | default: 77 | throw error 78 | } 79 | } 80 | 81 | /** 82 | * Event listener for HTTP server "listening" event. 83 | */ 84 | 85 | function onListening() { 86 | var addr = server.address() 87 | var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port 88 | console.log('Listening on ' + bind) 89 | } 90 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # 前端源码目录 2 | > 可以使用gulp或webpack,对前端项目进行编译、打包和自动构建 3 | 4 | -------------------------------------------------------------------------------- /client/gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const copy = require('gulp-copy') 3 | const concat = require('gulp-concat') 4 | const sass = require('gulp-sass') 5 | const minifycss = require('gulp-clean-css') 6 | const autoprefixer = require('gulp-autoprefixer') 7 | const spriter = require('gulp-css-spriter') 8 | const uglify = require('gulp-uglify') 9 | const imagemin = require('gulp-imagemin') 10 | const pngquant = require('imagemin-pngquant') 11 | const minifyhtml = require('gulp-minify-html') 12 | const rev = require('gulp-rev') 13 | const revcollector = require('gulp-rev-collector') 14 | const eslint = require('gulp-eslint') 15 | const sequence = require('gulp-sequence') 16 | const sourcemaps = require('gulp-sourcemaps') 17 | const del = require('del') 18 | 19 | let paths = { 20 | jsComSrc: './src/js/common/*.js', 21 | jsAppSrc: './src/js/*.js', 22 | jsDest: '../public/static/js', 23 | cssSrc: './src/css/**/*', 24 | cssDest: '../public/static/css', 25 | imgSrc: './src/img/**/*', 26 | imgDest: '../public/static/img', 27 | htmlSrc: './src/html/**/*', 28 | htmlDest: '../public/static/html', 29 | libSrc: './src/libs/**/*', 30 | libDest: '../public/static', 31 | dist: '../public/static/**/*', 32 | // manifestFile: './rev-manifest.json' 33 | } 34 | 35 | gulp.task('scripts', ['scripts-common', 'scripts-app']) 36 | 37 | gulp.task('scripts-common', function() { 38 | return gulp.src(paths.jsComSrc) 39 | .pipe(sourcemaps.init()) 40 | .pipe(concat('common.min.js')) 41 | .pipe(uglify()) 42 | // .pipe(rev()) // 文件名加MD5后缀 43 | .pipe(sourcemaps.write('./')) 44 | .pipe(gulp.dest(paths.jsDest)) 45 | // .pipe(rev.manifest()) // 生成一个rev-manifest.json 46 | // .pipe(gulp.dest('./')) // 将 rev-manifest.json 保存到 ./ 目录内 47 | }) 48 | 49 | gulp.task('scripts-app', function() { 50 | return gulp.src(paths.jsAppSrc) 51 | .pipe(sourcemaps.init()) 52 | .pipe(concat('app.min.js')) 53 | .pipe(uglify()) 54 | // .pipe(rev()) // 文件名加MD5后缀 55 | .pipe(sourcemaps.write('./')) 56 | .pipe(gulp.dest(paths.jsDest)) 57 | // .pipe(rev.manifest()) // 生成一个rev-manifest.json 58 | // .pipe(gulp.dest('./')) // 将 rev-manifest.json 保存到 ./ 目录内 59 | }) 60 | 61 | // gulp.task('rev', ['scripts'], function() { 62 | // gulp.src(['./rev-manifest.json', '../server/views/index.hbs']) // 读取 rev-manifest.json 文件以及需要进行文件名替换的文件 63 | // .pipe(revcollector()) // 执行文件内文件名的替换 64 | // .pipe(gulp.dest('../server/views')) // 替换后的文件输出的目录 65 | // }) 66 | 67 | gulp.task('images', function() { 68 | return gulp.src(paths.imgSrc) 69 | .pipe(imagemin({ 70 | optimizationLevel: 5, 71 | progressive: true, 72 | use: [pngquant()] 73 | })) 74 | .pipe(gulp.dest(paths.imgDest)) 75 | }) 76 | 77 | gulp.task('styles', function() { 78 | return gulp.src(paths.cssSrc) 79 | .pipe(sass()) // 编译scss 80 | .pipe(concat('app.min.css')) // 合并scss 81 | .pipe(autoprefixer()) // 浏览器厂商前缀 {browsers:["> 1%","Firefox >= 10","ie >= 9","iOS >= 4","Chrome >= 10"],cascade:false} 82 | // .pipe(spriter({ 83 | // // The path and file name of where we will save the sprite sheet 84 | // 'spriteSheet': paths.imgDest + '/spritesheet.png', 85 | // // Because we don't know where you will end up saving the CSS file at this point in the pipe, 86 | // // we need a litle help identifying where it will be. 87 | // 'pathToSpriteSheetFromCSS': '../img/spritesheet.png' 88 | // })) 89 | .pipe(minifycss()) // 压缩css 90 | .pipe(gulp.dest(paths.cssDest)) 91 | }) 92 | 93 | gulp.task('htmls', function() { 94 | gulp.src(paths.htmlSrc) 95 | .pipe(minifyhtml({ comments: false })) 96 | .pipe(gulp.dest(paths.htmlDest)) 97 | }) 98 | 99 | gulp.task('lint', function () { 100 | return gulp.src(['./src/js/**/*', '!node_modules/**']) 101 | .pipe(eslint()) 102 | .pipe(eslint.format()) 103 | .pipe(eslint.failAfterError()) 104 | }) 105 | 106 | gulp.task('clean', function(){ 107 | del([paths.dist], { force: true }) 108 | }) 109 | 110 | gulp.task('libs', function() { 111 | gulp.src(paths.libSrc) 112 | .pipe(copy(paths.libDest, { prefix: 1 })) 113 | .pipe(gulp.dest(paths.libDest + '/libs')) 114 | }) 115 | 116 | gulp.task('watch', function() { 117 | gulp.watch(paths.jsComSrc, ['scripts-common']) 118 | gulp.watch(paths.jsAppSrc, ['scripts-app']) 119 | gulp.watch(paths.cssSrc, ['styles']) 120 | gulp.watch(paths.imgSrc, ['images']) 121 | gulp.watch(paths.htmlSrc, ['htmls']) 122 | gulp.watch(paths.libSrc, ['libs']) 123 | }) 124 | 125 | gulp.task('build', ['clean'], function (cb) { 126 | // gulp.start('scripts', 'styles', 'images', 'htmls', 'libs') 127 | sequence('scripts', 'styles', 'images', 'htmls', 'libs')(cb) 128 | }) 129 | 130 | gulp.task('build-no-clean', function (cb) { 131 | gulp.start('scripts', 'styles', 'images', 'htmls', 'libs') 132 | }) 133 | 134 | gulp.task('default', sequence('build', 'watch')) 135 | 136 | 137 | // function SpriterGroup(pathArr) { 138 | // for (let i = 0; i < pathArr.length; i++) { 139 | // gulp.src(pathArr[i]) 140 | // .pipe(spriter({ 141 | // 'spriteSheet' : paths.imgDest + '/spriteSheet_' + i +'.png', 142 | // 'pathToSpriteSheetFormCss' : '../img/spriteSheet_' + i + '.png' 143 | // })) 144 | // .pipe(gulp.dest(paths.cssDest)) 145 | // } 146 | // } 147 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client-project", 3 | "version": "1.0.0", 4 | "description": "前端项目", 5 | "author": "super_xp@126.com", 6 | "private": true, 7 | "scripts": { 8 | "start": "gulp default", 9 | "build": "gulp build", 10 | "watch": "gulp watch" 11 | }, 12 | "dependencies": {}, 13 | "devDependencies": { 14 | "del": "^2.2.2", 15 | "gulp": "^3.9.1", 16 | "gulp-autoprefixer": "^3.1.1", 17 | "gulp-clean-css": "^3.0.4", 18 | "gulp-concat": "^2.6.1", 19 | "gulp-copy": "^1.0.0", 20 | "gulp-css-spriter": "^0.4.0", 21 | "gulp-eslint": "^3.0.1", 22 | "gulp-imagemin": "^3.2.0", 23 | "gulp-livereload": "^3.8.1", 24 | "gulp-minify-html": "^1.0.6", 25 | "gulp-rename": "^1.2.2", 26 | "gulp-replace": "^0.5.4", 27 | "gulp-rev": "^7.1.2", 28 | "gulp-rev-collector": "^1.1.1", 29 | "gulp-sass": "^3.1.0", 30 | "gulp-sequence": "^0.4.6", 31 | "gulp-sourcemaps": "^2.6.0", 32 | "gulp-uglify": "^2.1.2", 33 | "imagemin-pngquant": "^5.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /config/db.sql: -------------------------------------------------------------------------------- 1 | -- MySQL数据库,需管理员权限导入 2 | 3 | -- 4 | -- 数据库:db_test 5 | -- 编码:utf8 6 | -- 7 | DROP DATABASE IF EXISTS `db_test`; 8 | CREATE DATABASE `db_test` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; 9 | USE `db_test`; 10 | 11 | -- 12 | -- 授权:本地连接,增删改查 13 | -- 帐号:test 密码:*** (SELECT PASSWORD('***');) 14 | -- 15 | CREATE USER 'test'@'127.0.0.1' IDENTIFIED BY '*A0E2521E77EA33EF451BF2D1025F30B925D8F2F2'; 16 | GRANT SELECT,INSERT,UPDATE,DELETE ON `db_test`.* TO 'test'@'127.0.0.1'; 17 | 18 | -- -------------------------------------------------------- 19 | 20 | -- 21 | -- 表结构 前缀b(branch)表示分表,前缀s(single)表示单表 22 | -- 23 | 24 | /*--------------------------------------------------------------------------* 25 | NAME: 用户帐号表 - 变化频繁 26 | *--------------------------------------------------------------------------*/ 27 | CREATE TABLE b_account_0 ( 28 | uid INT UNSIGNED NOT NULL COMMENT '用户ID', 29 | gold INT UNSIGNED DEFAULT 0 COMMENT '金币', 30 | 31 | ext VARCHAR(255) DEFAULT '' COMMENT '扩展字段', 32 | ctime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', 33 | PRIMARY KEY(uid) 34 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 35 | 36 | /*--------------------------------------------------------------------------* 37 | NAME: 用户帐号基本信息表 - 变化不频繁 38 | *--------------------------------------------------------------------------*/ 39 | CREATE TABLE b_account2_0 ( 40 | uid INT UNSIGNED NOT NULL COMMENT '用户ID', 41 | realname VARCHAR(20) NOT NULL COMMENT '姓名', 42 | nickname VARCHAR(40) DEFAULT '' COMMENT '昵称', 43 | gender TINYINT DEFAULT 0 COMMENT '性别', 44 | avatar VARCHAR(255) DEFAULT '' COMMENT '头像', 45 | birthday DATE COMMENT '生日', 46 | phone VARCHAR(11) DEFAULT '' COMMENT '电话', 47 | email VARCHAR(45) DEFAULT '' COMMENT '邮箱', 48 | wechat VARCHAR(40) DEFAULT '' COMMENT '微信', 49 | qq VARCHAR(20) DEFAULT '' COMMENT 'QQ', 50 | province VARCHAR(20) DEFAULT '' COMMENT '省份', 51 | city VARCHAR(20) DEFAULT '' COMMENT '城市', 52 | address VARCHAR(255) DEFAULT '' COMMENT '住址', 53 | ext VARCHAR(255) DEFAULT '' COMMENT '扩展字段', 54 | ctime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', 55 | PRIMARY KEY(uid) 56 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 57 | 58 | /*--------------------------------------------------------------------------* 59 | NAME: 来源渠道 60 | *--------------------------------------------------------------------------*/ 61 | CREATE TABLE s_origin_channel ( 62 | id INT NOT NULL AUTO_INCREMENT COMMENT '渠道ID', 63 | name VARCHAR(40) NOT NULL COMMENT '名称', 64 | PRIMARY KEY(id) 65 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 66 | -------------------------------------------------------------------------------- /config/development.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 开发环境 3 | */ 4 | 5 | module.exports = { 6 | port: 3000, 7 | logging:{ 8 | type: 'dev' // :method :url :status :response-time ms - :res[content-length] 9 | }, 10 | NODE_ENV: 'development', 11 | BASE_URI: 'http://ip/api' 12 | } 13 | -------------------------------------------------------------------------------- /config/easemob.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 环信服务端集成配置 3 | */ 4 | 5 | module.exports = { 6 | org_name: '企业ID', 7 | app_name: 'APP名称', 8 | client_id: 'your app client id', 9 | client_secret: 'youre app client secret', 10 | host: 'a1.easemob.com', 11 | ca: __dirname + '/cacert/easemob.pem' 12 | } 13 | -------------------------------------------------------------------------------- /config/error_code.js: -------------------------------------------------------------------------------- 1 | /** 2 | * API 错误码 3 | */ 4 | 5 | // user 6 | exports.SIGNIN_ERROR = 10001 7 | exports.LOGOUT_ERROR = 10002 8 | exports.REGISTER_ERROR = 10003 9 | -------------------------------------------------------------------------------- /config/mongodb.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | host: '127.0.0.1', 3 | port: 27017, 4 | database: 'nodeserver', 5 | options: { 6 | db: { 7 | native_parser: true 8 | }, 9 | server: { 10 | auto_reconnect: true, 11 | poolSize: 5 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /config/nginx.conf: -------------------------------------------------------------------------------- 1 | http { 2 | # 启用 gzip 压缩功能 3 | gzip on; 4 | 5 | # 默认值是1.1,就是说对HTTP/1.1协议的请求才会进行gzip压缩 6 | gzip_http_version 1.1; 7 | 8 | gzip_vary on; 9 | 10 | # 压缩级别,1压缩比最小处理速度最快,9压缩比最大但处理最慢,同时也最消耗CPU,一般设置为3就可以了 11 | gzip_comp_level 6; 12 | 13 | # nginx 做前端代理时启用该选项,表示无论后端服务器的headers头返回什么信息,都无条件启用压缩 14 | gzip_proxied any; 15 | 16 | # 什么类型的页面或文档启用压缩 17 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png; 18 | 19 | # 最小压缩的页面,如果页面过于小,可能会越压越大,这里规定大于1K的页面才启用压缩 20 | gzip_min_length 1024; 21 | 22 | # 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流 23 | gzip_buffers 16 8k; 24 | 25 | # 禁用IE6的gzip压缩 26 | gzip_disable "MSIE [1-6].(?!.*SV1)"; 27 | 28 | 29 | server { 30 | listen 80; 31 | server_name example.com www.example.com; 32 | root /data/www/node-server/public; 33 | set $node_port 3000; 34 | 35 | location = / { 36 | proxy_http_version 1.1; 37 | proxy_set_header X-Real-IP $remote_addr; 38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 39 | proxy_set_header Host $http_host; 40 | proxy_set_header X-NginX-Proxy true; 41 | proxy_set_header Upgrade $http_upgrade; 42 | proxy_set_header Connection "upgrade"; 43 | proxy_pass http://127.0.0.1:$node_port$request_uri; 44 | proxy_redirect off; 45 | } 46 | 47 | ## 前端路由的 history 模式 48 | # location / { 49 | # try_files $uri $uri/ /index.html; 50 | # } 51 | 52 | location = /swagger/ { 53 | deny all; 54 | } 55 | 56 | location ~ /static/ { 57 | etag on; 58 | expires max; 59 | } 60 | 61 | location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) { 62 | root /data/www/node-server/public; 63 | access_log off; 64 | expires max; 65 | } 66 | } 67 | } 68 | 69 | 70 | 71 | 72 | ## http/2 nginx conf 73 | 74 | # server { 75 | # listen 80; 76 | # server_name example.com www.example.com; 77 | # rewrite ^(.*) https://example.com$1 permanent; 78 | # } 79 | # 80 | # server { 81 | # listen 443 ssl http2 fastopen=3 reuseport; 82 | # server_name www.thinkjs.org thinkjs.org; 83 | # set $node_port 3000; 84 | # 85 | # root /data/www/node-server/public; 86 | # 87 | # keepalive_timeout 70; 88 | # 89 | # ssl_certificate /path/to/certificate; 90 | # ssl_certificate_key /path/to/certificate.key; 91 | # ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 92 | # ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"; 93 | # ssl_prefer_server_ciphers on; 94 | 95 | # # openssl dhparam -out dhparams.pem 2048 96 | # ssl_dhparam /path/to/dhparams.pem; 97 | # 98 | # ssl_session_cache shared:SSL:10m; 99 | # ssl_session_timeout 10m; 100 | # 101 | # ssl_session_ticket_key /path/to/tls_session_ticket.key; 102 | # ssl_session_tickets on; 103 | # 104 | # ssl_stapling on; 105 | # ssl_stapling_verify on; 106 | # ssl_trusted_certificate /path/to/startssl_trust_chain.crt; 107 | # 108 | # 109 | # add_header x-Content-Type-Options nosniff; 110 | # add_header X-Frame-Options deny; 111 | # add_header Strict-Transport-Security "max-age=16070400"; 112 | # 113 | # index index.html index.htm; 114 | # if ( -f $request_filename/index.html ){ 115 | # rewrite (.*) $1/index.html break; 116 | # } 117 | # if ( !-f $request_filename ){ 118 | # rewrite (.*) /; 119 | # } 120 | # location = / { 121 | # proxy_http_version 1.1; 122 | # proxy_set_header X-Real-IP $remote_addr; 123 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 124 | # proxy_set_header Host $http_host; 125 | # proxy_set_header X-NginX-Proxy true; 126 | # proxy_set_header Upgrade $http_upgrade; 127 | # proxy_set_header Connection "upgrade"; 128 | # proxy_pass http://127.0.0.1:$node_port$request_uri; 129 | # proxy_redirect off; 130 | # } 131 | # 132 | # location = /swagger/ { 133 | # deny all; 134 | # } 135 | # 136 | # location ~ /static/ { 137 | # etag on; 138 | # expires max; 139 | # } 140 | #} 141 | 142 | -------------------------------------------------------------------------------- /config/orm.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | development: { 3 | database: 'db_test', 4 | username: 'test', 5 | password: '*A0E2521E77EA33EF451BF2D1025F30B925D8F2F2', 6 | options: { 7 | host: '127.0.0.1', 8 | port: 3306, 9 | dialect: 'mysql', //mysql|sqlite|postgres|mssql 10 | pool: { 11 | max: 5, 12 | min: 0, 13 | idle: 10000 14 | }, 15 | storage: 'path/to/database.sqlite' // SQLite only 16 | } 17 | }, 18 | production: { 19 | database: 'qy_foreground', 20 | username: 'qyfdb', 21 | password: '*9BCABC927E66F185539F7748D1BA16341236BC2C', 22 | options: { 23 | host: '127.0.0.1', 24 | port: 3306, 25 | dialect: 'mysql', //mysql|sqlite|postgres|mssql 26 | pool: { 27 | max: 5, 28 | min: 0, 29 | idle: 10000 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /config/pm2-gui.ini: -------------------------------------------------------------------------------- 1 | ; 2 | ; Home directory of pm2. 3 | ; 4 | pm2 = ~/.pm2 5 | ; 6 | ; The monitor will fetch system CPU/Memory amount after this certain time interval. 7 | ; it could be milliseconds or various time formats(https://github.com/zeit/ms) 8 | ; 9 | refresh = 5s 10 | ; 11 | ; Port of Web server and socket agent. 12 | ; 13 | port = 8088 14 | ; 15 | ; A value indicates whether or not run the pm2-gui as damonization. 16 | ; 17 | daemonize = true 18 | ; 19 | ; A value indicates whether or not the action buttons (i.e. `restart`, `stop all`...) should be displayed on web page. 20 | ; 21 | readonly = false 22 | ; 23 | ; The monitor will fetch process CPU/Memory amount after this certain time interval. 24 | ; it could be milliseconds or various time formats(https://github.com/zeit/ms) 25 | ; 26 | process_refresh = 3s 27 | 28 | [log] 29 | ; 30 | ; Log directory. 31 | ; 32 | dir = ../logs 33 | ; 34 | ; A value indicates whether or not display the [INFO], [ERROR].. prefixes before log message. 35 | ; 36 | prefix = true 37 | ; 38 | ; A value indicates whether or not display the local date string before log message. 39 | ; 40 | date = false 41 | ; 42 | ; Log level, one of debug, log, info, warn, error. 43 | ; 44 | level = info 45 | ; 46 | ; Socket.io origins check, e.g.: 47 | ; origins = 'example.com:* http://example.com:* http://www.example.com:8088' 48 | ; By default: 49 | ; origins = *:* 50 | 51 | [agent] 52 | ; 53 | ; This authorization will be used to authorize socket / web connections if it's set. 54 | ; 55 | authorization = AuTh 56 | ; 57 | ; A value indicates whether agent offline or not. 58 | ; 59 | ; offline = true 60 | [remotes] 61 | ; 62 | ; the dashboard and web server will use this section to connect remoting socket server 63 | ; server_name = [authorization@]host:port 64 | ; 65 | ; pm2@171 = AuTh@https://192.168.1.171:9002/sockserv 66 | ; pm2@172 = 192.168.1.172:9001 67 | ; pm2@173 = 192.168.1.173:9000 68 | ; -------------------------------------------------------------------------------- /config/pm2.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * Application configuration section 4 | * http://pm2.keymetrics.io/docs/usage/application-declaration/ 5 | */ 6 | apps: [ 7 | { 8 | name: "node-server", 9 | script: "./bin/www", 10 | watch: true, 11 | ignore_watch: [ 12 | "client", 13 | "public", 14 | "test", 15 | "logs", 16 | "node_modules" 17 | ], 18 | instances: 0, 19 | exec_mode: "cluster", 20 | max_memory_restart: "1G", 21 | error_file: "./logs/err.log", 22 | out_file: "./logs/out.log", 23 | merge_logs: false, 24 | log_date_format: 'YYYY-MM-DD HH:mm:ss', 25 | env: { 26 | PM2: "true" 27 | }, 28 | env_production: { 29 | NODE_ENV: "production" 30 | }, 31 | env_simulation: { 32 | NODE_ENV: "simulation" 33 | }, 34 | env_testing: { 35 | NODE_ENV: "testing" 36 | }, 37 | env_development: { 38 | NODE_ENV: "development" 39 | } 40 | } 41 | ], 42 | 43 | /** 44 | * Deployment section 45 | * http://pm2.keymetrics.io/docs/usage/deployment/ 46 | */ 47 | deploy: { 48 | production: { 49 | user: "node", 50 | host: ["212.83.163.1", "212.83.163.2"], 51 | ref: "origin/master", 52 | repo: "git@github.com:repo.git", 53 | path: "/home/node/node-server-project", 54 | "post-deploy": "npm install && npm run prod", 55 | env: { 56 | NODE_ENV: "production" 57 | } 58 | }, 59 | simulation: { 60 | user: "node", 61 | host: ["212.83.163.3"], 62 | ref: "origin/master", 63 | repo: "git@github.com:repo.git", 64 | path: "/home/node/node-server-project", 65 | "post-setup": "cnpm install && npm run simu", 66 | "post-deploy": "cnpm install && npm run simu", 67 | env: { 68 | NODE_ENV: "simulation" 69 | } 70 | }, 71 | testing: { 72 | user: "node", 73 | host: "212.83.163.1", 74 | ref: "origin/develop", 75 | repo: "git@github.com:repo.git", 76 | path: "/home/node/node-server-project", 77 | ssh_options: ["StrictHostKeyChecking=no", "PasswordAuthentication=no"], 78 | "post-setup": "cnpm install && npm run testing", 79 | "post-deploy": "cnpm install && npm run testing", 80 | env: { 81 | NODE_ENV: "testing" 82 | } 83 | } 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /config/production.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 生产环境 3 | */ 4 | 5 | module.exports = { 6 | port: 80, 7 | logging: { 8 | type: 'combined' // Standard Apache combined log output 9 | }, 10 | NODE_ENV: 'production', 11 | BASE_URI: 'http://ip/api' 12 | } 13 | -------------------------------------------------------------------------------- /config/rabbitmq.js: -------------------------------------------------------------------------------- 1 | /** 2 | * amqp 参数配置 3 | * @see https://github.com/dial-once/node-bunnymq 4 | */ 5 | 6 | module.exports = { 7 | host: 'amqp://localhost', // connect url 8 | prefetch: 5, // number of fetched messages at once on the channel 9 | requeue: true, // requeue put back message into the broker if consumer crashes/trigger exception 10 | timeout: 1000, // time between two reconnect (ms) 11 | rpcTimeout: 1000 // default timeout for RPC calls. If set to '0' there will be none. 12 | } 13 | -------------------------------------------------------------------------------- /config/redis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * redis 参数配置 3 | * @see https://github.com/NodeRedis/node_redis 4 | */ 5 | 6 | module.exports = { 7 | host: '127.0.0.1', 8 | port: 6379, 9 | password: null 10 | } 11 | -------------------------------------------------------------------------------- /config/secret.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JWT secret 3 | */ 4 | exports.token_secret_key = 'bm9kZXNlcnZlckFQSWp3dHNlY3JldA==' 5 | 6 | /** 7 | * md5 secret 8 | */ 9 | exports.md5_secret_key = 'servermd5key' 10 | -------------------------------------------------------------------------------- /config/simulation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿真环境 3 | */ 4 | 5 | module.exports = { 6 | port: 80, 7 | logging: { 8 | type: 'combined' // Standard Apache combined log output 9 | }, 10 | NODE_ENV: 'simulation', 11 | BASE_URI: 'http://ip/api' 12 | } 13 | -------------------------------------------------------------------------------- /config/testing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 测试环境 3 | */ 4 | 5 | module.exports = { 6 | port: 80, 7 | logging: { 8 | type: 'combined' // Standard Apache combined log output 9 | }, 10 | NODE_ENV: 'testing', 11 | BASE_URI: 'http://ip/api' 12 | } 13 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const nodemon = require('gulp-nodemon') 3 | const browserSync = require('browser-sync').create() 4 | const config = require('./config/' + process.env.NODE_ENV) 5 | 6 | /** 7 | * 启动本地server 8 | */ 9 | gulp.task("server", function(cb) { 10 | let started = false 11 | let stream = nodemon({ 12 | script: './bin/www', 13 | ext: 'js', 14 | watch: ['server/', 'app.js'], 15 | env: { 16 | 'NODE_ENV': config.NODE_ENV 17 | } 18 | }) 19 | 20 | stream.on('start', function () { 21 | if (!started) { 22 | cb() 23 | started = true 24 | } 25 | }).on('restart', function () { 26 | console.log('restarted!') 27 | }).on('crash', function() { 28 | console.error('Application has crashed!\n') 29 | stream.emit('restart', 3) // restart the server in 3 seconds 30 | }) 31 | }) 32 | 33 | /** 34 | * 同步浏览器 35 | */ 36 | gulp.task('browser-sync', ['server'], function() { 37 | var files = [ 38 | 'server/views/**/*.html', 39 | 'server/views/**/*.hbs', 40 | 'public/static/**/*.*' 41 | ] 42 | 43 | browserSync.init({ 44 | files: files, 45 | proxy: 'http://localhost:' + config.port, 46 | // browser: 'google chrome', 47 | // notify: false, 48 | // ui: false, 49 | port: parseInt(config.port) + 1 50 | }) 51 | 52 | gulp.watch(files).on('change', browserSync.reload) 53 | }) 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-server", 3 | "version": "1.0.0", 4 | "description": "基于node.js技术栈的服务器端项目框架示例", 5 | "author": "super_xp@126.com", 6 | "keywords": [ 7 | "node.js", 8 | "express", 9 | "restful api", 10 | "node-frameworek" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/xiaoping6688/node-server-project" 15 | }, 16 | "license": "MIT", 17 | "private": false, 18 | "scripts": { 19 | "installall": "(cnpm install) && (cd client && cnpm install)", 20 | "dev": "cross-env NODE_ENV=development supervisor -w server,app.js ./bin/www", 21 | "testing": "pm2 startOrRestart ./config/pm2.config.js --env testing", 22 | "simu": "pm2 startOrRestart ./config/pm2.config.js --env simulation", 23 | "prod": "pm2 startOrRestart ./config/pm2.config.js --env production", 24 | "setup:test": "pm2 deploy ./config/pm2.config.js testing setup", 25 | "setup:simu": "pm2 deploy ./config/pm2.config.js simulation setup", 26 | "setup:prod": "pm2 deploy ./config/pm2.config.js production setup", 27 | "deploy:test": "pm2 deploy ./config/pm2.config.js testing --force", 28 | "deploy:simu": "pm2 deploy ./config/pm2.config.js simulation", 29 | "deploy:prod": "pm2 deploy ./config/pm2.config.js production", 30 | "stop": "pm2 stop ./config/pm2.config.js", 31 | "reload": "pm2 reload ./config/pm2.config.js", 32 | "list": "pm2 list", 33 | "monit": "pm2 monit", 34 | "logs": "pm2 logs", 35 | "gui": "./node_modules/.bin/pm2-gui start ../../config/pm2-gui.ini", 36 | "debug": "node-debug ./bin/www", 37 | "client": "cd client && npm build", 38 | "live:client": "cd client && npm start", 39 | "live:server": "cross-env NODE_ENV=development gulp browser-sync", 40 | "test": "./node_modules/mocha/bin/mocha", 41 | "lint": "./node_modules/.bin/eslint app.js server", 42 | "update": "ncu -u -a" 43 | }, 44 | "dependencies": { 45 | "amqplib": "^0.5.1", 46 | "amqplib-rpc": "^2.0.4", 47 | "blueimp-md5": "^2.7.0", 48 | "body-parser": "~1.17.1", 49 | "bunnymq": "^2.2.2", 50 | "compression": "^1.6.2", 51 | "cookie-parser": "~1.4.3", 52 | "cors": "^2.8.1", 53 | "express": "~4.15.2", 54 | "express-jwt": "^5.1.0", 55 | "file-stream-rotator": "0.1.0", 56 | "form-data": "^2.1.2", 57 | "hbs": "~4.0.1", 58 | "html-minifier": "^3.4.2", 59 | "jsonwebtoken": "^7.3.0", 60 | "lodash": "^4.17.4", 61 | "memory-cache": "^0.1.6", 62 | "mongoose": "^4.8.6", 63 | "mongoosedao": "^1.0.13", 64 | "morgan": ">=1.9.1", 65 | "mount-routes": "^1.0.6", 66 | "multer": "^1.3.0", 67 | "mysql": "^2.13.0", 68 | "mysql2": "^1.2.0", 69 | "node-fetch": "^1.6.3", 70 | "pg": "^6.1.4", 71 | "pg-hstore": "^2.3.2", 72 | "redis": "^2.7.0", 73 | "request": "^2.81.0", 74 | "request-promise": "^4.1.1", 75 | "sequelize": "^5.3.0", 76 | "serve-favicon": "~2.4.1", 77 | "sqlite3": "^3.1.8", 78 | "thrift": "^0.10.0" 79 | }, 80 | "devDependencies": { 81 | "browser-sync": "^2.18.8", 82 | "cross-env": "^3.2.3", 83 | "eslint": "^3.17.1", 84 | "eslint-config-standard": "^7.0.1", 85 | "eslint-plugin-promise": "^3.5.0", 86 | "eslint-plugin-standard": "^2.1.1", 87 | "gulp": "^3.9.1", 88 | "gulp-nodemon": "^2.2.1", 89 | "if-env": "^1.0.0", 90 | "mocha": "^3.2.0", 91 | "pm2": "^2.4.2", 92 | "pm2-gui": "^0.1.4", 93 | "supertest": "^3.0.0", 94 | "supervisor": "^0.12.0" 95 | }, 96 | "engines": { 97 | "node": ">= 7.0.0", 98 | "npm": ">= 3.10.0" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # The robots.txt file is used to control how search engines index your live URLs. 2 | 3 | 4 | 5 | # To prevent search engines from seeing the site altogether, uncomment the next two lines: 6 | # User-Agent: * 7 | # Disallow: / 8 | -------------------------------------------------------------------------------- /public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/static/libs/bootstrap/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /public/static/libs/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /public/static/libs/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill 2 | * Copyright 2014 Scott Jehl 3 | * Licensed under MIT 4 | * https://j.mp/respondjs */ 5 | 6 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;bli>a,.navbar-default .nav>li>a:focus,.navbar-default .nav>li>a:focus:hover,.navbar-default .nav>li>a:hover{color:#08b}.text-faded{font-size:25px;font-family:Vollkorn,serif}.section-heading{font-family:Vollkorn,serif;font-size:45px;padding-bottom:10px}hr{border-color:#00468b;padding-bottom:10px}.description{margin-top:20px;padding-bottom:200px}.description li{font-family:Vollkorn,serif;font-size:25px;color:#525252;margin-left:28%;padding-top:5px}.gap{margin-top:200px}.troubleshootingtext{color:hsla(0,0%,100%,.7);padding-left:30%}.troubleshootingtext li{list-style-type:circle;font-size:25px;padding-bottom:5px}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.block.response_body.json:hover{cursor:pointer}.backdrop{color:blue}#myModal{height:100%}.modal-backdrop{bottom:0;position:fixed}.curl{padding:10px;font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em;max-height:400px;margin-top:5px;overflow-y:auto;background-color:#fcf6db;border:1px solid #e5e0c6;border-radius:4px}.curl_title{font-size:1.1em;margin:0;padding:15px 0 5px;font-family:Open Sans,Helvetica Neue,Arial,sans-serif;font-weight:500;line-height:1.1}.footer{display:none}.swagger-section .swagger-ui-wrap h2{padding:0}h2{margin:0;margin-bottom:5px}.markdown p,.swagger-section .swagger-ui-wrap .code{font-size:15px;font-family:Arvo,serif}.swagger-section .swagger-ui-wrap b{font-family:Arvo,serif}#signin:hover{cursor:pointer}.dropdown-menu{padding:15px}.navbar-right .dropdown-menu{left:0;right:auto}#signinbutton{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b}.navbar-default .nav>li .details{color:#000;text-transform:none;font-size:15px;font-weight:400;font-family:Open Sans,sans-serif;font-style:italic;line-height:20px;top:-2px}.navbar-default .nav>li .details:hover{color:#000}#signout{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b} -------------------------------------------------------------------------------- /public/swagger/css/typography.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/css/typography.css -------------------------------------------------------------------------------- /public/swagger/fonts/DroidSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/fonts/DroidSans-Bold.ttf -------------------------------------------------------------------------------- /public/swagger/fonts/DroidSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/fonts/DroidSans.ttf -------------------------------------------------------------------------------- /public/swagger/images/collapse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/collapse.gif -------------------------------------------------------------------------------- /public/swagger/images/expand.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/expand.gif -------------------------------------------------------------------------------- /public/swagger/images/explorer_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/explorer_icons.png -------------------------------------------------------------------------------- /public/swagger/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/favicon-16x16.png -------------------------------------------------------------------------------- /public/swagger/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/favicon-32x32.png -------------------------------------------------------------------------------- /public/swagger/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/favicon.ico -------------------------------------------------------------------------------- /public/swagger/images/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/logo_small.png -------------------------------------------------------------------------------- /public/swagger/images/pet_store_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/pet_store_api.png -------------------------------------------------------------------------------- /public/swagger/images/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/throbber.gif -------------------------------------------------------------------------------- /public/swagger/images/wordnik_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/public/swagger/images/wordnik_api.png -------------------------------------------------------------------------------- /public/swagger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 91 | 92 | 93 | 94 | 104 | 105 |
 
106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /public/swagger/lang/ca.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Advertència: Obsolet", 6 | "Implementation Notes":"Notes d'implementació", 7 | "Response Class":"Classe de la Resposta", 8 | "Status":"Estatus", 9 | "Parameters":"Paràmetres", 10 | "Parameter":"Paràmetre", 11 | "Value":"Valor", 12 | "Description":"Descripció", 13 | "Parameter Type":"Tipus del Paràmetre", 14 | "Data Type":"Tipus de la Dada", 15 | "Response Messages":"Missatges de la Resposta", 16 | "HTTP Status Code":"Codi d'Estatus HTTP", 17 | "Reason":"Raó", 18 | "Response Model":"Model de la Resposta", 19 | "Request URL":"URL de la Sol·licitud", 20 | "Response Body":"Cos de la Resposta", 21 | "Response Code":"Codi de la Resposta", 22 | "Response Headers":"Capçaleres de la Resposta", 23 | "Hide Response":"Amagar Resposta", 24 | "Try it out!":"Prova-ho!", 25 | "Show/Hide":"Mostrar/Amagar", 26 | "List Operations":"Llista Operacions", 27 | "Expand Operations":"Expandir Operacions", 28 | "Raw":"Cru", 29 | "can't parse JSON. Raw result":"no puc analitzar el JSON. Resultat cru", 30 | "Example Value":"Valor d'Exemple", 31 | "Model Schema":"Esquema del Model", 32 | "Model":"Model", 33 | "apply":"aplicar", 34 | "Username":"Nom d'usuari", 35 | "Password":"Contrasenya", 36 | "Terms of service":"Termes del servei", 37 | "Created by":"Creat per", 38 | "See more at":"Veure més en", 39 | "Contact the developer":"Contactar amb el desenvolupador", 40 | "api version":"versió de la api", 41 | "Response Content Type":"Tipus de Contingut de la Resposta", 42 | "fetching resource":"recollint recurs", 43 | "fetching resource list":"recollins llista de recursos", 44 | "Explore":"Explorant", 45 | "Show Swagger Petstore Example Apis":"Mostrar API d'Exemple Swagger Petstore", 46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No es pot llegir del servidor. Potser no teniu la configuració de control d'accés apropiada.", 47 | "Please specify the protocol for":"Si us plau, especifiqueu el protocol per a", 48 | "Can't read swagger JSON from":"No es pot llegir el JSON de swagger des de", 49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalitzada la càrrega del recurs informatiu. Renderitzant Swagger UI", 50 | "Unable to read api":"No es pot llegir l'api", 51 | "from path":"des de la ruta", 52 | "server returned":"el servidor ha retornat" 53 | }); 54 | -------------------------------------------------------------------------------- /public/swagger/lang/el.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Προειδοποίηση: Έχει αποσυρθεί", 6 | "Implementation Notes":"Σημειώσεις Υλοποίησης", 7 | "Response Class":"Απόκριση", 8 | "Status":"Κατάσταση", 9 | "Parameters":"Παράμετροι", 10 | "Parameter":"Παράμετρος", 11 | "Value":"Τιμή", 12 | "Description":"Περιγραφή", 13 | "Parameter Type":"Τύπος Παραμέτρου", 14 | "Data Type":"Τύπος Δεδομένων", 15 | "Response Messages":"Μηνύματα Απόκρισης", 16 | "HTTP Status Code":"Κωδικός Κατάστασης HTTP", 17 | "Reason":"Αιτιολογία", 18 | "Response Model":"Μοντέλο Απόκρισης", 19 | "Request URL":"URL Αιτήματος", 20 | "Response Body":"Σώμα Απόκρισης", 21 | "Response Code":"Κωδικός Απόκρισης", 22 | "Response Headers":"Επικεφαλίδες Απόκρισης", 23 | "Hide Response":"Απόκρυψη Απόκρισης", 24 | "Headers":"Επικεφαλίδες", 25 | "Try it out!":"Δοκιμάστε το!", 26 | "Show/Hide":"Εμφάνιση/Απόκρυψη", 27 | "List Operations":"Λίστα Λειτουργιών", 28 | "Expand Operations":"Ανάπτυξη Λειτουργιών", 29 | "Raw":"Ακατέργαστο", 30 | "can't parse JSON. Raw result":"αδυναμία ανάλυσης JSON. Ακατέργαστο αποτέλεσμα", 31 | "Example Value":"Παράδειγμα Τιμής", 32 | "Model Schema":"Σχήμα Μοντέλου", 33 | "Model":"Μοντέλο", 34 | "Click to set as parameter value":"Πατήστε για να θέσετε τιμή παραμέτρου", 35 | "apply":"εφαρμογή", 36 | "Username":"Όνομα χρήση", 37 | "Password":"Κωδικός πρόσβασης", 38 | "Terms of service":"Όροι χρήσης", 39 | "Created by":"Δημιουργήθηκε από", 40 | "See more at":"Δείτε περισσότερα στο", 41 | "Contact the developer":"Επικοινωνήστε με τον προγραμματιστή", 42 | "api version":"έκδοση api", 43 | "Response Content Type":"Τύπος Περιεχομένου Απόκρισης", 44 | "Parameter content type:":"Τύπος περιεχομένου παραμέτρου:", 45 | "fetching resource":"παραλαβή πόρου", 46 | "fetching resource list":"παραλαβή λίστας πόρων", 47 | "Explore":"Εξερεύνηση", 48 | "Show Swagger Petstore Example Apis":"Εμφάνιση Api Δειγμάτων Petstore του Swagger", 49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Αδυναμία ανάγνωσης από τον εξυπηρετητή. Μπορεί να μην έχει κατάλληλες ρυθμίσεις για access-control-origin.", 50 | "Please specify the protocol for":"Παρακαλώ προσδιορίστε το πρωτόκολλο για", 51 | "Can't read swagger JSON from":"Αδυναμία ανάγνωσης swagger JSON από", 52 | "Finished Loading Resource Information. Rendering Swagger UI":"Ολοκλήρωση Φόρτωσης Πληροφορικών Πόρου. Παρουσίαση Swagger UI", 53 | "Unable to read api":"Αδυναμία ανάγνωσης api", 54 | "from path":"από το μονοπάτι", 55 | "server returned":"ο εξυπηρετηρής επέστρεψε" 56 | }); 57 | -------------------------------------------------------------------------------- /public/swagger/lang/en.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Warning: Deprecated", 6 | "Implementation Notes":"Implementation Notes", 7 | "Response Class":"Response Class", 8 | "Status":"Status", 9 | "Parameters":"Parameters", 10 | "Parameter":"Parameter", 11 | "Value":"Value", 12 | "Description":"Description", 13 | "Parameter Type":"Parameter Type", 14 | "Data Type":"Data Type", 15 | "Response Messages":"Response Messages", 16 | "HTTP Status Code":"HTTP Status Code", 17 | "Reason":"Reason", 18 | "Response Model":"Response Model", 19 | "Request URL":"Request URL", 20 | "Response Body":"Response Body", 21 | "Response Code":"Response Code", 22 | "Response Headers":"Response Headers", 23 | "Hide Response":"Hide Response", 24 | "Headers":"Headers", 25 | "Try it out!":"Try it out!", 26 | "Show/Hide":"Show/Hide", 27 | "List Operations":"List Operations", 28 | "Expand Operations":"Expand Operations", 29 | "Raw":"Raw", 30 | "can't parse JSON. Raw result":"can't parse JSON. Raw result", 31 | "Example Value":"Example Value", 32 | "Model Schema":"Model Schema", 33 | "Model":"Model", 34 | "Click to set as parameter value":"Click to set as parameter value", 35 | "apply":"apply", 36 | "Username":"Username", 37 | "Password":"Password", 38 | "Terms of service":"Terms of service", 39 | "Created by":"Created by", 40 | "See more at":"See more at", 41 | "Contact the developer":"Contact the developer", 42 | "api version":"api version", 43 | "Response Content Type":"Response Content Type", 44 | "Parameter content type:":"Parameter content type:", 45 | "fetching resource":"fetching resource", 46 | "fetching resource list":"fetching resource list", 47 | "Explore":"Explore", 48 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", 49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.", 50 | "Please specify the protocol for":"Please specify the protocol for", 51 | "Can't read swagger JSON from":"Can't read swagger JSON from", 52 | "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI", 53 | "Unable to read api":"Unable to read api", 54 | "from path":"from path", 55 | "server returned":"server returned" 56 | }); 57 | -------------------------------------------------------------------------------- /public/swagger/lang/es.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Advertencia: Obsoleto", 6 | "Implementation Notes":"Notas de implementación", 7 | "Response Class":"Clase de la Respuesta", 8 | "Status":"Status", 9 | "Parameters":"Parámetros", 10 | "Parameter":"Parámetro", 11 | "Value":"Valor", 12 | "Description":"Descripción", 13 | "Parameter Type":"Tipo del Parámetro", 14 | "Data Type":"Tipo del Dato", 15 | "Response Messages":"Mensajes de la Respuesta", 16 | "HTTP Status Code":"Código de Status HTTP", 17 | "Reason":"Razón", 18 | "Response Model":"Modelo de la Respuesta", 19 | "Request URL":"URL de la Solicitud", 20 | "Response Body":"Cuerpo de la Respuesta", 21 | "Response Code":"Código de la Respuesta", 22 | "Response Headers":"Encabezados de la Respuesta", 23 | "Hide Response":"Ocultar Respuesta", 24 | "Try it out!":"Pruébalo!", 25 | "Show/Hide":"Mostrar/Ocultar", 26 | "List Operations":"Listar Operaciones", 27 | "Expand Operations":"Expandir Operaciones", 28 | "Raw":"Crudo", 29 | "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo", 30 | "Example Value":"Valor de Ejemplo", 31 | "Model Schema":"Esquema del Modelo", 32 | "Model":"Modelo", 33 | "apply":"aplicar", 34 | "Username":"Nombre de usuario", 35 | "Password":"Contraseña", 36 | "Terms of service":"Términos de Servicio", 37 | "Created by":"Creado por", 38 | "See more at":"Ver más en", 39 | "Contact the developer":"Contactar al desarrollador", 40 | "api version":"versión de la api", 41 | "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta", 42 | "fetching resource":"buscando recurso", 43 | "fetching resource list":"buscando lista del recurso", 44 | "Explore":"Explorar", 45 | "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore", 46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.", 47 | "Please specify the protocol for":"Por favor, especificar el protocola para", 48 | "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde", 49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI", 50 | "Unable to read api":"No se puede leer la api", 51 | "from path":"desde ruta", 52 | "server returned":"el servidor retornó" 53 | }); 54 | -------------------------------------------------------------------------------- /public/swagger/lang/fr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Avertissement : Obsolète", 6 | "Implementation Notes":"Notes d'implémentation", 7 | "Response Class":"Classe de la réponse", 8 | "Status":"Statut", 9 | "Parameters":"Paramètres", 10 | "Parameter":"Paramètre", 11 | "Value":"Valeur", 12 | "Description":"Description", 13 | "Parameter Type":"Type du paramètre", 14 | "Data Type":"Type de données", 15 | "Response Messages":"Messages de la réponse", 16 | "HTTP Status Code":"Code de statut HTTP", 17 | "Reason":"Raison", 18 | "Response Model":"Modèle de réponse", 19 | "Request URL":"URL appelée", 20 | "Response Body":"Corps de la réponse", 21 | "Response Code":"Code de la réponse", 22 | "Response Headers":"En-têtes de la réponse", 23 | "Hide Response":"Cacher la réponse", 24 | "Headers":"En-têtes", 25 | "Try it out!":"Testez !", 26 | "Show/Hide":"Afficher/Masquer", 27 | "List Operations":"Liste des opérations", 28 | "Expand Operations":"Développer les opérations", 29 | "Raw":"Brut", 30 | "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut", 31 | "Example Value":"Exemple la valeur", 32 | "Model Schema":"Définition du modèle", 33 | "Model":"Modèle", 34 | "apply":"appliquer", 35 | "Username":"Nom d'utilisateur", 36 | "Password":"Mot de passe", 37 | "Terms of service":"Conditions de service", 38 | "Created by":"Créé par", 39 | "See more at":"Voir plus sur", 40 | "Contact the developer":"Contacter le développeur", 41 | "api version":"version de l'api", 42 | "Response Content Type":"Content Type de la réponse", 43 | "fetching resource":"récupération de la ressource", 44 | "fetching resource list":"récupération de la liste de ressources", 45 | "Explore":"Explorer", 46 | "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger", 47 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.", 48 | "Please specify the protocol for":"Veuillez spécifier un protocole pour", 49 | "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de", 50 | "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI", 51 | "Unable to read api":"Impossible de lire l'api", 52 | "from path":"à partir du chemin", 53 | "server returned":"réponse du serveur" 54 | }); 55 | -------------------------------------------------------------------------------- /public/swagger/lang/geo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"ყურადღება: აღარ გამოიყენება", 6 | "Implementation Notes":"იმპლემენტაციის აღწერა", 7 | "Response Class":"რესპონს კლასი", 8 | "Status":"სტატუსი", 9 | "Parameters":"პარამეტრები", 10 | "Parameter":"პარამეტრი", 11 | "Value":"მნიშვნელობა", 12 | "Description":"აღწერა", 13 | "Parameter Type":"პარამეტრის ტიპი", 14 | "Data Type":"მონაცემის ტიპი", 15 | "Response Messages":"პასუხი", 16 | "HTTP Status Code":"HTTP სტატუსი", 17 | "Reason":"მიზეზი", 18 | "Response Model":"რესპონს მოდელი", 19 | "Request URL":"მოთხოვნის URL", 20 | "Response Body":"პასუხის სხეული", 21 | "Response Code":"პასუხის კოდი", 22 | "Response Headers":"პასუხის ჰედერები", 23 | "Hide Response":"დამალე პასუხი", 24 | "Headers":"ჰედერები", 25 | "Try it out!":"ცადე !", 26 | "Show/Hide":"გამოჩენა/დამალვა", 27 | "List Operations":"ოპერაციების სია", 28 | "Expand Operations":"ოპერაციები ვრცლად", 29 | "Raw":"ნედლი", 30 | "can't parse JSON. Raw result":"JSON-ის დამუშავება ვერ მოხერხდა. ნედლი პასუხი", 31 | "Example Value":"მაგალითი", 32 | "Model Schema":"მოდელის სტრუქტურა", 33 | "Model":"მოდელი", 34 | "Click to set as parameter value":"პარამეტრისთვის მნიშვნელობის მისანიჭებლად, დააკლიკე", 35 | "apply":"გამოყენება", 36 | "Username":"მოხმარებელი", 37 | "Password":"პაროლი", 38 | "Terms of service":"მომსახურების პირობები", 39 | "Created by":"შექმნა", 40 | "See more at":"ნახე ვრცლად", 41 | "Contact the developer":"დაუკავშირდი დეველოპერს", 42 | "api version":"api ვერსია", 43 | "Response Content Type":"პასუხის კონტენტის ტიპი", 44 | "Parameter content type:":"პარამეტრის კონტენტის ტიპი:", 45 | "fetching resource":"რესურსების მიღება", 46 | "fetching resource list":"რესურსების სიის მიღება", 47 | "Explore":"ნახვა", 48 | "Show Swagger Petstore Example Apis":"ნახე Swagger Petstore სამაგალითო Api", 49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"სერვერთან დაკავშირება ვერ ხერხდება. შეამოწმეთ access-control-origin.", 50 | "Please specify the protocol for":"მიუთითეთ პროტოკოლი", 51 | "Can't read swagger JSON from":"swagger JSON წაკითხვა ვერ მოხერხდა", 52 | "Finished Loading Resource Information. Rendering Swagger UI":"რესურსების ჩატვირთვა სრულდება. Swagger UI რენდერდება", 53 | "Unable to read api":"api წაკითხვა ვერ მოხერხდა", 54 | "from path":"მისამართიდან", 55 | "server returned":"სერვერმა დააბრუნა" 56 | }); 57 | -------------------------------------------------------------------------------- /public/swagger/lang/it.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Attenzione: Deprecato", 6 | "Implementation Notes":"Note di implementazione", 7 | "Response Class":"Classe della risposta", 8 | "Status":"Stato", 9 | "Parameters":"Parametri", 10 | "Parameter":"Parametro", 11 | "Value":"Valore", 12 | "Description":"Descrizione", 13 | "Parameter Type":"Tipo di parametro", 14 | "Data Type":"Tipo di dato", 15 | "Response Messages":"Messaggi della risposta", 16 | "HTTP Status Code":"Codice stato HTTP", 17 | "Reason":"Motivo", 18 | "Response Model":"Modello di risposta", 19 | "Request URL":"URL della richiesta", 20 | "Response Body":"Corpo della risposta", 21 | "Response Code":"Oggetto della risposta", 22 | "Response Headers":"Intestazioni della risposta", 23 | "Hide Response":"Nascondi risposta", 24 | "Try it out!":"Provalo!", 25 | "Show/Hide":"Mostra/Nascondi", 26 | "List Operations":"Mostra operazioni", 27 | "Expand Operations":"Espandi operazioni", 28 | "Raw":"Grezzo (raw)", 29 | "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).", 30 | "Model Schema":"Schema del modello", 31 | "Model":"Modello", 32 | "apply":"applica", 33 | "Username":"Nome utente", 34 | "Password":"Password", 35 | "Terms of service":"Condizioni del servizio", 36 | "Created by":"Creato da", 37 | "See more at":"Informazioni aggiuntive:", 38 | "Contact the developer":"Contatta lo sviluppatore", 39 | "api version":"versione api", 40 | "Response Content Type":"Tipo di contenuto (content type) della risposta", 41 | "fetching resource":"recuperando la risorsa", 42 | "fetching resource list":"recuperando lista risorse", 43 | "Explore":"Esplora", 44 | "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore", 45 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.", 46 | "Please specify the protocol for":"Si prega di specificare il protocollo per", 47 | "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:", 48 | "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata", 49 | "Unable to read api":"Impossibile leggere la api", 50 | "from path":"da cartella", 51 | "server returned":"il server ha restituito" 52 | }); 53 | -------------------------------------------------------------------------------- /public/swagger/lang/ja.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"警告: 廃止予定", 6 | "Implementation Notes":"実装メモ", 7 | "Response Class":"レスポンスクラス", 8 | "Status":"ステータス", 9 | "Parameters":"パラメータ群", 10 | "Parameter":"パラメータ", 11 | "Value":"値", 12 | "Description":"説明", 13 | "Parameter Type":"パラメータタイプ", 14 | "Data Type":"データタイプ", 15 | "Response Messages":"レスポンスメッセージ", 16 | "HTTP Status Code":"HTTPステータスコード", 17 | "Reason":"理由", 18 | "Response Model":"レスポンスモデル", 19 | "Request URL":"リクエストURL", 20 | "Response Body":"レスポンスボディ", 21 | "Response Code":"レスポンスコード", 22 | "Response Headers":"レスポンスヘッダ", 23 | "Hide Response":"レスポンスを隠す", 24 | "Headers":"ヘッダ", 25 | "Try it out!":"実際に実行!", 26 | "Show/Hide":"表示/非表示", 27 | "List Operations":"操作一覧", 28 | "Expand Operations":"操作の展開", 29 | "Raw":"未加工", 30 | "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果", 31 | "Example Value":"値の例", 32 | "Model Schema":"モデルスキーマ", 33 | "Model":"モデル", 34 | "Click to set as parameter value":"パラメータ値と設定するにはクリック", 35 | "apply":"実行", 36 | "Username":"ユーザ名", 37 | "Password":"パスワード", 38 | "Terms of service":"サービス利用規約", 39 | "Created by":"Created by", 40 | "See more at":"詳細を見る", 41 | "Contact the developer":"開発者に連絡", 42 | "api version":"APIバージョン", 43 | "Response Content Type":"レスポンス コンテンツタイプ", 44 | "Parameter content type:":"パラメータコンテンツタイプ:", 45 | "fetching resource":"リソースの取得", 46 | "fetching resource list":"リソース一覧の取得", 47 | "Explore":"調査", 48 | "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示", 49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.", 50 | "Please specify the protocol for":"プロトコルを指定してください", 51 | "Can't read swagger JSON from":"次からswagger JSONを読み込めません", 52 | "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています", 53 | "Unable to read api":"APIを読み込めません", 54 | "from path":"次のパスから", 55 | "server returned":"サーバからの返答" 56 | }); 57 | -------------------------------------------------------------------------------- /public/swagger/lang/ko-kr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"경고:폐기예정됨", 6 | "Implementation Notes":"구현 노트", 7 | "Response Class":"응답 클래스", 8 | "Status":"상태", 9 | "Parameters":"매개변수들", 10 | "Parameter":"매개변수", 11 | "Value":"값", 12 | "Description":"설명", 13 | "Parameter Type":"매개변수 타입", 14 | "Data Type":"데이터 타입", 15 | "Response Messages":"응답 메세지", 16 | "HTTP Status Code":"HTTP 상태 코드", 17 | "Reason":"원인", 18 | "Response Model":"응답 모델", 19 | "Request URL":"요청 URL", 20 | "Response Body":"응답 본문", 21 | "Response Code":"응답 코드", 22 | "Response Headers":"응답 헤더", 23 | "Hide Response":"응답 숨기기", 24 | "Headers":"헤더", 25 | "Try it out!":"써보기!", 26 | "Show/Hide":"보이기/숨기기", 27 | "List Operations":"목록 작업", 28 | "Expand Operations":"전개 작업", 29 | "Raw":"원본", 30 | "can't parse JSON. Raw result":"JSON을 파싱할수 없음. 원본결과:", 31 | "Model Schema":"모델 스키마", 32 | "Model":"모델", 33 | "apply":"적용", 34 | "Username":"사용자 이름", 35 | "Password":"암호", 36 | "Terms of service":"이용약관", 37 | "Created by":"작성자", 38 | "See more at":"추가정보:", 39 | "Contact the developer":"개발자에게 문의", 40 | "api version":"api버전", 41 | "Response Content Type":"응답Content Type", 42 | "fetching resource":"리소스 가져오기", 43 | "fetching resource list":"리소스 목록 가져오기", 44 | "Explore":"탐색", 45 | "Show Swagger Petstore Example Apis":"Swagger Petstore 예제 보기", 46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"서버로부터 읽어들일수 없습니다. access-control-origin 설정이 올바르지 않을수 있습니다.", 47 | "Please specify the protocol for":"다음을 위한 프로토콜을 정하세요", 48 | "Can't read swagger JSON from":"swagger JSON 을 다음으로 부터 읽을수 없습니다", 49 | "Finished Loading Resource Information. Rendering Swagger UI":"리소스 정보 불러오기 완료. Swagger UI 랜더링", 50 | "Unable to read api":"api를 읽을 수 없습니다.", 51 | "from path":"다음 경로로 부터", 52 | "server returned":"서버 응답함." 53 | }); 54 | -------------------------------------------------------------------------------- /public/swagger/lang/pl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Uwaga: Wycofane", 6 | "Implementation Notes":"Uwagi Implementacji", 7 | "Response Class":"Klasa Odpowiedzi", 8 | "Status":"Status", 9 | "Parameters":"Parametry", 10 | "Parameter":"Parametr", 11 | "Value":"Wartość", 12 | "Description":"Opis", 13 | "Parameter Type":"Typ Parametru", 14 | "Data Type":"Typ Danych", 15 | "Response Messages":"Wiadomości Odpowiedzi", 16 | "HTTP Status Code":"Kod Statusu HTTP", 17 | "Reason":"Przyczyna", 18 | "Response Model":"Model Odpowiedzi", 19 | "Request URL":"URL Wywołania", 20 | "Response Body":"Treść Odpowiedzi", 21 | "Response Code":"Kod Odpowiedzi", 22 | "Response Headers":"Nagłówki Odpowiedzi", 23 | "Hide Response":"Ukryj Odpowiedź", 24 | "Headers":"Nagłówki", 25 | "Try it out!":"Wypróbuj!", 26 | "Show/Hide":"Pokaż/Ukryj", 27 | "List Operations":"Lista Operacji", 28 | "Expand Operations":"Rozwiń Operacje", 29 | "Raw":"Nieprzetworzone", 30 | "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane", 31 | "Model Schema":"Schemat Modelu", 32 | "Model":"Model", 33 | "apply":"użyj", 34 | "Username":"Nazwa użytkownika", 35 | "Password":"Hasło", 36 | "Terms of service":"Warunki używania", 37 | "Created by":"Utworzone przez", 38 | "See more at":"Zobacz więcej na", 39 | "Contact the developer":"Kontakt z deweloperem", 40 | "api version":"wersja api", 41 | "Response Content Type":"Typ Zasobu Odpowiedzi", 42 | "fetching resource":"ładowanie zasobu", 43 | "fetching resource list":"ładowanie listy zasobów", 44 | "Explore":"Eksploruj", 45 | "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore", 46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.", 47 | "Please specify the protocol for":"Proszę podać protokół dla", 48 | "Can't read swagger JSON from":"Nie można odczytać swagger JSON z", 49 | "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI", 50 | "Unable to read api":"Nie można odczytać api", 51 | "from path":"ze ścieżki", 52 | "server returned":"serwer zwrócił" 53 | }); 54 | -------------------------------------------------------------------------------- /public/swagger/lang/pt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Aviso: Depreciado", 6 | "Implementation Notes":"Notas de Implementação", 7 | "Response Class":"Classe de resposta", 8 | "Status":"Status", 9 | "Parameters":"Parâmetros", 10 | "Parameter":"Parâmetro", 11 | "Value":"Valor", 12 | "Description":"Descrição", 13 | "Parameter Type":"Tipo de parâmetro", 14 | "Data Type":"Tipo de dados", 15 | "Response Messages":"Mensagens de resposta", 16 | "HTTP Status Code":"Código de status HTTP", 17 | "Reason":"Razão", 18 | "Response Model":"Modelo resposta", 19 | "Request URL":"URL requisição", 20 | "Response Body":"Corpo da resposta", 21 | "Response Code":"Código da resposta", 22 | "Response Headers":"Cabeçalho da resposta", 23 | "Headers":"Cabeçalhos", 24 | "Hide Response":"Esconder resposta", 25 | "Try it out!":"Tente agora!", 26 | "Show/Hide":"Mostrar/Esconder", 27 | "List Operations":"Listar operações", 28 | "Expand Operations":"Expandir operações", 29 | "Raw":"Cru", 30 | "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru", 31 | "Model Schema":"Modelo esquema", 32 | "Model":"Modelo", 33 | "apply":"Aplicar", 34 | "Username":"Usuário", 35 | "Password":"Senha", 36 | "Terms of service":"Termos do serviço", 37 | "Created by":"Criado por", 38 | "See more at":"Veja mais em", 39 | "Contact the developer":"Contate o desenvolvedor", 40 | "api version":"Versão api", 41 | "Response Content Type":"Tipo de conteúdo da resposta", 42 | "fetching resource":"busca recurso", 43 | "fetching resource list":"buscando lista de recursos", 44 | "Explore":"Explorar", 45 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", 46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin", 47 | "Please specify the protocol for":"Por favor especifique o protocolo", 48 | "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de", 49 | "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI", 50 | "Unable to read api":"Não foi possível ler api", 51 | "from path":"do caminho", 52 | "server returned":"servidor retornou" 53 | }); 54 | -------------------------------------------------------------------------------- /public/swagger/lang/ru.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Предупреждение: Устарело", 6 | "Implementation Notes":"Заметки", 7 | "Response Class":"Пример ответа", 8 | "Status":"Статус", 9 | "Parameters":"Параметры", 10 | "Parameter":"Параметр", 11 | "Value":"Значение", 12 | "Description":"Описание", 13 | "Parameter Type":"Тип параметра", 14 | "Data Type":"Тип данных", 15 | "HTTP Status Code":"HTTP код", 16 | "Reason":"Причина", 17 | "Response Model":"Структура ответа", 18 | "Request URL":"URL запроса", 19 | "Response Body":"Тело ответа", 20 | "Response Code":"HTTP код ответа", 21 | "Response Headers":"Заголовки ответа", 22 | "Hide Response":"Спрятать ответ", 23 | "Headers":"Заголовки", 24 | "Response Messages":"Что может прийти в ответ", 25 | "Try it out!":"Попробовать!", 26 | "Show/Hide":"Показать/Скрыть", 27 | "List Operations":"Операции кратко", 28 | "Expand Operations":"Операции подробно", 29 | "Raw":"В сыром виде", 30 | "can't parse JSON. Raw result":"Не удается распарсить ответ:", 31 | "Example Value":"Пример", 32 | "Model Schema":"Структура", 33 | "Model":"Описание", 34 | "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра", 35 | "apply":"применить", 36 | "Username":"Имя пользователя", 37 | "Password":"Пароль", 38 | "Terms of service":"Условия использования", 39 | "Created by":"Разработано", 40 | "See more at":"Еще тут", 41 | "Contact the developer":"Связаться с разработчиком", 42 | "api version":"Версия API", 43 | "Response Content Type":"Content Type ответа", 44 | "Parameter content type:":"Content Type параметра:", 45 | "fetching resource":"Получение ресурса", 46 | "fetching resource list":"Получение ресурсов", 47 | "Explore":"Показать", 48 | "Show Swagger Petstore Example Apis":"Показать примеры АПИ", 49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа", 50 | "Please specify the protocol for":"Пожалуйста, укажите протокол для", 51 | "Can't read swagger JSON from":"Не получается прочитать swagger json из", 52 | "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим", 53 | "Unable to read api":"Не удалось прочитать api", 54 | "from path":"по адресу", 55 | "server returned":"сервер сказал" 56 | }); 57 | -------------------------------------------------------------------------------- /public/swagger/lang/tr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"Uyarı: Deprecated", 6 | "Implementation Notes":"Gerçekleştirim Notları", 7 | "Response Class":"Dönen Sınıf", 8 | "Status":"Statü", 9 | "Parameters":"Parametreler", 10 | "Parameter":"Parametre", 11 | "Value":"Değer", 12 | "Description":"Açıklama", 13 | "Parameter Type":"Parametre Tipi", 14 | "Data Type":"Veri Tipi", 15 | "Response Messages":"Dönüş Mesajı", 16 | "HTTP Status Code":"HTTP Statü Kodu", 17 | "Reason":"Gerekçe", 18 | "Response Model":"Dönüş Modeli", 19 | "Request URL":"İstek URL", 20 | "Response Body":"Dönüş İçeriği", 21 | "Response Code":"Dönüş Kodu", 22 | "Response Headers":"Dönüş Üst Bilgileri", 23 | "Hide Response":"Dönüşü Gizle", 24 | "Headers":"Üst Bilgiler", 25 | "Try it out!":"Dene!", 26 | "Show/Hide":"Göster/Gizle", 27 | "List Operations":"Operasyonları Listele", 28 | "Expand Operations":"Operasyonları Aç", 29 | "Raw":"Ham", 30 | "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç", 31 | "Model Schema":"Model Şema", 32 | "Model":"Model", 33 | "apply":"uygula", 34 | "Username":"Kullanıcı Adı", 35 | "Password":"Parola", 36 | "Terms of service":"Servis şartları", 37 | "Created by":"Oluşturan", 38 | "See more at":"Daha fazlası için", 39 | "Contact the developer":"Geliştirici ile İletişime Geçin", 40 | "api version":"api versiyon", 41 | "Response Content Type":"Dönüş İçerik Tipi", 42 | "fetching resource":"kaynak getiriliyor", 43 | "fetching resource list":"kaynak listesi getiriliyor", 44 | "Explore":"Keşfet", 45 | "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör", 46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.", 47 | "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz", 48 | "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor", 49 | "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor", 50 | "Unable to read api":"api okunamadı", 51 | "from path":"yoldan", 52 | "server returned":"sunucuya dönüldü" 53 | }); 54 | -------------------------------------------------------------------------------- /public/swagger/lang/translator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Translator for documentation pages. 5 | * 6 | * To enable translation you should include one of language-files in your index.html 7 | * after . 8 | * For example - 9 | * 10 | * If you wish to translate some new texts you should do two things: 11 | * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. 12 | * 2. Mark that text it templates this way New Phrase or . 13 | * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate. 14 | * 15 | */ 16 | window.SwaggerTranslator = { 17 | 18 | _words:[], 19 | 20 | translate: function(sel) { 21 | var $this = this; 22 | sel = sel || '[data-sw-translate]'; 23 | 24 | $(sel).each(function() { 25 | $(this).html($this._tryTranslate($(this).html())); 26 | 27 | $(this).val($this._tryTranslate($(this).val())); 28 | $(this).attr('title', $this._tryTranslate($(this).attr('title'))); 29 | }); 30 | }, 31 | 32 | _tryTranslate: function(word) { 33 | return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; 34 | }, 35 | 36 | learn: function(wordsMap) { 37 | this._words = wordsMap; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /public/swagger/lang/zh-cn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jshint quotmark: double */ 4 | window.SwaggerTranslator.learn({ 5 | "Warning: Deprecated":"警告:已过时", 6 | "Implementation Notes":"实现备注", 7 | "Response Class":"响应类", 8 | "Status":"状态", 9 | "Parameters":"参数", 10 | "Parameter":"参数", 11 | "Value":"值", 12 | "Description":"描述", 13 | "Parameter Type":"参数类型", 14 | "Data Type":"数据类型", 15 | "Response Messages":"响应消息", 16 | "HTTP Status Code":"HTTP状态码", 17 | "Reason":"原因", 18 | "Response Model":"响应模型", 19 | "Request URL":"请求URL", 20 | "Response Body":"响应体", 21 | "Response Code":"响应码", 22 | "Response Headers":"响应头", 23 | "Hide Response":"隐藏响应", 24 | "Headers":"头", 25 | "Try it out!":"试一下!", 26 | "Show/Hide":"显示/隐藏", 27 | "List Operations":"显示操作", 28 | "Expand Operations":"展开操作", 29 | "Raw":"原始", 30 | "can't parse JSON. Raw result":"无法解析JSON. 原始结果", 31 | "Example Value":"示例", 32 | "Click to set as parameter value":"点击设置参数", 33 | "Model Schema":"模型架构", 34 | "Model":"模型", 35 | "apply":"应用", 36 | "Username":"用户名", 37 | "Password":"密码", 38 | "Terms of service":"服务条款", 39 | "Created by":"创建者", 40 | "See more at":"查看更多:", 41 | "Contact the developer":"联系开发者", 42 | "api version":"api版本", 43 | "Response Content Type":"响应Content Type", 44 | "Parameter content type:":"参数类型:", 45 | "fetching resource":"正在获取资源", 46 | "fetching resource list":"正在获取资源列表", 47 | "Explore":"浏览", 48 | "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis", 49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。", 50 | "Please specify the protocol for":"请指定协议:", 51 | "Can't read swagger JSON from":"无法读取swagger JSON于", 52 | "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI", 53 | "Unable to read api":"无法读取api", 54 | "from path":"从路径", 55 | "server returned":"服务器返回" 56 | }); 57 | -------------------------------------------------------------------------------- /public/swagger/lib/highlight.9.1.0.pack.js: -------------------------------------------------------------------------------- 1 | !function(e){"undefined"!=typeof exports?e(exports):(self.hljs=e({}),"function"==typeof define&&define.amd&&define("hljs",[],function(){return self.hljs}))}(function(e){function r(e){return e.replace(/&/gm,"&").replace(//gm,">")}function t(e){return e.nodeName.toLowerCase()}function n(e,r){var t=e&&e.exec(r);return t&&0==t.index}function a(e){return/^(no-?highlight|plain|text)$/i.test(e)}function c(e){var r,t,n,c=e.className+" ";if(c+=e.parentNode?e.parentNode.className:"",t=/\blang(?:uage)?-([\w-]+)\b/i.exec(c))return E(t[1])?t[1]:"no-highlight";for(c=c.split(/\s+/),r=0,n=c.length;n>r;r++)if(E(c[r])||a(c[r]))return c[r]}function i(e,r){var t,n={};for(t in e)n[t]=e[t];if(r)for(t in r)n[t]=r[t];return n}function o(e){var r=[];return function n(e,a){for(var c=e.firstChild;c;c=c.nextSibling)3==c.nodeType?a+=c.nodeValue.length:1==c.nodeType&&(r.push({event:"start",offset:a,node:c}),a=n(c,a),t(c).match(/br|hr|img|input/)||r.push({event:"stop",offset:a,node:c}));return a}(e,0),r}function s(e,n,a){function c(){return e.length&&n.length?e[0].offset!=n[0].offset?e[0].offset"}function o(e){l+=""}function s(e){("start"==e.event?i:o)(e.node)}for(var u=0,l="",f=[];e.length||n.length;){var b=c();if(l+=r(a.substr(u,b[0].offset-u)),u=b[0].offset,b==e){f.reverse().forEach(o);do s(b.splice(0,1)[0]),b=c();while(b==e&&b.length&&b[0].offset==u);f.reverse().forEach(i)}else"start"==b[0].event?f.push(b[0].node):f.pop(),s(b.splice(0,1)[0])}return l+r(a.substr(u))}function u(e){function r(e){return e&&e.source||e}function t(t,n){return new RegExp(r(t),"m"+(e.cI?"i":"")+(n?"g":""))}function n(a,c){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},s=function(r,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[r,t[1]?Number(t[1]):1]})};"string"==typeof a.k?s("keyword",a.k):Object.keys(a.k).forEach(function(e){s(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\b\w+\b/,!0),c&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=r(a.e)||"",a.eW&&c.tE&&(a.tE+=(a.e?"|":"")+c.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var u=[];a.c.forEach(function(e){e.v?e.v.forEach(function(r){u.push(i(e,r))}):u.push("self"==e?a:e)}),a.c=u,a.c.forEach(function(e){n(e,a)}),a.starts&&n(a.starts,c);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(r).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}n(e)}function l(e,t,a,c){function i(e,r){for(var t=0;t";return c+=e+'">',c+r+i}function p(){if(!M.k)return r(B);var e="",t=0;M.lR.lastIndex=0;for(var n=M.lR.exec(B);n;){e+=r(B.substr(t,n.index-t));var a=b(M,n);a?(L+=a[1],e+=g(a[0],r(n[0]))):e+=r(n[0]),t=M.lR.lastIndex,n=M.lR.exec(B)}return e+r(B.substr(t))}function h(){var e="string"==typeof M.sL;if(e&&!y[M.sL])return r(B);var t=e?l(M.sL,B,!0,R[M.sL]):f(B,M.sL.length?M.sL:void 0);return M.r>0&&(L+=t.r),e&&(R[M.sL]=t.top),g(t.language,t.value,!1,!0)}function d(){return void 0!==M.sL?h():p()}function m(e,t){var n=e.cN?g(e.cN,"",!0):"";e.rB?(x+=n,B=""):e.eB?(x+=r(t)+n,B=""):(x+=n,B=t),M=Object.create(e,{parent:{value:M}})}function v(e,t){if(B+=e,void 0===t)return x+=d(),0;var n=i(t,M);if(n)return x+=d(),m(n,t),n.rB?0:t.length;var a=o(M,t);if(a){var c=M;c.rE||c.eE||(B+=t),x+=d();do M.cN&&(x+=""),L+=M.r,M=M.parent;while(M!=a.parent);return c.eE&&(x+=r(t)),B="",a.starts&&m(a.starts,""),c.rE?0:t.length}if(s(t,M))throw new Error('Illegal lexeme "'+t+'" for mode "'+(M.cN||"")+'"');return B+=t,t.length||1}var N=E(e);if(!N)throw new Error('Unknown language: "'+e+'"');u(N);var C,M=c||N,R={},x="";for(C=M;C!=N;C=C.parent)C.cN&&(x=g(C.cN,"",!0)+x);var B="",L=0;try{for(var S,A,k=0;M.t.lastIndex=k,S=M.t.exec(t),S;)A=v(t.substr(k,S.index-k),S[0]),k=S.index+A;for(v(t.substr(k)),C=M;C.parent;C=C.parent)C.cN&&(x+="");return{r:L,value:x,language:e,top:M}}catch(I){if(-1!=I.message.indexOf("Illegal"))return{r:0,value:r(t)};throw I}}function f(e,t){t=t||w.languages||Object.keys(y);var n={r:0,value:r(e)},a=n;return t.forEach(function(r){if(E(r)){var t=l(r,e,!1);t.language=r,t.r>a.r&&(a=t),t.r>n.r&&(a=n,n=t)}}),a.language&&(n.second_best=a),n}function b(e){return w.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,r){return r.replace(/\t/g,w.tabReplace)})),w.useBR&&(e=e.replace(/\n/g,"
")),e}function g(e,r,t){var n=r?C[r]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(n)&&a.push(n),a.join(" ").trim()}function p(e){var r=c(e);if(!a(r)){var t;w.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):t=e;var n=t.textContent,i=r?l(r,n,!0):f(n),u=o(t);if(u.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=i.value,i.value=s(u,o(p),n)}i.value=b(i.value),e.innerHTML=i.value,e.className=g(e.className,r,i.language),e.result={language:i.language,re:i.r},i.second_best&&(e.second_best={language:i.second_best.language,re:i.second_best.r})}}function h(e){w=i(w,e)}function d(){if(!d.called){d.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function m(){addEventListener("DOMContentLoaded",d,!1),addEventListener("load",d,!1)}function v(r,t){var n=y[r]=t(e);n.aliases&&n.aliases.forEach(function(e){C[e]=r})}function N(){return Object.keys(y)}function E(e){return e=(e||"").toLowerCase(),y[e]||y[C[e]]}var w={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},y={},C={};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=b,e.highlightBlock=p,e.configure=h,e.initHighlighting=d,e.initHighlightingOnLoad=m,e.registerLanguage=v,e.listLanguages=N,e.getLanguage=E,e.inherit=i,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(r,t,n){var a=e.inherit({cN:"comment",b:r,e:t,c:[]},n||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e}),hljs.registerLanguage("json",function(e){var r={literal:"true false null"},t=[e.QSM,e.CNM],n={e:",",eW:!0,eE:!0,c:t,k:r},a={b:"{",e:"}",c:[{cN:"attr",b:'\\s*"',e:'"\\s*:\\s*',eB:!0,eE:!0,c:[e.BE],i:"\\n",starts:n}],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(n)],i:"\\S"};return t.splice(t.length,0,a,c),{c:t,k:r,i:"\\S"}}),hljs.registerLanguage("xml",function(e){var r="[A-Za-z0-9\\._:-]+",t={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php"},n={eW:!0,i:/]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},e.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[n],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[n],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},t,{cN:"meta",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},n]}]}}),hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}}),hljs.registerLanguage("css",function(e){var r="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\s*\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:r,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}}); -------------------------------------------------------------------------------- /public/swagger/lib/highlight.9.1.0.pack_extended.js: -------------------------------------------------------------------------------- 1 | "use strict";!function(){var h,l;h=hljs.configure,hljs.configure=function(l){var i=l.highlightSizeThreshold;hljs.highlightSizeThreshold=i===+i?i:null,h.call(this,l)},l=hljs.highlightBlock,hljs.highlightBlock=function(h){var i=h.innerHTML,g=hljs.highlightSizeThreshold;(null==g||g>i.length)&&l.call(hljs,h)}}(); -------------------------------------------------------------------------------- /public/swagger/lib/jquery.ba-bbq.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){function n(e){return"string"==typeof e}function r(e){var t=g.call(arguments,1);return function(){return e.apply(this,t.concat(g.call(arguments)))}}function o(e){return e.replace(/^[^#]*#?(.*)$/,"$1")}function a(e){return e.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function i(r,o,a,i,c){var u,s,p,h,d;return i!==f?(p=a.match(r?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/),d=p[3]||"",2===c&&n(i)?s=i.replace(r?R:E,""):(h=l(p[2]),i=n(i)?l[r?A:w](i):i,s=2===c?i:1===c?e.extend({},i,h):e.extend({},h,i),s=b(s),r&&(s=s.replace(m,y))),u=p[1]+(r?"#":s||!p[1]?"?":"")+s+d):u=o(a!==f?a:t[S][q]),u}function c(e,t,r){return t===f||"boolean"==typeof t?(r=t,t=b[e?A:w]()):t=n(t)?t.replace(e?R:E,""):t,l(t,r)}function u(t,r,o,a){return n(o)||"object"==typeof o||(a=o,o=r,r=f),this.each(function(){var n=e(this),i=r||v()[(this.nodeName||"").toLowerCase()]||"",c=i&&n.attr(i)||"";n.attr(i,b[t](c,o,a))})}var f,s,l,p,h,d,v,m,g=Array.prototype.slice,y=decodeURIComponent,b=e.param,$=e.bbq=e.bbq||{},x=e.event.special,j="hashchange",w="querystring",A="fragment",N="elemUrlAttr",S="location",q="href",C="src",E=/^.*\?|#.*$/g,R=/^.*\#/,U={};b[w]=r(i,0,a),b[A]=s=r(i,1,o),s.noEscape=function(t){t=t||"";var n=e.map(t.split(""),encodeURIComponent);m=new RegExp(n.join("|"),"g")},s.noEscape(",/"),e.deparam=l=function(t,n){var r={},o={"true":!0,"false":!1,"null":null};return e.each(t.replace(/\+/g," ").split("&"),function(t,a){var i,c=a.split("="),u=y(c[0]),s=r,l=0,p=u.split("]["),h=p.length-1;if(/\[/.test(p[0])&&/\]$/.test(p[h])?(p[h]=p[h].replace(/\]$/,""),p=p.shift().split("[").concat(p),h=p.length-1):h=0,2===c.length)if(i=y(c[1]),n&&(i=i&&!isNaN(i)?+i:"undefined"===i?f:o[i]!==f?o[i]:i),h)for(;l<=h;l++)u=""===p[l]?s.length:p[l],s=s[u]=l').hide().insertAfter("body")[0].contentWindow,s=function(){return r(a.document[i][u])},(f=function(e,t){if(e!==t){var n=a.document;n.open().close(),n[i].hash="#"+e}})(r()))}var o,a,f,s,p={};return p.start=function(){if(!o){var a=r();f||n(),function l(){var n=r(),p=s(a);n!==a?(f(a=n,p),e(t).trigger(c)):p!==a&&(t[i][u]=t[i][u].replace(/#.*/,"")+"#"+p),o=setTimeout(l,e[c+"Delay"])}()}},p.stop=function(){a||(o&&clearTimeout(o),o=0)},p}()}(jQuery,this); -------------------------------------------------------------------------------- /public/swagger/lib/jquery.slideto.min.js: -------------------------------------------------------------------------------- 1 | !function(i){i.fn.slideto=function(o){return o=i.extend({slide_duration:"slow",highlight_duration:3e3,highlight:!0,highlight_color:"#FFFF99"},o),this.each(function(){obj=i(this),i("body").animate({scrollTop:obj.offset().top},o.slide_duration,function(){o.highlight&&i.ui.version&&obj.effect("highlight",{color:o.highlight_color},o.highlight_duration)})})}}(jQuery); -------------------------------------------------------------------------------- /public/swagger/lib/jquery.wiggle.min.js: -------------------------------------------------------------------------------- 1 | jQuery.fn.wiggle=function(e){var a={speed:50,wiggles:3,travel:5,callback:null},e=jQuery.extend(a,e);return this.each(function(){var a=this,l=(jQuery(this).wrap('
').css("position","relative"),0);for(i=1;i<=e.wiggles;i++)jQuery(this).animate({left:"-="+e.travel},e.speed).animate({left:"+="+2*e.travel},2*e.speed).animate({left:"-="+e.travel},e.speed,function(){l++,jQuery(a).parent().hasClass("wiggle-wrap")&&jQuery(a).parent().replaceWith(a),l==e.wiggles&&jQuery.isFunction(e.callback)&&e.callback()})})}; -------------------------------------------------------------------------------- /public/swagger/lib/object-assign-pollyfill.js: -------------------------------------------------------------------------------- 1 | "function"!=typeof Object.assign&&!function(){Object.assign=function(n){"use strict";if(void 0===n||null===n)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(n),o=1;o','
Select OAuth2.0 Scopes
','
',"

Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.",'Learn how to use',"

","

"+appName+" API requires the following scopes. Select which ones you want to grant to Swagger UI.

",'
    ',"
",'

','
',"
",""].join("")),$(document.body).append(popupDialog),popup=popupDialog.find("ul.api-popup-scopes").empty(),p=0;p",popup.append(str);var r=$(window),s=r.width(),c=r.height(),l=r.scrollTop(),d=popupDialog.outerWidth(),u=popupDialog.outerHeight(),h=(c-u)/2+l,g=(s-d)/2;popupDialog.css({top:(h<0?0:h)+"px",left:(g<0?0:g)+"px"}),popupDialog.find("button.api-popup-cancel").click(function(){popupMask.hide(),popupDialog.hide(),popupDialog.empty(),popupDialog=[]}),$("button.api-popup-authbtn").unbind(),popupDialog.find("button.api-popup-authbtn").click(function(){function e(e){return e.vendorExtensions["x-tokenName"]||e.tokenName}popupMask.hide(),popupDialog.hide();var o,i=window.swaggerUi.api.authSchemes,n=window.location,a=location.pathname.substring(0,location.pathname.lastIndexOf("/")),t=n.protocol+"//"+n.host+a+"/o2c.html",p=window.oAuthRedirectUrl||t,r=null,s=[],c=popup.find("input:checked"),l=[];for(k=0;k0?void log("auth unable initialize oauth: "+i):($("pre code").each(function(e,o){hljs.highlightBlock(o)}),$(".api-ic").unbind(),void $(".api-ic").click(function(e){$(e.target).hasClass("ic-off")?handleLogin():handleLogout()}))}function clientCredentialsFlow(e,o,i){var n={client_id:clientId,client_secret:clientSecret,scope:e.join(" "),grant_type:"client_credentials"};$.ajax({url:o,type:"POST",data:n,success:function(e,o,n){onOAuthComplete(e,i)},error:function(e,o,i){onOAuthComplete("")}})}var appName,popupMask,popupDialog,clientId,realm,redirect_uri,clientSecret,scopeSeparator,additionalQueryStringParams;window.processOAuthCode=function(e){var o=e.state,i=window.location,n=location.pathname.substring(0,location.pathname.lastIndexOf("/")),a=i.protocol+"//"+i.host+n+"/o2c.html",t=window.oAuthRedirectUrl||a,p={client_id:clientId,code:e.code,grant_type:"authorization_code",redirect_uri:t};clientSecret&&(p.client_secret=clientSecret),$.ajax({url:window.swaggerUiAuth.tokenUrl,type:"POST",data:p,success:function(e,i,n){onOAuthComplete(e,o)},error:function(e,o,i){onOAuthComplete("")}})},window.onOAuthComplete=function(e,o){if(e)if(e.error){var i=$("input[type=checkbox],.secured");i.each(function(e){i[e].checked=!1}),alert(e.error)}else{var n=e[window.swaggerUiAuth.tokenName];if(o||(o=e.state),n){var a=null;$.each($(".auth .api-ic .api_information_panel"),function(e,o){var i=o;if(i&&i.childNodes){var n=[];$.each(i.childNodes,function(e,o){var i=o.innerHTML;i&&n.push(i)});for(var t=[],p=0;p0?(a=o.parentNode.parentNode,$(a.parentNode).find(".api-ic.ic-on").addClass("ic-off"),$(a.parentNode).find(".api-ic.ic-on").removeClass("ic-on"),$(a).find(".api-ic").addClass("ic-warning"),$(a).find(".api-ic").removeClass("ic-error")):(a=o.parentNode.parentNode,$(a.parentNode).find(".api-ic.ic-off").addClass("ic-on"),$(a.parentNode).find(".api-ic.ic-off").removeClass("ic-off"),$(a).find(".api-ic").addClass("ic-info"),$(a).find(".api-ic").removeClass("ic-warning"),$(a).find(".api-ic").removeClass("ic-error"))}}),"undefined"!=typeof window.swaggerUi&&(window.swaggerUi.api.clientAuthorizations.add(window.swaggerUiAuth.OAuthSchemeKey,new SwaggerClient.ApiKeyAuthorization("Authorization","Bearer "+n,"header")),window.swaggerUi.load())}}}; -------------------------------------------------------------------------------- /public/swagger/o2c.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /server/controllers/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户逻辑控制器 3 | */ 4 | 5 | var tokenUtil = require('../utils/token') 6 | var code = require('../../config/error_code') 7 | 8 | /** 9 | * 用户登录 10 | */ 11 | exports.login = function(req, res) { 12 | var username = req.query.username || '' 13 | var password = req.query.password || '' 14 | 15 | if (username == '' || password == '') { 16 | return res.api(null, { code: code.SIGNIN_ERROR, msg:'账号或密码不能为空' }) 17 | } 18 | 19 | // TODO 20 | var userInfo = { 21 | id: '123', 22 | name: '张三', 23 | gender: 0, 24 | age: 18 25 | } 26 | 27 | var token = tokenUtil.generateToken({ uid: userInfo.id }) 28 | res.cookie('token', token) 29 | return res.api({ token: token, user: userInfo }) 30 | } 31 | 32 | /** 33 | * 用户退出 34 | */ 35 | exports.logout = function(req, res) { 36 | if (req.user) { 37 | delete req.user 38 | res.clearCookie('token') 39 | return res.sendStatus(200) 40 | } else { 41 | return res.sendStatus(401) 42 | } 43 | } 44 | 45 | /** 46 | * 用户查询 47 | */ 48 | exports.getUser = function(req, res) { 49 | 50 | } 51 | 52 | /** 53 | * 用户注册 54 | */ 55 | exports.addUser = function(req, res) { 56 | 57 | } 58 | 59 | exports.updateUser = function(req, res) { 60 | 61 | } 62 | 63 | exports.delUser = function(req, res) { 64 | 65 | } 66 | -------------------------------------------------------------------------------- /server/middlewares/api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * res.api middleware 3 | * 4 | * @output 5 | * 6 | * { 7 | * "data": {}, 8 | * "status": { 9 | * "code": 0, 10 | * "msg": "success" 11 | * } 12 | * } 13 | * 14 | * 15 | * @usage 16 | * 17 | * return res.api(data) 18 | * return res.api_error(err) 19 | * 20 | * return res.api(500, err, { 21 | * code: 1, 22 | * msg: 'delete failed!' 23 | * }) 24 | * 25 | * return res.api(null, { 26 | * code: 10000, 27 | * msg: 'delete failed!' 28 | * }) 29 | * 30 | */ 31 | 32 | // API 基本状态码 33 | const API_SUCCESS_CODE = 0 34 | const API_ERROR_CODE = -1 35 | 36 | module.exports = function (req, res, next) { 37 | // set api header 38 | // res.setHeader('Access-Control-Allow-Origin', '*') 39 | // res.setHeader('Access-Control-Allow-Methods', 'GET, POST') 40 | // res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization') 41 | 42 | res.api = api 43 | res.api_error = api_error 44 | 45 | next() 46 | } 47 | 48 | function api() { 49 | var _res = this 50 | 51 | if (typeof(_res) != "object" && _is_not_has_prototype('end')) { 52 | arguments = [] 53 | console.dir('not a object') 54 | } 55 | 56 | if (arguments.length == 1) { 57 | var http_code = 200 58 | var api_data = arguments[0] 59 | var api_status = { 60 | code: API_SUCCESS_CODE, 61 | msg: 'success' 62 | } 63 | 64 | return _api(http_code, api_data, api_status) 65 | 66 | } else if (arguments.length == 2) { 67 | var http_code = 200 68 | var api_data = arguments[0] 69 | var api_status = arguments[1] 70 | 71 | return _api(http_code, api_data, api_status) 72 | 73 | } else if (arguments.length == 3) { 74 | var http_code = arguments[0] 75 | var api_data = arguments[1] 76 | var api_status = arguments[2] 77 | 78 | return _api(http_code, api_data, api_status) 79 | 80 | } else { 81 | var http_code = 200 82 | var api_data = {} 83 | var api_status = { 84 | code: -2, 85 | msg: 'res.api params error or res is not a express.response object!' 86 | } 87 | 88 | return _api(http_code, api_data, api_status) 89 | } 90 | 91 | function _is_not_has_prototype(name) { 92 | console.dir(_res) 93 | return !_res.hasOwnProperty(name) && (name in _res) 94 | } 95 | 96 | function _api (http_code, data, status) { 97 | if (_res.is_jsonp && _res.is_jsonp == true) { 98 | return _res.status(http_code).jsonp({ 99 | data: data, 100 | status: status 101 | }) 102 | } else { 103 | return _res.status(http_code).json({ 104 | data: data, 105 | status: status 106 | }) 107 | } 108 | } 109 | } 110 | 111 | function api_error(data){ 112 | var _res = this 113 | var _error_code = 200 114 | var _error_status_code = API_ERROR_CODE 115 | var _error_status_msg = 'api error' 116 | 117 | if (_res.api_error_code) { 118 | _error_code = _res.api_error_code 119 | } 120 | 121 | if (_res.api_error_status_code) { 122 | _error_status_code = _res.api_error_status_code 123 | } 124 | 125 | if (_res.api_error_status_msg) { 126 | _error_status_msg = _res.api_error_status_msg 127 | } 128 | 129 | _res.api(_error_code, data, { 130 | code: _error_status_code, 131 | msg: _error_status_msg 132 | }) 133 | } 134 | -------------------------------------------------------------------------------- /server/middlewares/auth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JWT认证中间件 3 | */ 4 | 5 | var jwt = require('express-jwt') 6 | var secret = require('../../config/secret').token_secret_key 7 | var tokenUtil = require('../utils/token') 8 | 9 | module.exports = jwt({ 10 | secret: Buffer.from(secret, 'base64'), 11 | requestProperty: 'user', // By default, the decoded token is attached to req.user 12 | credentialsRequired: true, // You might want to use this module to identify registered users while still providing access to unregistered users 13 | getToken: tokenUtil.getToken // Where the token is 14 | }).unless({ // 排除路径 15 | path: [ 16 | '/rest/token', 17 | '/rest/user/regist', 18 | '/rest/user/login', 19 | // /^(?!\/rest\/).*/ // 所有非rest路由 20 | '/login' 21 | ] 22 | }) 23 | -------------------------------------------------------------------------------- /server/middlewares/compress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 压缩中间件(gzip) 3 | * 注:生产环境配置nginx来处理压缩和静态文件 4 | */ 5 | 6 | var compression = require('compression') 7 | 8 | var compressOptions = { 9 | threshold: 0, 10 | filter: shouldCompress 11 | } 12 | 13 | function shouldCompress (req, res) { 14 | if (req.headers['x-no-compression']) { // don't compress responses 15 | return false 16 | } 17 | 18 | // fallback to standard filter function 19 | return compression.filter(req, res) 20 | } 21 | 22 | module.exports = compression(compressOptions) 23 | -------------------------------------------------------------------------------- /server/middlewares/interceptor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 拦截器 3 | */ 4 | 5 | var tokenUtil = require('../utils/token') 6 | 7 | module.exports = function (req, res, next) { 8 | // 刷新页面Token(注:此处针对单一web项目) 9 | var oldToken = tokenUtil.getToken(req) 10 | if (oldToken && tokenUtil.verifyToken(oldToken)) { 11 | var newTokent = tokenUtil.refreshToken(oldToken) 12 | res.cookie('token', newTokent) 13 | } 14 | 15 | // console.log('intercept: ' + req.path) 16 | next() 17 | } 18 | -------------------------------------------------------------------------------- /server/middlewares/logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 日志中间件 3 | */ 4 | 5 | var morgan = require('morgan') 6 | var path = require('path') 7 | var fs = require('fs') 8 | var FileStreamRotator = require('file-stream-rotator') 9 | 10 | var logDirectory = path.join(__dirname, '..', '..', 'logs') 11 | var config = require('../../config/' + process.env.NODE_ENV) 12 | 13 | // ensure log directory exists 14 | fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory) 15 | 16 | // create a rotating write stream 17 | var accessLogStream = FileStreamRotator.getStream({ 18 | date_format: 'YYYYMMDD', 19 | filename: path.join(logDirectory, 'access-%DATE%.log'), 20 | frequency: 'daily', 21 | verbose: false 22 | }) 23 | 24 | var logger = morgan(config.logging.type, { stream: accessLogStream }) 25 | 26 | module.exports = logger 27 | -------------------------------------------------------------------------------- /server/models/User.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户模型(mongodb) 3 | */ 4 | 5 | var MongooseDao = require('mongoosedao') 6 | var mongodb = require('../utils/mongodb') 7 | var Schema = mongodb.Schema 8 | 9 | var UserSchema = new Schema({ 10 | username: { 11 | type: String, 12 | required: true, 13 | index: { 14 | unique: true 15 | } 16 | }, 17 | password: { 18 | type: String, 19 | required: true 20 | }, 21 | avatar: String, 22 | created_at: { 23 | type: Date, 24 | "default": Date.now 25 | } 26 | }) 27 | 28 | UserSchema.methods.find_by_name = function (cb) { 29 | return this.model('UserModel').find({ 30 | username: this.username 31 | }, cb) 32 | } 33 | 34 | UserSchema.methods.is_exist = function (cb) { 35 | var query = { 36 | username: this.username, 37 | password: this.password 38 | } 39 | return this.model('UserModel').findOne(query, cb) 40 | } 41 | 42 | UserSchema.statics.delete_by_name = function(name, cb_succ, cb_fail) { 43 | 44 | } 45 | 46 | var UserModel = mongodb.model('UserModel', UserSchema) 47 | 48 | var UserDao = new MongooseDao(UserModel) 49 | 50 | module.exports = UserDao 51 | -------------------------------------------------------------------------------- /server/models/UserORM.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户模型(orm) 3 | */ 4 | 5 | var Sequelize = require('sequelize') 6 | var orm = require('../utils/orm') 7 | 8 | var UserModel = orm.define('UserModel', { 9 | id: { 10 | type : Sequelize.INTEGER, 11 | autoIncrement : true, 12 | primaryKey : true, 13 | unique : true 14 | }, 15 | username: { 16 | type: Sequelize.STRING, 17 | allowNull: false, 18 | unique: true 19 | }, 20 | password: { 21 | type: Sequelize.STRING, 22 | allowNull: false 23 | }, 24 | avatar: { 25 | type: Sequelize.STRING, 26 | }, 27 | created_at: { 28 | type: Sequelize.DATE, 29 | "defaultValue": Sequelize.NOW 30 | } 31 | }) 32 | 33 | module.exports = UserModel 34 | -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 首页路由 3 | */ 4 | 5 | var express = require('express') 6 | var router = express.Router() 7 | 8 | router.get('/', function(req, res, next) { 9 | res.render('index', { title: 'Server', content: new Date() }) 10 | }) 11 | 12 | module.exports = router 13 | -------------------------------------------------------------------------------- /server/routes/login.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 登录路由 3 | */ 4 | 5 | var express = require('express') 6 | var router = express.Router() 7 | 8 | router.get('/', function(req, res, next) { 9 | res.render('login', { layout: false }) 10 | }) 11 | 12 | module.exports = router 13 | -------------------------------------------------------------------------------- /server/routes/rest/token.js: -------------------------------------------------------------------------------- 1 | /** 2 | * token 续期(一般针对非web项目,不依赖cookie) 3 | * TODO 检测刷新有效期,防止无限刷新永不过期? 4 | */ 5 | 6 | var express = require('express') 7 | var router = express.Router() 8 | var tokenUtil = require('../../utils/token') 9 | 10 | router.get('/', function (req, res, next) { 11 | var oldToken = tokenUtil.getToken(req) 12 | if (oldToken) { 13 | var newTokent = tokenUtil.refreshToken(oldToken) 14 | res.api(newTokent) 15 | } else { 16 | res.api_error('No authorization token was found') 17 | } 18 | }) 19 | 20 | module.exports = router 21 | -------------------------------------------------------------------------------- /server/routes/rest/user.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var userCtrl = require('../../controllers/user') 3 | var router = express.Router() 4 | 5 | // 用户登录 6 | router.get('/login', userCtrl.login) 7 | 8 | // 用户退出 9 | router.get('/logout', userCtrl.logout) 10 | 11 | // 查询所有用户 12 | // router.get('/', userCtrl.getUsers) 13 | 14 | // 查询用户 15 | router.get('/:id', userCtrl.getUser) 16 | 17 | // 更新用户 18 | router.put('/:id', userCtrl.updateUser) 19 | 20 | // 新增用户 21 | router.post('/regist', userCtrl.addUser) 22 | 23 | // 删除用户 24 | router.delete('/:id', userCtrl.delUser) 25 | 26 | module.exports = router 27 | -------------------------------------------------------------------------------- /server/services/thrift/shared.thrift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * This Thrift file can be included by other Thrift files that want to share 22 | * these definitions. 23 | */ 24 | 25 | namespace cpp shared 26 | namespace d share // "shared" would collide with the eponymous D keyword. 27 | namespace dart shared 28 | namespace java shared 29 | namespace perl shared 30 | namespace php shared 31 | namespace haxe shared 32 | namespace netcore shared 33 | 34 | struct SharedStruct { 35 | 1: i32 key 36 | 2: string value 37 | } 38 | 39 | service SharedService { 40 | SharedStruct getStruct(1: i32 key) 41 | } -------------------------------------------------------------------------------- /server/services/thrift/tutorial/gen/tutorial_types.js: -------------------------------------------------------------------------------- 1 | // 2 | // Autogenerated by Thrift Compiler (0.10.0) 3 | // 4 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | // 6 | "use strict"; 7 | 8 | var thrift = require('thrift'); 9 | var Thrift = thrift.Thrift; 10 | var Q = thrift.Q; 11 | 12 | var shared_ttypes = require('./shared_types'); 13 | 14 | 15 | var ttypes = module.exports = {}; 16 | ttypes.Operation = { 17 | 'ADD' : 1, 18 | 'SUBTRACT' : 2, 19 | 'MULTIPLY' : 3, 20 | 'DIVIDE' : 4 21 | }; 22 | var Work = module.exports.Work = function(args) { 23 | this.num1 = 0; 24 | this.num2 = null; 25 | this.op = null; 26 | this.comment = null; 27 | if (args) { 28 | if (args.num1 !== undefined && args.num1 !== null) { 29 | this.num1 = args.num1; 30 | } 31 | if (args.num2 !== undefined && args.num2 !== null) { 32 | this.num2 = args.num2; 33 | } 34 | if (args.op !== undefined && args.op !== null) { 35 | this.op = args.op; 36 | } 37 | if (args.comment !== undefined && args.comment !== null) { 38 | this.comment = args.comment; 39 | } 40 | } 41 | }; 42 | Work.prototype = {}; 43 | Work.prototype.read = function(input) { 44 | input.readStructBegin(); 45 | while (true) 46 | { 47 | var ret = input.readFieldBegin(); 48 | var fname = ret.fname; 49 | var ftype = ret.ftype; 50 | var fid = ret.fid; 51 | if (ftype == Thrift.Type.STOP) { 52 | break; 53 | } 54 | switch (fid) 55 | { 56 | case 1: 57 | if (ftype == Thrift.Type.I32) { 58 | this.num1 = input.readI32(); 59 | } else { 60 | input.skip(ftype); 61 | } 62 | break; 63 | case 2: 64 | if (ftype == Thrift.Type.I32) { 65 | this.num2 = input.readI32(); 66 | } else { 67 | input.skip(ftype); 68 | } 69 | break; 70 | case 3: 71 | if (ftype == Thrift.Type.I32) { 72 | this.op = input.readI32(); 73 | } else { 74 | input.skip(ftype); 75 | } 76 | break; 77 | case 4: 78 | if (ftype == Thrift.Type.STRING) { 79 | this.comment = input.readString(); 80 | } else { 81 | input.skip(ftype); 82 | } 83 | break; 84 | default: 85 | input.skip(ftype); 86 | } 87 | input.readFieldEnd(); 88 | } 89 | input.readStructEnd(); 90 | return; 91 | }; 92 | 93 | Work.prototype.write = function(output) { 94 | output.writeStructBegin('Work'); 95 | if (this.num1 !== null && this.num1 !== undefined) { 96 | output.writeFieldBegin('num1', Thrift.Type.I32, 1); 97 | output.writeI32(this.num1); 98 | output.writeFieldEnd(); 99 | } 100 | if (this.num2 !== null && this.num2 !== undefined) { 101 | output.writeFieldBegin('num2', Thrift.Type.I32, 2); 102 | output.writeI32(this.num2); 103 | output.writeFieldEnd(); 104 | } 105 | if (this.op !== null && this.op !== undefined) { 106 | output.writeFieldBegin('op', Thrift.Type.I32, 3); 107 | output.writeI32(this.op); 108 | output.writeFieldEnd(); 109 | } 110 | if (this.comment !== null && this.comment !== undefined) { 111 | output.writeFieldBegin('comment', Thrift.Type.STRING, 4); 112 | output.writeString(this.comment); 113 | output.writeFieldEnd(); 114 | } 115 | output.writeFieldStop(); 116 | output.writeStructEnd(); 117 | return; 118 | }; 119 | 120 | var InvalidOperation = module.exports.InvalidOperation = function(args) { 121 | Thrift.TException.call(this, "InvalidOperation"); 122 | this.name = "InvalidOperation"; 123 | this.whatOp = null; 124 | this.why = null; 125 | if (args) { 126 | if (args.whatOp !== undefined && args.whatOp !== null) { 127 | this.whatOp = args.whatOp; 128 | } 129 | if (args.why !== undefined && args.why !== null) { 130 | this.why = args.why; 131 | } 132 | } 133 | }; 134 | Thrift.inherits(InvalidOperation, Thrift.TException); 135 | InvalidOperation.prototype.name = 'InvalidOperation'; 136 | InvalidOperation.prototype.read = function(input) { 137 | input.readStructBegin(); 138 | while (true) 139 | { 140 | var ret = input.readFieldBegin(); 141 | var fname = ret.fname; 142 | var ftype = ret.ftype; 143 | var fid = ret.fid; 144 | if (ftype == Thrift.Type.STOP) { 145 | break; 146 | } 147 | switch (fid) 148 | { 149 | case 1: 150 | if (ftype == Thrift.Type.I32) { 151 | this.whatOp = input.readI32(); 152 | } else { 153 | input.skip(ftype); 154 | } 155 | break; 156 | case 2: 157 | if (ftype == Thrift.Type.STRING) { 158 | this.why = input.readString(); 159 | } else { 160 | input.skip(ftype); 161 | } 162 | break; 163 | default: 164 | input.skip(ftype); 165 | } 166 | input.readFieldEnd(); 167 | } 168 | input.readStructEnd(); 169 | return; 170 | }; 171 | 172 | InvalidOperation.prototype.write = function(output) { 173 | output.writeStructBegin('InvalidOperation'); 174 | if (this.whatOp !== null && this.whatOp !== undefined) { 175 | output.writeFieldBegin('whatOp', Thrift.Type.I32, 1); 176 | output.writeI32(this.whatOp); 177 | output.writeFieldEnd(); 178 | } 179 | if (this.why !== null && this.why !== undefined) { 180 | output.writeFieldBegin('why', Thrift.Type.STRING, 2); 181 | output.writeString(this.why); 182 | output.writeFieldEnd(); 183 | } 184 | output.writeFieldStop(); 185 | output.writeStructEnd(); 186 | return; 187 | }; 188 | 189 | ttypes.INT32CONSTANT = 9853; 190 | ttypes.MAPCONSTANT = { 191 | 'hello' : 'world', 192 | 'goodnight' : 'moon' 193 | }; 194 | -------------------------------------------------------------------------------- /server/services/thrift/tutorial/tutorial.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Apache Thrift 是 Facebook 开源的一种高效的、支持多种编程语言的远程服务调用的框架, 3 | * 采用二进制数据传输,适用于高并发、大数据量和多语言开发环境。 4 | * @see http://thrift.apache.org/ 5 | * 6 | * tutorial.thrift 是我们定义好的目标语言对应的接口数据结构, 7 | * 然后通过thrift命令生成node端相应的引用文件,如下: 8 | * 9 | * 10 | * thrift --gen js:node -o ./server/services/thrift/tutorial -out ./server/services/thrift/tutorial/gen ./server/services/thrift/tutorial/tutorial.thrift 11 | * 12 | * 13 | * Java端参考:http://qifuguang.me/2015/09/11/Thrift%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/ 14 | */ 15 | 16 | var thrift = require('thrift') 17 | var Calculator = require('./gen/Calculator') 18 | var ttypes = require('./gen/tutorial_types') 19 | 20 | var transport = thrift.TBufferedTransport 21 | var protocol = thrift.TBinaryProtocol 22 | 23 | var connection = thrift.createConnection('localhost', 9090, { 24 | transport : transport, 25 | protocol : protocol 26 | }) 27 | 28 | connection.on('error', function(err) { 29 | console.error(err) 30 | }) 31 | 32 | // Create a Calculator client with the connection 33 | var client = thrift.createClient(Calculator, connection) 34 | 35 | var work = new ttypes.Work() 36 | 37 | module.exports = { 38 | ping: function() { 39 | client.ping(function(err, response) { 40 | console.log('ping()') 41 | }) 42 | }, 43 | add: function(arg1, arg2) { 44 | client.add(1,1, function(err, response) { 45 | console.log("1+1=" + response) 46 | }) 47 | }, 48 | subtract: function(num1, num2) { 49 | work.op = ttypes.Operation.SUBTRACT 50 | work.num1 = num1 51 | work.num2 = num2 52 | 53 | client.calculate(1, work, function(err, message) { 54 | console.log(`${num1}-${num2}=${message}`) 55 | 56 | client.getStruct(1, function(err, message){ 57 | console.log('Check log: ' + message.value) 58 | }) 59 | }) 60 | }, 61 | close: function () { //close the connection once we're done 62 | connection.end() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /server/services/thrift/tutorial/tutorial.thrift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | # Thrift Tutorial 21 | # Mark Slee (mcslee@facebook.com) 22 | # 23 | # This file aims to teach you how to use Thrift, in a .thrift file. Neato. The 24 | # first thing to notice is that .thrift files support standard shell comments. 25 | # This lets you make your thrift file executable and include your Thrift build 26 | # step on the top line. And you can place comments like this anywhere you like. 27 | # 28 | # Before running this file, you will need to have installed the thrift compiler 29 | # into /usr/local/bin. 30 | 31 | /** 32 | * The first thing to know about are types. The available types in Thrift are: 33 | * 34 | * bool Boolean, one byte 35 | * i8 (byte) Signed 8-bit integer 36 | * i16 Signed 16-bit integer 37 | * i32 Signed 32-bit integer 38 | * i64 Signed 64-bit integer 39 | * double 64-bit floating point value 40 | * string String 41 | * binary Blob (byte array) 42 | * map Map from one type to another 43 | * list Ordered list of one type 44 | * set Set of unique elements of one type 45 | * 46 | * Did you also notice that Thrift supports C style comments? 47 | */ 48 | 49 | // Just in case you were wondering... yes. We support simple C comments too. 50 | 51 | /** 52 | * Thrift files can reference other Thrift files to include common struct 53 | * and service definitions. These are found using the current path, or by 54 | * searching relative to any paths specified with the -I compiler flag. 55 | * 56 | * Included objects are accessed using the name of the .thrift file as a 57 | * prefix. i.e. shared.SharedObject 58 | */ 59 | include "../shared.thrift" 60 | 61 | /** 62 | * Thrift files can namespace, package, or prefix their output in various 63 | * target languages. 64 | */ 65 | namespace cpp tutorial 66 | namespace d tutorial 67 | namespace dart tutorial 68 | namespace java tutorial 69 | namespace php tutorial 70 | namespace perl tutorial 71 | namespace haxe tutorial 72 | namespace netcore tutorial 73 | 74 | /** 75 | * Thrift lets you do typedefs to get pretty names for your types. Standard 76 | * C style here. 77 | */ 78 | typedef i32 MyInteger 79 | 80 | /** 81 | * Thrift also lets you define constants for use across languages. Complex 82 | * types and structs are specified using JSON notation. 83 | */ 84 | const i32 INT32CONSTANT = 9853 85 | const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} 86 | 87 | /** 88 | * You can define enums, which are just 32 bit integers. Values are optional 89 | * and start at 1 if not supplied, C style again. 90 | */ 91 | enum Operation { 92 | ADD = 1, 93 | SUBTRACT = 2, 94 | MULTIPLY = 3, 95 | DIVIDE = 4 96 | } 97 | 98 | /** 99 | * Structs are the basic complex data structures. They are comprised of fields 100 | * which each have an integer identifier, a type, a symbolic name, and an 101 | * optional default value. 102 | * 103 | * Fields can be declared "optional", which ensures they will not be included 104 | * in the serialized output if they aren't set. Note that this requires some 105 | * manual management in some languages. 106 | */ 107 | struct Work { 108 | 1: i32 num1 = 0, 109 | 2: i32 num2, 110 | 3: Operation op, 111 | 4: optional string comment, 112 | } 113 | 114 | /** 115 | * Structs can also be exceptions, if they are nasty. 116 | */ 117 | exception InvalidOperation { 118 | 1: i32 whatOp, 119 | 2: string why 120 | } 121 | 122 | /** 123 | * Ahh, now onto the cool part, defining a service. Services just need a name 124 | * and can optionally inherit from another service using the extends keyword. 125 | */ 126 | service Calculator extends shared.SharedService { 127 | 128 | /** 129 | * A method definition looks like C code. It has a return type, arguments, 130 | * and optionally a list of exceptions that it may throw. Note that argument 131 | * lists and exception lists are specified using the exact same syntax as 132 | * field lists in struct or exception definitions. 133 | */ 134 | 135 | void ping(), 136 | 137 | i32 add(1:i32 num1, 2:i32 num2), 138 | 139 | i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), 140 | 141 | /** 142 | * This method has a oneway modifier. That means the client only makes 143 | * a request and does not listen for any response at all. Oneway methods 144 | * must be void. 145 | */ 146 | oneway void zip() 147 | 148 | } 149 | 150 | /** 151 | * That just about covers the basics. Take a look in the test/ folder for more 152 | * detailed examples. After you run this file, your generated code shows up 153 | * in folders with names gen-. The generated code isn't too scary 154 | * to look at. It even has pretty indentation. 155 | */ -------------------------------------------------------------------------------- /server/services/users.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户数据服务 3 | */ 4 | -------------------------------------------------------------------------------- /server/utils/aes.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto') 2 | 3 | export function encrypt(data, key) { 4 | const cipher = crypto.createCipher('aes192', key) 5 | var crypted = cipher.update(data, 'utf8', 'hex') 6 | crypted += cipher.final('hex') 7 | return crypted 8 | } 9 | 10 | export function decrypt(encrypted, key) { 11 | const decipher = crypto.createDecipher('aes192', key) 12 | var decrypted = decipher.update(encrypted, 'hex', 'utf8') 13 | decrypted += decipher.final('utf8') 14 | return decrypted 15 | } 16 | -------------------------------------------------------------------------------- /server/utils/easemob/ChatHistory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 聊天历史记录 3 | */ 4 | 5 | var client = require('./client') 6 | 7 | function ChatHistory () { 8 | //Get chat history 9 | this.getChatMessages = function (ql, limit, cursor, callback) { 10 | client.client({ 11 | path: 'chatmessages', 12 | method: 'GET', 13 | query: { 'ql': ql, 'limit': limit, 'cursor': cursor }, 14 | headers: {}, 15 | callback: function (data) { 16 | // console.log(data) 17 | typeof callback == 'function' && callback(data) 18 | } 19 | }) 20 | } 21 | } 22 | 23 | module.exports = ChatHistory 24 | -------------------------------------------------------------------------------- /server/utils/easemob/ChatRoom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 聊天室 3 | */ 4 | 5 | var client = require('./client') 6 | 7 | function ChatRoom () { 8 | 9 | //Create a chat room 10 | this.createChatRoom = function (json, callback) { 11 | var data = { 12 | name: json.name, 13 | description: json.description, 14 | maxusers: json.maxusers, 15 | owner: json.owner, 16 | members: json.members 17 | } 18 | client.client({ 19 | data: data, 20 | path: 'chatrooms', 21 | method: 'POST', 22 | callback: function (data) { 23 | console.log(data) 24 | typeof callback == 'function' && callback(data) 25 | } 26 | }) 27 | } 28 | 29 | //Update chat room details 30 | this.modifyChatRoom = function (json, callback) { 31 | var data = { 32 | name: json.name, 33 | description: json.description, 34 | maxusers: json.maxusers 35 | } 36 | client.client({ 37 | data: data, 38 | path: 'chatrooms/' + json.chatroom_id, 39 | method: 'PUT', 40 | callback: function (data) { 41 | console.log(data) 42 | typeof callback == 'function' && callback(data) 43 | } 44 | }) 45 | } 46 | 47 | //Delete a chat room 48 | this.deleteChatRoom = function (chatroom_id, callback) { 49 | client.client({ 50 | path: 'chatrooms/' + chatroom_id, 51 | method: 'DELETE', 52 | callback: function (data) { 53 | console.log(data) 54 | typeof callback == 'function' && callback(data) 55 | } 56 | }) 57 | } 58 | 59 | //Get all chat rooms 60 | this.getChatRooms = function (callback) { 61 | client.client({ 62 | path: 'chatrooms', 63 | method: 'GET', 64 | callback: function (data) { 65 | console.log(data) 66 | typeof callback == 'function' && callback(data) 67 | } 68 | }) 69 | } 70 | 71 | //Get chat room detail 72 | this.getChatRoomDetail = function (chatroom_id, callback) { 73 | client.client({ 74 | path: 'chatrooms/' + chatroom_id, 75 | method: 'GET', 76 | callback: function (data) { 77 | console.log(data) 78 | typeof callback == 'function' && callback(data) 79 | } 80 | }) 81 | } 82 | 83 | //Get all chat room of user joined 84 | this.getChatRoomJoined = function (username, callback) { 85 | client.client({ 86 | path: 'users/' + username + '/joined_chatrooms', 87 | method: 'GET', 88 | callback: function (data) { 89 | console.log(data) 90 | typeof callback == 'function' && callback(data) 91 | } 92 | }) 93 | } 94 | //Add a member to chat room 95 | this.addChatRoomMember = function (chatroomid, username, callback) { 96 | client.client({ 97 | path: 'chatrooms/' + chatroomid + '/users/' + username, 98 | method: 'POST', 99 | callback: function (data) { 100 | console.log(data) 101 | typeof callback == 'function' && callback(data) 102 | } 103 | }) 104 | } 105 | //Add multiple members to chat room 106 | this.addChatRoomMembers = function (chatroomid, json, callback) { 107 | var data = {usernames: json} 108 | client.client({ 109 | path: 'chatrooms/' + chatroomid + '/users/', 110 | method: 'POST', 111 | data: data, 112 | callback: function (data) { 113 | console.log(data) 114 | typeof callback == 'function' && callback(data) 115 | } 116 | }) 117 | } 118 | 119 | //Remove a member from chat room 120 | this.deleteChatRoomMember = function (chatroomid, username, callback) { 121 | client.client({ 122 | path: 'chatrooms/' + chatroomid + '/users/' + username, 123 | method: 'DELETE', 124 | callback: function (data) { 125 | console.log(data) 126 | typeof callback == 'function' && callback(data) 127 | } 128 | }) 129 | } 130 | 131 | //Remove multiple member from chat room 132 | this.deleteChatRoomMembers = function (chatroomid, usernames, callback) { 133 | client.client({ 134 | path: 'chatrooms/' + chatroomid + '/users/' + usernames, 135 | method: 'DELETE', 136 | callback: function (data) { 137 | console.log(data) 138 | typeof callback == 'function' && callback(data) 139 | } 140 | }) 141 | } 142 | } 143 | 144 | module.exports = ChatRoom 145 | -------------------------------------------------------------------------------- /server/utils/easemob/Files.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 文件操作 3 | */ 4 | 5 | var fs = require('fs') 6 | var FormData = require('form-data') 7 | var client = require('./client') 8 | 9 | function Files() { 10 | 11 | //Upload file 12 | //Warning: File cannot be over 10MB, otherwise will fail. 13 | this.uploadFile = function (json, callback) { 14 | var form = new FormData() 15 | form.append('file', fs.createReadStream(json.filePath)) 16 | client.client({ 17 | path: 'chatfiles', 18 | method: 'POST', 19 | form: form, 20 | headers: {'restrict-access': json.restrictAccess}, 21 | callback: function (data) { 22 | console.log(data) 23 | if (typeof callback == 'function') 24 | callback(data) 25 | } 26 | }, client.uploadFileWithToken) 27 | } 28 | 29 | //Download file 30 | this.downloadFile = function downloadFile(json, callback) { 31 | json = json || {} 32 | client.client({ 33 | path: 'chatfiles/' + json.uuid, 34 | method: 'GET', 35 | headers: { 'accept': ' application/octet-stream', 'share-secret': json.shareSecret }, 36 | callback: function (data) { 37 | console.log(data) 38 | if (typeof callback == 'function') 39 | callback(data) 40 | } 41 | }) 42 | } 43 | 44 | //Download thumbnail 45 | this.downloadThumbnail = function downloadThumbnail(json) { 46 | json = json || {} 47 | client.client({ 48 | path: 'chatfiles/' + json.uuid, 49 | method: 'GET', 50 | headers: { 51 | 'accept': ' application/octet-stream', 52 | 'share-secret': json.shareSecret, 53 | 'thumbnail': json.thumbnail 54 | }, 55 | callback: function (data) { 56 | // console.log(data) 57 | typeof json.callback == 'function' && json.callback(data) 58 | } 59 | }) 60 | } 61 | } 62 | 63 | module.exports = Files 64 | -------------------------------------------------------------------------------- /server/utils/easemob/Group.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 群组 3 | */ 4 | 5 | var client = require('./client') 6 | 7 | function Group() { 8 | 9 | //Get all groups 10 | this.getGroups = function getGroups(callback) { 11 | client.client({ 12 | path: 'chatgroups', 13 | method: 'GET', 14 | callback: function (data) { 15 | // console.log(data) 16 | typeof callback == 'function' && callback(data) 17 | } 18 | }) 19 | } 20 | 21 | //Get group(s) detial 22 | this.getGroupDetail = function (group_ids, callback) { 23 | client.client({ 24 | path: 'chatgroups/' + group_ids, 25 | method: 'GET', 26 | callback: function (data) { 27 | // console.log(data) 28 | typeof callback == 'function' && callback(data) 29 | } 30 | }) 31 | } 32 | 33 | //Create a group 34 | this.createGroup = function (json, callback) { 35 | var json = json || {} 36 | var data = { 37 | groupname: json.groupname, 38 | desc: json.desc, 39 | public: json.public, 40 | maxusers: json.maxusers, 41 | approval: json.approval, 42 | owner: json.owner, 43 | members: json.members 44 | } 45 | client.client({ 46 | data: data, 47 | path: 'chatgroups', 48 | method: 'POST', 49 | callback: function (data) { 50 | // console.log(data) 51 | typeof callback == 'function' && callback(data) 52 | } 53 | }) 54 | } 55 | 56 | //Modify group information 57 | this.modifyGroupInfo = function (json) { 58 | var json = json || {} 59 | var data = { 60 | groupname: json.groupname, 61 | description: json.description, 62 | maxusers: json.maxusers 63 | } 64 | client.client({ 65 | data: data, 66 | path: 'chatgroups/' + json.group_id, 67 | method: 'PUT', 68 | callback: function (data) { 69 | // console.log(data) 70 | typeof json.callback == 'function' && json.callback(data) 71 | } 72 | }) 73 | } 74 | 75 | //Delete a group 76 | this.deleteGroup = function (group_id, callback) { 77 | client.client({ 78 | path: 'chatgroups/' + group_id, 79 | method: 'DELETE', 80 | callback: function (data) { 81 | // console.log(data) 82 | typeof callback == 'function' && callback(data) 83 | } 84 | }) 85 | } 86 | 87 | //Get members of Group 88 | this.getGroupUsers = function (group_id, callback) { 89 | client.client({ 90 | path: 'chatgroups/' + group_id + '/users', 91 | method: 'GET', 92 | callback: function (data) { 93 | // console.log(data) 94 | typeof callback == 'function' && callback(data) 95 | } 96 | }) 97 | } 98 | 99 | //Add a user to group 100 | this.addGroupMember = function (groupid, username, callback) { 101 | client.client({ 102 | path: 'chatgroups/' + groupid + '/users/' + username, 103 | method: 'POST', 104 | callback: function (data) { 105 | // console.log(data) 106 | typeof callback == 'function' && callback(data) 107 | } 108 | }) 109 | } 110 | 111 | //Add multiple users to group 112 | this.addGroupMembers = function (groupid, users, callback) { 113 | var data = {usernames: users} 114 | client.client({ 115 | data: data, 116 | path: 'chatgroups/' + groupid + '/users', 117 | method: 'POST', 118 | callback: function (data) { 119 | // console.log(data) 120 | typeof callback == 'function' && callback(data) 121 | } 122 | }) 123 | } 124 | 125 | //Remove a member from group 126 | this.deleteGroupMember = function (groupid, username, callback) { 127 | client.client({ 128 | path: '/chatgroups/' + groupid + '/users/' + username, 129 | method: 'DELETE', 130 | callback: function (data) { 131 | // console.log(data) 132 | typeof callback == 'function' && callback(data) 133 | } 134 | }) 135 | } 136 | 137 | //Remove multiple members from group 138 | this.deleteGroupMembers = function (groupid, users, callback) { 139 | client.client({ 140 | path: 'chatgroups/' + groupid + '/users/' + users, 141 | method: 'DELETE', 142 | callback: function (data) { 143 | // console.log(data) 144 | typeof callback == 'function' && callback(data) 145 | } 146 | }) 147 | } 148 | 149 | //Get a list of groups of user joined 150 | this.getGroupsForUser = function (username, callback) { 151 | client.client({ 152 | path: 'users/' + username + '/joined_chatgroups', 153 | method: 'GET', 154 | callback: function (data) { 155 | // console.log(data) 156 | typeof callback == 'function' && callback(data) 157 | } 158 | }) 159 | } 160 | 161 | //Update group owner 162 | this.changeGroupOwner = function (json) { 163 | var json = json || {} 164 | var data = { 165 | newowner: json.newowner, 166 | } 167 | client.client({ 168 | data: data, 169 | path: 'chatgroups/' + json.group_id, 170 | method: 'PUT', 171 | callback: function (data) { 172 | // console.log(data) 173 | typeof json.callback == 'function' && json.callback(data) 174 | } 175 | }) 176 | } 177 | 178 | //Get group blocked user 179 | this.getGroupBlackList = function (groupid, callback) { 180 | client.client({ 181 | path: 'chatgroups/' + groupid + '/blocks/users', 182 | method: 'GET', 183 | callback: function (data) { 184 | // console.log(data) 185 | typeof callback == 'function' && callback(data) 186 | } 187 | }) 188 | } 189 | 190 | //Add user to blacklist of group 191 | this.addGroupBlackMember = function (groupid, username, callback) { 192 | client.client({ 193 | path: 'chatgroups/' + groupid + '/blocks/users/' + username, 194 | method: 'POST', 195 | callback: function (data) { 196 | // console.log(data) 197 | typeof callback == 'function' && callback(data) 198 | } 199 | }) 200 | } 201 | 202 | //Remove user from blacklist of group 203 | this.deleteGroupBlackMember = function (groupid, username, callback) { 204 | client.client({ 205 | path: 'chatgroups/' + groupid + '/blocks/users/' + username, 206 | method: 'DELETE', 207 | callback: function (data) { 208 | // console.log(data) 209 | typeof callback == 'function' && callback(data) 210 | } 211 | }) 212 | } 213 | } 214 | 215 | module.exports = Group 216 | -------------------------------------------------------------------------------- /server/utils/easemob/SendMessage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 发送消息 3 | */ 4 | 5 | var client = require('./client') 6 | 7 | function SendMessage () { 8 | //Send text message 9 | this.sendText = function (json) { 10 | var json = json || {} 11 | var data = { 12 | target_type: json.type, 13 | target: json.target, 14 | msg: { type: 'txt', msg: json.content }, 15 | from: json.from 16 | } 17 | json.ext && (data.ext = json.ext) 18 | client.client({ 19 | data: data, 20 | path: 'messages', 21 | method: 'POST', 22 | callback: function (data) { 23 | // console.log(data) 24 | typeof json.callback == 'function' && json.callback(data) 25 | } 26 | }) 27 | } 28 | 29 | //Send image message 30 | this.sendImage = function (json) { 31 | var json = json || {} 32 | var data = { 33 | target_type: json.type, 34 | target: json.target, 35 | msg: { 36 | type: 'img', 37 | url: json.url, 38 | filename: json.filename, 39 | secret: json.secret, 40 | size: {width: 480, height: 720} 41 | }, 42 | from: json.from, 43 | } 44 | json.ext && (data.ext = json.ext) 45 | client.client({ 46 | data: data, 47 | path: 'messages', 48 | method: 'POST', 49 | callback: function (data) { 50 | // console.log(data) 51 | typeof json.callback == 'function' && json.callback(data) 52 | } 53 | }) 54 | } 55 | 56 | //Send audio message 57 | this.sendAudio = function (json) { 58 | var json = json || {} 59 | var data = { 60 | target_type: json.type, 61 | target: json.target, 62 | msg: { type: 'audio', url: json.url, filename: json.filename, length: json.length, secret: json.secret }, 63 | from: json.from, 64 | } 65 | json.ext && (data.ext = json.ext) 66 | client.client({ 67 | data: data, 68 | path: 'messages', 69 | method: 'POST', 70 | callback: function (data) { 71 | // console.log(data) 72 | typeof json.callback == 'function' && json.callback(data) 73 | } 74 | }) 75 | } 76 | 77 | //Send video message 78 | this.sendVideo = function (json) { 79 | var json = json || {} 80 | var data = { 81 | target_type: json.type, 82 | target: json.target, 83 | msg: { 84 | type: 'video', 85 | url: json.url, 86 | filename: json.filename, 87 | thumb: json.thumb, 88 | length: json.length, 89 | file_length: json.file_length, 90 | thumb_secret: json.thumb_secret, 91 | secret: json.secret 92 | }, 93 | from: json.from, 94 | } 95 | json.ext && (data.ext = json.ext) 96 | client.client({ 97 | data: data, 98 | path: 'messages', 99 | method: 'POST', 100 | callback: function (data) { 101 | // console.log(data) 102 | typeof json.callback == 'function' && json.callback(data) 103 | } 104 | }) 105 | } 106 | 107 | //Send commend message 108 | this.sendCmd = function (json) { 109 | var json = json || {} 110 | var data = { 111 | target_type: json.type, 112 | target: json.target, 113 | msg: { type: 'cmd', action: json.action }, 114 | from: json.from, 115 | } 116 | json.ext && (data.ext = json.ext) 117 | client.client({ 118 | data: data, 119 | path: 'messages', 120 | method: 'POST', 121 | callback: function (data) { 122 | // console.log(data) 123 | typeof json.callback == 'function' && json.callback(data) 124 | } 125 | }) 126 | } 127 | } 128 | 129 | module.exports = SendMessage 130 | -------------------------------------------------------------------------------- /server/utils/easemob/Token.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 请求Tocken 3 | */ 4 | 5 | var config = require('../../../config/easemob') 6 | var request = require('./request') 7 | 8 | function Token () { 9 | var client_id = config.client_id 10 | var client_secret = config.client_secret 11 | var token = '' 12 | var expiredAt 13 | 14 | this.getToken = function () { 15 | return token 16 | } 17 | 18 | this.accessToken = function(callback) { 19 | var data = { grant_type: 'client_credentials', client_id: client_id, client_secret: client_secret } 20 | request.httpRequest({ 21 | data: data, 22 | path: 'token', 23 | method: 'POST', 24 | header: { 'Content-Type': 'application/json' }, 25 | callback: function (data) { 26 | var d = JSON.parse(data) 27 | token = d.access_token 28 | expiredAt = d.expires_in * 1000 + new Date().getMilliseconds() 29 | // console.log('token is: ' + token) 30 | if (typeof callback == 'function') 31 | callback(token) 32 | } 33 | }) 34 | } 35 | 36 | //Check token is expired 37 | this.isExpire = function(){ 38 | return new Date().getMilliseconds() > expiredAt 39 | } 40 | } 41 | 42 | module.exports = Token 43 | -------------------------------------------------------------------------------- /server/utils/easemob/User.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户操作 3 | */ 4 | 5 | var client = require('./client') 6 | 7 | function User () { 8 | 9 | //Create a user 10 | this.createUser = function (username, password, callback) { 11 | var data = { username: username, password: password } 12 | client.client({ 13 | data: data, 14 | path: 'users', 15 | method: 'POST', 16 | headers: {}, 17 | callback: function (data) { 18 | // console.log(data) 19 | if (typeof callback == 'function') 20 | callback(data) 21 | } 22 | }) 23 | } 24 | 25 | //Create multiple users 26 | this.createUsers = function (users, callback) { 27 | client.client({ 28 | data: users, 29 | path: 'users', 30 | method: 'POST', 31 | headers:{}, 32 | callback: function (data) { 33 | // console.log(data) 34 | typeof callback == 'function' && callback(data) 35 | } 36 | }) 37 | } 38 | 39 | //Get a user 40 | this.getUser = function (username, callback) { 41 | client.client({ 42 | path: 'users/' + username, 43 | method: 'GET', 44 | headers: {}, 45 | callback: function (data) { 46 | // console.log(data) 47 | if (typeof callback == 'function') 48 | callback(data) 49 | } 50 | }) 51 | } 52 | 53 | //Get users in batch 54 | this.getUsers = function (limit, cursor, callback) { 55 | client.client({ 56 | path: 'users', 57 | method: 'GET', 58 | headers: {}, 59 | query: { 'limit': limit, 'cursor':cursor }, 60 | callback: function (data) { 61 | // console.log(data) 62 | if (typeof callback == 'function') 63 | callback(data) 64 | } 65 | }) 66 | } 67 | 68 | //Delete a user 69 | this.deleteUser = function (username, callback) { 70 | client.client({ 71 | path: 'users/' + username, 72 | method: 'DELETE', 73 | headers: {}, 74 | callback: function (data) { 75 | // console.log(data) 76 | if (typeof callback == 'function') 77 | callback(data) 78 | } 79 | }) 80 | } 81 | 82 | //Delete users in batch 83 | this.deleteUsers = function (limit, cursor, callback) { 84 | client.client({ 85 | path: 'users', 86 | method: 'DELETE', 87 | headers: {}, 88 | query: { 'limit': limit, 'cursor': cursor }, 89 | callback: function (data) { 90 | // console.log(data) 91 | if (typeof callback == 'function') 92 | callback(data) 93 | } 94 | }) 95 | } 96 | 97 | //Reset user's password 98 | this.resetPassword = function (username, oldpwd, newpwd, callback) { 99 | var data = { oldpassword: oldpwd, newpassword: newpwd } 100 | client.client({ 101 | data: data, 102 | path: 'users/' + username + '/password', 103 | method: 'PUT', 104 | headers: {}, 105 | callback: function (data) { 106 | // console.log(data) 107 | if (typeof callback == 'function') 108 | callback(data) 109 | } 110 | }) 111 | } 112 | 113 | //Update user's nickname 114 | this.editNickname = function (username, nickname, callback) { 115 | var data = { nickname: nickname } 116 | client.client({ 117 | data: data, 118 | path: 'users/' + username, 119 | method: 'PUT', 120 | headers: {}, 121 | callback: function (data) { 122 | // console.log(data) 123 | if (typeof callback == 'function') 124 | callback(data) 125 | } 126 | }) 127 | } 128 | 129 | //Add a friend for user 130 | this.addFriend = function (username, friendname, callback) { 131 | client.client({ 132 | path: 'users/' + username + '/contacts/users/' + friendname, 133 | method: 'POST', 134 | headers: {}, 135 | callback: function (data) { 136 | // console.log(data) 137 | if (typeof callback == 'function') 138 | callback(data) 139 | } 140 | }) 141 | } 142 | 143 | //Delete a friend for user 144 | this.deleteFriend = function (username, friendname, callback) { 145 | client.client({ 146 | path: 'users/' + username + '/contacts/users/' + friendname, 147 | method: 'DELETE', 148 | callback: function (data) { 149 | // console.log(data) 150 | typeof callback == 'function' && callback(data) 151 | } 152 | }) 153 | } 154 | 155 | //Get user's friends list 156 | this.showFriends = function (username, callback) { 157 | client.client({ 158 | path: 'users/' + username + '/contacts/users', 159 | method: 'GET', 160 | callback: function (data) { 161 | // console.log(data) 162 | typeof callback == 'function' && callback(data) 163 | } 164 | }) 165 | } 166 | 167 | //Get user's blacklist 168 | this.getBlacklist = function (username, callback) { 169 | client.client({ 170 | path: 'users/' + username + '/blocks/users', 171 | method: 'GET', 172 | callback: function (data) { 173 | // console.log(data) 174 | typeof callback == 'function' && callback(data) 175 | } 176 | }) 177 | } 178 | 179 | //Block user(s) 180 | this.addUserForBlacklist = function (username, users, callback) { 181 | var data = { usernames: users } 182 | client.client({ 183 | data: data, 184 | path: 'users/' + username + '/blocks/users', 185 | method: 'POST', 186 | callback: function (data) { 187 | // console.log(data) 188 | typeof callback == 'function' && callback(data) 189 | } 190 | }) 191 | } 192 | 193 | //UnBlock user(s) 194 | this.deleteUserFromBlacklist = function (username, blackuser, callback) { 195 | client.client({ 196 | path: 'users/' + username + '/blocks/users/' + blackuser, 197 | method: 'DELETE', 198 | callback: function (data) { 199 | // console.log(data) 200 | typeof callback == 'function' && callback(data) 201 | } 202 | }) 203 | } 204 | 205 | //Get user online status 206 | this.isOnline = function (username, callback) { 207 | client.client({ 208 | path: 'users/' + username + '/status', 209 | method: 'GET', 210 | callback: function (data) { 211 | // console.log(data) 212 | typeof callback == 'function' && callback(data) 213 | } 214 | }) 215 | } 216 | 217 | //Get offline message count 218 | this.getOfflineMessages = function (username, callback) { 219 | client.client({ 220 | path: 'users/' + username + '/offline_msg_count', 221 | method: 'GET', 222 | callback: function (data) { 223 | // console.log(data) 224 | typeof callback == 'function' && callback(data) 225 | } 226 | }) 227 | } 228 | 229 | //Get offline message status 230 | this.getOfflineMessageStatus = function (username, msgid, callback) { 231 | client.client({ 232 | path: 'users/' + username + '/offline_msg_status/' + msgid, 233 | method: 'GET', 234 | callback: function (data) { 235 | // console.log(data) 236 | typeof callback == 'function' && callback(data) 237 | } 238 | }) 239 | } 240 | 241 | //Deactivate user account 242 | this.deactivateUser = function (username, callback) { 243 | client.client({ 244 | path: 'users/' + username + '/deactivate', 245 | method: 'POST', 246 | callback: function (data) { 247 | // console.log(data) 248 | typeof callback == 'function' && callback(data) 249 | } 250 | }) 251 | } 252 | 253 | //Activation user account 254 | this.activateUser = function (username, callback) { 255 | client.client({ 256 | path: 'users/' + username + '/activate', 257 | method: 'POST', 258 | callback: function (data) { 259 | // console.log(data) 260 | typeof callback == 'function' && callback(data) 261 | } 262 | }) 263 | } 264 | 265 | //Logout user 266 | this.disconnectUser = function (username, callback) { 267 | client.client({ 268 | path: 'users/' + username + '/disconnect', 269 | method: 'GET', 270 | callback: function (data) { 271 | // console.log(data) 272 | typeof callback == 'function' && callback(data) 273 | } 274 | }) 275 | } 276 | } 277 | 278 | module.exports = User 279 | -------------------------------------------------------------------------------- /server/utils/easemob/client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 聊天室 3 | */ 4 | 5 | var Token = require('./Token') 6 | var request = require('./request') 7 | 8 | var Initialized = false 9 | var token = new Token() 10 | 11 | function client (json, callback) { 12 | if (!Initialized || token.isExpire()) { 13 | token.accessToken(function () { 14 | Initialized = true 15 | if (typeof callback == 'function') { 16 | callback(json) 17 | }else { 18 | httpRequestWithToken(json) 19 | } 20 | }) 21 | 22 | } else { 23 | if (typeof callback == 'function') { 24 | callback(json) 25 | }else { 26 | httpRequestWithToken(json) 27 | } 28 | } 29 | 30 | } 31 | 32 | function httpRequestWithToken (json) { 33 | if (token == null) { 34 | console.log('err: failed to access token!') 35 | } else { 36 | json.headers = json.headers || {} 37 | json.headers['Content-Type'] = 'application/json' 38 | json.headers['Authorization'] = 'Bearer ' + token.getToken() 39 | request.httpRequest(json) 40 | } 41 | } 42 | 43 | function uploadFileWithToken (json) { 44 | if (token == null) { 45 | console.log('err: failed to access token!') 46 | } else { 47 | json.headers = json.headers || {} 48 | json.headers['http'] = 'multipart/form-data' 49 | json.headers['Authorization'] = 'Bearer ' + token.getToken() 50 | request.uploadFile(json) 51 | } 52 | } 53 | 54 | module.exports = { 55 | client: client, 56 | httpRequestWithToken: httpRequestWithToken, 57 | uploadFileWithToken: uploadFileWithToken 58 | } 59 | -------------------------------------------------------------------------------- /server/utils/easemob/request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https请求 3 | */ 4 | 5 | var https = require('https') 6 | var config = require('../../../config/easemob') 7 | var fs = require('fs') 8 | var fetch = require('node-fetch') 9 | 10 | var host = config.host 11 | var org_name = config.org_name 12 | var app_name = config.app_name 13 | 14 | exports.httpRequest = function (json) { 15 | json = json || {} 16 | json.data = json.data || {} 17 | json.method = json.method || 'GET' 18 | json.headers = json.headers || {} 19 | json.query = json.query || {} 20 | 21 | var postData = JSON.stringify(json.data) 22 | var ca = fs.readFileSync(config.ca, 'utf-8') 23 | //request parameters 24 | var options = { 25 | host: host, 26 | path: '/' + org_name + '/' + app_name + '/' + json.path, 27 | method: json.method, 28 | headers: json.headers, 29 | ca: [ca], 30 | agent: false 31 | } 32 | //connect with query parameters 33 | if (json.query != null) { 34 | options.path += '?' 35 | for (var key in json.query) { 36 | if (json.query[key] != null) { 37 | options.path += key + '=' + json.query[key] + '&' 38 | } 39 | } 40 | options.path = options.path.substring(0, options.path.length - 1) 41 | } 42 | //send request 43 | var req = https.request(options, function (res) { 44 | var chunks = '' 45 | var size = 0 46 | res.setEncoding('utf8') 47 | // console.log('------------------------------request--------------------------------') 48 | // console.log('host: ' + options.host + '\n' + 'path: ' + options.path + '\n' + 'method: ' + options.method) 49 | 50 | res.on('data', function (chunk) { 51 | chunks += chunk 52 | size += chunk.length 53 | }) 54 | res.on('end', function () { 55 | //get response data 56 | //var data = JSON.parse(Buffer.concat(chunks, size).toString()) 57 | // console.log('------------------------------response--------------------------------') 58 | // console.log('StatusCode: ' + res.statusCode) 59 | if (typeof json.callback == 'function') 60 | json.callback(chunks) 61 | }) 62 | }) 63 | 64 | //print error message 65 | req.on('error', function (e) { 66 | console.log('problem with request: ' + e.message) 67 | }) 68 | 69 | // write data to request body 70 | req.write(postData) 71 | req.end() 72 | } 73 | 74 | exports.uploadFile = function (json) { 75 | json = json || {} 76 | json.data = json.data || {} 77 | json.method = json.method || 'POST' 78 | json.headers = json.headers || {} 79 | json.query = json.query || {} 80 | json.form = json.form || {} 81 | var ca = fs.readFileSync(config.ca, 'utf-8') 82 | // console.log('------------------------------request--------------------------------') 83 | // console.log('host: ' + host + '\n' + 'path: ' + json.path + '\n' + 'method: ' + json.method) 84 | fetch('https://' + host + '/' + org_name + '/' + app_name + '/' + json.path, { 85 | method: json.method, 86 | body: json.form, 87 | headers: json.headers, 88 | ca: [ca] 89 | }).then(function (res) { 90 | // console.log('------------------------------response--------------------------------') 91 | // console.log('StatusCode: ' + res.status) 92 | return res.json() 93 | }).then(function (json) { 94 | console.log(json) 95 | }).catch(function (err) { 96 | console.log(err) 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /server/utils/hbs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * handlebars 配置及扩展函数 3 | */ 4 | 5 | var hbs = require('hbs') 6 | var path = require('path') 7 | 8 | var blocks = {} 9 | 10 | // 模版继承 11 | hbs.registerHelper('extend', function(name, context) { 12 | var block = blocks[name] 13 | if (!block) { 14 | block = blocks[name] = [] 15 | } 16 | 17 | block.push(context.fn(this)) // for older versions of handlebars, use block.push(context(this)); 18 | }) 19 | 20 | hbs.registerHelper('block', function(name) { 21 | var val = (blocks[name] || []).join('\n') 22 | 23 | blocks[name] = [] // clear the block 24 | return val 25 | }) 26 | 27 | // 注册子模版 28 | hbs.registerPartials(path.join(__dirname, '..', 'views', 'partials')) 29 | -------------------------------------------------------------------------------- /server/utils/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HTTP数据通信模块 3 | */ 4 | 5 | var request = require('request-promise') 6 | var querystring = require('querystring') 7 | 8 | // 缺省请求头 9 | var defaultHeaders = { 10 | 'Accept': 'application/json', 11 | 'Content-Type': 'application/json' // application/x-www-form-urlencoded 12 | } 13 | 14 | // 请求参数加工 15 | function mutate (uri, options) { 16 | options = options || {} 17 | options.headers = options.headers || {} 18 | options.uri = uri 19 | 20 | Object.assign(options.headers, defaultHeaders) 21 | 22 | if (options.body) { 23 | if (typeof options.body === 'object') { 24 | options.body = JSON.stringify(options.body) 25 | } 26 | } 27 | 28 | if (options.qs) { 29 | if (typeof options.qs === 'object') { 30 | options.qs = querystring.stringify(options.qs) 31 | } 32 | uri += (uri.indexOf('?') !== -1) ? '&' : '?' 33 | options.uri = uri + options.qs 34 | options.qs = null 35 | } 36 | 37 | options.json = true 38 | 39 | console.log(`Request ${options.uri}` + (options.body ? ' : ' + options.body : '')) 40 | 41 | return options 42 | } 43 | 44 | /** 45 | * 接口调用服务 46 | * @param {String} uri 接口API(必填) 47 | * @param {Object} options 请求参数(选填){headers, body, query, ...options} 48 | * @return {Object} Promise 49 | * @throws {Error} 50 | */ 51 | var callService = function (uri, options = {}) { 52 | return request(mutate(uri, options)).then(response => { 53 | console.log(`Response ${uri} :`, response) 54 | return response 55 | }) 56 | } 57 | 58 | exports.callService = callService 59 | 60 | exports.get = function (url, args, options = {}) { 61 | options.method = 'GET' 62 | options.qs = args 63 | return callService(url, options) 64 | } 65 | 66 | exports.post = function (url, args, options = {}) { 67 | options.method = 'POST' 68 | options.body = args 69 | return callService(url, options) 70 | } 71 | 72 | exports.put = function (url, args, options = {}) { 73 | options.method = 'PUT' 74 | options.body = args 75 | return callService(url, options) 76 | } 77 | 78 | exports.patch = function (url, args, options = {}) { 79 | options.method = 'PATCH' 80 | options.body = args 81 | return callService(url, options) 82 | } 83 | 84 | exports.del = function (url, args, options = {}) { 85 | options.method = 'DELETE' 86 | options.qs = args 87 | return callService(url, options) 88 | } 89 | -------------------------------------------------------------------------------- /server/utils/md5.js: -------------------------------------------------------------------------------- 1 | /** 2 | * md5加密(with secret-key) 3 | */ 4 | 5 | var md5 = require('blueimp-md5') 6 | 7 | var secretKey = require('../../config/secret').md5_secret_key 8 | 9 | module.exports = function (value) { 10 | return md5(value, secretKey) 11 | } 12 | -------------------------------------------------------------------------------- /server/utils/mongodb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MongoDB 3 | */ 4 | 5 | var mongoose = require('mongoose') 6 | var config = require('../../config/mongodb') 7 | 8 | var uri = 'mongodb://' + config.host + ':' + config.port + '/' + config.database 9 | 10 | mongoose.connect(uri, config.options, function (err, res) { 11 | if (err) { 12 | console.log('[mongoose] Error connecting to: ' + connectionString + '. ' + err) 13 | return process.exit(1) 14 | } else { 15 | return console.log('[mongoose] Successfully connected to: ' + connectionString) 16 | } 17 | }) 18 | 19 | mongoose.connection.on('error', console.error.bind(console, 'mongoose connection error:')) 20 | mongoose.connection.once('open', function() { 21 | return console.log('mongoose open success') 22 | }) 23 | 24 | module.exports = mongoose 25 | -------------------------------------------------------------------------------- /server/utils/orm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 对象关系映射(ORM) 3 | * 基于Promise,支持 Postgres, MySQL, SQLite and Microsoft SQL Server 4 | */ 5 | 6 | var Sequelize = require('sequelize') 7 | 8 | var env = process.env.NODE_ENV ? process.env.NODE_ENV : 'development' 9 | var config = require('../../config/orm')[env] 10 | 11 | // Setting up a connection 12 | var sequelize = new Sequelize( 13 | config.database, 14 | config.username, 15 | config.password, 16 | config.options 17 | ) 18 | 19 | // Test the connection 20 | sequelize.authenticate().then(function(err) { 21 | console.log('Database connection has been established successfully.'); 22 | }).catch(function (err) { 23 | console.log('Unable to connect to the database:', err); 24 | }) 25 | 26 | module.exports = sequelize 27 | -------------------------------------------------------------------------------- /server/utils/rabbitmq.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RabbitMQ 消息队列,简单实现了消息订阅、发布和RPC调用 3 | * @see https://github.com/dial-once/node-bunnymq 4 | * 也可参考 https://github.com/tjmehta/amqplib-rpc 实现方式 5 | */ 6 | 7 | var bunnymq = require('bunnymq') 8 | var config = require('../../config/rabbitmq') 9 | 10 | var conn = bunnymq(config) 11 | var producer = conn.producer 12 | var consumer = conn.consumer 13 | 14 | /** 15 | * Producer (publisher), can send messages to a named queue. 16 | */ 17 | exports.publish = function (queueName, content) { 18 | producer.produce(queueName, content) 19 | } 20 | 21 | /** 22 | * Consumer (subscriber), can handle messages from a named queue. 23 | */ 24 | exports.subscribe = function (queueName, callback) { 25 | consumer.consume(queueName, callback) 26 | } 27 | 28 | /** 29 | * RPC invoking 30 | * @param {String} queueName 队列名 31 | * @param {Object} content 传递的参数 32 | * @param {Function} callback 回调函数,参数为返回值 33 | */ 34 | exports.rpcCall = function (queueName, content, callback) { 35 | producer.produce(queueName, content, { rpc: true }).then(callback) 36 | } 37 | 38 | /** 39 | * RPC provider 40 | * @param {String} queueName 队列名 41 | * @param {Function} handler 处理函数,其返回值可以是普通数据类型或Promise对象 42 | */ 43 | exports.rpcReceive = function (queueName, handler) { 44 | consumer.consume(queueName, handler) 45 | } 46 | -------------------------------------------------------------------------------- /server/utils/redis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Redis 缓存 3 | */ 4 | 5 | var redis = require('redis') 6 | var redisOptions = require('../../config/redis') 7 | 8 | var redisClient = redis.createClient(redisOptions) 9 | 10 | redisClient.on('error', function (err) { 11 | console.log('Error ' + err) 12 | }) 13 | 14 | redisClient.on('connect', function () { 15 | console.log('Redis is ready') 16 | }) 17 | 18 | exports.redis = redis 19 | exports.redisClient = redisClient 20 | -------------------------------------------------------------------------------- /server/utils/sql.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 生成SQL语句 3 | */ 4 | 5 | const util = require('./util') 6 | 7 | /** 8 | * 根据参数生成SQL插入语句 9 | * 10 | * @param table 表名(字符串) 11 | * @param record 要插入的记录行(对象)【字段名=>值...】 12 | * @param updatefields 要更新的字段(数组),更新方式是直接给字段赋值,【字段名1,字段名2...】 13 | * @param changefields 要更新的字段(对象),更新方式是在原字段值基础上追加,【字段名=>追加值...】 14 | * @return 返回sql插入语句(字符串) 15 | */ 16 | exports.insert = function (table, record, updatefields = [], changefield = {}) { 17 | let sql = `INSERT INTO ${table} (` 18 | sql += Object.keys(record).join(', ') 19 | sql += ") VALUES(" 20 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ') 21 | sql += ")" 22 | 23 | //在插入记录的时候先判断记录是否存在(唯一索引或主键),如果不存在则插入,否则更新 24 | if (!util.isEmpty(updatefields) || !util.isEmpty(changefield)) { 25 | sql += " ON DUPLICATE KEY UPDATE " 26 | 27 | sql += updatefields.map(v => `${v}='${util.escapeSql(record[v])}'`).join(', ') 28 | // or 29 | let flag = 0 30 | if (!util.isEmpty(updatefields)) { 31 | flag = 1 32 | } 33 | 34 | for (let k in changefield) { 35 | let v = changefield[k] 36 | if (util.isNumber(v)) { 37 | sql += `${flag == 0 ? "" : ", "}${k}=${k}${v >= 0 ? "+" : ""}${v}` 38 | } else { 39 | sql += `${flag == 0 ? "" : ", "}${k}=CONCAT(${k},'${util.escapeSql(v)}')` 40 | } 41 | flag = 1 42 | } 43 | } 44 | 45 | return sql 46 | } 47 | 48 | /** 49 | * 向同一个表批量插入大量数据的时候,用这个函数效率高 50 | * 51 | * @param table 表名(字符串) 52 | * @param records 要插入的多行记录(对象数组)【【字段名=>值...】...】 53 | * @return 返回sql多行插入语句(字符串) 54 | * @see #insert() 55 | */ 56 | exports.insertMore = function (table, records) { 57 | let sql = `INSERT INTO ${table} (` 58 | sql += Object.keys(records[0]).join(', ') 59 | sql += ") VALUES" 60 | 61 | for (let record of records) { 62 | sql += "(" 63 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ') 64 | sql += ")," 65 | } 66 | 67 | sql = util.trim(sql, ",") 68 | 69 | return sql 70 | } 71 | 72 | /** 73 | * 根据参数生成SQL更新语句 74 | * 75 | * @param table 表名(字符串) 76 | * @param updatefields 要更新的字段(对象),更新方式是直接给字段赋值,【字段名=>值...】 77 | * @param where 删除条件(对象),只判断相等条件,其他条件请用exwhere参数 【键=>值...】 78 | * @param changefields 要更新的字段(对象),更新方式是在原字段值基础上追加,【字段名=>追加值...】 79 | * @param exwhere 扩展条件(字符串),不含"where"关键字 80 | * @return 返回sql更新语句(字符串) 81 | */ 82 | exports.update = function (table, updatefield, where, changefield = {}, exwhere = '') { 83 | let sql = `UPDATE ${table} SET ` 84 | let flag = 0 85 | for (let k in updatefield) { 86 | let v = updatefield[k] 87 | sql += `${flag == 0 ? "" : ", "}${k}='${util.escapeSql(v)}'` 88 | flag = 1 89 | } 90 | 91 | flag = 0 92 | if (!util.isEmpty(updatefield)) { 93 | flag = 1 94 | } 95 | for (let k in changefield) { 96 | let v = changefield[k] 97 | if (util.isNumber(v)) { 98 | sql += `${flag == 0 ? "" : ", "}${k}=${k}${v >= 0 ? "+" : ""}${v}` 99 | } else { 100 | sql += `${flag == 0 ? "" : ", "}${k}=CONCAT(${k},'${util.escapeSql(v)}')` 101 | } 102 | flag = 1 103 | } 104 | 105 | flag = 0 106 | for (let k in where) { 107 | let v = where[k] 108 | sql += `${flag == 0 ? " WHERE " : " AND "}${k}='${util.escapeSql(v)}'` 109 | flag = 1 110 | } 111 | 112 | if (exwhere.length > 0) { 113 | sql += (flag == 0 ? " WHERE " : " AND ") + exwhere 114 | } 115 | 116 | return sql 117 | } 118 | 119 | /** 120 | * 根据参数生成SQL查询语句 121 | * 122 | * @param table 表名(字符串) 123 | * @param fields 要查询的字段(数组),【字段名1,字段名2...】 124 | * @param where 删除条件(对象),只判断相等条件,其他条件请用exwhere参数 【键=>值...】 125 | * @param exwhere 扩展条件(字符串),不含"where"关键字 126 | * @param other 其他语句(字符串),如limit、order by、group by等 一般不建议使用 127 | * @return 返回sql删除语句(字符串) 128 | */ 129 | exports.select = function (table, fields, where, exwhere = "", other = "") { 130 | let sql = `SELECT ${util.isEmpty(fields) ? '*' : fields.join(", ")} FROM ${table}` 131 | let flag = 0 132 | 133 | for (let k in where) { 134 | let v = where[k] 135 | sql += `${flag == 0 ? " WHERE " : " AND "}${k}='${util.escapeSql(v)}'` 136 | flag = 1 137 | } 138 | 139 | if (exwhere.length > 0) { 140 | sql += (flag == 0 ? " WHERE " : " AND ") + exwhere 141 | } 142 | 143 | if (other.length > 0) { 144 | sql += " " + other 145 | } 146 | 147 | return sql 148 | } 149 | 150 | /** 151 | *
152 |  * 根据参数生成SQL替换语句
153 |  * REPLACE的运行与INSERT很相像。只有一点除外,如果表中的一个旧记录与一个用于PRIMARY KEY或一个UNIQUE索引的新记录具有相同的值,则在新记录被插入之前,旧记录被删除。
154 |  * 注意,除非表有一个PRIMARY KEY或UNIQUE索引,否则,使用一个REPLACE语句没有意义。该语句会与INSERT相同,因为没有索引被用于确定是否新行复制了其它的行。
155 |  * 
156 | * 157 | * @param table 表名(字符串) 158 | * @param record 要插入或替换的记录行(对象)【字段名=>值...】 159 | * @return 返回sql替换语句(字符串) 160 | */ 161 | exports.replace = function (table, record) { 162 | let sql = `REPLACE INTO ${table} (` 163 | sql += Object.keys(record).join(', ') 164 | sql += ") VALUES(" 165 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ') 166 | sql += ")" 167 | 168 | return sql 169 | } 170 | 171 | /** 172 | * 向同一个表批量插入或替换大量数据的时候,用这个函数效率高 173 | * 174 | * @param table 表名(字符串) 175 | * @param records 要插入或替换的多行记录(对象数组)【【字段名=>值...】...】 176 | * @return 返回sql多行插入或替换语句(字符串) 177 | * @see #replace() 178 | */ 179 | exports.replaceMore = function (table, records) { 180 | let sql = `REPLACE INTO ${table} (` 181 | sql += Object.keys(records[0]).join(', ') 182 | sql += ") VALUES" 183 | 184 | for (let record of records) { 185 | sql += "(" 186 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ') 187 | sql += ")," 188 | } 189 | 190 | sql = util.trim(sql, ",") 191 | 192 | return sql 193 | } 194 | 195 | /** 196 | * 根据参数生成SQL删除语句 197 | * 198 | * @param table 表名(字符串) 199 | * @param where 删除条件(对象),只判断相等条件,其他条件请用exwhere参数 【键=>值...】 200 | * @param exwhere 扩展条件(字符串),不含"where"关键字 201 | * @return 返回sql删除语句(字符串) 202 | */ 203 | exports.delete = function (table, where, exwhere = "") { 204 | let sql = `DELETE FROM ${table}` 205 | let flag = 0 206 | 207 | for (let k in where) { 208 | let v = where[k] 209 | sql += `${flag == 0 ? " WHERE " : " AND "}${k}='${util.escapeSql(v)}'` 210 | flag = 1 211 | } 212 | 213 | if (exwhere.length > 0) { 214 | sql += (flag == 0 ? " WHERE " : " AND ") + exwhere 215 | } 216 | 217 | return sql 218 | } 219 | -------------------------------------------------------------------------------- /server/utils/token.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JWT token管理 3 | */ 4 | 5 | var jwt = require('jsonwebtoken') 6 | var secretKey = require('../../config/secret').token_secret_key 7 | 8 | // 一般token过期策略:移动端按月,web端按周 9 | var TOKEN_EXPIRATION = 60 * 60 // 秒 10 | 11 | var secret = Buffer.from(secretKey, 'base64') 12 | 13 | exports.generateToken = function (payload) { 14 | var token = jwt.sign(payload, secret, { expiresIn: TOKEN_EXPIRATION }) 15 | return token 16 | } 17 | 18 | exports.verifyToken = function (token) { 19 | try { 20 | var payload = jwt.verify(token, secret) 21 | return payload 22 | 23 | } catch (err) { 24 | return false 25 | } 26 | } 27 | 28 | exports.decodeToken = function (token) { 29 | var payload = jwt.decode(token) 30 | return payload 31 | } 32 | 33 | exports.refreshToken = function (token) { 34 | var payload = this.decodeToken(token) 35 | // console.dir(payload) 36 | var token = null 37 | if (payload) { 38 | token = jwt.sign({ uid: payload.uid }, secret, { expiresIn: TOKEN_EXPIRATION }) 39 | } 40 | 41 | return token 42 | } 43 | 44 | exports.getToken = function (req) { 45 | if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { // Authorization: Bearer [token] 46 | return req.headers.authorization.split(' ')[1]; 47 | } else if (req.query && req.query.token) { 48 | return req.query.token 49 | } else if (req.cookies && req.cookies.token) { // for page 50 | return req.cookies.token 51 | } 52 | return null 53 | } 54 | -------------------------------------------------------------------------------- /server/utils/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 工具类、实用函数 3 | */ 4 | 5 | const Sequelize = require('sequelize') 6 | const trimFunc = require('lodash/trim') 7 | const escapeFunc = require('lodash/escape') 8 | const isEmptyFunc = require('lodash/isEmpty') 9 | 10 | /** 11 | * 找出第一个符合条件的数组成员 12 | */ 13 | exports.findItem = function (arr, key, value) { 14 | return arr.find(item => item[key] === value) 15 | } 16 | 17 | exports.findNameById = function (arr, id) { 18 | let item = findItem(arr, 'id', id) 19 | return item ? item.name : '' 20 | } 21 | 22 | exports.isObjectLike = function (value) { 23 | return !!value && typeof value == 'object' 24 | } 25 | 26 | exports.isNumber = function (value) { 27 | return typeof value == 'number' || (this.isObjectLike(value) && Object.prototype.toString.call(value) == '[object Number]') 28 | } 29 | 30 | /** 31 | * 转义sql参数防止注入攻击 32 | */ 33 | exports.escapeSql = function (string) { 34 | // return Sequelize.escape(string) // XXX 35 | return escapeFunc(string) 36 | } 37 | 38 | /** 39 | * 去掉字符串前后空白或指定字符 40 | */ 41 | exports.trim = function (string, chars) { 42 | return trimFunc(string, chars) // es6 String.trim 不支持 chars 参数 43 | } 44 | 45 | /** 46 | * Checks if value is an empty object, collection, map, or set. 47 | */ 48 | exports.isEmpty = function (value) { 49 | return isEmptyFunc(value) 50 | } 51 | -------------------------------------------------------------------------------- /server/views/error.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Error 8 | 9 | 10 | 11 |

{{message}}

12 |

{{error.status}}

13 |
{{error.stack}}
14 | 15 | 16 | -------------------------------------------------------------------------------- /server/views/index.hbs: -------------------------------------------------------------------------------- 1 |

{{content}}

2 | -------------------------------------------------------------------------------- /server/views/layout.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{title}} 8 | 9 | {{{block "stylesheets"}}} 10 | 11 | 12 | {{> header }} 13 | 14 | {{{body}}} 15 | 16 | 17 | {{{block "scripts"}}} 18 | 19 | 20 | -------------------------------------------------------------------------------- /server/views/login.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 管理系统 | 登录 7 | 8 | 9 | 10 | 11 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 91 | 92 | 93 | 94 | 95 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /server/views/partials/header.hbs: -------------------------------------------------------------------------------- 1 |

{{title}}

-------------------------------------------------------------------------------- /server/views/partials/sidebar.hbs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoping6688/node-server-project/a33b25a9b06cc0c670a51fddbce7b4750672644e/server/views/partials/sidebar.hbs -------------------------------------------------------------------------------- /test/api/login.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert') 2 | const request = require('supertest') 3 | const app = require('../../app') 4 | 5 | describe('GET /rest/user/login', function() { 6 | it('respond with json', function(done) { 7 | request(app) 8 | .get('/rest/user/login') 9 | .send({ username: 'test', password: '123' }) 10 | .type('application/json') 11 | .set('Accept', 'application/json') 12 | .expect(200) 13 | .end(function(err, res) { 14 | if (err) return done(err) 15 | 16 | console.log(JSON.stringify(res.body)) 17 | assert.equal(res.body.status.code, 0) 18 | done() 19 | }) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /test/unit/sql.js: -------------------------------------------------------------------------------- 1 | const sql = require('../../server/utils/sql') 2 | 3 | console.log(sql.insert('table_name', { 4 | field1: '字段1', 5 | field2: '字段2', 6 | field3: '3' 7 | })) 8 | 9 | console.log(sql.insert('table_name', { 10 | field1: '字段1', 11 | field2: '字段2', 12 | field3: '3' 13 | }, [ 14 | 'field1' 15 | ], { 16 | field2: '追加2', 17 | field3: 3 18 | })) 19 | 20 | console.log(sql.insertMore('table_name', [{ 21 | field1: '字段1', 22 | field2: '字段2', 23 | field3: '3' 24 | },{ 25 | field1: '字段1', 26 | field2: '字段2', 27 | field3: '3' 28 | }])) 29 | 30 | console.log(sql.update('table_name', { 31 | field1: '字段1', 32 | field2: '字段2', 33 | field3: '3' 34 | }, { 35 | id: '123' 36 | })) 37 | 38 | console.log(sql.update('table_name', null, { 39 | id: '123' 40 | }, { 41 | field3: '3' 42 | })) 43 | 44 | console.log(sql.select('table_name', ['field1', 'field2'], { 45 | id: '123' 46 | })) 47 | 48 | console.log(sql.select('table_name', [], { 49 | id: '123' 50 | })) 51 | 52 | console.log(sql.delete('table_name', { 53 | //id: '123' 54 | }, 'id2="1"')) 55 | 56 | console.log(sql.replace('table_name', { 57 | field1: '字段1', 58 | field2: '字段2', 59 | field3: '3' 60 | })) 61 | 62 | console.log(sql.replaceMore('table_name', [{ 63 | field1: '字段1', 64 | field2: '字段2', 65 | field3: '3' 66 | },{ 67 | field1: '字段1', 68 | field2: '字段2', 69 | field3: '3' 70 | }])) 71 | --------------------------------------------------------------------------------