├── .eslintrc ├── .gitignore ├── LICENSE ├── development.js ├── package.json ├── pm2.json ├── production.js ├── src ├── bootstrap │ ├── master.js │ └── worker.js ├── config │ ├── adapter.js │ ├── adapter │ │ ├── cache.js │ │ ├── model.js │ │ ├── session.js │ │ ├── view.js │ │ └── websocket.js │ ├── config.js │ ├── crontab.js │ ├── extend.js │ ├── locales │ │ ├── en-US.js │ │ └── zh-CN.js │ ├── middleware.js │ ├── router.js │ └── validator.js ├── controller │ ├── cache.js │ ├── crontab.js │ ├── index.js │ ├── model.js │ ├── mongoose.js │ ├── payload.js │ ├── rest.js │ ├── session.js │ ├── user.js │ ├── user │ │ └── manage.js │ ├── validate.js │ └── websocket.js ├── logic │ ├── index.js │ ├── user.js │ └── validate.js └── model │ ├── front │ ├── user.js │ └── www.js │ ├── index.js │ ├── post.js │ ├── user.js │ └── user2.js ├── view ├── index_index.html ├── payload │ ├── base.html │ ├── index.html │ ├── request.html │ └── upload.html ├── validate_index.html └── websocket_index.html └── www └── static └── js └── a.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "rules": { 8 | "strict": [0], 9 | "eqeqeq": 2, 10 | "quotes": [2, "single", {"allowTemplateLiterals": true}], 11 | "no-underscore-dangle": 0, 12 | "eol-last": 0, 13 | "camelcase": 0, 14 | "no-loop-func": 0, 15 | "no-trailing-spaces": 0, 16 | "consistent-return": 0, 17 | "new-cap": 0, 18 | "no-shadow": 0, 19 | "semi": 0, 20 | "no-process-exit": 0, 21 | "no-empty": 0, 22 | "yoda": 0, 23 | "no-const-assign": "warn", 24 | "no-new-func": 0, 25 | "no-labels": 0, 26 | "no-this-before-super": "warn", 27 | "no-undef": "warn", 28 | "no-unreachable": "warn", 29 | "no-unused-vars": "warn", 30 | "valid-typeof": "warn" 31 | }, 32 | "globals": { 33 | "think": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | app 40 | 41 | runtime -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ThinkJS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /development.js: -------------------------------------------------------------------------------- 1 | const Application = require('thinkjs'); 2 | const babel = require('think-babel'); 3 | const watcher = require('think-watcher'); 4 | const notifier = require('node-notifier'); 5 | 6 | const instance = new Application({ 7 | ROOT_PATH: __dirname, 8 | watcher: watcher, 9 | transpiler: [babel, { 10 | presets: ['think-node'] 11 | }], 12 | notifier: notifier.notify.bind(notifier), 13 | env: 'development' 14 | }); 15 | 16 | instance.run(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "think-demo", 3 | "description": "Helper for ThinkJS", 4 | "version": "1.0.0", 5 | "author": { 6 | "name": "welefen", 7 | "email": "welefen@gmail.com" 8 | }, 9 | "scripts": { 10 | "start": "node development.js", 11 | "test": "eslint index.js && nyc ava test/", 12 | "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov" 13 | }, 14 | "ava": { 15 | "require": [ 16 | "babel-core/register" 17 | ] 18 | }, 19 | "contributors": [], 20 | "main": "index.js", 21 | "dependencies": { 22 | "babel-preset-think-node": "^1.0.0", 23 | "node-notifier": "^5.0.2", 24 | "think-cache-file": "~1.0.8", 25 | "think-fetch": "^1.0.0", 26 | "think-i18n": "^1.2.3", 27 | "think-model": "*", 28 | "think-mongoose": "^1.0.1", 29 | "think-session-cookie": "^1.0.0", 30 | "think-session-file": "^1.0.0", 31 | "think-view": "^1.0.0", 32 | "think-view-nunjucks": "^1.0.1", 33 | "think-watcher": "^3.0.0", 34 | "think-websocket": "^1.0.0", 35 | "think-websocket-socket.io": "^1.0.0", 36 | "thinkjs": "^3.0.0" 37 | }, 38 | "devDependencies": { 39 | "think-inspect": "0.0.2", 40 | "think-babel": "^1.0.3" 41 | }, 42 | "keywords": [], 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/thinkjs/think-demo" 46 | }, 47 | "engines": { 48 | "node": ">=6.0.0" 49 | }, 50 | "readmeFilename": "README.md", 51 | "bugs": { 52 | "url": "https://github.com/thinkjs/think-demo/issues" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pm2.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [{ 3 | "name": "demo", 4 | "script": "index.js", 5 | "cwd": "/Users/welefen/Develop/git/thinkjs3/thinkjs/demo", 6 | "exec_mode": "fork", 7 | "max_memory_restart": "1G", 8 | "autorestart": true, 9 | "node_args": [], 10 | "args": [], 11 | "env": { 12 | 13 | } 14 | }] 15 | } -------------------------------------------------------------------------------- /production.js: -------------------------------------------------------------------------------- 1 | const Application = require('thinkjs'); 2 | 3 | const instance = new Application({ 4 | ROOT_PATH: __dirname, 5 | env: 'production' 6 | }); 7 | 8 | instance.run(); -------------------------------------------------------------------------------- /src/bootstrap/master.js: -------------------------------------------------------------------------------- 1 | //Invoked in master process 2 | console.log('invoke in master') -------------------------------------------------------------------------------- /src/bootstrap/worker.js: -------------------------------------------------------------------------------- 1 | //Invoked in worker process 2 | console.log('invoke in worker'); -------------------------------------------------------------------------------- /src/config/adapter.js: -------------------------------------------------------------------------------- 1 | exports.model = require('./adapter/model.js'); 2 | exports.view = require('./adapter/view.js'); 3 | exports.session = require('./adapter/session.js'); 4 | exports.cache = require('./adapter/cache.js'); 5 | exports.websocket = require('./adapter/websocket.js'); 6 | -------------------------------------------------------------------------------- /src/config/adapter/cache.js: -------------------------------------------------------------------------------- 1 | const fileCache = require('think-cache-file'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | type: 'file', 6 | common: { 7 | timeout: 24 * 60 * 60 * 1000, // millisecond 8 | }, 9 | file: { 10 | handle: fileCache, 11 | cachePath: path.join(think.ROOT_PATH, 'runtime/cache'), // absolute path is necessarily required 12 | pathDepth: 1, 13 | gcInterval: 24 * 60 * 60 * 1000 // gc 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/config/adapter/model.js: -------------------------------------------------------------------------------- 1 | const isDev = think.env === 'development'; 2 | module.exports = { 3 | type: 'mysql', 4 | common: { 5 | logConnect: isDev, 6 | logSql: isDev, 7 | logger: msg => { 8 | think.isError(msg) ? think.logger.error(msg) : think.logger.info(msg); 9 | } 10 | }, 11 | mongoose: { 12 | host: '127.0.0.1', 13 | port: 27017, 14 | database: 'test', 15 | prefix: 'test_' 16 | }, 17 | mysql: { 18 | database: 'firekylin13', 19 | prefix: 'fk_', 20 | encoding: 'utf8', 21 | nums_per_page: 10, 22 | host: '127.0.0.1', 23 | port: '', 24 | user: 'root', 25 | password: 'root' 26 | } 27 | }; -------------------------------------------------------------------------------- /src/config/adapter/session.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const cookieSession = require('think-session-cookie'); 3 | const fileSession = require('think-session-file'); 4 | 5 | module.exports = { 6 | type: 'mysql', 7 | common: { 8 | cookie: { 9 | name: 'test', 10 | keys: ['werwer', 'werwer'], 11 | signed: true 12 | } 13 | }, 14 | cookie: { 15 | handle: cookieSession, 16 | cookie: { 17 | maxAge: 1009990 * 1000, 18 | keys: ['welefen', 'suredy'], 19 | encrypt: true 20 | } 21 | }, 22 | file: { 23 | handle: fileSession, 24 | sessionPath: path.join(think.ROOT_PATH, 'runtime/session') 25 | } 26 | } -------------------------------------------------------------------------------- /src/config/adapter/view.js: -------------------------------------------------------------------------------- 1 | const nunjucks = require('think-view-nunjucks'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | type: 'nunjucks', 6 | common: { 7 | viewPath: path.join(think.ROOT_PATH, 'view'), 8 | sep: '_', 9 | extname: '.html' 10 | }, 11 | nunjucks: { 12 | handle: nunjucks 13 | } 14 | } -------------------------------------------------------------------------------- /src/config/adapter/websocket.js: -------------------------------------------------------------------------------- 1 | const socketio = require('think-websocket-socket.io'); 2 | 3 | module.exports = { 4 | type: 'socket.io', 5 | 'socket.io': { 6 | handle: socketio, 7 | messages: { 8 | open: 'websocket/open', 9 | close: 'websocket/close', 10 | test: 'websocket/test' 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/config/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | workers: 0 3 | } -------------------------------------------------------------------------------- /src/config/crontab.js: -------------------------------------------------------------------------------- 1 | module.exports = [{ 2 | interval: '1s', 3 | type: 'all', 4 | enable: false, 5 | handle: function(){ 6 | console.log(`crontab all, pid: ${process.pid}`); 7 | } 8 | }, { 9 | interval: '1s', 10 | type: 'one', 11 | enable: false, 12 | handle: 'crontab/index' 13 | }] -------------------------------------------------------------------------------- /src/config/extend.js: -------------------------------------------------------------------------------- 1 | const view = require('think-view'); 2 | const fetch = require('think-fetch'); 3 | const model = require('think-model'); 4 | const createI18n = require('think-i18n'); 5 | const path = require('path'); 6 | const websocket = require('think-websocket'); 7 | const mongoose = require('think-mongoose'); 8 | 9 | var regCn = /^cn.*$/; 10 | var regEn = /^en.*$/; 11 | const i18n = createI18n({ 12 | app: think.app, 13 | i18nFolder: path.resolve(__dirname, './locales'), 14 | defaultLocale: 'zh-cn', 15 | getLocale: {by: 'query', name: 'locale'}, 16 | localesMapping(locales) { 17 | for(l of locales) { 18 | if(regCn.test(l)) { 19 | return 'zh-cn'; 20 | } 21 | if(regEn.test(l)) { 22 | return 'en-us'; 23 | } 24 | } 25 | // default 26 | return 'zh-cn'; 27 | }, 28 | // debugLocale: 'cn' 29 | }) 30 | 31 | module.exports = [ 32 | view, //make application support view 33 | fetch, // HTTP request client 34 | model(think.app), 35 | i18n, 36 | websocket(think.app), 37 | mongoose(think.app) 38 | ]; 39 | 40 | -------------------------------------------------------------------------------- /src/config/locales/en-US.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | localeId: 'en-us', 3 | numeralFormat: { 4 | delimiters: { 5 | thousands: ',', 6 | decimal: '.' 7 | }, 8 | abbreviations: { 9 | thousand: 'k', 10 | million: 'm', 11 | billion: 'b', 12 | trillion: 't' 13 | }, 14 | ordinal: function(number) { 15 | var b = number % 10; 16 | return (~~(number % 100 / 10) === 1) ? 'th' : 17 | (b === 1) ? 'st' : 18 | (b === 2) ? 'nd' : 19 | (b === 3) ? 'rd' : 'th'; 20 | }, 21 | currency: { 22 | symbol: '$' 23 | }, 24 | formats: [ // 定义缩写 25 | {name: 'currency', format: '$ 0,0[.]00'} 26 | ] 27 | }, 28 | translation: { 29 | "messages" : { 30 | "" : { 31 | "domain" : "messages", 32 | "lang" : "en", 33 | "plural_forms" : "nplurals=2; plural=(n != 1);", 34 | }, 35 | "some key" : [ "some key"] 36 | }, 37 | "setting" : { 38 | "" : { 39 | "domain" : "setting", 40 | "lang" : "en", 41 | "plural_forms" : "nplurals=2; plural=(n != 1);", 42 | }, 43 | "some key" : [ "some key in setting domain"] 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/config/locales/zh-CN.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | localeId: 'zh-cn', 3 | dateFormat: { 4 | months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), 5 | monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), 6 | weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), 7 | weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'), 8 | weekdaysMin : '日_一_二_三_四_五_六'.split('_'), 9 | longDateFormat : { 10 | LT : 'HH:mm', 11 | LTS : 'HH:mm:ss', 12 | L : 'YYYY年MMMD日', 13 | LL : 'YYYY年MMMD日', 14 | LLL : 'YYYY年MMMD日Ah点mm分', 15 | LLLL : 'YYYY年MMMD日ddddAh点mm分', 16 | l : 'YYYY年MMMD日', 17 | ll : 'YYYY年MMMD日', 18 | lll : 'YYYY年MMMD日 HH:mm', 19 | llll : 'YYYY年MMMD日dddd自定义的格式 HH:mm' 20 | }, 21 | meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, 22 | meridiemHour: function (hour, meridiem) { 23 | if (hour === 12) { 24 | hour = 0; 25 | } 26 | if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') { 27 | return hour; 28 | } else if (meridiem === '下午' || meridiem === '晚上') { 29 | return hour + 12; 30 | } else { 31 | // '中午' 32 | return hour >= 11 ? hour : hour + 12; 33 | } 34 | }, 35 | meridiem : function (hour, minute, isLower) { 36 | var hm = hour * 100 + minute; 37 | if (hm < 600) { 38 | return '凌晨'; 39 | } else if (hm < 900) { 40 | return '早上'; 41 | } else if (hm < 1130) { 42 | return '上午'; 43 | } else if (hm < 1230) { 44 | return '中午'; 45 | } else if (hm < 1800) { 46 | return '下午'; 47 | } else { 48 | return '晚上'; 49 | } 50 | }, 51 | calendar : { 52 | sameDay : '[今天]LT', 53 | nextDay : '[明天]LT', 54 | nextWeek : '[下]ddddLT', 55 | lastDay : '[昨天]LT', 56 | lastWeek : '[上]ddddLT', 57 | sameElse : 'L' 58 | }, 59 | dayOfMonthOrdinalParse: /\d{1,2}(日|月|周)/, 60 | ordinal : function (number, period) { 61 | switch (period) { 62 | case 'd': 63 | case 'D': 64 | case 'DDD': 65 | return number + '日'; 66 | case 'M': 67 | return number + '月'; 68 | case 'w': 69 | case 'W': 70 | return number + '周'; 71 | default: 72 | return number; 73 | } 74 | }, 75 | relativeTime : { 76 | future : '%s内', 77 | past : '%s前', 78 | s : '几秒', 79 | m : '1 分钟', 80 | mm : '%d 分钟', 81 | h : '1 小时', 82 | hh : '%d 小时', 83 | d : '1 天', 84 | dd : '%d 天', 85 | M : '1 个月', 86 | MM : '%d 个月', 87 | y : '1 年', 88 | yy : '%d 年' 89 | }, 90 | week : { 91 | // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 92 | dow : 1, // Monday is the first day of the week. 93 | doy : 4 // The week that contains Jan 4th is the first week of the year. 94 | } 95 | }, 96 | numeralFormat: { 97 | delimiters: { 98 | thousands: ',', 99 | decimal: '.' 100 | }, 101 | abbreviations: { 102 | thousand: '千', 103 | million: '百万', 104 | billion: '十亿', 105 | trillion: '兆' 106 | }, 107 | ordinal: function (number) { 108 | return '.'; 109 | }, 110 | currency: { 111 | symbol: '¥' 112 | }, 113 | formats: [ // 定义缩写 114 | {name: 'currency', format: '0,0[.]00 $'} // numeral(1000).format(currency) === numeral(1000).format('0,0[.]00 $') 115 | ] 116 | }, 117 | translation: { 118 | "messages" : { 119 | "" : { 120 | "domain" : "messages", 121 | "lang" : "cn", 122 | "plural_forms" : "nplurals=1; plural=(n != 1);", 123 | }, 124 | "some key" : [ "一些键"] 125 | }, 126 | "setting" : { 127 | "" : { 128 | "domain" : "setting", 129 | "lang" : "cn", 130 | "plural_forms" : "nplurals=1; plural=(n != 1);", 131 | }, 132 | "some key" : [ "一些设置"] 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /src/config/middleware.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const isDev = think.env === 'development'; 4 | 5 | module.exports = [ 6 | { 7 | handle: 'meta', 8 | options: { 9 | logRequest: isDev, 10 | sendResponseTime: isDev 11 | } 12 | }, 13 | { 14 | handle: 'resource', 15 | enable: isDev, 16 | options: { 17 | root: path.join(think.ROOT_PATH, 'www'), 18 | publicPath: /^\/(static|favicon\.ico)/ 19 | } 20 | }, 21 | { 22 | handle: 'trace', 23 | enable: !think.isCli, 24 | options: { 25 | debug: isDev 26 | } 27 | }, 28 | { 29 | handle: 'payload', 30 | options: {} 31 | }, 32 | { 33 | handle: 'router', 34 | options: {} 35 | }, 36 | 'logic', 37 | 'controller' 38 | ]; 39 | -------------------------------------------------------------------------------- /src/config/router.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | [/\/user/, 'user', 'rest'], 3 | ['/test/:name', '/testwww', 'redirect'], 4 | ['/post/:id/comments/:cid?', 'comment', 'rest'], 5 | [ /^\/article\/list\/(\w+)/, 'article/:1'] 6 | ]; 7 | -------------------------------------------------------------------------------- /src/config/validator.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | _newrule: function(validValue, { currentQuery }) { 4 | console.log('query-->', currentQuery); 5 | return validValue; 6 | }, 7 | newrule: function(value, { parsedValidValue }) { 8 | return value === parsedValidValue; 9 | } 10 | }, 11 | messages: { 12 | newrule: 'this is newrule custom message' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/controller/cache.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Controller { 2 | 3 | /** 4 | * default set and get cache 5 | */ 6 | async setAction() { 7 | await this.cache('name', 'lushijie'); 8 | let name = await this.cache('name'); 9 | return this.success(name); 10 | } 11 | 12 | /** 13 | * del cache 14 | */ 15 | async delAction() { 16 | await this.cache('name', 'lushijie'); 17 | let name = await this.cache('name', null); 18 | return this.success(name); 19 | } 20 | 21 | /** 22 | * value is function 23 | */ 24 | async funAction() { 25 | // return fn() if cache not exist 26 | let name = await this.cache('name', function(a) { 27 | return a + '-thinkjs'; 28 | }); 29 | 30 | // return cache'value if cache exist 31 | await this.cache('email', 'power@126.com'); 32 | let email = await this.cache('email', function(a) { 33 | return a + '+thinkjs'; 34 | }); 35 | return this.success('name:' + name + ';' + 'email:' + email); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/controller/crontab.js: -------------------------------------------------------------------------------- 1 | module.exports = class CrontabController extends think.Controller { 2 | indexAction(){ 3 | think.logger.info('test'); 4 | console.log('test'); 5 | this.success(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/controller/index.js: -------------------------------------------------------------------------------- 1 | module.exports = class IndexController extends think.Controller { 2 | __before(){ 3 | } 4 | async indexAction(){ 5 | this.body = 'www' 6 | // var __ = this.getI18n(); 7 | // console.log(__('some key')); 8 | //await this.display('index_index'); 9 | } 10 | __after(){ 11 | } 12 | } -------------------------------------------------------------------------------- /src/controller/model.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Controller { 2 | async indexAction() { 3 | let user = await this.model('user').getUser(1); 4 | if( think.isEmpty(user) ) { 5 | return this.fail(3000, 'www'); 6 | } 7 | 8 | return this.success(user); 9 | } 10 | async transactionAction(){ 11 | let user = this.model('user'); 12 | await user.transaction(async () => { 13 | let post = this.model('post'); 14 | post.db(user.db()); 15 | await user.add({name: 'test1'}); 16 | await post.add({title: 'title1', user_id: 1}); 17 | }); 18 | this.success(); 19 | } 20 | async addTransAction() { 21 | let userModel = this.model('user'); 22 | try { 23 | let userId = await userModel.trans(); 24 | return this.success(userId); 25 | } catch(e) { 26 | return this.fail(e); 27 | } 28 | } 29 | 30 | async cacheAction() { 31 | let userId = this.query('id'); 32 | let user = await this.model('user') 33 | .where({id: userId}) 34 | .cache('user_' + userId) 35 | .find(); 36 | 37 | if(think.isEmpty(user)) { 38 | return this.fail(); 39 | } 40 | 41 | return this.success(user); 42 | } 43 | } -------------------------------------------------------------------------------- /src/controller/mongoose.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Controller { 2 | async indexAction() { 3 | console.log('index action') 4 | const user = this.mongoose('front/www', 'mongoose'); 5 | const ret = await user.create({ 6 | title: 'title', 7 | author: 'author', 8 | body: 'body' 9 | }); 10 | const data = await user.getList(); 11 | console.log('data', data) 12 | return this.success(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/controller/payload.js: -------------------------------------------------------------------------------- 1 | module.exports = class PayloadController extends think.Controller { 2 | async indexAction() { 3 | await this.display('payload/index.html'); 4 | } 5 | 6 | async requestAction() { 7 | await this.display('payload/request.html'); 8 | } 9 | 10 | async uploadAction() { 11 | await this.display('payload/upload.html'); 12 | } 13 | 14 | async demoAction() { 15 | this.ctx.body = { 16 | query: this.query(), 17 | file: this.file(), 18 | post: this.post() 19 | }; 20 | } 21 | } -------------------------------------------------------------------------------- /src/controller/rest.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const assert = require('assert'); 3 | 4 | module.exports = class extends think.Controller { 5 | constructor(ctx){ 6 | super(ctx); 7 | this.resource = this.getResource(); 8 | this.id = this.getId(); 9 | assert(think.isFunction(this.model), 'this.model must be a function'); 10 | this.modelInstance = this.model(this.resource); 11 | } 12 | __before(){} 13 | /** 14 | * get resource 15 | * @return {String} [resource name] 16 | */ 17 | getResource(){ 18 | let filename = this.__filename || __filename; 19 | let last = filename.lastIndexOf(path.sep); 20 | return filename.substr(last + 1, filename.length - last - 4); 21 | } 22 | getId(){ 23 | let id = this.get('id'); 24 | if(id && think.isString(id) || think.isNumber(id)){ 25 | return id; 26 | } 27 | let last = this.ctx.path.split('/').slice(-1)[0]; 28 | if(last !== this.resource){ 29 | return last; 30 | } 31 | return ''; 32 | } 33 | async getAction(){ 34 | let data; 35 | if (this.id) { 36 | let pk = await this.modelInstance.getPk(); 37 | data = await this.modelInstance.where({[pk]: this.id}).find(); 38 | return this.success(data); 39 | } 40 | data = await this.modelInstance.select(); 41 | return this.success(data); 42 | } 43 | /** 44 | * put resource 45 | * @return {Promise} [] 46 | */ 47 | async postAction(){ 48 | let pk = await this.modelInstance.getPk(); 49 | let data = this.post(); 50 | delete data[pk]; 51 | if(think.isEmpty(data)){ 52 | return this.fail('data is empty'); 53 | } 54 | let insertId = await this.modelInstance.add(data); 55 | return this.success({id: insertId}); 56 | } 57 | /** 58 | * delete resource 59 | * @return {Promise} [] 60 | */ 61 | async deleteAction(){ 62 | if (!this.id) { 63 | return this.fail('params error'); 64 | } 65 | let pk = await this.modelInstance.getPk(); 66 | let rows = await this.modelInstance.where({[pk]: this.id}).delete(); 67 | return this.success({affectedRows: rows}); 68 | } 69 | /** 70 | * update resource 71 | * @return {Promise} [] 72 | */ 73 | async putAction(){ 74 | if (!this.id) { 75 | return this.fail('params error'); 76 | } 77 | let pk = await this.modelInstance.getPk(); 78 | let data = this.post(); 79 | delete data[pk]; 80 | if (think.isEmpty(data)) { 81 | return this.fail('data is empty'); 82 | } 83 | let rows = await this.modelInstance.where({[pk]: this.id}).update(data); 84 | return this.success({affectedRows: rows}); 85 | } 86 | __call(){ 87 | 88 | } 89 | } -------------------------------------------------------------------------------- /src/controller/session.js: -------------------------------------------------------------------------------- 1 | module.exports = class SessionController extends think.Controller { 2 | indexAction(){ 3 | this.success(231); 4 | } 5 | /** 6 | * set session: default is file 7 | */ 8 | async setAction(){ 9 | await this.session('name', 'value'); 10 | let value = await this.session('num') | 0; 11 | await this.session('num', value + 1); 12 | await this.session('test', {name: 'test'}) 13 | return this.success(); 14 | } 15 | /** 16 | * get session: file 17 | */ 18 | async getAction(){ 19 | let data = await this.session(); 20 | return this.success(data); 21 | } 22 | /** 23 | * set session: cookie 24 | */ 25 | async set2Action(){ 26 | await this.session('num2', '3', {type: 'cookie'}); 27 | //let value = await this.session('num2') | 0; 28 | await this.session('num2', 1); 29 | //await this.session('test', {name: 'test'}); 30 | return this.success(); 31 | } 32 | /** 33 | * get session: cookie 34 | */ 35 | async get2Action(){ 36 | let data = await this.session('num2', undefined, {type: 'cookie'}); 37 | return this.success(data); 38 | } 39 | /** 40 | * set session: redis 41 | */ 42 | async set3Action(){ 43 | await this.session('name', 'redis', { 44 | type: 'redis' 45 | }); 46 | let value = await this.session('num') | 0; 47 | await this.session('num', value + 1); 48 | await this.session('test', {name: 'test'}) 49 | return this.success(); 50 | } 51 | /** 52 | * get session: redis 53 | */ 54 | async get3Action(){ 55 | let data = await this.session('test', undefined, { 56 | type: 'cookie' 57 | }); 58 | this.success(data); 59 | } 60 | /** 61 | * remove session 62 | */ 63 | async rmAction(){ 64 | await this.session(null); 65 | return this.success(); 66 | } 67 | } -------------------------------------------------------------------------------- /src/controller/user.js: -------------------------------------------------------------------------------- 1 | const BaseRest = require('./rest.js'); 2 | module.exports = class extends BaseRest { 3 | 4 | } -------------------------------------------------------------------------------- /src/controller/user/manage.js: -------------------------------------------------------------------------------- 1 | 2 | const index = require('../index.js'); 3 | 4 | module.exports = class extends index { 5 | async indexAction(){ 6 | 7 | let data = await Promise.resolve(666 + ':' + process.env.THINK_PROCESS_ID); 8 | this.ctx.body = data; 9 | setTimeout(() => { 10 | xxx(); 11 | }, 1000) 12 | } 13 | testAction(){ 14 | this.body = 'test' 15 | } 16 | } -------------------------------------------------------------------------------- /src/controller/validate.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Controller { 2 | __before() { 3 | //console.log('__before') 4 | } 5 | async __call() { 6 | await this.display('validate_index'); 7 | } 8 | __after() { 9 | //console.log('__after') 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/controller/websocket.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Controller { 2 | indexAction(){ 3 | return this.display('websocket_index'); 4 | } 5 | openAction(){ 6 | this.cookie('websocket', 'socket.io'); 7 | this.broadcast('user', {name: 'new uesr'}) 8 | } 9 | testAction(){ 10 | // console.log('data', this.data); 11 | // console.log('cookie:test', this.cookie('think_locale')) 12 | this.emit('hello', {name: 'test'}) 13 | } 14 | closeAction(){ 15 | // this.ctx.res.statusCode = 200; 16 | this.body = 'test'; 17 | } 18 | } -------------------------------------------------------------------------------- /src/logic/index.js: -------------------------------------------------------------------------------- 1 | module.exports = class IndexLogic extends think.Logic { 2 | 3 | } -------------------------------------------------------------------------------- /src/logic/user.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Logic { 2 | indexAction(){ 3 | 4 | } 5 | } -------------------------------------------------------------------------------- /src/logic/validate.js: -------------------------------------------------------------------------------- 1 | let METHOD_MAP = { 2 | GET: 'param', 3 | POST: 'post', 4 | FILE: 'file', 5 | PUT: 'post', 6 | DELETE: 'post', 7 | PATCH: 'post', 8 | LINK: 'post', 9 | UNLINK: 'post' 10 | }; 11 | 12 | let output = (that, rules, msgs) => { 13 | let ctxMethod = that.ctx.method.toUpperCase(); 14 | let ret = msgs ? that.validate(rules, msgs) : that.validate(rules); 15 | if(!ret) { 16 | console.log(that.validateErrors); 17 | }else { 18 | console.log('Validate Pass:',that.ctx[METHOD_MAP[ctxMethod]]()); 19 | } 20 | } 21 | 22 | module.exports = class IndexLogic extends think.Logic { 23 | __before() { 24 | 25 | } 26 | 27 | newAction() { 28 | let rules = { 29 | username: { 30 | newrule: 'hello' 31 | } 32 | } 33 | output(this, rules); 34 | } 35 | 36 | indexAction() { 37 | let rules = { 38 | username: { 39 | required: true 40 | } 41 | }; 42 | output(this, rules); 43 | } 44 | 45 | postAction() { 46 | let rules = { 47 | username: { 48 | required: true, 49 | method: 'post' 50 | } 51 | }; 52 | output(this, rules); 53 | } 54 | 55 | trimAction() { 56 | let rules = { 57 | username: { 58 | required: true, 59 | trim: true, 60 | default: 'Tom ' 61 | } 62 | }; 63 | output(this, rules); 64 | } 65 | 66 | parseAction() { 67 | let rules = { 68 | username: { 69 | requiredIf: ['name', 'lushijie', 'tom'] 70 | } 71 | }; 72 | output(this, rules); 73 | } 74 | 75 | convertAction() { 76 | let rules = { 77 | num: { 78 | float: true, 79 | default: '12.09' 80 | }, 81 | flag: { 82 | boolean: true, 83 | default: 'yes' 84 | }, 85 | list: { 86 | array: true, 87 | default: 'tom' 88 | } 89 | }; 90 | output(this, rules); 91 | } 92 | 93 | arrayAction() { 94 | let rules = { 95 | list: { 96 | array: true, 97 | children: { 98 | int: true, 99 | default: 666 100 | }, 101 | default: ['1', '3', ''] 102 | } 103 | }; 104 | output(this, rules); 105 | } 106 | 107 | objectAction() { 108 | let rules = { 109 | obj: { 110 | object: true, 111 | children: { 112 | int: true, 113 | trim: true, 114 | default: 666 115 | }, 116 | default: {a: '123', b: '456 ', c: ''} 117 | } 118 | }; 119 | output(this, rules); 120 | } 121 | 122 | errmsgAction() { 123 | let rules = { 124 | notice: { 125 | required: true 126 | }, 127 | username: { 128 | required: true 129 | }, 130 | email: { 131 | required: true 132 | }, 133 | obj: { 134 | object: true, 135 | children: { 136 | int: true 137 | }, 138 | default: { 139 | a: 'a', 140 | b: 'b', 141 | c: 'c', 142 | d: 'd', 143 | e: '23' 144 | } 145 | } 146 | }; 147 | 148 | let msgs = { 149 | required: 'This is required error message', 150 | username: 'This is username error message', 151 | email: { 152 | required: 'This is email error message' 153 | }, 154 | obj: { 155 | 'a': { 156 | int: 'This is error message for obj.a.int' 157 | }, 158 | 'b': 'This is error message for obj.b', 159 | 'c,d': 'This is error message for obj.c & obj.d' 160 | } 161 | } 162 | output(this, rules, msgs); 163 | } 164 | 165 | allowAction() { 166 | this.allowMethods = 'POST'; 167 | } 168 | 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/model/front/user.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Mongoose { 2 | get schema() { 3 | return { 4 | title: String, 5 | author: String, 6 | body: String, 7 | } 8 | } 9 | getList() { 10 | return this.find(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/model/front/www.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Mongoose { 2 | get schema() { 3 | return { 4 | title: String, 5 | author: String, 6 | body: String, 7 | } 8 | } 9 | getList() { 10 | return this.mongoose('front/user').getList(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/model/index.js: -------------------------------------------------------------------------------- 1 | module.exports = class {}; -------------------------------------------------------------------------------- /src/model/post.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Model { 2 | getList(){ 3 | return this.select(); 4 | } 5 | } -------------------------------------------------------------------------------- /src/model/user.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Model { 2 | get relation() { 3 | return { 4 | post: think.Model.HAS_MANY 5 | } 6 | } 7 | 8 | async getUser(id) { 9 | return this.where({id}).find(); 10 | } 11 | 12 | async trans() { 13 | await this.startTrans(); 14 | try{ 15 | await this.startTrans(); 16 | let userId = await this.add({name: 'xxx', email: 'test@gmail.com'}); 17 | await this.where({id: userId}).update({ 18 | name: 'lizheming' 19 | }); 20 | 21 | await this.commit(); 22 | return userId; 23 | }catch(e){ 24 | await this.rollback(); 25 | throw e; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/model/user2.js: -------------------------------------------------------------------------------- 1 | module.exports = class extends think.Mongoose { 2 | get schema() { 3 | return { 4 | title: String, 5 | author: String, 6 | body: String, 7 | } 8 | } 9 | getList() { 10 | return this.find(); 11 | } 12 | } -------------------------------------------------------------------------------- /view/index_index.html: -------------------------------------------------------------------------------- 1 |

{{title}}

2 | 3 |

下面是i18n展示 4 | 英文 5 | 中文 6 |

7 |
8 |
{{ __('some key') }}
9 |
{{ __.jed.dgettext('setting', 'some key') }}
10 |
{{ __.moment().format('llll') }}
11 |
{{ __.numeral(1000).format('currency') }}
12 |
13 | -------------------------------------------------------------------------------- /view/payload/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Payload Demo 6 | 7 | 8 | {% block header %}{% endblock %} 9 | {% block body %}{% endblock %} 10 | 11 | 12 | 82 | {% block loadJs %}{% endblock %} 83 | 84 | -------------------------------------------------------------------------------- /view/payload/index.html: -------------------------------------------------------------------------------- 1 | {% extends "./base.html" %} 2 | 3 | {% block header %} 4 |

Payload Demo

5 | {% endblock %} 6 | {% block body %} 7 | 11 | {% endblock %} -------------------------------------------------------------------------------- /view/payload/request.html: -------------------------------------------------------------------------------- 1 | {% extends "./base.html" %} 2 | 3 | {% block header %} 4 |

Request Demo

5 |
6 | Payload Demo > payload request demo 7 |
8 | {% endblock %} 9 | {% block body %} 10 |
11 |
12 | 13 | 14 | 15 | 16 |
17 |
18 |

请求信息

19 |
20 |
21 |
22 | {% endblock %} 23 | 24 | {% block loadJs %} 25 | 95 | {% endblock%} -------------------------------------------------------------------------------- /view/payload/upload.html: -------------------------------------------------------------------------------- 1 | {% extends "./base.html" %} 2 | 3 | {% block header %} 4 |

Upload Demo

5 |
6 | Payload Demo > payload upload demo 7 |
8 | {% endblock %} 9 | {% block body %} 10 |
11 |
12 |
13 | file upload (support multi file upload)
14 | 15 |
16 |
17 |

请求信息

18 |
19 |
20 |
21 | {% endblock %} 22 | 23 | {% block loadJs %} 24 | 72 | {% endblock%} 73 | -------------------------------------------------------------------------------- /view/validate_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Validate 8 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /view/websocket_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 29 | 30 | -------------------------------------------------------------------------------- /www/static/js/a.js: -------------------------------------------------------------------------------- 1 | var a = 1; --------------------------------------------------------------------------------