├── .gitignore
├── README.md
├── config
├── default.js
└── info.js
├── index.js
├── lib
└── mysql.js
├── middlewares
└── check.js
├── package-lock.json
├── package.json
├── public
├── avatar.jpg
├── custom.css
├── favicon.ico
├── images
│ ├── article.PNG
│ ├── home.PNG
│ ├── login.PNG
│ └── photo.png
├── jquery.min.js
├── normalize.css
├── pagination.js
├── pictureHandle.js
├── skeleton.css
└── tools.js
├── routers
├── comments.js
├── pages.js
├── posts.js
├── signin.js
├── signout.js
└── upload.js
├── setup.js
└── views
├── comment.ejs
├── create.ejs
├── createpage.ejs
├── edit.ejs
├── editpage.ejs
├── footer.ejs
├── header.ejs
├── img.ejs
├── photo.ejs
├── posts.ejs
├── sPage.ejs
├── sPost.ejs
├── signin.ejs
├── uploadimg.ejs
└── uploadphoto.ejs
/.gitignore:
--------------------------------------------------------------------------------
1 | .deploy_git/
2 | node_modules/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Koa2 + MySQL Blog
2 |
3 | 实现了Markdown语法,相册,图床,验证码登陆,IP请求次数限制,邮件提醒,评论敏感词过滤等功能。
4 |
5 | ## 主要功能
6 |
7 | * 文章发布/修改/删除
8 | * 单页新建/修改/删除
9 | * 相册上传/图片自动压缩优化
10 | * 评论/回复/敏感词过滤/邮件提醒
11 | * 后台登陆/验证码
12 | * IP请求次数限制
13 |
14 | ## 2018.04.26 更新 - 修改界面
15 |
16 | 重新设计了页面,更加简洁大气。
17 |
18 | ## 安装说明
19 |
20 | 修改 config 文件夹下的 default.js 与 info.js 的相关配置。
21 |
22 | 第一次使用请先创建数据库
23 |
24 | 进入登录mysql输入命令:
25 |
26 | ```
27 | create database `najeh` default character set utf8 collate utf8_general_ci;
28 | ```
29 |
30 | 修改 setup.js 里面的默认管理员用户名和密码。
31 |
32 | 创建完数据库以后进入此目录 `node setup.js` 后即可根据下面信息创建管理员用户。
33 |
34 | ## 运行
35 |
36 | ```
37 | node index.js
38 | ```
39 | 后台地址:http://localhost:3000/signin
40 |
41 | 默认账号:admin
42 | 默认密码:123456
43 |
44 | ## 截图
45 |
46 | 
47 | 
48 | 
49 | 
50 |
51 | ## 部分功能使用到的模块
52 |
53 | * EJS模板引擎
54 | * koa2-ratelimit 防止恶意多次登陆请求
55 | * markdown-it Markdown解析器
56 | * nodemailer 邮件提醒
57 | * text-censor 评论敏感词过滤
58 | * trek-captcha 验证码生成
--------------------------------------------------------------------------------
/config/default.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | // 启动端口
3 | port: 3000,
4 | // 数据库配置
5 | database: {
6 | DATABASE: 'najeh',
7 | USERNAME: 'root',
8 | PASSWORD: '123456',
9 | PORT: '3306',
10 | HOST: 'localhost'
11 | }
12 | }
13 |
14 | module.exports = config
--------------------------------------------------------------------------------
/config/info.js:
--------------------------------------------------------------------------------
1 | const info = {
2 | //域名
3 | domain: "https://",
4 | //博客名称
5 | websiteTitle: "小骆博客",
6 | //首页名称
7 | websiteIndexTitle: "小骆博客 - 记录生活与成长",
8 | //显示在首页html的meta简介
9 | websiteDescription: "Luo's Blog , 记录成长,分享生活与技术的点滴!",
10 | //头像地址
11 | avator: "/avatar.jpg",
12 | //显示在头部的简介
13 | indexDescription: "记录生活与成长",
14 | //博主昵称
15 | myUsername: "小骆",
16 | //邮箱
17 | myEmail: "xxx@qq.com",
18 | //发件邮箱
19 | stmpEmail: "i@xxx.cn",
20 | //发件邮箱密码
21 | stmpEmailPass: "123456",
22 | //邮箱port
23 | stmpPort: 465,
24 | //邮箱host
25 | stmpHost: "smtp.exmail.qq.com",
26 | //统计代码
27 | statistics: `
28 |
29 | `
30 | }
31 |
32 | module.exports = info
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const Koa=require('koa');
2 | const convert = require('koa-convert')
3 | const path=require('path')
4 | const bodyParser = require('koa-bodyparser');
5 | const ejs=require('ejs');
6 | const session = require('koa-session-minimal');
7 | const MysqlStore = require('koa-mysql-session');
8 | const config = require('./config/default.js');
9 | const info = require('./config/info.js');
10 | const router=require('koa-router')
11 | const views = require('koa-views')
12 | // const koaStatic = require('koa-static')
13 | const staticCache = require('koa-static-cache')
14 | const app = new Koa()
15 |
16 | //全局函数
17 | app.use(convert(function* (next){
18 | this.state = info
19 | yield *next
20 | }))
21 |
22 | // session存储配置
23 | const sessionMysqlConfig= {
24 | user: config.database.USERNAME,
25 | password: config.database.PASSWORD,
26 | database: config.database.DATABASE,
27 | host: config.database.HOST,
28 | }
29 |
30 | // 配置session中间件
31 | app.use(session({
32 | key: 'USER_SID',
33 | store: new MysqlStore(sessionMysqlConfig)
34 | }))
35 |
36 | // 配置静态资源加载中间件
37 | // app.use(koaStatic(
38 | // path.join(__dirname , './public')
39 | // ))
40 |
41 | // 缓存
42 | app.use(staticCache(path.join(__dirname, './public'), { dynamic: true }, {
43 | maxAge: 365 * 24 * 60 * 60
44 | }))
45 | app.use(staticCache(path.join(__dirname, './images'), { dynamic: true }, {
46 | maxAge: 365 * 24 * 60 * 60
47 | }))
48 |
49 | // 配置服务端模板渲染引擎中间件
50 | app.use(views(path.join(__dirname, './views'), {
51 | extension: 'ejs'
52 | }))
53 | app.use(bodyParser({
54 | formLimit: '1mb'
55 | }))
56 |
57 | // 路由
58 | app.use(require('./routers/signin.js').routes())
59 | app.use(require('./routers/posts.js').routes())
60 | app.use(require('./routers/signout.js').routes())
61 | app.use(require('./routers/pages.js').routes())
62 | app.use(require('./routers/upload.js').routes())
63 | app.use(require('./routers/comments.js').routes())
64 |
65 |
66 | app.listen(config.port)
67 |
68 | console.log(`listening on port ${config.port}`)
69 |
--------------------------------------------------------------------------------
/lib/mysql.js:
--------------------------------------------------------------------------------
1 | var mysql = require('mysql');
2 | var config = require('../config/default.js')
3 |
4 | var pool = mysql.createPool({
5 | host : config.database.HOST,
6 | user : config.database.USERNAME,
7 | password : config.database.PASSWORD,
8 | database : config.database.DATABASE
9 | });
10 |
11 | let query = ( sql, values ) => {
12 |
13 | return new Promise(( resolve, reject ) => {
14 | pool.getConnection( (err, connection) => {
15 | if (err) {
16 | reject( err )
17 | } else {
18 | connection.query(sql, values, ( err, rows) => {
19 | if ( err ) {
20 | reject( err )
21 | } else {
22 | resolve( rows )
23 | }
24 | connection.release()
25 | })
26 | }
27 | })
28 | })
29 |
30 | }
31 |
32 |
33 | // let query = function( sql, values ) {
34 | // pool.getConnection(function(err, connection) {
35 | // // 使用连接
36 | // connection.query( sql,values, function(err, rows) {
37 | // // 使用连接执行查询
38 | // console.log(rows)
39 | // connection.release();
40 | // //连接不再使用,返回到连接池
41 | // });
42 | // });
43 | // }
44 |
45 | let users =
46 | `create table if not exists users(
47 | id INT NOT NULL AUTO_INCREMENT,
48 | name VARCHAR(100) NOT NULL,
49 | pass VARCHAR(100) NOT NULL,
50 | PRIMARY KEY ( id )
51 | );`
52 |
53 | let posts =
54 | `create table if not exists posts(
55 | id INT NOT NULL AUTO_INCREMENT,
56 | title TEXT(0) NOT NULL,
57 | content TEXT(0) NOT NULL,
58 | md TEXT(0) NOT NULL,
59 | moment VARCHAR(100) NOT NULL,
60 | pv VARCHAR(40) NOT NULL DEFAULT '0',
61 | PRIMARY KEY ( id )
62 | );`
63 |
64 | let pages =
65 | `create table if not exists pages(
66 | id INT NOT NULL AUTO_INCREMENT,
67 | linkname VARCHAR(100) NOT NULL,
68 | title TEXT(0) NOT NULL,
69 | content TEXT(0) NOT NULL,
70 | md TEXT(0) NOT NULL,
71 | hascom VARCHAR(40) NOT NULL,
72 | PRIMARY KEY ( id )
73 | );`
74 |
75 | let comments =
76 | `create table if not exists comments(
77 | id INT NOT NULL AUTO_INCREMENT,
78 | name VARCHAR(100) NOT NULL,
79 | email VARCHAR(100) NOT NULL,
80 | website VARCHAR(100) NOT NULL,
81 | content VARCHAR(140) NOT NULL,
82 | link VARCHAR(100) NOT NULL,
83 | reply INT NOT NULL,
84 | replyuser VARCHAR(100) NOT NULL,
85 | moment VARCHAR(100) NOT NULL,
86 | PRIMARY KEY ( id )
87 | );`
88 |
89 | let photos =
90 | `create table if not exists photos(
91 | id INT NOT NULL AUTO_INCREMENT,
92 | name VARCHAR(100) NOT NULL,
93 | title VARCHAR(100) NOT NULL,
94 | moment VARCHAR(100) NOT NULL,
95 | PRIMARY KEY ( id )
96 | );`
97 |
98 | let imgs =
99 | `create table if not exists imgs(
100 | id INT NOT NULL AUTO_INCREMENT,
101 | name VARCHAR(100) NOT NULL,
102 | moment VARCHAR(100) NOT NULL,
103 | PRIMARY KEY ( id )
104 | );`
105 |
106 | let createTable = ( sql ) => {
107 | return query( sql, [] )
108 | }
109 |
110 | // 建表
111 | createTable(users)
112 | createTable(posts)
113 | createTable(pages)
114 | createTable(comments)
115 | createTable(photos)
116 | createTable(imgs)
117 |
118 | // 创建用户
119 | let insertData = ( value ) => {
120 | let _sql = "insert into users set name=?,pass=?;"
121 | return query( _sql, value )
122 | }
123 |
124 | // 删除用户
125 | let deleteData = ( value ) => {
126 | let _sql = `delete from users where name = "${value}"`
127 | return query(_sql)
128 | }
129 |
130 | // 查找用户
131 | let findDataByName = ( name ) => {
132 | let _sql = `select * from users where name="${name}";`
133 | return query( _sql )
134 | }
135 | // 发表文章
136 | let insertPost = ( value ) => {
137 | let _sql = "insert into posts set title=?,content=?,md=?,moment=?;"
138 | return query( _sql, value )
139 | }
140 |
141 | // 更新浏览数
142 | let updatePostPv = ( value ) => {
143 | let _sql = "update posts set pv=? where id=?"
144 | return query( _sql, value )
145 | }
146 |
147 | // 通过文章id查找
148 | let findDataById = ( id ) => {
149 | let _sql = `select * from posts where id="${id}";`
150 | return query( _sql)
151 | }
152 | // 查询所有文章
153 | let findAllPost = () => {
154 | let _sql = ` select * FROM posts;`
155 | return query( _sql)
156 | }
157 | // 查询分页文章
158 | let findPostByPage = ( page ) => {
159 | let _sql = ` select * FROM posts order by id desc limit ${(page-1)*5},5;`
160 | return query( _sql)
161 | }
162 | // 更新修改文章
163 | let updatePost = (values) => {
164 | let _sql = `update posts set title=?,content=?,md=? where id=?`
165 | return query(_sql,values)
166 | }
167 | // 删除文章
168 | let deletePost = (id) => {
169 | let _sql = `delete from posts where id = ${id}`
170 | return query(_sql)
171 | }
172 |
173 | // 创建新页面
174 | let insertPage = ( value ) => {
175 | let _sql = "insert into pages set linkname=?,title=?,md=?,content=?,hascom=?;"
176 | return query( _sql, value )
177 | }
178 |
179 | // 更新单页面
180 | let updatePage = (values) => {
181 | let _sql = `update pages set linkname=?, title=?,content=?,md=?,hascom=? where id=?`
182 | return query(_sql,values)
183 | }
184 |
185 | // 删除单页面
186 | let deletePage = (linkname) => {
187 | let _sql = `delete from pages where linkname ="${linkname}"`
188 | return query(_sql)
189 | }
190 |
191 | // 通过页面链接查找
192 | let findPageDataByLink = ( linkname ) => {
193 | let _sql = `select * from pages where linkname="${linkname}";`
194 | return query( _sql)
195 | }
196 |
197 | // 查找全部单页面标题和链接
198 | let findPageInfoById = () => {
199 | let _sql = `select title,linkname from pages;`
200 | return query( _sql)
201 | }
202 |
203 | // 新增评论
204 | let createComment = ( value ) => {
205 | let _sql = "insert into comments set name=?,email=?,website=?,content=?,link=?,reply=?,replyuser=?,moment=?;"
206 | return query( _sql, value )
207 | }
208 |
209 | // 获取评论人
210 | let findCommentInfo = (id,link) => {
211 | let _sql = `select name,email from comments where id="${id}" and link="${link}";`
212 | return query( _sql)
213 | }
214 |
215 | // 获取页面评论
216 | let findComments = (link) => {
217 | let _sql = `select * from comments where link="${link}" order by id desc;`
218 | return query( _sql)
219 | }
220 |
221 | // 删除评论
222 | let deleteComments = (id) => {
223 | let _sql = `delete from comments where id = ${id}`
224 | return query(_sql)
225 | }
226 |
227 | // 删除某页评论
228 | let deleteCommentsByLink = (link) => {
229 | let _sql = `delete from comments where link = "${link}"`
230 | return query(_sql)
231 | }
232 |
233 | // 新增图片
234 | let uploadImg = ( value ) => {
235 | let _sql = "insert into imgs set name=?,moment=?;"
236 | return query( _sql, value )
237 | }
238 |
239 | // 查询全部图片
240 | let findAllImgs = () => {
241 | let _sql = `select * from imgs;`
242 | return query( _sql)
243 | }
244 |
245 | // 查询分页图片
246 | let findImgByPage = ( page ) => {
247 | let _sql = ` select * FROM imgs order by id desc limit ${(page-1)*10},10;`
248 | return query( _sql)
249 | }
250 |
251 | // 删除图片
252 | let deleteImg = (id) => {
253 | let _sql = `delete from imgs where id = ${id}`
254 | return query(_sql)
255 | }
256 |
257 | // 新增相册图片
258 | let uploadPhoto = ( value ) => {
259 | let _sql = "insert into photos set name=?,title=?,moment=?;"
260 | return query( _sql, value )
261 | }
262 |
263 | // 查询全部相册图片
264 | let findAllPhotos = () => {
265 | let _sql = `select * from photos;`
266 | return query( _sql)
267 | }
268 |
269 | // 查询分页相册图片
270 | let findPhotoByPage = ( page ) => {
271 | let _sql = ` select * FROM photos order by id desc limit ${(page-1)*5},5;`
272 | return query( _sql)
273 | }
274 |
275 | // 删除相册图片
276 | let deletePhoto = (id) => {
277 | let _sql = `delete from photos where id = ${id}`
278 | return query(_sql)
279 | }
280 |
281 | module.exports = {
282 | insertData,
283 | deleteData,
284 | query,
285 | createTable,
286 | findDataByName,
287 | insertPost,
288 | findAllPost,
289 | findPostByPage,
290 | findDataById,
291 | updatePost,
292 | deletePost,
293 | updatePostPv,
294 | insertPage,
295 | updatePage,
296 | deletePage,
297 | findPageDataByLink,
298 | findPageInfoById,
299 | createComment,
300 | findComments,
301 | deleteComments,
302 | deleteCommentsByLink,
303 | findCommentInfo,
304 | uploadImg,
305 | findAllImgs,
306 | findImgByPage,
307 | deleteImg,
308 | uploadPhoto,
309 | findAllPhotos,
310 | findPhotoByPage,
311 | deletePhoto
312 | }
313 |
314 |
--------------------------------------------------------------------------------
/middlewares/check.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | // 已经登录了
4 | checkNotLogin: (ctx) => {
5 | if (ctx.session && ctx.session.user) {
6 | ctx.redirect('/');
7 | return false;
8 | }
9 | return true;
10 | },
11 | //没有登录
12 | checkLogin: (ctx) => {
13 | if (!ctx.session || !ctx.session.user) {
14 | ctx.redirect('/');
15 | return false;
16 | }
17 | return true;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Luog",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@types/geojson": {
8 | "version": "1.0.6",
9 | "resolved": "http://registry.npm.taobao.org/@types/geojson/download/@types/geojson-1.0.6.tgz",
10 | "integrity": "sha1-PgKXJyjGkkjCrwjWCkjLuGgP/98="
11 | },
12 | "@types/node": {
13 | "version": "9.3.0",
14 | "resolved": "http://registry.npm.taobao.org/@types/node/download/@types/node-9.3.0.tgz",
15 | "integrity": "sha1-OhKc2nxOXfJAlwJiaJLLS5ZUbdU="
16 | },
17 | "abbrev": {
18 | "version": "1.1.1",
19 | "resolved": "http://registry.npm.taobao.org/abbrev/download/abbrev-1.1.1.tgz",
20 | "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg="
21 | },
22 | "accepts": {
23 | "version": "1.3.4",
24 | "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.4.tgz",
25 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
26 | "requires": {
27 | "mime-types": "2.1.17",
28 | "negotiator": "0.6.1"
29 | }
30 | },
31 | "ansi-styles": {
32 | "version": "3.2.0",
33 | "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.0.tgz",
34 | "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
35 | "requires": {
36 | "color-convert": "1.9.1"
37 | }
38 | },
39 | "any-promise": {
40 | "version": "1.3.0",
41 | "resolved": "http://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz",
42 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
43 | },
44 | "argparse": {
45 | "version": "1.0.9",
46 | "resolved": "http://registry.npm.taobao.org/argparse/download/argparse-1.0.9.tgz",
47 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
48 | "requires": {
49 | "sprintf-js": "1.0.3"
50 | }
51 | },
52 | "assertion-error": {
53 | "version": "1.1.0",
54 | "resolved": "http://registry.npm.taobao.org/assertion-error/download/assertion-error-1.1.0.tgz",
55 | "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs=",
56 | "dev": true
57 | },
58 | "balanced-match": {
59 | "version": "1.0.0",
60 | "resolved": "http://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz",
61 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
62 | "dev": true
63 | },
64 | "bignumber.js": {
65 | "version": "4.0.4",
66 | "resolved": "http://registry.npm.taobao.org/bignumber.js/download/bignumber.js-4.0.4.tgz",
67 | "integrity": "sha1-fED1q80tZiOre5loLufbgbEYiaQ="
68 | },
69 | "bluebird": {
70 | "version": "3.5.1",
71 | "resolved": "http://registry.npm.taobao.org/bluebird/download/bluebird-3.5.1.tgz",
72 | "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk="
73 | },
74 | "brace-expansion": {
75 | "version": "1.1.8",
76 | "resolved": "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.8.tgz",
77 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
78 | "dev": true,
79 | "requires": {
80 | "balanced-match": "1.0.0",
81 | "concat-map": "0.0.1"
82 | }
83 | },
84 | "browser-stdout": {
85 | "version": "1.3.0",
86 | "resolved": "http://registry.npm.taobao.org/browser-stdout/download/browser-stdout-1.3.0.tgz",
87 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
88 | "dev": true
89 | },
90 | "bytes": {
91 | "version": "3.0.0",
92 | "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz",
93 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
94 | },
95 | "chai": {
96 | "version": "4.1.2",
97 | "resolved": "http://registry.npm.taobao.org/chai/download/chai-4.1.2.tgz",
98 | "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
99 | "dev": true,
100 | "requires": {
101 | "assertion-error": "1.1.0",
102 | "check-error": "1.0.2",
103 | "deep-eql": "3.0.1",
104 | "get-func-name": "2.0.0",
105 | "pathval": "1.1.0",
106 | "type-detect": "4.0.5"
107 | }
108 | },
109 | "chalk": {
110 | "version": "2.1.0",
111 | "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-2.1.0.tgz",
112 | "integrity": "sha1-rFvs8U+iG5nGySynp9fP1bF+dD4=",
113 | "requires": {
114 | "ansi-styles": "3.2.0",
115 | "escape-string-regexp": "1.0.5",
116 | "supports-color": "4.5.0"
117 | }
118 | },
119 | "charenc": {
120 | "version": "0.0.2",
121 | "resolved": "http://registry.npm.taobao.org/charenc/download/charenc-0.0.2.tgz",
122 | "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
123 | },
124 | "check-error": {
125 | "version": "1.0.2",
126 | "resolved": "http://registry.npm.taobao.org/check-error/download/check-error-1.0.2.tgz",
127 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
128 | "dev": true
129 | },
130 | "cls-bluebird": {
131 | "version": "2.1.0",
132 | "resolved": "http://registry.npm.taobao.org/cls-bluebird/download/cls-bluebird-2.1.0.tgz",
133 | "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=",
134 | "requires": {
135 | "is-bluebird": "1.0.2",
136 | "shimmer": "1.2.0"
137 | }
138 | },
139 | "co": {
140 | "version": "4.6.0",
141 | "resolved": "http://registry.npm.taobao.org/co/download/co-4.6.0.tgz",
142 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
143 | },
144 | "co-body": {
145 | "version": "5.1.1",
146 | "resolved": "http://registry.npm.taobao.org/co-body/download/co-body-5.1.1.tgz",
147 | "integrity": "sha1-2XeB0eM0S6SoIP0YBr3fg0FQUjY=",
148 | "requires": {
149 | "inflation": "2.0.0",
150 | "qs": "6.5.1",
151 | "raw-body": "2.3.2",
152 | "type-is": "1.6.15"
153 | }
154 | },
155 | "co-mysql": {
156 | "version": "0.4.1",
157 | "resolved": "http://registry.npm.taobao.org/co-mysql/download/co-mysql-0.4.1.tgz",
158 | "integrity": "sha1-cnPr/ydoHAPDivmAvH4o94p7GTk=",
159 | "requires": {
160 | "mysql": "2.15.0"
161 | }
162 | },
163 | "color-convert": {
164 | "version": "1.9.1",
165 | "resolved": "http://registry.npm.taobao.org/color-convert/download/color-convert-1.9.1.tgz",
166 | "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=",
167 | "requires": {
168 | "color-name": "1.1.3"
169 | }
170 | },
171 | "color-name": {
172 | "version": "1.1.3",
173 | "resolved": "http://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz",
174 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
175 | },
176 | "commander": {
177 | "version": "2.13.0",
178 | "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz",
179 | "integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w="
180 | },
181 | "compressible": {
182 | "version": "2.0.12",
183 | "resolved": "http://registry.npm.taobao.org/compressible/download/compressible-2.0.12.tgz",
184 | "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=",
185 | "requires": {
186 | "mime-db": "1.30.0"
187 | }
188 | },
189 | "concat-map": {
190 | "version": "0.0.1",
191 | "resolved": "http://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
192 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
193 | "dev": true
194 | },
195 | "condense-newlines": {
196 | "version": "0.2.1",
197 | "resolved": "http://registry.npm.taobao.org/condense-newlines/download/condense-newlines-0.2.1.tgz",
198 | "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=",
199 | "requires": {
200 | "extend-shallow": "2.0.1",
201 | "is-whitespace": "0.3.0",
202 | "kind-of": "3.2.2"
203 | }
204 | },
205 | "config-chain": {
206 | "version": "1.1.11",
207 | "resolved": "http://registry.npm.taobao.org/config-chain/download/config-chain-1.1.11.tgz",
208 | "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=",
209 | "requires": {
210 | "ini": "1.3.5",
211 | "proto-list": "1.2.4"
212 | }
213 | },
214 | "config-lite": {
215 | "version": "2.1.0",
216 | "resolved": "http://registry.npm.taobao.org/config-lite/download/config-lite-2.1.0.tgz",
217 | "integrity": "sha1-TeOPEGADKldT8Gr1j18Tgqzsbcg=",
218 | "requires": {
219 | "chalk": "2.1.0",
220 | "js-yaml": "3.9.1",
221 | "lodash": "4.17.4",
222 | "optimist": "0.6.1",
223 | "resolve": "1.4.0",
224 | "toml": "2.3.2"
225 | }
226 | },
227 | "consolidate": {
228 | "version": "0.15.0",
229 | "resolved": "http://registry.npm.taobao.org/consolidate/download/consolidate-0.15.0.tgz",
230 | "integrity": "sha1-OXkYkBKX1fZX0KZRSjBQIkWiCYA=",
231 | "requires": {
232 | "bluebird": "3.5.1"
233 | }
234 | },
235 | "content-disposition": {
236 | "version": "0.5.2",
237 | "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz",
238 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
239 | },
240 | "content-type": {
241 | "version": "1.0.4",
242 | "resolved": "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz",
243 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js="
244 | },
245 | "cookies": {
246 | "version": "0.7.1",
247 | "resolved": "http://registry.npm.taobao.org/cookies/download/cookies-0.7.1.tgz",
248 | "integrity": "sha1-fIphX1SBxhq58WyDNzG8uPZjuZs=",
249 | "requires": {
250 | "depd": "1.1.2",
251 | "keygrip": "1.0.2"
252 | }
253 | },
254 | "copy-to": {
255 | "version": "2.0.1",
256 | "resolved": "http://registry.npm.taobao.org/copy-to/download/copy-to-2.0.1.tgz",
257 | "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU="
258 | },
259 | "core-util-is": {
260 | "version": "1.0.2",
261 | "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz",
262 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
263 | },
264 | "crypt": {
265 | "version": "0.0.2",
266 | "resolved": "http://registry.npm.taobao.org/crypt/download/crypt-0.0.2.tgz",
267 | "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
268 | },
269 | "debug": {
270 | "version": "3.1.0",
271 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
272 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
273 | "requires": {
274 | "ms": "2.0.0"
275 | }
276 | },
277 | "deep-eql": {
278 | "version": "3.0.1",
279 | "resolved": "http://registry.npm.taobao.org/deep-eql/download/deep-eql-3.0.1.tgz",
280 | "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=",
281 | "dev": true,
282 | "requires": {
283 | "type-detect": "4.0.5"
284 | }
285 | },
286 | "deep-equal": {
287 | "version": "1.0.1",
288 | "resolved": "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz",
289 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
290 | },
291 | "delegates": {
292 | "version": "1.0.0",
293 | "resolved": "http://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz",
294 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
295 | },
296 | "depd": {
297 | "version": "1.1.2",
298 | "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
299 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
300 | },
301 | "destroy": {
302 | "version": "1.0.4",
303 | "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz",
304 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
305 | },
306 | "diff": {
307 | "version": "3.3.1",
308 | "resolved": "http://registry.npm.taobao.org/diff/download/diff-3.3.1.tgz",
309 | "integrity": "sha1-qoVnpu7QPFMfyJ0/cRzQ5SWd7HU=",
310 | "dev": true
311 | },
312 | "dottie": {
313 | "version": "2.0.0",
314 | "resolved": "http://registry.npm.taobao.org/dottie/download/dottie-2.0.0.tgz",
315 | "integrity": "sha1-2hkZgci41xPKARXViYzzl8Lw3dA="
316 | },
317 | "editorconfig": {
318 | "version": "0.13.3",
319 | "resolved": "http://registry.npm.taobao.org/editorconfig/download/editorconfig-0.13.3.tgz",
320 | "integrity": "sha1-5SGeWHlR1glY/ZTqmpoAjN7/GzQ=",
321 | "requires": {
322 | "bluebird": "3.5.1",
323 | "commander": "2.13.0",
324 | "lru-cache": "3.2.0",
325 | "semver": "5.4.1",
326 | "sigmund": "1.0.1"
327 | }
328 | },
329 | "ee-first": {
330 | "version": "1.1.1",
331 | "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
332 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
333 | },
334 | "ejs": {
335 | "version": "2.5.7",
336 | "resolved": "http://registry.npm.taobao.org/ejs/download/ejs-2.5.7.tgz",
337 | "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
338 | },
339 | "entities": {
340 | "version": "1.1.1",
341 | "resolved": "http://registry.npm.taobao.org/entities/download/entities-1.1.1.tgz",
342 | "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
343 | },
344 | "error-inject": {
345 | "version": "1.0.0",
346 | "resolved": "http://registry.npm.taobao.org/error-inject/download/error-inject-1.0.0.tgz",
347 | "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc="
348 | },
349 | "escape-html": {
350 | "version": "1.0.3",
351 | "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz",
352 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
353 | },
354 | "escape-string-regexp": {
355 | "version": "1.0.5",
356 | "resolved": "http://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz",
357 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
358 | },
359 | "esprima": {
360 | "version": "4.0.0",
361 | "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-4.0.0.tgz",
362 | "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ="
363 | },
364 | "extend-shallow": {
365 | "version": "2.0.1",
366 | "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
367 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
368 | "requires": {
369 | "is-extendable": "0.1.1"
370 | }
371 | },
372 | "fresh": {
373 | "version": "0.5.2",
374 | "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz",
375 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
376 | },
377 | "fs-extra": {
378 | "version": "4.0.3",
379 | "resolved": "http://registry.npm.taobao.org/fs-extra/download/fs-extra-4.0.3.tgz",
380 | "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=",
381 | "requires": {
382 | "graceful-fs": "4.1.11",
383 | "jsonfile": "4.0.0",
384 | "universalify": "0.1.1"
385 | }
386 | },
387 | "fs-readdir-recursive": {
388 | "version": "1.0.0",
389 | "resolved": "http://registry.npm.taobao.org/fs-readdir-recursive/download/fs-readdir-recursive-1.0.0.tgz",
390 | "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA="
391 | },
392 | "fs.realpath": {
393 | "version": "1.0.0",
394 | "resolved": "http://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
395 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
396 | "dev": true
397 | },
398 | "generic-pool": {
399 | "version": "3.4.0",
400 | "resolved": "http://registry.npm.taobao.org/generic-pool/download/generic-pool-3.4.0.tgz",
401 | "integrity": "sha1-a3b8IBu0mg/zgUUPWFNSN4+xwI8="
402 | },
403 | "get-func-name": {
404 | "version": "2.0.0",
405 | "resolved": "http://registry.npm.taobao.org/get-func-name/download/get-func-name-2.0.0.tgz",
406 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
407 | "dev": true
408 | },
409 | "get-paths": {
410 | "version": "0.0.2",
411 | "resolved": "http://registry.npm.taobao.org/get-paths/download/get-paths-0.0.2.tgz",
412 | "integrity": "sha1-qcJ7Go0AbJMaTyb899FUbjrXG+o=",
413 | "requires": {
414 | "fs-extra": "4.0.3"
415 | }
416 | },
417 | "glob": {
418 | "version": "7.1.2",
419 | "resolved": "http://registry.npm.taobao.org/glob/download/glob-7.1.2.tgz",
420 | "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
421 | "dev": true,
422 | "requires": {
423 | "fs.realpath": "1.0.0",
424 | "inflight": "1.0.6",
425 | "inherits": "2.0.3",
426 | "minimatch": "3.0.4",
427 | "once": "1.4.0",
428 | "path-is-absolute": "1.0.1"
429 | }
430 | },
431 | "graceful-fs": {
432 | "version": "4.1.11",
433 | "resolved": "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.11.tgz",
434 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
435 | },
436 | "growl": {
437 | "version": "1.10.3",
438 | "resolved": "http://registry.npm.taobao.org/growl/download/growl-1.10.3.tgz",
439 | "integrity": "sha1-GSa6kM8+3+KttJJ/WIC8IsZseQ8=",
440 | "dev": true
441 | },
442 | "has-flag": {
443 | "version": "2.0.0",
444 | "resolved": "http://registry.npm.taobao.org/has-flag/download/has-flag-2.0.0.tgz",
445 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
446 | },
447 | "he": {
448 | "version": "1.1.1",
449 | "resolved": "http://registry.npm.taobao.org/he/download/he-1.1.1.tgz",
450 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
451 | "dev": true
452 | },
453 | "http-assert": {
454 | "version": "1.3.0",
455 | "resolved": "http://registry.npm.taobao.org/http-assert/download/http-assert-1.3.0.tgz",
456 | "integrity": "sha1-oxpc+IyHPsu1eWkH1NbxMujAHko=",
457 | "requires": {
458 | "deep-equal": "1.0.1",
459 | "http-errors": "1.6.2"
460 | }
461 | },
462 | "http-errors": {
463 | "version": "1.6.2",
464 | "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.2.tgz",
465 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
466 | "requires": {
467 | "depd": "1.1.1",
468 | "inherits": "2.0.3",
469 | "setprototypeof": "1.0.3",
470 | "statuses": "1.4.0"
471 | },
472 | "dependencies": {
473 | "depd": {
474 | "version": "1.1.1",
475 | "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.1.tgz",
476 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
477 | }
478 | }
479 | },
480 | "iconv-lite": {
481 | "version": "0.4.19",
482 | "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.19.tgz",
483 | "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs="
484 | },
485 | "inflation": {
486 | "version": "2.0.0",
487 | "resolved": "http://registry.npm.taobao.org/inflation/download/inflation-2.0.0.tgz",
488 | "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8="
489 | },
490 | "inflection": {
491 | "version": "1.12.0",
492 | "resolved": "http://registry.npm.taobao.org/inflection/download/inflection-1.12.0.tgz",
493 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY="
494 | },
495 | "inflight": {
496 | "version": "1.0.6",
497 | "resolved": "http://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz",
498 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
499 | "dev": true,
500 | "requires": {
501 | "once": "1.4.0",
502 | "wrappy": "1.0.2"
503 | }
504 | },
505 | "inherits": {
506 | "version": "2.0.3",
507 | "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz",
508 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
509 | },
510 | "ini": {
511 | "version": "1.3.5",
512 | "resolved": "http://registry.npm.taobao.org/ini/download/ini-1.3.5.tgz",
513 | "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc="
514 | },
515 | "is-bluebird": {
516 | "version": "1.0.2",
517 | "resolved": "http://registry.npm.taobao.org/is-bluebird/download/is-bluebird-1.0.2.tgz",
518 | "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI="
519 | },
520 | "is-buffer": {
521 | "version": "1.1.6",
522 | "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz",
523 | "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4="
524 | },
525 | "is-extendable": {
526 | "version": "0.1.1",
527 | "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz",
528 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
529 | },
530 | "is-generator-function": {
531 | "version": "1.0.7",
532 | "resolved": "http://registry.npm.taobao.org/is-generator-function/download/is-generator-function-1.0.7.tgz",
533 | "integrity": "sha1-0hMuUpuwAAp/gHlNS99c1eWBNSI="
534 | },
535 | "is-whitespace": {
536 | "version": "0.3.0",
537 | "resolved": "http://registry.npm.taobao.org/is-whitespace/download/is-whitespace-0.3.0.tgz",
538 | "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38="
539 | },
540 | "isarray": {
541 | "version": "1.0.0",
542 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz",
543 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
544 | },
545 | "js-beautify": {
546 | "version": "1.7.5",
547 | "resolved": "http://registry.npm.taobao.org/js-beautify/download/js-beautify-1.7.5.tgz",
548 | "integrity": "sha1-adllHvYNu2SfZVJ7U2dJUBOKeRk=",
549 | "requires": {
550 | "config-chain": "1.1.11",
551 | "editorconfig": "0.13.3",
552 | "mkdirp": "0.5.1",
553 | "nopt": "3.0.6"
554 | }
555 | },
556 | "js-yaml": {
557 | "version": "3.9.1",
558 | "resolved": "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.9.1.tgz",
559 | "integrity": "sha1-CHdc69/dNZIJ8NKs04PI+GppBKA=",
560 | "requires": {
561 | "argparse": "1.0.9",
562 | "esprima": "4.0.0"
563 | }
564 | },
565 | "jsonfile": {
566 | "version": "4.0.0",
567 | "resolved": "http://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz",
568 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
569 | "requires": {
570 | "graceful-fs": "4.1.11"
571 | }
572 | },
573 | "keygrip": {
574 | "version": "1.0.2",
575 | "resolved": "http://registry.npm.taobao.org/keygrip/download/keygrip-1.0.2.tgz",
576 | "integrity": "sha1-rTKXxVcGneqLz+ek+kkbdcXd65E="
577 | },
578 | "kind-of": {
579 | "version": "3.2.2",
580 | "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
581 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
582 | "requires": {
583 | "is-buffer": "1.1.6"
584 | }
585 | },
586 | "koa": {
587 | "version": "2.4.1",
588 | "resolved": "http://registry.npm.taobao.org/koa/download/koa-2.4.1.tgz",
589 | "integrity": "sha1-1EnPuXCn6dpXH2me2kC7njLrFIQ=",
590 | "requires": {
591 | "accepts": "1.3.4",
592 | "content-disposition": "0.5.2",
593 | "content-type": "1.0.4",
594 | "cookies": "0.7.1",
595 | "debug": "3.1.0",
596 | "delegates": "1.0.0",
597 | "depd": "1.1.2",
598 | "destroy": "1.0.4",
599 | "error-inject": "1.0.0",
600 | "escape-html": "1.0.3",
601 | "fresh": "0.5.2",
602 | "http-assert": "1.3.0",
603 | "http-errors": "1.6.2",
604 | "is-generator-function": "1.0.7",
605 | "koa-compose": "4.0.0",
606 | "koa-convert": "1.2.0",
607 | "koa-is-json": "1.0.0",
608 | "mime-types": "2.1.17",
609 | "on-finished": "2.3.0",
610 | "only": "0.0.2",
611 | "parseurl": "1.3.2",
612 | "statuses": "1.4.0",
613 | "type-is": "1.6.15",
614 | "vary": "1.1.2"
615 | }
616 | },
617 | "koa-bodyparser": {
618 | "version": "4.2.0",
619 | "resolved": "http://registry.npm.taobao.org/koa-bodyparser/download/koa-bodyparser-4.2.0.tgz",
620 | "integrity": "sha1-vObgi8Zfhwm20fqpQRx/DYk4qlQ=",
621 | "requires": {
622 | "co-body": "5.1.1",
623 | "copy-to": "2.0.1"
624 | }
625 | },
626 | "koa-compose": {
627 | "version": "4.0.0",
628 | "resolved": "http://registry.npm.taobao.org/koa-compose/download/koa-compose-4.0.0.tgz",
629 | "integrity": "sha1-KAClE9nDYe8NY4UrA45Pby1adzw="
630 | },
631 | "koa-convert": {
632 | "version": "1.2.0",
633 | "resolved": "http://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz",
634 | "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=",
635 | "requires": {
636 | "co": "4.6.0",
637 | "koa-compose": "3.2.1"
638 | },
639 | "dependencies": {
640 | "koa-compose": {
641 | "version": "3.2.1",
642 | "resolved": "http://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz",
643 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=",
644 | "requires": {
645 | "any-promise": "1.3.0"
646 | }
647 | }
648 | }
649 | },
650 | "koa-is-json": {
651 | "version": "1.0.0",
652 | "resolved": "http://registry.npm.taobao.org/koa-is-json/download/koa-is-json-1.0.0.tgz",
653 | "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ="
654 | },
655 | "koa-mysql-session": {
656 | "version": "0.0.2",
657 | "resolved": "http://registry.npm.taobao.org/koa-mysql-session/download/koa-mysql-session-0.0.2.tgz",
658 | "integrity": "sha1-t/MvTdLDel95kiYXl8WTc3BO3Ik=",
659 | "requires": {
660 | "co": "3.1.0",
661 | "co-mysql": "0.4.1"
662 | },
663 | "dependencies": {
664 | "co": {
665 | "version": "3.1.0",
666 | "resolved": "http://registry.npm.taobao.org/co/download/co-3.1.0.tgz",
667 | "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g="
668 | }
669 | }
670 | },
671 | "koa-router": {
672 | "version": "7.3.0",
673 | "resolved": "http://registry.npm.taobao.org/koa-router/download/koa-router-7.3.0.tgz",
674 | "integrity": "sha1-JB8ESaxc0QcYMamj2AtSH6+2uqE=",
675 | "requires": {
676 | "debug": "3.1.0",
677 | "http-errors": "1.6.2",
678 | "koa-compose": "3.2.1",
679 | "methods": "1.1.2",
680 | "path-to-regexp": "1.7.0",
681 | "urijs": "1.19.0"
682 | },
683 | "dependencies": {
684 | "koa-compose": {
685 | "version": "3.2.1",
686 | "resolved": "http://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz",
687 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=",
688 | "requires": {
689 | "any-promise": "1.3.0"
690 | }
691 | }
692 | }
693 | },
694 | "koa-send": {
695 | "version": "4.1.2",
696 | "resolved": "http://registry.npm.taobao.org/koa-send/download/koa-send-4.1.2.tgz",
697 | "integrity": "sha1-koYdGExNhFilT5LmcI4JsU1kERw=",
698 | "requires": {
699 | "debug": "2.6.9",
700 | "http-errors": "1.6.2",
701 | "mz": "2.7.0",
702 | "resolve-path": "1.3.3"
703 | },
704 | "dependencies": {
705 | "debug": {
706 | "version": "2.6.9",
707 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz",
708 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
709 | "requires": {
710 | "ms": "2.0.0"
711 | }
712 | }
713 | }
714 | },
715 | "koa-session-minimal": {
716 | "version": "3.0.4",
717 | "resolved": "http://registry.npm.taobao.org/koa-session-minimal/download/koa-session-minimal-3.0.4.tgz",
718 | "integrity": "sha1-1qFb7u131dPiakIdu5imH2Oor80=",
719 | "requires": {
720 | "co": "4.6.0",
721 | "deep-equal": "1.0.1",
722 | "uid-safe": "2.1.5"
723 | }
724 | },
725 | "koa-static": {
726 | "version": "4.0.2",
727 | "resolved": "http://registry.npm.taobao.org/koa-static/download/koa-static-4.0.2.tgz",
728 | "integrity": "sha1-bNqS2I13Hcqtnw2CXNlKYxyGGho=",
729 | "requires": {
730 | "debug": "2.6.9",
731 | "koa-send": "4.1.2"
732 | },
733 | "dependencies": {
734 | "debug": {
735 | "version": "2.6.9",
736 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz",
737 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
738 | "requires": {
739 | "ms": "2.0.0"
740 | }
741 | }
742 | }
743 | },
744 | "koa-static-cache": {
745 | "version": "5.1.1",
746 | "resolved": "http://registry.npm.taobao.org/koa-static-cache/download/koa-static-cache-5.1.1.tgz",
747 | "integrity": "sha1-1z3HkYP9BS+GpHoLZAgNhnDeijg=",
748 | "requires": {
749 | "compressible": "2.0.12",
750 | "debug": "3.1.0",
751 | "fs-readdir-recursive": "1.0.0",
752 | "mime-types": "2.1.17",
753 | "mz": "2.6.0"
754 | },
755 | "dependencies": {
756 | "mz": {
757 | "version": "2.6.0",
758 | "resolved": "http://registry.npm.taobao.org/mz/download/mz-2.6.0.tgz",
759 | "integrity": "sha1-yLhSHZWN8KTydoAl22nHGe5O8c4=",
760 | "requires": {
761 | "any-promise": "1.3.0",
762 | "object-assign": "4.1.1",
763 | "thenify-all": "1.6.0"
764 | }
765 | }
766 | }
767 | },
768 | "koa-views": {
769 | "version": "6.1.3",
770 | "resolved": "http://registry.npm.taobao.org/koa-views/download/koa-views-6.1.3.tgz",
771 | "integrity": "sha1-ZusEpgKMaG0bvu32uo+QaaG6QEo=",
772 | "requires": {
773 | "consolidate": "0.15.0",
774 | "debug": "3.1.0",
775 | "get-paths": "0.0.2",
776 | "koa-send": "4.1.2",
777 | "mz": "2.7.0",
778 | "pretty": "2.0.0"
779 | }
780 | },
781 | "koa2-ratelimit": {
782 | "version": "0.4.3",
783 | "resolved": "http://registry.npm.taobao.org/koa2-ratelimit/download/koa2-ratelimit-0.4.3.tgz",
784 | "integrity": "sha1-UR0c8w8fknf0bpD0wroQz5GcItA=",
785 | "requires": {
786 | "moment": "2.20.1",
787 | "sequelize": "4.31.2"
788 | }
789 | },
790 | "linkify-it": {
791 | "version": "2.0.3",
792 | "resolved": "http://registry.npm.taobao.org/linkify-it/download/linkify-it-2.0.3.tgz",
793 | "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=",
794 | "requires": {
795 | "uc.micro": "1.0.3"
796 | }
797 | },
798 | "lodash": {
799 | "version": "4.17.4",
800 | "resolved": "http://registry.npm.taobao.org/lodash/download/lodash-4.17.4.tgz",
801 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
802 | },
803 | "lru-cache": {
804 | "version": "3.2.0",
805 | "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-3.2.0.tgz",
806 | "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=",
807 | "requires": {
808 | "pseudomap": "1.0.2"
809 | }
810 | },
811 | "markdown-it": {
812 | "version": "8.4.0",
813 | "resolved": "http://registry.npm.taobao.org/markdown-it/download/markdown-it-8.4.0.tgz",
814 | "integrity": "sha1-4kAIgb8XH3AY7RvZ2kQdrIr2MG0=",
815 | "requires": {
816 | "argparse": "1.0.9",
817 | "entities": "1.1.1",
818 | "linkify-it": "2.0.3",
819 | "mdurl": "1.0.1",
820 | "uc.micro": "1.0.3"
821 | }
822 | },
823 | "md5": {
824 | "version": "2.2.1",
825 | "resolved": "http://registry.npm.taobao.org/md5/download/md5-2.2.1.tgz",
826 | "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
827 | "requires": {
828 | "charenc": "0.0.2",
829 | "crypt": "0.0.2",
830 | "is-buffer": "1.1.6"
831 | }
832 | },
833 | "mdurl": {
834 | "version": "1.0.1",
835 | "resolved": "http://registry.npm.taobao.org/mdurl/download/mdurl-1.0.1.tgz",
836 | "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
837 | },
838 | "media-typer": {
839 | "version": "0.3.0",
840 | "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz",
841 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
842 | },
843 | "methods": {
844 | "version": "1.1.2",
845 | "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz",
846 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
847 | },
848 | "mime-db": {
849 | "version": "1.30.0",
850 | "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.30.0.tgz",
851 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
852 | },
853 | "mime-types": {
854 | "version": "2.1.17",
855 | "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.17.tgz",
856 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
857 | "requires": {
858 | "mime-db": "1.30.0"
859 | }
860 | },
861 | "minimatch": {
862 | "version": "3.0.4",
863 | "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz",
864 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
865 | "dev": true,
866 | "requires": {
867 | "brace-expansion": "1.1.8"
868 | }
869 | },
870 | "minimist": {
871 | "version": "0.0.10",
872 | "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.10.tgz",
873 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
874 | },
875 | "mkdirp": {
876 | "version": "0.5.1",
877 | "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz",
878 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
879 | "requires": {
880 | "minimist": "0.0.8"
881 | },
882 | "dependencies": {
883 | "minimist": {
884 | "version": "0.0.8",
885 | "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz",
886 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
887 | }
888 | }
889 | },
890 | "mocha": {
891 | "version": "4.1.0",
892 | "resolved": "http://registry.npm.taobao.org/mocha/download/mocha-4.1.0.tgz",
893 | "integrity": "sha1-fYbPvPNcuCnidUwy4XNV7AUzh5Q=",
894 | "dev": true,
895 | "requires": {
896 | "browser-stdout": "1.3.0",
897 | "commander": "2.11.0",
898 | "debug": "3.1.0",
899 | "diff": "3.3.1",
900 | "escape-string-regexp": "1.0.5",
901 | "glob": "7.1.2",
902 | "growl": "1.10.3",
903 | "he": "1.1.1",
904 | "mkdirp": "0.5.1",
905 | "supports-color": "4.4.0"
906 | },
907 | "dependencies": {
908 | "commander": {
909 | "version": "2.11.0",
910 | "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.11.0.tgz",
911 | "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=",
912 | "dev": true
913 | },
914 | "supports-color": {
915 | "version": "4.4.0",
916 | "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-4.4.0.tgz",
917 | "integrity": "sha1-iD992rwWUUKyphQn8zUt7RldGj4=",
918 | "dev": true,
919 | "requires": {
920 | "has-flag": "2.0.0"
921 | }
922 | }
923 | }
924 | },
925 | "moment": {
926 | "version": "2.20.1",
927 | "resolved": "http://registry.npm.taobao.org/moment/download/moment-2.20.1.tgz",
928 | "integrity": "sha1-1usaRsvMFKKy+UNBEsH/iQfzE/0="
929 | },
930 | "moment-timezone": {
931 | "version": "0.5.14",
932 | "resolved": "http://registry.npm.taobao.org/moment-timezone/download/moment-timezone-0.5.14.tgz",
933 | "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=",
934 | "requires": {
935 | "moment": "2.20.1"
936 | }
937 | },
938 | "ms": {
939 | "version": "2.0.0",
940 | "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz",
941 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
942 | },
943 | "mysql": {
944 | "version": "2.15.0",
945 | "resolved": "http://registry.npm.taobao.org/mysql/download/mysql-2.15.0.tgz",
946 | "integrity": "sha1-6haEEVY0Po8uR/yJhexBzdlXO1w=",
947 | "requires": {
948 | "bignumber.js": "4.0.4",
949 | "readable-stream": "2.3.3",
950 | "safe-buffer": "5.1.1",
951 | "sqlstring": "2.3.0"
952 | }
953 | },
954 | "mz": {
955 | "version": "2.7.0",
956 | "resolved": "http://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz",
957 | "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=",
958 | "requires": {
959 | "any-promise": "1.3.0",
960 | "object-assign": "4.1.1",
961 | "thenify-all": "1.6.0"
962 | }
963 | },
964 | "negotiator": {
965 | "version": "0.6.1",
966 | "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz",
967 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
968 | },
969 | "nodemailer": {
970 | "version": "4.4.2",
971 | "resolved": "http://registry.npm.taobao.org/nodemailer/download/nodemailer-4.4.2.tgz",
972 | "integrity": "sha1-8hX7iOihBS+fkwg5CeEW0refyN4="
973 | },
974 | "nopt": {
975 | "version": "3.0.6",
976 | "resolved": "http://registry.npm.taobao.org/nopt/download/nopt-3.0.6.tgz",
977 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
978 | "requires": {
979 | "abbrev": "1.1.1"
980 | }
981 | },
982 | "object-assign": {
983 | "version": "4.1.1",
984 | "resolved": "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz",
985 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
986 | },
987 | "on-finished": {
988 | "version": "2.3.0",
989 | "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz",
990 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
991 | "requires": {
992 | "ee-first": "1.1.1"
993 | }
994 | },
995 | "once": {
996 | "version": "1.4.0",
997 | "resolved": "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz",
998 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
999 | "dev": true,
1000 | "requires": {
1001 | "wrappy": "1.0.2"
1002 | }
1003 | },
1004 | "only": {
1005 | "version": "0.0.2",
1006 | "resolved": "http://registry.npm.taobao.org/only/download/only-0.0.2.tgz",
1007 | "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q="
1008 | },
1009 | "optimist": {
1010 | "version": "0.6.1",
1011 | "resolved": "http://registry.npm.taobao.org/optimist/download/optimist-0.6.1.tgz",
1012 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
1013 | "requires": {
1014 | "minimist": "0.0.10",
1015 | "wordwrap": "0.0.3"
1016 | }
1017 | },
1018 | "parseurl": {
1019 | "version": "1.3.2",
1020 | "resolved": "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz",
1021 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
1022 | },
1023 | "path-is-absolute": {
1024 | "version": "1.0.1",
1025 | "resolved": "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz",
1026 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
1027 | },
1028 | "path-parse": {
1029 | "version": "1.0.5",
1030 | "resolved": "http://registry.npm.taobao.org/path-parse/download/path-parse-1.0.5.tgz",
1031 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
1032 | },
1033 | "path-to-regexp": {
1034 | "version": "1.7.0",
1035 | "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-1.7.0.tgz",
1036 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
1037 | "requires": {
1038 | "isarray": "0.0.1"
1039 | },
1040 | "dependencies": {
1041 | "isarray": {
1042 | "version": "0.0.1",
1043 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz",
1044 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
1045 | }
1046 | }
1047 | },
1048 | "pathval": {
1049 | "version": "1.1.0",
1050 | "resolved": "http://registry.npm.taobao.org/pathval/download/pathval-1.1.0.tgz",
1051 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
1052 | "dev": true
1053 | },
1054 | "pretty": {
1055 | "version": "2.0.0",
1056 | "resolved": "http://registry.npm.taobao.org/pretty/download/pretty-2.0.0.tgz",
1057 | "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=",
1058 | "requires": {
1059 | "condense-newlines": "0.2.1",
1060 | "extend-shallow": "2.0.1",
1061 | "js-beautify": "1.7.5"
1062 | }
1063 | },
1064 | "process-nextick-args": {
1065 | "version": "1.0.7",
1066 | "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-1.0.7.tgz",
1067 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
1068 | },
1069 | "proto-list": {
1070 | "version": "1.2.4",
1071 | "resolved": "http://registry.npm.taobao.org/proto-list/download/proto-list-1.2.4.tgz",
1072 | "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
1073 | },
1074 | "pseudomap": {
1075 | "version": "1.0.2",
1076 | "resolved": "http://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz",
1077 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
1078 | },
1079 | "qs": {
1080 | "version": "6.5.1",
1081 | "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.1.tgz",
1082 | "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg="
1083 | },
1084 | "random-bytes": {
1085 | "version": "1.0.0",
1086 | "resolved": "http://registry.npm.taobao.org/random-bytes/download/random-bytes-1.0.0.tgz",
1087 | "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
1088 | },
1089 | "raw-body": {
1090 | "version": "2.3.2",
1091 | "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.2.tgz",
1092 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
1093 | "requires": {
1094 | "bytes": "3.0.0",
1095 | "http-errors": "1.6.2",
1096 | "iconv-lite": "0.4.19",
1097 | "unpipe": "1.0.0"
1098 | }
1099 | },
1100 | "readable-stream": {
1101 | "version": "2.3.3",
1102 | "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.3.tgz",
1103 | "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=",
1104 | "requires": {
1105 | "core-util-is": "1.0.2",
1106 | "inherits": "2.0.3",
1107 | "isarray": "1.0.0",
1108 | "process-nextick-args": "1.0.7",
1109 | "safe-buffer": "5.1.1",
1110 | "string_decoder": "1.0.3",
1111 | "util-deprecate": "1.0.2"
1112 | }
1113 | },
1114 | "resolve": {
1115 | "version": "1.4.0",
1116 | "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.4.0.tgz",
1117 | "integrity": "sha1-p1vgHFPaJdk0qY69DkxKcxL5KoY=",
1118 | "requires": {
1119 | "path-parse": "1.0.5"
1120 | }
1121 | },
1122 | "resolve-path": {
1123 | "version": "1.3.3",
1124 | "resolved": "http://registry.npm.taobao.org/resolve-path/download/resolve-path-1.3.3.tgz",
1125 | "integrity": "sha1-TYOrpkaMK45jKldeP1Kw+g2+Glw=",
1126 | "requires": {
1127 | "http-errors": "1.5.1",
1128 | "path-is-absolute": "1.0.1"
1129 | },
1130 | "dependencies": {
1131 | "http-errors": {
1132 | "version": "1.5.1",
1133 | "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.5.1.tgz",
1134 | "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=",
1135 | "requires": {
1136 | "inherits": "2.0.3",
1137 | "setprototypeof": "1.0.2",
1138 | "statuses": "1.4.0"
1139 | }
1140 | },
1141 | "setprototypeof": {
1142 | "version": "1.0.2",
1143 | "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.2.tgz",
1144 | "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg="
1145 | }
1146 | }
1147 | },
1148 | "retry-as-promised": {
1149 | "version": "2.3.2",
1150 | "resolved": "http://registry.npm.taobao.org/retry-as-promised/download/retry-as-promised-2.3.2.tgz",
1151 | "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=",
1152 | "requires": {
1153 | "bluebird": "3.5.1",
1154 | "debug": "2.6.9"
1155 | },
1156 | "dependencies": {
1157 | "debug": {
1158 | "version": "2.6.9",
1159 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz",
1160 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
1161 | "requires": {
1162 | "ms": "2.0.0"
1163 | }
1164 | }
1165 | }
1166 | },
1167 | "safe-buffer": {
1168 | "version": "5.1.1",
1169 | "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.1.tgz",
1170 | "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM="
1171 | },
1172 | "semver": {
1173 | "version": "5.4.1",
1174 | "resolved": "http://registry.npm.taobao.org/semver/download/semver-5.4.1.tgz",
1175 | "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4="
1176 | },
1177 | "sequelize": {
1178 | "version": "4.31.2",
1179 | "resolved": "http://registry.npm.taobao.org/sequelize/download/sequelize-4.31.2.tgz",
1180 | "integrity": "sha1-S0FMObrBiudJRu1JswD1vH5CNGI=",
1181 | "requires": {
1182 | "bluebird": "3.5.1",
1183 | "cls-bluebird": "2.1.0",
1184 | "debug": "3.1.0",
1185 | "depd": "1.1.2",
1186 | "dottie": "2.0.0",
1187 | "generic-pool": "3.4.0",
1188 | "inflection": "1.12.0",
1189 | "lodash": "4.17.4",
1190 | "moment": "2.20.1",
1191 | "moment-timezone": "0.5.14",
1192 | "retry-as-promised": "2.3.2",
1193 | "semver": "5.4.1",
1194 | "terraformer-wkt-parser": "1.1.2",
1195 | "toposort-class": "1.0.1",
1196 | "uuid": "3.1.0",
1197 | "validator": "9.2.0",
1198 | "wkx": "0.4.2"
1199 | }
1200 | },
1201 | "setprototypeof": {
1202 | "version": "1.0.3",
1203 | "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz",
1204 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
1205 | },
1206 | "shimmer": {
1207 | "version": "1.2.0",
1208 | "resolved": "http://registry.npm.taobao.org/shimmer/download/shimmer-1.2.0.tgz",
1209 | "integrity": "sha1-+Wb3VVeJdj502IQRk2haXnhzZmU="
1210 | },
1211 | "sigmund": {
1212 | "version": "1.0.1",
1213 | "resolved": "http://registry.npm.taobao.org/sigmund/download/sigmund-1.0.1.tgz",
1214 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
1215 | },
1216 | "sprintf-js": {
1217 | "version": "1.0.3",
1218 | "resolved": "http://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz",
1219 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
1220 | },
1221 | "sqlstring": {
1222 | "version": "2.3.0",
1223 | "resolved": "http://registry.npm.taobao.org/sqlstring/download/sqlstring-2.3.0.tgz",
1224 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg="
1225 | },
1226 | "statuses": {
1227 | "version": "1.4.0",
1228 | "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz",
1229 | "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic="
1230 | },
1231 | "string_decoder": {
1232 | "version": "1.0.3",
1233 | "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.0.3.tgz",
1234 | "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
1235 | "requires": {
1236 | "safe-buffer": "5.1.1"
1237 | }
1238 | },
1239 | "supports-color": {
1240 | "version": "4.5.0",
1241 | "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-4.5.0.tgz",
1242 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
1243 | "requires": {
1244 | "has-flag": "2.0.0"
1245 | }
1246 | },
1247 | "terraformer": {
1248 | "version": "1.0.8",
1249 | "resolved": "http://registry.npm.taobao.org/terraformer/download/terraformer-1.0.8.tgz",
1250 | "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=",
1251 | "requires": {
1252 | "@types/geojson": "1.0.6"
1253 | }
1254 | },
1255 | "terraformer-wkt-parser": {
1256 | "version": "1.1.2",
1257 | "resolved": "http://registry.npm.taobao.org/terraformer-wkt-parser/download/terraformer-wkt-parser-1.1.2.tgz",
1258 | "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=",
1259 | "requires": {
1260 | "terraformer": "1.0.8"
1261 | }
1262 | },
1263 | "text-censor": {
1264 | "version": "1.0.2",
1265 | "resolved": "http://registry.npm.taobao.org/text-censor/download/text-censor-1.0.2.tgz",
1266 | "integrity": "sha1-Z6ftmukXSVlhOqHyufabZrkIokk="
1267 | },
1268 | "thenify": {
1269 | "version": "3.3.0",
1270 | "resolved": "http://registry.npm.taobao.org/thenify/download/thenify-3.3.0.tgz",
1271 | "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=",
1272 | "requires": {
1273 | "any-promise": "1.3.0"
1274 | }
1275 | },
1276 | "thenify-all": {
1277 | "version": "1.6.0",
1278 | "resolved": "http://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz",
1279 | "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
1280 | "requires": {
1281 | "thenify": "3.3.0"
1282 | }
1283 | },
1284 | "toml": {
1285 | "version": "2.3.2",
1286 | "resolved": "http://registry.npm.taobao.org/toml/download/toml-2.3.2.tgz",
1287 | "integrity": "sha1-Xt7VykKIeSSUn9BusOlVZWAB6DQ="
1288 | },
1289 | "toposort-class": {
1290 | "version": "1.0.1",
1291 | "resolved": "http://registry.npm.taobao.org/toposort-class/download/toposort-class-1.0.1.tgz",
1292 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg="
1293 | },
1294 | "trek-captcha": {
1295 | "version": "0.4.0",
1296 | "resolved": "http://registry.npm.taobao.org/trek-captcha/download/trek-captcha-0.4.0.tgz",
1297 | "integrity": "sha1-IbV8SeLUMcJmr/IQDMqzO24TwMA="
1298 | },
1299 | "type-detect": {
1300 | "version": "4.0.5",
1301 | "resolved": "http://registry.npm.taobao.org/type-detect/download/type-detect-4.0.5.tgz",
1302 | "integrity": "sha1-1w5byB223io4G8rKDG4MvcdjXeI=",
1303 | "dev": true
1304 | },
1305 | "type-is": {
1306 | "version": "1.6.15",
1307 | "resolved": "http://registry.npm.taobao.org/type-is/download/type-is-1.6.15.tgz",
1308 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
1309 | "requires": {
1310 | "media-typer": "0.3.0",
1311 | "mime-types": "2.1.17"
1312 | }
1313 | },
1314 | "uc.micro": {
1315 | "version": "1.0.3",
1316 | "resolved": "http://registry.npm.taobao.org/uc.micro/download/uc.micro-1.0.3.tgz",
1317 | "integrity": "sha1-ftUNXg+an7ClczeSWfKndFjVAZI="
1318 | },
1319 | "uid-safe": {
1320 | "version": "2.1.5",
1321 | "resolved": "http://registry.npm.taobao.org/uid-safe/download/uid-safe-2.1.5.tgz",
1322 | "integrity": "sha1-Kz1cckDo/C5Y+Komnl7knAhXvTo=",
1323 | "requires": {
1324 | "random-bytes": "1.0.0"
1325 | }
1326 | },
1327 | "universalify": {
1328 | "version": "0.1.1",
1329 | "resolved": "http://registry.npm.taobao.org/universalify/download/universalify-0.1.1.tgz",
1330 | "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
1331 | },
1332 | "unpipe": {
1333 | "version": "1.0.0",
1334 | "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz",
1335 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
1336 | },
1337 | "urijs": {
1338 | "version": "1.19.0",
1339 | "resolved": "http://registry.npm.taobao.org/urijs/download/urijs-1.19.0.tgz",
1340 | "integrity": "sha1-2KooTQ50aXA6aYitBFxMv98IraA="
1341 | },
1342 | "util-deprecate": {
1343 | "version": "1.0.2",
1344 | "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz",
1345 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
1346 | },
1347 | "uuid": {
1348 | "version": "3.1.0",
1349 | "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.1.0.tgz",
1350 | "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ="
1351 | },
1352 | "validator": {
1353 | "version": "9.2.0",
1354 | "resolved": "http://registry.npm.taobao.org/validator/download/validator-9.2.0.tgz",
1355 | "integrity": "sha1-rSFu7V83ysMab+AM6rH2uIve0D4="
1356 | },
1357 | "vary": {
1358 | "version": "1.1.2",
1359 | "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz",
1360 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
1361 | },
1362 | "wkx": {
1363 | "version": "0.4.2",
1364 | "resolved": "http://registry.npm.taobao.org/wkx/download/wkx-0.4.2.tgz",
1365 | "integrity": "sha1-d201pjSlwi5lbkdEvetU+D/Szo0=",
1366 | "requires": {
1367 | "@types/node": "9.3.0"
1368 | }
1369 | },
1370 | "wordwrap": {
1371 | "version": "0.0.3",
1372 | "resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-0.0.3.tgz",
1373 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
1374 | },
1375 | "wrappy": {
1376 | "version": "1.0.2",
1377 | "resolved": "http://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz",
1378 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1379 | "dev": true
1380 | }
1381 | }
1382 | }
1383 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Koa2 blog",
3 | "version": "1.0.0",
4 | "description": "A simple blog system.",
5 | "main": "index.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "scripts": {
10 | "start": "node index.js"
11 | },
12 | "author": "Najeh Luo",
13 | "license": "MIT",
14 | "dependencies": {
15 | "config-lite": "^2.0.0",
16 | "ejs": "^2.5.6",
17 | "koa": "^2.3.0",
18 | "koa-bodyparser": "^4.2.0",
19 | "koa-convert": "^1.2.0",
20 | "koa-mysql-session": "^0.0.2",
21 | "koa-router": "^7.2.1",
22 | "koa-session-minimal": "^3.0.4",
23 | "koa-static": "^4.0.0",
24 | "koa-static-cache": "^5.1.1",
25 | "koa-views": "^6.0.2",
26 | "koa2-ratelimit": "^0.4.3",
27 | "markdown-it": "^8.4.0",
28 | "md5": "^2.2.1",
29 | "moment": "^2.18.1",
30 | "mysql": "^2.13.0",
31 | "nodemailer": "^4.4.2",
32 | "text-censor": "^1.0.2",
33 | "trek-captcha": "^0.4.0"
34 | },
35 | "devDependencies": {
36 | "chai": "^4.1.2",
37 | "mocha": "^4.0.1"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/public/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/avatar.jpg
--------------------------------------------------------------------------------
/public/custom.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Cairo,PingHei,'PingFang SC',Helvetica Neue,'Work Sans','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif;
3 | background-color: #FCFCFC;
4 | }
5 |
6 | h1 { font-size: 2.1rem; }
7 | h2 { font-size: 1.9rem; }
8 | h3 { font-size: 1.7rem; }
9 | h4,
10 | h5,
11 | h6 { font-size: 1.5rem; }
12 |
13 | img {
14 | max-width: 100%;
15 | height: auto;
16 | vertical-align: middle;
17 | border: 0;
18 | }
19 |
20 | header,
21 | footer {
22 | margin: 4rem 0;
23 | text-align: center;
24 | }
25 |
26 | main {
27 | margin: 4rem 0;
28 | }
29 |
30 | .container {
31 | width: 90%;
32 | max-width: 700px;
33 | }
34 |
35 | .header-logo img {
36 | width: 80px;
37 | height: 80px;
38 | border-radius: 50%;
39 | border: 1px solid #E1E1E1;
40 | box-shadow: 0 0 0 3px #fff, 0 0 0 4px #eee;
41 | }
42 |
43 | .header-logo img:hover {
44 | border-color: #F1F1F1;
45 | }
46 |
47 | nav {
48 | text-align: right;
49 | padding: 20px 20px 0;
50 | }
51 |
52 | nav a {
53 | padding: 8px 6px 8px 0;
54 | color: #333;
55 | font-weight: 300;
56 | font-size: 1.4rem;
57 | text-decoration: none;
58 | }
59 |
60 | .site-title {
61 | margin-top: 2rem;
62 | color: #444;
63 | font-weight: 400;
64 | font-size: 2.4rem;
65 | }
66 |
67 | .site-second-title {
68 | font-size: 1.4rem;
69 | font-weight: 300;
70 | font-style: normal;
71 | margin-top: 10px;
72 | text-transform: uppercase;
73 | color: #aaa;
74 | /* letter-spacing: .5rem; */
75 | word-spacing: .5rem;
76 | }
77 |
78 | .article {
79 | padding: 20px 0;
80 | border-top: 1px solid #eee;
81 | }
82 |
83 | .article:last-child {
84 | border-bottom: 1px solid #eee;
85 | }
86 |
87 | .entry-title {
88 | margin-bottom: 0;
89 | position: relative;
90 | }
91 |
92 | .entry-title a {
93 | text-decoration: none;
94 | color: #333;
95 | font: 300 19px/1.7 Cairo,PingHei,'PingFang SC',Helvetica Neue,'Work Sans','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif;
96 | display: block;
97 | text-transform: uppercase;
98 | }
99 |
100 | .entry-meta {
101 | display: inline-block;
102 | margin-bottom: 2rem;
103 | font-size: 1.7rem;
104 | color: #888;
105 | float: right;
106 | }
107 |
108 | @media screen and (max-width: 500px) {
109 | .entry-meta {
110 | display: none;
111 | }
112 | }
113 |
114 | .article-title {
115 | text-align: center;
116 | margin-bottom: 1rem;
117 | font-size: 2.8rem;
118 | color: #222;
119 | }
120 |
121 | .article-meta {
122 | text-align: center;
123 | margin-bottom: 2rem;
124 | font-size: 1.7rem;
125 | color: #888;
126 | }
127 |
128 | .article h1, .article h2, .article h3, .article h4, .article h5, .article h6{
129 | font-weight: 400;
130 | }
131 |
132 | .footer-link {
133 | margin: 2rem 0;
134 | }
135 | .footer-link a {
136 | text-decoration: none;
137 | }
138 | .iconfont {
139 | font-size: 3rem;
140 | color: #cdd4da;
141 | }
142 | /* .icon-qq {
143 | color: rgb(0, 108, 226);
144 | }
145 | .icon-weibo {
146 | color: rgb(230, 22, 45);
147 | }
148 | .icon-github {
149 | color: #333;
150 | }
151 | .icon-zhihu {
152 | color: rgb(94, 170, 222);
153 | } */
154 |
155 | .copyright {
156 | color: #222;
157 | }
158 | .copyright a {
159 | color: #5694f1;
160 | text-decoration: none;
161 | }
162 | .hr {
163 | height: 1px;
164 | margin: 2rem 0;
165 | background: #E1E1E1;
166 | background: -webkit-gradient(linear, left top, right top, from(white), color-stop(#E1E1E1), to(white));
167 | background: -webkit-linear-gradient(left, white, #E1E1E1, white);
168 | background: linear-gradient(to right, white, #E1E1E1, white);
169 | }
170 |
171 | .message {
172 | position: fixed;
173 | top: -100%;
174 | left: 50%;
175 | transform: translateX(-50%);
176 | padding: 1em 1em;
177 | background: rgba(0, 0, 0, 0.7);
178 | color: #fff;
179 | border-bottom-left-radius: .4em;
180 | border-bottom-right-radius: .4em;
181 | z-index: 99999;
182 | }
183 |
184 | .submit {
185 | background-color: #8796a3;
186 | border-radius: 5px;
187 | color: #fff;
188 | text-align: center;
189 | }
190 |
191 | .signout, .submit, .delete_post, .submit_comment {
192 | cursor: pointer;
193 | }
194 |
195 | .signout {
196 | padding: 8px 6px 8px 0;
197 | color: #333;
198 | font-weight: 300;
199 | font-size: 1.4rem;
200 | text-decoration: none;
201 | }
202 |
203 | .pagenav a {
204 | padding: 0 5px
205 | }
206 |
207 | .pagenav a:hover {
208 | background-color: #32393f;
209 | color: #fff
210 | }
211 |
212 | .photo_item {
213 | width: 100%;
214 | }
215 |
216 | .photo_wrap {
217 | display: inline-block;
218 | margin: 0.625em;
219 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/article.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/article.PNG
--------------------------------------------------------------------------------
/public/images/home.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/home.PNG
--------------------------------------------------------------------------------
/public/images/login.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/login.PNG
--------------------------------------------------------------------------------
/public/images/photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/photo.png
--------------------------------------------------------------------------------
/public/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2 |
3 | /**
4 | * 1. Set default font family to sans-serif.
5 | * 2. Prevent iOS text size adjust after orientation change, without disabling
6 | * user zoom.
7 | */
8 |
9 | html {
10 | font-family: sans-serif; /* 1 */
11 | -ms-text-size-adjust: 100%; /* 2 */
12 | -webkit-text-size-adjust: 100%; /* 2 */
13 | }
14 |
15 | /**
16 | * Remove default margin.
17 | */
18 |
19 | body {
20 | margin: 0;
21 | }
22 |
23 | /* HTML5 display definitions
24 | ========================================================================== */
25 |
26 | /**
27 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
29 | * and Firefox.
30 | * Correct `block` display not defined for `main` in IE 11.
31 | */
32 |
33 | article,
34 | aside,
35 | details,
36 | figcaption,
37 | figure,
38 | footer,
39 | header,
40 | hgroup,
41 | main,
42 | menu,
43 | nav,
44 | section,
45 | summary {
46 | display: block;
47 | }
48 |
49 | /**
50 | * 1. Correct `inline-block` display not defined in IE 8/9.
51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
52 | */
53 |
54 | audio,
55 | canvas,
56 | progress,
57 | video {
58 | display: inline-block; /* 1 */
59 | vertical-align: baseline; /* 2 */
60 | }
61 |
62 | /**
63 | * Prevent modern browsers from displaying `audio` without controls.
64 | * Remove excess height in iOS 5 devices.
65 | */
66 |
67 | audio:not([controls]) {
68 | display: none;
69 | height: 0;
70 | }
71 |
72 | /**
73 | * Address `[hidden]` styling not present in IE 8/9/10.
74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
75 | */
76 |
77 | [hidden],
78 | template {
79 | display: none;
80 | }
81 |
82 | /* Links
83 | ========================================================================== */
84 |
85 | /**
86 | * Remove the gray background color from active links in IE 10.
87 | */
88 |
89 | a {
90 | background-color: transparent;
91 | }
92 |
93 | /**
94 | * Improve readability when focused and also mouse hovered in all browsers.
95 | */
96 |
97 | a:active,
98 | a:hover {
99 | outline: 0;
100 | }
101 |
102 | /* Text-level semantics
103 | ========================================================================== */
104 |
105 | /**
106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107 | */
108 |
109 | abbr[title] {
110 | border-bottom: 1px dotted;
111 | }
112 |
113 | /**
114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115 | */
116 |
117 | b,
118 | strong {
119 | font-weight: bold;
120 | }
121 |
122 | /**
123 | * Address styling not present in Safari and Chrome.
124 | */
125 |
126 | dfn {
127 | font-style: italic;
128 | }
129 |
130 | /**
131 | * Address variable `h1` font-size and margin within `section` and `article`
132 | * contexts in Firefox 4+, Safari, and Chrome.
133 | */
134 |
135 | h1 {
136 | font-size: 2em;
137 | margin: 0.67em 0;
138 | }
139 |
140 | /**
141 | * Address styling not present in IE 8/9.
142 | */
143 |
144 | mark {
145 | background: #ff0;
146 | color: #000;
147 | }
148 |
149 | /**
150 | * Address inconsistent and variable font size in all browsers.
151 | */
152 |
153 | small {
154 | font-size: 80%;
155 | }
156 |
157 | /**
158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159 | */
160 |
161 | sub,
162 | sup {
163 | font-size: 75%;
164 | line-height: 0;
165 | position: relative;
166 | vertical-align: baseline;
167 | }
168 |
169 | sup {
170 | top: -0.5em;
171 | }
172 |
173 | sub {
174 | bottom: -0.25em;
175 | }
176 |
177 | /* Embedded content
178 | ========================================================================== */
179 |
180 | /**
181 | * Remove border when inside `a` element in IE 8/9/10.
182 | */
183 |
184 | img {
185 | border: 0;
186 | }
187 |
188 | /**
189 | * Correct overflow not hidden in IE 9/10/11.
190 | */
191 |
192 | svg:not(:root) {
193 | overflow: hidden;
194 | }
195 |
196 | /* Grouping content
197 | ========================================================================== */
198 |
199 | /**
200 | * Address margin not present in IE 8/9 and Safari.
201 | */
202 |
203 | figure {
204 | margin: 1em 40px;
205 | }
206 |
207 | /**
208 | * Address differences between Firefox and other browsers.
209 | */
210 |
211 | hr {
212 | -moz-box-sizing: content-box;
213 | box-sizing: content-box;
214 | height: 0;
215 | }
216 |
217 | /**
218 | * Contain overflow in all browsers.
219 | */
220 |
221 | pre {
222 | overflow: auto;
223 | }
224 |
225 | /**
226 | * Address odd `em`-unit font size rendering in all browsers.
227 | */
228 |
229 | code,
230 | kbd,
231 | pre,
232 | samp {
233 | font-family: monospace, monospace;
234 | font-size: 1em;
235 | }
236 |
237 | /* Forms
238 | ========================================================================== */
239 |
240 | /**
241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
242 | * styling of `select`, unless a `border` property is set.
243 | */
244 |
245 | /**
246 | * 1. Correct color not being inherited.
247 | * Known issue: affects color of disabled elements.
248 | * 2. Correct font properties not being inherited.
249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
250 | */
251 |
252 | button,
253 | input,
254 | optgroup,
255 | select,
256 | textarea {
257 | color: inherit; /* 1 */
258 | font: inherit; /* 2 */
259 | margin: 0; /* 3 */
260 | }
261 |
262 | /**
263 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
264 | */
265 |
266 | button {
267 | overflow: visible;
268 | }
269 |
270 | /**
271 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
272 | * All other form control elements do not inherit `text-transform` values.
273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
274 | * Correct `select` style inheritance in Firefox.
275 | */
276 |
277 | button,
278 | select {
279 | text-transform: none;
280 | }
281 |
282 | /**
283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
284 | * and `video` controls.
285 | * 2. Correct inability to style clickable `input` types in iOS.
286 | * 3. Improve usability and consistency of cursor style between image-type
287 | * `input` and others.
288 | */
289 |
290 | button,
291 | html input[type="button"], /* 1 */
292 | input[type="reset"],
293 | input[type="submit"] {
294 | -webkit-appearance: button; /* 2 */
295 | cursor: pointer; /* 3 */
296 | }
297 |
298 | /**
299 | * Re-set default cursor for disabled elements.
300 | */
301 |
302 | button[disabled],
303 | html input[disabled] {
304 | cursor: default;
305 | }
306 |
307 | /**
308 | * Remove inner padding and border in Firefox 4+.
309 | */
310 |
311 | button::-moz-focus-inner,
312 | input::-moz-focus-inner {
313 | border: 0;
314 | padding: 0;
315 | }
316 |
317 | /**
318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
319 | * the UA stylesheet.
320 | */
321 |
322 | input {
323 | line-height: normal;
324 | }
325 |
326 | /**
327 | * It's recommended that you don't attempt to style these elements.
328 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
329 | *
330 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
331 | * 2. Remove excess padding in IE 8/9/10.
332 | */
333 |
334 | input[type="checkbox"],
335 | input[type="radio"] {
336 | box-sizing: border-box; /* 1 */
337 | padding: 0; /* 2 */
338 | }
339 |
340 | /**
341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
342 | * `font-size` values of the `input`, it causes the cursor style of the
343 | * decrement button to change from `default` to `text`.
344 | */
345 |
346 | input[type="number"]::-webkit-inner-spin-button,
347 | input[type="number"]::-webkit-outer-spin-button {
348 | height: auto;
349 | }
350 |
351 | /**
352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
354 | * (include `-moz` to future-proof).
355 | */
356 |
357 | input[type="search"] {
358 | -webkit-appearance: textfield; /* 1 */
359 | -moz-box-sizing: content-box;
360 | -webkit-box-sizing: content-box; /* 2 */
361 | box-sizing: content-box;
362 | }
363 |
364 | /**
365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
366 | * Safari (but not Chrome) clips the cancel button when the search input has
367 | * padding (and `textfield` appearance).
368 | */
369 |
370 | input[type="search"]::-webkit-search-cancel-button,
371 | input[type="search"]::-webkit-search-decoration {
372 | -webkit-appearance: none;
373 | }
374 |
375 | /**
376 | * Define consistent border, margin, and padding.
377 | */
378 |
379 | fieldset {
380 | border: 1px solid #c0c0c0;
381 | margin: 0 2px;
382 | padding: 0.35em 0.625em 0.75em;
383 | }
384 |
385 | /**
386 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
388 | */
389 |
390 | legend {
391 | border: 0; /* 1 */
392 | padding: 0; /* 2 */
393 | }
394 |
395 | /**
396 | * Remove default vertical scrollbar in IE 8/9/10/11.
397 | */
398 |
399 | textarea {
400 | overflow: auto;
401 | }
402 |
403 | /**
404 | * Don't inherit the `font-weight` (applied by a rule above).
405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
406 | */
407 |
408 | optgroup {
409 | font-weight: bold;
410 | }
411 |
412 | /* Tables
413 | ========================================================================== */
414 |
415 | /**
416 | * Remove most spacing between table cells.
417 | */
418 |
419 | table {
420 | border-collapse: collapse;
421 | border-spacing: 0;
422 | }
423 |
424 | td,
425 | th {
426 | padding: 0;
427 | }
--------------------------------------------------------------------------------
/public/pagination.js:
--------------------------------------------------------------------------------
1 | function pagination(data,callback){
2 | // css鏍峰紡
3 | if(!document.getElementById('pageStyle')){
4 | var style = document.createElement('style')
5 | style.id = 'pageStyle'
6 | style.innerHTML='.pagination{text-align:center;}.pagination a,.pagination span{margin:0 .1em;color:#39434d;background:#fff;text-decoration:none;border-radius:4px;user-select:none;cursor:pointer}.pagination a:hover,.pagination span:hover{color:#fff;background:#8796a3}.pagination .active{color:#fff;background:#8796a3;cursor:default;}.pagination input{width:40px;padding:7px 0;border:none;outline:0;border:1px solid #ddd;border-radius:4px;text-align:center;margin:0 5px}.pagination i{font-style: normal;margin:0 5px;color:#999}.pagination input:focus{border:1px solid #428bca}'
7 | document.getElementsByTagName('head')[0].appendChild(style)
8 | }
9 | var page = document.getElementById(data.selector.slice(1)),
10 | nextPage = document.getElementById('nextPage'),
11 | // prevPage = document.getElementById('prevPage'),
12 | inputGo = document.getElementById('inputGo'),
13 | currentPage = data.currentPage,
14 | nowPage = currentPage ? currentPage : 1,
15 | visiblePage = Math.ceil(data.visiblePage / 2),
16 | i_html = '',
17 | pageOneLoad = data.pageOneLoad ? false : true;
18 | // 鍒濆鍖�
19 | pageAction(nowPage)
20 | function pageAction(dataPage){
21 | nowPage = dataPage;
22 | i_html = '';
23 | var count = data.count <= 1 ? 1 : data.count ? data.count : 2
24 | startPage = dataPage - data.count <= 1 ? 1 : dataPage - data.count,
25 | endPage = dataPage + data.count >= data.totalPage ? data.totalPage : dataPage + data.count,
26 | prevPage = data.prev ? data.prev : '<',
27 | nextPage = data.next ? data.next : '>';
28 | // if (dataPage > 1) {
29 | // i_html += ''+ prevPage +''
30 | // if (data.first) {
31 | // i_html += '首页'
32 | // }
33 | // }
34 | if (dataPage >= 5) {
35 | for (var i = 1 ; i <= 2; i++) {
36 | i_html += ''+ i +''
37 | }
38 | i_html += '...'
39 | }
40 | for (var j = startPage; j <= endPage ; j++) {
41 | i_html += ''+ j +''
42 | }
43 | if (endPage + 1 < data.totalPage) {
44 | i_html += '...'
45 | for (var i = (endPage > data.totalPage - 2 ? data.totalPage : data.totalPage - 1 ); i <= data.totalPage; i++) {
46 | i_html += ''+ i +''
47 | }
48 | if (data.last) {
49 | i_html += '灏鹃〉'
50 | }
51 | i_html += ''+ nextPage +''
52 | }
53 | if (data.showTotalPage && data.totalPage >= 1) {
54 | i_html += ''+ nowPage+'/'+data.totalPage +''
55 | }
56 | if (data.jumpBtn && data.totalPage >= 1) {
57 | i_html += '鍓嶅線椤� 纭畾'
58 | }
59 | page.innerHTML = i_html;
60 | var pageA = page.getElementsByTagName('a');
61 | for (var i = 0,pageALength = pageA.length; i < pageALength; i++) {
62 | pageA[i].className = ''
63 | if (pageA[i].getAttribute('data-page') == dataPage ) {
64 | pageA[i].className = "active"
65 | }
66 | }
67 | // 绗竴椤典笉璇锋眰
68 | if (!pageOneLoad) {
69 | callback && callback.call(null,dataPage)
70 | }
71 | }
72 | page.onclick = function(event){
73 | var event = event || window.event,
74 | target = event.target || event.srcElement,
75 | dataPage = parseInt(target.getAttribute('data-page'));
76 | pageOneLoad = false;
77 | if (target.className == 'active') return
78 | if (target.nodeName.toLowerCase() == 'a') {
79 | pageAction(dataPage)
80 | }
81 | if (target.id == 'nextPage') {
82 | nowPage++
83 | pageAction(nowPage)
84 | }
85 | if (target.id == 'prevPage') {
86 | nowPage--
87 | pageAction(nowPage)
88 | }
89 | if (target.id == 'inputGo') {
90 | var pageInput = document.getElementById('pageInput'),
91 | goPage = pageInput.value > data.totalPage ? 1 : /[1-9]+/g.test(pageInput.value) ? pageInput.value : 1;
92 | pageAction(parseInt(goPage))
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/public/pictureHandle.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var _upFile=document.getElementById("upFile");
3 |
4 | _upFile.addEventListener("change",function(){
5 |
6 | if (_upFile.files.length === 0) {
7 | // alert("璇烽€夋嫨鍥剧墖");
8 | return; }
9 | var oFile = _upFile.files[0];
10 | //if (!rFilter.test(oFile.type)) { alert("You must select a valid image file!"); return; }
11 |
12 | /* if(oFile.size>5*1024*1024){
13 | message(myCache.par.lang,{cn:"鐓х墖涓婁紶锛氭枃浠朵笉鑳借秴杩�5MB!璇蜂娇鐢ㄥ閲忔洿灏忕殑鐓х墖銆�",en:"璇佷功涓婁紶锛氭枃浠朵笉鑳借秴杩�100K!"})
14 |
15 | return;
16 | }*/
17 | if(!new RegExp("(jpg|jpeg|png)+","gi").test(oFile.type)){
18 | // alert("鐓х墖涓婁紶锛氭枃浠剁被鍨嬪繀椤绘槸JPG銆丣PEG銆丳NG");
19 | return;
20 | }
21 |
22 | var reader = new FileReader();
23 | reader.onload = function(e) {
24 | var base64Img= e.target.result;
25 | //鍘嬬缉鍓嶉瑙�
26 | // $("#preview").attr("src",base64Img);
27 |
28 | //--鎵цresize銆�
29 | var _ir=ImageResizer({
30 | resizeMode:"auto"
31 | ,dataSource:base64Img
32 | ,dataSourceType:"base64"
33 | ,maxWidth:1200 //鍏佽鐨勬渶澶у搴�
34 | ,maxHeight:600 //鍏佽鐨勬渶澶ч珮搴︺€�
35 | ,onTmpImgGenerate:function(img){
36 |
37 | }
38 | ,success:function(resizeImgBase64,canvas){
39 | //鍘嬬缉鍚庨瑙�
40 | $("#nextview").attr("src",resizeImgBase64);
41 |
42 | //璧嬪€煎埌闅愯棌鍩熶紶缁欏悗鍙�
43 | $('#img').val(resizeImgBase64.substr(23));
44 |
45 |
46 |
47 | }
48 | ,debug:true
49 | });
50 |
51 | };
52 | reader.readAsDataURL(oFile);
53 |
54 | },false);
55 |
56 | });
--------------------------------------------------------------------------------
/public/skeleton.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skeleton V2.0.4
3 | * Copyright 2014, Dave Gamache
4 | * www.getskeleton.com
5 | * Free to use under the MIT license.
6 | * http://www.opensource.org/licenses/mit-license.php
7 | * 12/29/2014
8 | */
9 |
10 |
11 | /* Table of contents
12 | ––––––––––––––––––––––––––––––––––––––––––––––––––
13 | - Grid
14 | - Base Styles
15 | - Typography
16 | - Links
17 | - Buttons
18 | - Forms
19 | - Lists
20 | - Code
21 | - Tables
22 | - Spacing
23 | - Utilities
24 | - Clearing
25 | - Media Queries
26 | */
27 |
28 |
29 | /* Grid
30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
31 | .container {
32 | position: relative;
33 | width: 100%;
34 | max-width: 960px;
35 | margin: 0 auto;
36 | /* padding: 0 20px; */
37 | box-sizing: border-box; }
38 | .column,
39 | .columns {
40 | width: 100%;
41 | float: left;
42 | box-sizing: border-box; }
43 |
44 | /* For devices larger than 400px */
45 | @media (min-width: 400px) {
46 | .container {
47 | width: 85%;
48 | padding: 0; }
49 | }
50 |
51 | /* For devices larger than 550px */
52 | @media (min-width: 550px) {
53 | .container {
54 | width: 80%; }
55 | .column,
56 | .columns {
57 | margin-left: 4%; }
58 | .column:first-child,
59 | .columns:first-child {
60 | margin-left: 0; }
61 |
62 | .one.column,
63 | .one.columns { width: 4.66666666667%; }
64 | .two.columns { width: 13.3333333333%; }
65 | .three.columns { width: 22%; }
66 | .four.columns { width: 30.6666666667%; }
67 | .five.columns { width: 39.3333333333%; }
68 | .six.columns { width: 48%; }
69 | .seven.columns { width: 56.6666666667%; }
70 | .eight.columns { width: 65.3333333333%; }
71 | .nine.columns { width: 74.0%; }
72 | .ten.columns { width: 82.6666666667%; }
73 | .eleven.columns { width: 91.3333333333%; }
74 | .twelve.columns { width: 100%; margin-left: 0; }
75 |
76 | .one-third.column { width: 30.6666666667%; }
77 | .two-thirds.column { width: 65.3333333333%; }
78 |
79 | .one-half.column { width: 48%; }
80 |
81 | /* Offsets */
82 | .offset-by-one.column,
83 | .offset-by-one.columns { margin-left: 8.66666666667%; }
84 | .offset-by-two.column,
85 | .offset-by-two.columns { margin-left: 17.3333333333%; }
86 | .offset-by-three.column,
87 | .offset-by-three.columns { margin-left: 26%; }
88 | .offset-by-four.column,
89 | .offset-by-four.columns { margin-left: 34.6666666667%; }
90 | .offset-by-five.column,
91 | .offset-by-five.columns { margin-left: 43.3333333333%; }
92 | .offset-by-six.column,
93 | .offset-by-six.columns { margin-left: 52%; }
94 | .offset-by-seven.column,
95 | .offset-by-seven.columns { margin-left: 60.6666666667%; }
96 | .offset-by-eight.column,
97 | .offset-by-eight.columns { margin-left: 69.3333333333%; }
98 | .offset-by-nine.column,
99 | .offset-by-nine.columns { margin-left: 78.0%; }
100 | .offset-by-ten.column,
101 | .offset-by-ten.columns { margin-left: 86.6666666667%; }
102 | .offset-by-eleven.column,
103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; }
104 |
105 | .offset-by-one-third.column,
106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; }
107 | .offset-by-two-thirds.column,
108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
109 |
110 | .offset-by-one-half.column,
111 | .offset-by-one-half.columns { margin-left: 52%; }
112 |
113 | }
114 |
115 |
116 | /* Base Styles
117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
118 | /* NOTE
119 | html is set to 62.5% so that all the REM measurements throughout Skeleton
120 | are based on 10px sizing. So basically 1.5rem = 15px :) */
121 | html {
122 | font-size: 62.5%; }
123 | body {
124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
125 | line-height: 1.6;
126 | font-weight: 400;
127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
128 | color: #222; }
129 |
130 |
131 | /* Typography
132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
133 | h1, h2, h3, h4, h5, h6 {
134 | margin-top: 0;
135 | margin-bottom: 2rem;
136 | font-weight: 300; }
137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
143 |
144 | /* Larger than phablet */
145 | @media (min-width: 550px) {
146 | h1 { font-size: 5.0rem; }
147 | h2 { font-size: 4.2rem; }
148 | h3 { font-size: 3.6rem; }
149 | h4 { font-size: 3.0rem; }
150 | h5 { font-size: 2.4rem; }
151 | h6 { font-size: 1.5rem; }
152 | }
153 |
154 | p {
155 | margin-top: 0; }
156 |
157 |
158 | /* Links
159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
160 | a {
161 | color: #1EAEDB; }
162 | a:hover {
163 | color: #0FA0CE; }
164 |
165 |
166 | /* Buttons
167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
168 | .button,
169 | button,
170 | input[type="submit"],
171 | input[type="reset"],
172 | input[type="button"] {
173 | display: inline-block;
174 | height: 38px;
175 | padding: 0 30px;
176 | color: #555;
177 | text-align: center;
178 | font-size: 11px;
179 | font-weight: 600;
180 | line-height: 38px;
181 | letter-spacing: .1rem;
182 | text-transform: uppercase;
183 | text-decoration: none;
184 | white-space: nowrap;
185 | background-color: transparent;
186 | border-radius: 4px;
187 | border: 1px solid #bbb;
188 | cursor: pointer;
189 | box-sizing: border-box; }
190 | .button:hover,
191 | button:hover,
192 | input[type="submit"]:hover,
193 | input[type="reset"]:hover,
194 | input[type="button"]:hover,
195 | .button:focus,
196 | button:focus,
197 | input[type="submit"]:focus,
198 | input[type="reset"]:focus,
199 | input[type="button"]:focus {
200 | color: #333;
201 | border-color: #888;
202 | outline: 0; }
203 | .button.button-primary,
204 | button.button-primary,
205 | input[type="submit"].button-primary,
206 | input[type="reset"].button-primary,
207 | input[type="button"].button-primary {
208 | color: #FFF;
209 | background-color: #33C3F0;
210 | border-color: #33C3F0; }
211 | .button.button-primary:hover,
212 | button.button-primary:hover,
213 | input[type="submit"].button-primary:hover,
214 | input[type="reset"].button-primary:hover,
215 | input[type="button"].button-primary:hover,
216 | .button.button-primary:focus,
217 | button.button-primary:focus,
218 | input[type="submit"].button-primary:focus,
219 | input[type="reset"].button-primary:focus,
220 | input[type="button"].button-primary:focus {
221 | color: #FFF;
222 | background-color: #1EAEDB;
223 | border-color: #1EAEDB; }
224 |
225 |
226 | /* Forms
227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
228 | input[type="email"],
229 | input[type="number"],
230 | input[type="search"],
231 | input[type="text"],
232 | input[type="tel"],
233 | input[type="url"],
234 | input[type="password"],
235 | textarea,
236 | select {
237 | height: 38px;
238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
239 | background-color: #fff;
240 | border: 1px solid #D1D1D1;
241 | border-radius: 4px;
242 | box-shadow: none;
243 | box-sizing: border-box; }
244 | /* Removes awkward default styles on some inputs for iOS */
245 | input[type="email"],
246 | input[type="number"],
247 | input[type="search"],
248 | input[type="text"],
249 | input[type="tel"],
250 | input[type="url"],
251 | input[type="password"],
252 | textarea {
253 | -webkit-appearance: none;
254 | -moz-appearance: none;
255 | appearance: none; }
256 | textarea {
257 | min-height: 65px;
258 | padding-top: 6px;
259 | padding-bottom: 6px; }
260 | input[type="email"]:focus,
261 | input[type="number"]:focus,
262 | input[type="search"]:focus,
263 | input[type="text"]:focus,
264 | input[type="tel"]:focus,
265 | input[type="url"]:focus,
266 | input[type="password"]:focus,
267 | textarea:focus,
268 | select:focus {
269 | border: 1px solid #33C3F0;
270 | outline: 0; }
271 | label,
272 | legend {
273 | display: block;
274 | margin-bottom: .5rem;
275 | font-weight: 600; }
276 | fieldset {
277 | padding: 0;
278 | border-width: 0; }
279 | input[type="checkbox"],
280 | input[type="radio"] {
281 | display: inline; }
282 | label > .label-body {
283 | display: inline-block;
284 | margin-left: .5rem;
285 | font-weight: normal; }
286 |
287 |
288 | /* Lists
289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
290 | ul {
291 | list-style: circle inside; }
292 | ol {
293 | list-style: decimal inside; }
294 | ol, ul {
295 | padding-left: 0;
296 | margin-top: 0; }
297 | ul ul,
298 | ul ol,
299 | ol ol,
300 | ol ul {
301 | margin: 1.5rem 0 1.5rem 3rem;
302 | font-size: 90%; }
303 | li {
304 | margin-bottom: 1rem; }
305 |
306 |
307 | /* Code
308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
309 | code {
310 | padding: .2rem .5rem;
311 | margin: 0 .2rem;
312 | font-size: 90%;
313 | white-space: nowrap;
314 | background: #F1F1F1;
315 | border: 1px solid #E1E1E1;
316 | border-radius: 4px; }
317 | pre > code {
318 | display: block;
319 | padding: 1rem 1.5rem;
320 | white-space: pre; }
321 |
322 |
323 | /* Tables
324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
325 | th,
326 | td {
327 | padding: 12px 15px;
328 | text-align: left;
329 | border-bottom: 1px solid #E1E1E1; }
330 | th:first-child,
331 | td:first-child {
332 | padding-left: 0; }
333 | th:last-child,
334 | td:last-child {
335 | padding-right: 0; }
336 |
337 |
338 | /* Spacing
339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
340 | button,
341 | .button {
342 | margin-bottom: 1rem; }
343 | input,
344 | textarea,
345 | select,
346 | fieldset {
347 | margin-bottom: 1.5rem; }
348 | pre,
349 | blockquote,
350 | dl,
351 | figure,
352 | table,
353 | p,
354 | ul,
355 | ol,
356 | form {
357 | margin-bottom: 2.5rem; }
358 |
359 |
360 | /* Utilities
361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
362 | .u-full-width {
363 | width: 100%;
364 | box-sizing: border-box; }
365 | .u-max-full-width {
366 | max-width: 100%;
367 | box-sizing: border-box; }
368 | .u-pull-right {
369 | float: right; }
370 | .u-pull-left {
371 | float: left; }
372 |
373 |
374 | /* Misc
375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
376 | hr {
377 | margin-top: 3rem;
378 | margin-bottom: 3.5rem;
379 | border-width: 0;
380 | border-top: 1px solid #E1E1E1; }
381 |
382 |
383 | /* Clearing
384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
385 |
386 | /* Self Clearing Goodness */
387 | .container:after,
388 | .row:after,
389 | .u-cf {
390 | content: "";
391 | display: table;
392 | clear: both; }
393 |
394 |
395 | /* Media Queries
396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */
397 | /*
398 | Note: The best way to structure the use of media queries is to create the queries
399 | near the relevant code. For example, if you wanted to change the styles for buttons
400 | on small devices, paste the mobile query code up in the buttons section and style it
401 | there.
402 | */
403 |
404 |
405 | /* Larger than mobile */
406 | @media (min-width: 400px) {}
407 |
408 | /* Larger than phablet (also point when grid becomes active) */
409 | @media (min-width: 550px) {}
410 |
411 | /* Larger than tablet */
412 | @media (min-width: 750px) {}
413 |
414 | /* Larger than desktop */
415 | @media (min-width: 1000px) {}
416 |
417 | /* Larger than Desktop HD */
418 | @media (min-width: 1200px) {}
419 |
--------------------------------------------------------------------------------
/public/tools.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 杩欐槸鍩轰簬html5鐨勫墠绔浘鐗囧伐鍏凤紝鍘嬬缉宸ュ叿銆�
3 | */
4 | var ImageResizer=function(opts){
5 | var settings={
6 | resizeMode:"auto"//鍘嬬缉妯″紡锛屾€诲叡鏈変笁绉� auto,width,height auto琛ㄧず鑷姩鏍规嵁鏈€澶х殑瀹藉害鍙婇珮搴︾瓑姣斿帇缂╋紝width琛ㄧず鍙牴鎹搴︽潵鍒ゆ柇鏄惁闇€瑕佺瓑姣斾緥鍘嬬缉锛宧eight绫讳技銆�
7 | ,dataSource:"" //鏁版嵁婧愩€傛暟鎹簮鏄寚闇€瑕佸帇缂╃殑鏁版嵁婧愶紝鏈変笁绉嶇被鍨嬶紝image鍥剧墖鍏冪礌锛宐ase64瀛楃涓诧紝canvas瀵硅薄锛岃繕鏈夐€夋嫨鏂囦欢鏃跺€欑殑file瀵硅薄銆傘€傘€�
8 | ,dataSourceType:"image" //image base64 canvas
9 | ,maxWidth:150 //鍏佽鐨勬渶澶у搴�
10 | ,maxHeight:200 //鍏佽鐨勬渶澶ч珮搴︺€�
11 | ,onTmpImgGenerate:function(img){} //褰撲腑闂村浘鐗囩敓鎴愭椂鍊欑殑鎵ц鏂规硶銆傘€傝繖涓椂鍊欒涓嶈涔变慨鏀硅繖鍥剧墖锛屽惁鍒欎細鎵撲贡鍘嬬缉鍚庣殑缁撴灉銆�
12 | ,success:function(resizeImgBase64,canvas){
13 |
14 | }//鍘嬬缉鎴愬姛鍚庡浘鐗囩殑base64瀛楃涓叉暟鎹€�
15 | ,debug:false //鏄惁寮€鍚皟璇曟ā寮忋€�
16 |
17 | };
18 | var appData={};
19 | $.extend(settings,opts);
20 |
21 | var _debug=function(str,styles){
22 | if(settings.debug==true){
23 | if(styles){
24 | console.log(str,styles);
25 | }
26 | else{
27 | console.log(str);
28 | }
29 | }
30 | };
31 | var innerTools={
32 | getBase4FromImgFile:function(file,callBack){
33 |
34 | var reader = new FileReader();
35 | reader.onload = function(e) {
36 | var base64Img= e.target.result;
37 | //var $img = $('').attr("src", e.target.result)
38 | //$('#preview').empty().append($img)
39 | if(callBack){
40 | callBack(base64Img);
41 | }
42 | };
43 | reader.readAsDataURL(file);
44 | }
45 |
46 | //--澶勭悊鏁版嵁婧愩€傘€傘€傘€傚皢鎵€鏈夋暟鎹簮閮藉鐞嗘垚涓哄浘鐗囧浘鐗囧璞★紝鏂逛究澶勭悊銆�
47 | ,getImgFromDataSource:function(datasource,dataSourceType,callback){
48 | var _me=this;
49 | var img1=new Image();
50 | if(dataSourceType=="img"||dataSourceType=="image"){
51 | img1.src=$(datasource).attr("src");
52 | if(callback){
53 | callback(img1);
54 | }
55 | }
56 | else if(dataSourceType=="base64"){
57 | img1.src=datasource;
58 | if(callback){
59 | callback(img1);
60 | } }
61 | else if(dataSourceType=="canvas"){
62 | img1.src = datasource.toDataURL("image/jpeg");
63 | if(callback){
64 | callback(img1);
65 | }
66 | }
67 | else if(dataSourceType=="file"){
68 | _me.getBase4FromImgFile(function(base64str){
69 | img1.src=base64str;
70 | if(callback){
71 | callback(img1);
72 | }
73 | });
74 | }
75 |
76 | }
77 | //璁$畻鍥剧墖鐨勯渶瑕佸帇缂╃殑灏哄銆傚綋鐒讹紝鍘嬬缉妯″紡锛屽帇缂╅檺鍒剁洿鎺ヤ粠setting閲岄潰鍙栧嚭鏉ャ€�
78 | ,getResizeSizeFromImg:function(img){
79 | var _img_info={
80 | w:$(img)[0].naturalWidth,
81 | h:$(img)[0].naturalHeight
82 | };
83 | console.log("鐪熷疄灏哄锛�");
84 | console.log(_img_info);
85 | var _resize_info={
86 | w:0
87 | ,h:0
88 | };
89 | if(_img_info.w<=settings.maxWidth&&_img_info.h<=settings.maxHeight){
90 | return _img_info;
91 | }
92 | if(settings.resizeMode=="auto"){
93 | var _percent_scale=parseFloat(_img_info.w/_img_info.h);
94 | var _size1={
95 | w:0
96 | ,h:0
97 | };
98 | var _size_by_mw={
99 | w:settings.maxWidth
100 | ,h:parseInt(settings.maxWidth/_percent_scale)
101 | };
102 | var _size_by_mh={
103 | w:parseInt(settings.maxHeight*_percent_scale)
104 | ,h:settings.maxHeight
105 | };
106 | if(_size_by_mw.h<=settings.maxHeight){
107 | return _size_by_mw;
108 | }
109 | if(_size_by_mh.w<=settings.maxWidth){
110 | return _size_by_mh;
111 | }
112 |
113 | return {
114 | w:settings.maxWidth
115 | ,h:settings.maxHeight
116 | };
117 |
118 | }
119 | if(settings.resizeMode=="width"){
120 | if(_img_info.w<=settings.maxWidth){
121 | return _img_info;
122 | }
123 | var _size_by_mw={
124 | w:settings.maxWidth
125 | ,h:parseInt(settings.maxWidth/_percent_scale)
126 | };
127 | return _size_by_mw;
128 | }
129 |
130 | if(settings.resizeMode=="height"){
131 | if(_img_info.h<=settings.maxHeight){
132 |
133 | return _img_info;
134 | }
135 | var _size_by_mh={
136 | w:parseInt(settings.maxHeight*_percent_scale)
137 | ,h:settings.maxHeight
138 | };
139 | return _size_by_mh;
140 | }
141 |
142 | }
143 | //--灏嗙浉鍏冲浘鐗囧璞$敾鍒癱anvas閲岄潰鍘汇€�
144 | ,drawToCanvas:function(img,theW,theH,realW,realH,callback){
145 |
146 | var canvas = document.createElement("canvas");
147 | canvas.width=theW;
148 | canvas.height=theH;
149 | var ctx = canvas.getContext('2d');
150 | ctx.drawImage(img,
151 | 0,//sourceX,
152 | 0,//sourceY,
153 | realW,//sourceWidth,
154 | realH,//sourceHeight,
155 | 0,//destX,
156 | 0,//destY,
157 | theW,//destWidth,
158 | theH//destHeight
159 | );
160 |
161 | //--鑾峰彇base64瀛楃涓插強canvas瀵硅薄浼犵粰success鍑芥暟銆�
162 | var base64str=canvas.toDataURL("image/jpeg");
163 | if(callback){
164 | callback(base64str,canvas);
165 | }
166 | }
167 | };
168 |
169 | //--寮€濮嬪鐞嗐€�
170 | (function(){
171 | innerTools.getImgFromDataSource(settings.dataSource,settings.dataSourceType,function(_tmp_img){
172 |
173 | setTimeout(function(){
174 | var __tmpImg=_tmp_img;
175 | settings.onTmpImgGenerate(_tmp_img);
176 | //--璁$畻灏哄銆�
177 | var _limitSizeInfo=innerTools.getResizeSizeFromImg(__tmpImg);
178 | console.log(_limitSizeInfo);
179 | var _img_info={
180 | w:$(__tmpImg)[0].naturalWidth,
181 | h:$(__tmpImg)[0].naturalHeight
182 | };
183 |
184 | innerTools.drawToCanvas(__tmpImg,_limitSizeInfo.w,_limitSizeInfo.h,_img_info.w,_img_info.h,function(base64str,canvas){
185 | settings.success(base64str,canvas);
186 | });
187 | },1000);
188 |
189 |
190 | });
191 | })();
192 |
193 | var returnObject={
194 |
195 |
196 | };
197 |
198 | return returnObject;
199 | };
--------------------------------------------------------------------------------
/routers/comments.js:
--------------------------------------------------------------------------------
1 | const RateLimit = require('koa2-ratelimit').RateLimit;
2 | const router = require('koa-router')();
3 | const userModel = require('../lib/mysql.js')
4 | const config = require('../config/info.js')
5 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin
6 | const checkLogin = require('../middlewares/check.js').checkLogin;
7 | const moment = require('moment')
8 | const tc = require('text-censor')
9 | const nodemailer = require('nodemailer')
10 |
11 | const mailTransport = nodemailer.createTransport({
12 | host: config.stmpHost,
13 | port: config.stmpPort,
14 | secureConnection: true, // 使用SSL方式(安全方式,防止被窃取信息)
15 | auth: {
16 | user: config.stmpEmail,
17 | pass: config.stmpEmailPass
18 | },
19 | });
20 |
21 |
22 | const commentLimiter = RateLimit.middleware({
23 | interval: 10 * 60 * 1000, // 10min
24 | delayAfter: 1, // begin slowing down responses after the first request
25 | timeWait: 3 * 1000, // slow down subsequent responses by 3 seconds per request
26 | max: 5, // start blocking after 5 requests
27 | prefixKey: 'post/comment/:link/push', // to allow the bdd to Differentiate the endpoint
28 | message: "Too many accounts created from this IP, please try again after 10min"
29 | });
30 |
31 | // post 提交评论
32 | router.post('/comment/:link/push', commentLimiter, async (ctx, next) => {
33 | let name = ctx.request.body.name,
34 | email = ctx.request.body.email,
35 | content = ctx.request.body.content,
36 | website = ctx.request.body.website,
37 | reply = ctx.request.body.reply,
38 | replyuser = '',
39 | replyemail = '',
40 | link = ctx.params.link,
41 | type = 'post',
42 | time = moment().format('YYYY-MM-DD HH:mm:ss'),
43 | newName = name.replace(/[<">']/g, (target) => {
44 | return {
45 | '<': '<',
46 | '"': '"',
47 | '>': '>',
48 | "'": '''
49 | }[target]
50 | }),
51 | newContent = content.replace(/[<">']/g, (target) => {
52 | return {
53 | '<': '<',
54 | '"': '"',
55 | '>': '>',
56 | "'": '''
57 | }[target]
58 | });
59 | let testNum = /^[1-9]+[0-9]*]*$/;
60 | if(!testNum.test(link)){
61 | type = 'page';
62 |
63 | }
64 | await userModel.findCommentInfo(reply, link)
65 | .then(result => {
66 | if (result.length != 0) {
67 | replyuser = result[0].name;
68 | replyemail = result[0].email;
69 | console.log(result)
70 | } else {
71 | reply = 0
72 | }
73 | })
74 | tc.filter(newName, function (err, censored) {
75 | newName = censored
76 | })
77 | tc.filter(newContent, function (err, censored) {
78 | newContent = censored
79 | })
80 | // console.log([newName, email, website, newContent, link, reply, replyuser, time])
81 | // let reg = /[a-zA-Z0-9_]{1,10}/;
82 | let reg = /^\d*([a-zA-Z])+\d*$/;
83 | let urlreg = /^$|^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/;
84 | let ereg = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
85 | // [\u4e00-\u9fa5_a-zA-Z0-9_]{1,10}
86 |
87 |
88 | if(type == 'post'){
89 | mailOptions = {
90 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>',
91 | to: config.myEmail,
92 | subject: config.websiteTitle+' - 你有一条评论',
93 | text: '您的博客有一条新评论,来自用户' + name + ':' + content + ' 文章地址为:'+config.domain+'/post/'+link,
94 | };
95 | }else{
96 | mailOptions = {
97 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>',
98 | to: config.myEmail,
99 | subject: config.websiteTitle+' - 你有一条评论',
100 | text: '您的博客有一条新评论,来自用户' + name + ':' + content + ' 页面地址为:'+config.domain+'/s/'+link,
101 | };
102 | }
103 | if (!urlreg.test(website) || !ereg.test(email) || newName == '') {
104 | ctx.body = false
105 | } else {
106 | await userModel.createComment([newName, email, website, newContent, link, reply, replyuser, time])
107 | .then(() => {
108 | ctx.body = true
109 | }).catch(() => {
110 | ctx.body = false
111 | })
112 | if (ctx.session.user) {
113 | if(type == 'post'){
114 | mailOptions = {
115 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>',
116 | to: replyemail,
117 | subject: config.websiteTitle+' - 你有一条回复评论',
118 | text: '您有一条回复评论 文章地址为:'+config.domain+'/post/'+link,
119 | };
120 | }else{
121 | mailOptions = {
122 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>',
123 | to: replyemail,
124 | subject: config.websiteTitle+' - 你有一条回复评论',
125 | text: '您有一条回复评论 页面地址为:'+config.domain+'/s/'+link,
126 | };
127 | }
128 | mailTransport.sendMail(mailOptions, function (err, msg) {
129 | if (err) {
130 | console.log(err);
131 | // res.render('index', { title: err });
132 | }
133 | else {
134 | console.log(msg);
135 | // res.render('index', { title: "已接收:" + msg.accepted });
136 | }
137 | });
138 | } else {
139 | mailTransport.sendMail(mailOptions, function (err, msg) {
140 | if (err) {
141 | console.log(err);
142 | // res.render('index', { title: err });
143 | }
144 | else {
145 | console.log(msg);
146 | // res.render('index', { title: "已接收:" + msg.accepted });
147 | }
148 | });
149 | }
150 | }
151 | })
152 |
153 | // 删除评论
154 | router.post('/comment/:id/remove', async (ctx, next) => {
155 | let id = ctx.params.id,
156 | allow;
157 | if (ctx.session.user) {
158 | allow = true
159 | } else {
160 | allow = false
161 | }
162 | if (allow) {
163 | await userModel.deleteComments(id)
164 | .then(() => {
165 | ctx.body = {
166 | data: 1
167 | }
168 | }).catch(() => {
169 | ctx.body = {
170 | data: 2
171 | }
172 | })
173 | } else {
174 | ctx.body = {
175 | data: 3
176 | }
177 | }
178 | })
179 | module.exports = router
--------------------------------------------------------------------------------
/routers/pages.js:
--------------------------------------------------------------------------------
1 | const router = require('koa-router')();
2 | const userModel = require('../lib/mysql.js')
3 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin
4 | const checkLogin = require('../middlewares/check.js').checkLogin;
5 | const md = require('markdown-it')();
6 |
7 | // 单页面
8 | router.get('/s/:linkname', async (ctx, next) => {
9 | let res, pagesArr, comres;
10 | await userModel.findPageDataByLink(ctx.params.linkname)
11 | .then(result => {
12 | //console.log(result )
13 | res = result
14 | console.log(res[0])
15 | })
16 | await userModel.findPageInfoById()
17 | .then(result => {
18 | pagesArr = result;
19 | })
20 | await userModel.findComments(ctx.params.linkname)
21 | .then(result => {
22 | comres = result;
23 | })
24 | await ctx.render('sPage', {
25 | session: ctx.session,
26 | comments: comres,
27 | comments_length: comres.length,
28 | pagesArr: pagesArr,
29 | pages: res[0]
30 | })
31 |
32 | })
33 |
34 |
35 | // 创建页面
36 | router.get('/createpage', async (ctx, next) => {
37 | await checkLogin(ctx)
38 | await ctx.render('createpage', {
39 | session: ctx.session,
40 | })
41 | })
42 |
43 | // post 创建新页面
44 | router.post('/createpage', async (ctx, next) => {
45 | let linkname = ctx.request.body.linkname,
46 | title = ctx.request.body.title,
47 | content = ctx.request.body.content,
48 | hascom = ctx.request.body.hascom,
49 | allowEdit = true,
50 | newTitle = title.replace(/[<">']/g, (target) => {
51 | return {
52 | '<': '<',
53 | '"': '"',
54 | '>': '>',
55 | "'": '''
56 | }[target]
57 | });
58 | // let reg = /[a-zA-Z0-9_]{1,10}/;
59 | let reg = /^\d*([a-zA-Z])+\d*$/;
60 | // [\u4e00-\u9fa5_a-zA-Z0-9_]{1,10}
61 | // console.log([linkname,name, newTitle, md.render(content), content,typeof hascom])
62 |
63 | if (!ctx.session.user) {
64 | allowEdit = false
65 | } else {
66 | // allowEdit = true
67 | await userModel.findPageDataByLink(linkname)
68 | .then(result => {
69 | let cln = result;
70 | if (result.length === 0) {
71 | allowEdit = true
72 | } else {
73 | allowEdit = false
74 | }
75 | })
76 | }
77 | if (linkname.match(reg) === null || hascom.match(reg) === null) {
78 | ctx.body = 'unallow'
79 | } else {
80 | if (allowEdit) {
81 | await userModel.insertPage([linkname.match(reg)[0], newTitle, md.render(content), content, hascom.match(reg)[0]])
82 | .then(() => {
83 | ctx.body = true
84 | }).catch(() => {
85 | ctx.body = false
86 | })
87 | } else {
88 | ctx.body = 'error'
89 | }
90 | }
91 |
92 | })
93 |
94 | // 编辑单页面
95 | router.get('/s/:linkname/edit', async (ctx, next) => {
96 | let name = ctx.session.user,
97 | linkname = ctx.params.linkname,
98 | res;
99 | await checkLogin(ctx)
100 | await userModel.findPageDataByLink(linkname)
101 | .then(result => {
102 | res = result[0];
103 | console.log(result)
104 | })
105 | await ctx.render('editpage', {
106 | session: ctx.session,
107 | pagesContent: res.content,
108 | pagesLinkname: res.linkname,
109 | pagesTitle: res.title,
110 | pagesHascom: res.hascom
111 | })
112 |
113 | })
114 |
115 | // post 编辑单页面
116 | router.post('/s/:linkname/edit', async (ctx, next) => {
117 | let title = ctx.request.body.title,
118 | content = ctx.request.body.content,
119 | description = ctx.request.body.description,
120 | hascom = ctx.request.body.hascom,
121 | linkname = ctx.params.linkname,
122 | ln = ctx.request.body.linkname,
123 | pageid,
124 | allowEdit = true,
125 | // 现在使用markdown不需要单独转义
126 | newTitle = title.replace(/[<">']/g, (target) => {
127 | return {
128 | '<': '<',
129 | '"': '"',
130 | '>': '>',
131 | "'": '''
132 | }[target]
133 | });
134 | // let reg = /[a-zA-Z0-9_]{1,10}/;
135 | let reg = /^\d*([a-zA-Z])+\d*$/;
136 | // console.log(ln.match(reg))
137 | await userModel.findPageDataByLink(linkname)
138 | .then(res => {
139 | // console.log(res[0].name,ctx.session.user)
140 | if (!ctx.session.user) {
141 | allowEdit = false
142 | } else {
143 | console.log(res[0].id)
144 | pageid = res[0].id
145 | allowEdit = true
146 | }
147 | })
148 | if (ln.match(reg) === null || hascom.match(reg) === null) {
149 | ctx.body = 'unallow'
150 | } else {
151 | if (allowEdit) {
152 | await userModel.updatePage([ln.match(reg)[0], newTitle, content, md.render(content), hascom.match(reg)[0], pageid])
153 | .then(() => {
154 | ctx.body = true
155 | }).catch(() => {
156 | ctx.body = false
157 | })
158 | } else {
159 | ctx.body = 'error'
160 | }
161 | }
162 | })
163 |
164 | // 删除单页面
165 | router.post('/s/:linkname/remove', async (ctx, next) => {
166 | let linkname = ctx.params.linkname;
167 | if (ctx.session.user) {
168 | await userModel.deleteCommentsByLink(linkname);
169 | await userModel.deletePage(linkname)
170 | .then(() => {
171 | ctx.body = {
172 | data: 1
173 | }
174 | }).catch(() => {
175 | ctx.body = {
176 | data: 2
177 | }
178 | })
179 | } else {
180 | ctx.body = {
181 | data: 3
182 | }
183 | }
184 | })
185 |
186 | module.exports = router
--------------------------------------------------------------------------------
/routers/posts.js:
--------------------------------------------------------------------------------
1 | const router = require('koa-router')();
2 | const userModel = require('../lib/mysql.js')
3 | const moment = require('moment')
4 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin
5 | const checkLogin = require('../middlewares/check.js').checkLogin;
6 | const md = require('markdown-it')();
7 |
8 |
9 |
10 | // 文章页
11 | router.get('/', async (ctx, next) => {
12 | let res,
13 | postsLength,
14 | pagesArr;
15 | await userModel.findPostByPage(1)
16 | .then(result => {
17 | //console.log(result)
18 | res = result
19 | })
20 | await userModel.findAllPost()
21 | .then(result => {
22 | postsLength = result.length
23 | })
24 | await userModel.findPageInfoById()
25 | .then(result => {
26 | pagesArr = result;
27 | })
28 | await ctx.render('posts', {
29 | session: ctx.session,
30 | posts: res,
31 | postsLength: postsLength,
32 | pagesArr: pagesArr,
33 | postsPageLength: Math.ceil(postsLength / 5),
34 |
35 | })
36 |
37 | })
38 |
39 | // 首页分页,每次输出10条
40 | router.post('/post/page', async (ctx, next) => {
41 | let page = ctx.request.body.page;
42 | await userModel.findPostByPage(page)
43 | .then(result => {
44 | //console.log(result)
45 | ctx.body = result
46 | }).catch(() => {
47 | ctx.body = 'error'
48 | })
49 | })
50 |
51 | // 单篇文章页
52 | router.get('/post/:postId', async (ctx, next) => {
53 | let res,
54 | comres,
55 | pageOne,
56 | res_pv,
57 | pagesArr,
58 | res_summary;
59 | await userModel.findDataById(ctx.params.postId)
60 | .then(result => {
61 | res = result[0]
62 | res_summary = result[0].md.substr(0, 50)
63 | res_pv = parseInt(result[0]['pv'])
64 | res_pv += 1
65 | // console.log(res_pv)
66 | })
67 | await userModel.findPageInfoById()
68 | .then(result => {
69 | pagesArr = result;
70 | })
71 | await userModel.findComments(ctx.params.postId)
72 | .then(result => {
73 | comres = result;
74 | })
75 | await userModel.updatePostPv([res_pv, ctx.params.postId])
76 | console.log(res.id)
77 | await ctx.render('sPost', {
78 | session: ctx.session,
79 | posts: res,
80 | comments: comres,
81 | comments_length: comres.length,
82 | pagesArr: pagesArr,
83 | pageOne: pageOne,
84 | Summary: res_summary
85 | })
86 |
87 | })
88 |
89 | // 发表文章页面
90 | router.get('/create', async (ctx, next) => {
91 | await checkLogin(ctx)
92 | await ctx.render('create', {
93 | session: ctx.session,
94 | })
95 | })
96 |
97 | // post 发表文章
98 | router.post('/create', async (ctx, next) => {
99 | let title = ctx.request.body.title,
100 | content = ctx.request.body.content,
101 | time = moment().format('MMM, Do, YYYY'),
102 | allow = true,
103 | // 现在使用markdown不需要单独转义
104 | newContent = content.replace(/[<">']/g, (target) => {
105 | return {
106 | '<': '<',
107 | '"': '"',
108 | '>': '>',
109 | "'": '''
110 | }[target]
111 | }),
112 | newTitle = title.replace(/[<">']/g, (target) => {
113 | return {
114 | '<': '<',
115 | '"': '"',
116 | '>': '>',
117 | "'": '''
118 | }[target]
119 | });
120 | if (ctx.session.user) {
121 | allow = true
122 | } else {
123 | allow = false
124 | }
125 | //console.log([name, newTitle, content, id, time])
126 | if (allow) {
127 | await userModel.insertPost([newTitle, md.render(content), content, time])
128 | .then(() => {
129 | ctx.body = true
130 | }).catch(() => {
131 | ctx.body = false
132 | })
133 | } else {
134 | ctx.body = 'error'
135 | }
136 |
137 | })
138 |
139 |
140 |
141 | // 编辑单篇文章页面
142 | router.get('/post/:postId/edit', async (ctx, next) => {
143 | let name = ctx.session.user,
144 | postId = ctx.params.postId,
145 | res;
146 | await checkLogin(ctx)
147 | await userModel.findDataById(postId)
148 | .then(result => {
149 | res = result[0]
150 | })
151 | await ctx.render('edit', {
152 | session: ctx.session,
153 | postsContent: res.md,
154 | postsTitle: res.title
155 | })
156 |
157 | })
158 |
159 | // post 编辑单篇文章
160 | router.post('/post/:postId/edit', async (ctx, next) => {
161 | let title = ctx.request.body.title,
162 | content = ctx.request.body.content,
163 | id = ctx.session.id,
164 | postId = ctx.params.postId,
165 | allowEdit = true;
166 | // 现在使用markdown不需要单独转义
167 | newTitle = title.replace(/[<">']/g, (target) => {
168 | return {
169 | '<': '<',
170 | '"': '"',
171 | '>': '>',
172 | "'": '''
173 | }[target]
174 | }),
175 | newContent = content.replace(/[<">']/g, (target) => {
176 | return {
177 | '<': '<',
178 | '"': '"',
179 | '>': '>',
180 | "'": '''
181 | }[target]
182 | });
183 | await userModel.findDataById(postId)
184 | .then(res => {
185 | // console.log(Boolean('ctx.session.user'))
186 | if (res[0].id === postId && ctx.session.user) {
187 | allowEdit = false
188 | } else {
189 | allowEdit = true
190 | }
191 | })
192 | if (allowEdit) {
193 | await userModel.updatePost([newTitle, md.render(content), content, postId])
194 | .then(() => {
195 | ctx.body = true
196 | }).catch(() => {
197 | ctx.body = false
198 | })
199 | } else {
200 | ctx.body = 'error'
201 | }
202 | })
203 |
204 | // 删除单篇文章
205 | router.post('/post/:postId/remove', async (ctx, next) => {
206 | let postId = ctx.params.postId,
207 | allow;
208 | if (ctx.session.user) {
209 | allow = true
210 | } else {
211 | allow = false
212 | }
213 | if (allow) {
214 | await userModel.deletePost(postId)
215 | .then(() => {
216 | ctx.body = {
217 | data: 1
218 | }
219 | }).catch(() => {
220 | ctx.body = {
221 | data: 2
222 | }
223 | })
224 | await userModel.deleteCommentsByLink(postId);
225 | } else {
226 | ctx.body = {
227 | data: 3
228 | }
229 | }
230 | })
231 |
232 |
233 | module.exports = router
--------------------------------------------------------------------------------
/routers/signin.js:
--------------------------------------------------------------------------------
1 | const RateLimit = require('koa2-ratelimit').RateLimit;
2 | const router = require('koa-router')();
3 | const userModel = require('../lib/mysql.js')
4 | const md5 = require('md5')
5 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin
6 | const checkLogin = require('../middlewares/check.js').checkLogin
7 | const fs = require('fs')
8 | const captcha = require('trek-captcha')
9 |
10 | const getloginimiter = RateLimit.middleware({
11 | interval: 15*60*1000, // 15 minutes
12 | max: 100,
13 | prefixKey: 'get/signin' // to allow the bdd to Differentiate the endpoint
14 | });
15 |
16 | const loginLimiter = RateLimit.middleware({
17 | interval: 10*60*1000, // 10min
18 | delayAfter: 1, // begin slowing down responses after the first request
19 | timeWait: 3*1000, // slow down subsequent responses by 3 seconds per request
20 | max: 5, // start blocking after 5 requests
21 | prefixKey: 'post/signin', // to allow the bdd to Differentiate the endpoint
22 | message: "Too many accounts created from this IP, please try again after 10min"
23 | });
24 |
25 | router.get('/signin', getloginimiter, async(ctx, next) => {
26 | await checkNotLogin(ctx)
27 | const { token, buffer } = await captcha()
28 | // fs.createWriteStream('public/code.gif').on('finish', () => console.log(token)).end(buffer);
29 | console.log(token)
30 | let codeBase64 = buffer.toString('base64');
31 | ctx.session.code = token
32 | await ctx.render('signin', {
33 | session: ctx.session,
34 | code:codeBase64
35 | })
36 | console.log(ctx.session)
37 | })
38 |
39 | router.post('/signin', loginLimiter, async(ctx, next) => {
40 | console.log(ctx.request.body)
41 | let name = ctx.request.body.name;
42 | let pass = ctx.request.body.password;
43 | let code = ctx.request.body.code;
44 | await userModel.findDataByName(name)
45 | .then(result => {
46 | let res = result;
47 | if(code!=ctx.session.code){
48 | ctx.body = 0
49 | console.log('验证码错误')
50 | }
51 | else if (name === res[0]['name'] && md5(pass) === res[0]['pass'] ) {
52 | ctx.body = true
53 | ctx.session.user = res[0]['name']
54 | ctx.session.id = res[0]['id']
55 | delete ctx.session.code;
56 | console.log('ctx.session.id', ctx.session.id)
57 | console.log('session', ctx.session)
58 | console.log('登录成功')
59 | }else{
60 | ctx.body = false
61 | console.log('登录失败')
62 | }
63 | }).catch(err => {
64 | console.log(err)
65 | })
66 |
67 | })
68 |
69 | module.exports = router
--------------------------------------------------------------------------------
/routers/signout.js:
--------------------------------------------------------------------------------
1 | const router = require('koa-router')();
2 |
3 | router.get('/signout', async(ctx, next) => {
4 | ctx.session = null;
5 | console.log('登出成功')
6 | ctx.body = true
7 | })
8 |
9 | module.exports = router
--------------------------------------------------------------------------------
/routers/upload.js:
--------------------------------------------------------------------------------
1 | const router = require('koa-router')();
2 | const userModel = require('../lib/mysql.js')
3 | const moment = require('moment')
4 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin
5 | const checkLogin = require('../middlewares/check.js').checkLogin;
6 | const fs = require('fs')
7 |
8 | //上传图片页面
9 | router.get('/uploadimg', async (ctx, next) => {
10 | await checkLogin(ctx)
11 | await ctx.render('uploadimg', {
12 | session: ctx.session,
13 | })
14 | })
15 |
16 | // post 上传图片
17 | router.post('/uploadimg/upload', async (ctx, next) => {
18 | let img = ctx.request.body.img,
19 | imgname = moment().unix(),
20 | time = moment().format('YYYY-MM-DD HH:mm:ss'),
21 | allowEdit = true;
22 | if (!ctx.session.user) {
23 | allowEdit = false
24 | } else {
25 | allowEdit = true
26 | }
27 | if (allowEdit) {
28 | let imgBuffer = new Buffer(img, 'base64');
29 | // console.log(imgBuffer)
30 | fs.createWriteStream('public/images/' + imgname + '.gif').on('finish', () => {
31 | }).end(imgBuffer);
32 | await userModel.uploadImg([imgname, time])
33 | .then(() => {
34 | ctx.body = {
35 | status: true,
36 | imgurl: ''
37 | }
38 | }).catch(() => {
39 | console.log('upload_img_error')
40 | })
41 |
42 | } else {
43 | ctx.body = {
44 | status: false
45 | }
46 | }
47 | })
48 |
49 | //图片管理页面
50 | router.get('/img', async (ctx, next) => {
51 | let res,
52 | imgsLength;
53 | await checkLogin(ctx)
54 | await userModel.findImgByPage(1)
55 | .then(result => {
56 | //console.log(result)
57 | res = result
58 | })
59 | await userModel.findAllImgs()
60 | .then(result => {
61 | imgsLength = result.length
62 | })
63 | await ctx.render('img', {
64 | session: ctx.session,
65 | imgs: res,
66 | imgsLength: imgsLength,
67 | imgsPageLength: Math.ceil(imgsLength / 10),
68 | })
69 | })
70 |
71 |
72 | // 分页,每次输出10条
73 | router.post('/img/page', async (ctx, next) => {
74 | let page = ctx.request.body.page;
75 | await userModel.findImgByPage(page)
76 | .then(result => {
77 | //console.log(result)
78 | ctx.body = result
79 | }).catch(() => {
80 | ctx.body = 'error'
81 | })
82 | })
83 |
84 | // post 删除图片
85 | router.post('/img/delete', async (ctx, next) => {
86 | let id = ctx.request.body.id,
87 | name = ctx.request.body.name
88 | allowEdit = true;
89 | if (!ctx.session.user) {
90 | allowEdit = false
91 | } else {
92 | allowEdit = true
93 | }
94 | if (allowEdit) {
95 | await userModel.deleteImg(id)
96 | .then(() => {
97 | fs.unlink('public/images/'+name+'.gif',function (err) {
98 | if(err) throw err;
99 | console.log('删除成功')
100 | })
101 | ctx.body = true
102 | }).catch(() => {
103 | ctx.body = false
104 | })
105 |
106 | } else {
107 | ctx.body = false
108 | }
109 | })
110 |
111 | //相册页面
112 | router.get('/photo', async (ctx, next) => {
113 | let res,
114 | photosLength,pagesArr;
115 | // await checkLogin(ctx)
116 | await userModel.findPageInfoById()
117 | .then(result => {
118 | pagesArr = result;
119 | })
120 | await userModel.findPhotoByPage(1)
121 | .then(result => {
122 | //console.log(result)
123 | res = result
124 | })
125 | await userModel.findAllPhotos()
126 | .then(result => {
127 | photosLength = result.length
128 | })
129 | await ctx.render('photo', {
130 | session: ctx.session,
131 | imgs: res,
132 | pagesArr:pagesArr,
133 | photosLength: photosLength,
134 | photosPageLength: Math.ceil(photosLength / 5),
135 | })
136 | })
137 |
138 | //上传相册图片页面
139 | router.get('/uploadphoto', async (ctx, next) => {
140 | await checkLogin(ctx)
141 | await ctx.render('uploadphoto', {
142 | session: ctx.session,
143 | })
144 | })
145 |
146 | // post 上传相册图片
147 | router.post('/uploadphoto/upload', async (ctx, next) => {
148 | let img = ctx.request.body.img,
149 | imgname = moment().unix(),
150 | title = ctx.request.body.title,
151 | time = moment().format('YYYY-MM-DD HH:mm:ss'),
152 | allowEdit = true;
153 | if (!ctx.session.user) {
154 | allowEdit = false
155 | } else {
156 | allowEdit = true
157 | }
158 | if (allowEdit) {
159 | let imgBuffer = new Buffer(img, 'base64');
160 | // console.log(imgBuffer)
161 | fs.createWriteStream('public/photos/' + imgname + '.gif').on('finish', () => {
162 | }).end(imgBuffer);
163 | await userModel.uploadPhoto([imgname, title,time])
164 | .then(() => {
165 | ctx.body = {
166 | status: true
167 | }
168 | }).catch(() => {
169 | console.log('upload_img_error')
170 | })
171 |
172 | } else {
173 | ctx.body = {
174 | status: false
175 | }
176 | }
177 | })
178 |
179 | // 相册分页,每次输出10条
180 | router.post('/photo/page', async (ctx, next) => {
181 | let page = ctx.request.body.page;
182 | await userModel.findPhotoByPage(page)
183 | .then(result => {
184 | //console.log(result)
185 | ctx.body = result
186 | }).catch(() => {
187 | ctx.body = 'error'
188 | })
189 | })
190 |
191 | // post 删除相册图片
192 | router.post('/photo/delete', async (ctx, next) => {
193 | let id = ctx.request.body.id,
194 | name = ctx.request.body.name
195 | allowEdit = true;
196 | if (!ctx.session.user) {
197 | allowEdit = false
198 | } else {
199 | allowEdit = true
200 | }
201 | if (allowEdit) {
202 | await userModel.deletePhoto(id)
203 | .then(() => {
204 | fs.unlink('public/photos/'+name+'.gif',function (err) {
205 | if(err) throw err;
206 | console.log('删除成功')
207 | })
208 | ctx.body = true
209 | }).catch(() => {
210 | ctx.body = false
211 | })
212 |
213 | } else {
214 | ctx.body = false
215 | }
216 | })
217 |
218 | module.exports = router
--------------------------------------------------------------------------------
/setup.js:
--------------------------------------------------------------------------------
1 | const apiModel = require('./lib/mysql.js')
2 | const md5 = require('md5')
3 |
4 | //第一次使用请先创建数据库
5 | // 进入登录mysql输入命令:create database `najeh` default character set utf8 collate utf8_general_ci;
6 |
7 | //创建完数据库以后进入此目录 node setup.js 后即可根据下面信息创建管理员用户
8 |
9 | //创建管理员
10 | apiModel.insertData(['admin', md5('123456')]).then(() => {
11 | console.log('创建成功');
12 | process.exit();
13 | })
14 |
15 | //删除管理员
16 | // apiModel.deleteData('admin').then(() => {
17 | // console.log('删除成功');
18 | // process.exit();
19 | // })
--------------------------------------------------------------------------------
/views/comment.ejs:
--------------------------------------------------------------------------------
1 |
<%- comments_length %>条评论
4 | <% } %> 5 |6 | <% comments.forEach(function(res){ %> 7 |-
8 |
9 |
10 | <%- res.name %>:
11 |
12 |
13 | <% if(res.replyuser != ''){ %>
14 | @<%- res.replyuser %>
15 |
16 | <% } %>
17 | <%- res.content %>
18 |
19 |
20 | <%- res.moment %>
21 |
22 | 回复
23 | <% if(session.user ){ %>
24 | 删除
25 | <% } %>
26 |
27 | <% }) %>
28 |
29 |留下一条评论
30 | 53 |