diff --git a/LICENSE b/LICENSE index 8363a1e..b9065e1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) Alibaba Group Holding Limited and other contributors. +Copyright (c) 2017-present Alibaba Group Holding Limited and other contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index c274b7d..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,14 +0,0 @@ -environment: - matrix: - - nodejs_version: '8' - -install: - - ps: Install-Product node $env:nodejs_version - - npm i npminstall && node_modules\.bin\npminstall - -test_script: - - node --version - - npm --version - - npm run test - -build: off diff --git a/bin/test.js b/bin/test.js index 0f8b2da..d65f66f 100644 --- a/bin/test.js +++ b/bin/test.js @@ -39,7 +39,7 @@ class Test extends Command { ); try { const flag = argv.c ? ' -c' : ''; - await this.runscript(`npminstall${flag}`, { cwd: dir }); + await this.runscript(`npmupdate${flag}`, { cwd: dir }); await this.runscript('npm test', { cwd: dir }); console.info('%s success\n', chalk.green('✔')); success.add(dir); diff --git a/multipart-file-mode/.gitignore b/multipart-file-mode/.gitignore new file mode 100644 index 0000000..c2c9783 --- /dev/null +++ b/multipart-file-mode/.gitignore @@ -0,0 +1,3 @@ +upload_dirs +!upload_dirs/keepit +app/public diff --git a/multipart-file-mode/app/controller/ajax.js b/multipart-file-mode/app/controller/ajax.js new file mode 100644 index 0000000..69c3e9d --- /dev/null +++ b/multipart-file-mode/app/controller/ajax.js @@ -0,0 +1,29 @@ +'use strict'; + +const fs = require('mz/fs'); +const path = require('path'); +const Controller = require('egg').Controller; +const pump = require('mz-modules/pump'); + +module.exports = class extends Controller { + async show() { + await this.ctx.render('page/ajax.html'); + } + + async upload() { + const { ctx } = this; + const file = ctx.request.files[0]; + if (!file) return ctx.throw(404); + + const filename = encodeURIComponent(ctx.request.body.name) + path.extname(file.filename).toLowerCase(); + const targetPath = path.join(this.config.baseDir, 'app/public', filename); + const source = fs.createReadStream(file.filepath); + const target = fs.createWriteStream(targetPath); + await pump(source, target); + ctx.logger.warn('save %s to %s', file.filepath, targetPath); + // delete tmp file + await fs.unlink(file.filepath); + + ctx.body = { url: '/public/' + filename }; + } +}; diff --git a/multipart-file-mode/app/controller/form.js b/multipart-file-mode/app/controller/form.js new file mode 100644 index 0000000..4886a46 --- /dev/null +++ b/multipart-file-mode/app/controller/form.js @@ -0,0 +1,29 @@ +'use strict'; + +const fs = require('mz/fs'); +const path = require('path'); +const pump = require('mz-modules/pump'); +const Controller = require('egg').Controller; + +module.exports = class extends Controller { + async show() { + await this.ctx.render('page/form.html'); + } + + async upload() { + const { ctx } = this; + const file = ctx.request.files[0]; + if (!file) return ctx.throw(404); + + const filename = encodeURIComponent(ctx.request.body.name) + path.extname(file.filename).toLowerCase(); + const targetPath = path.join(this.config.baseDir, 'app/public', filename); + const source = fs.createReadStream(file.filepath); + const target = fs.createWriteStream(targetPath); + await pump(source, target); + ctx.logger.warn('save %s to %s', file.filepath, targetPath); + // delete tmp file + await fs.unlink(file.filepath); + + ctx.redirect('/public/' + filename); + } +}; diff --git a/multipart-file-mode/app/controller/home.js b/multipart-file-mode/app/controller/home.js new file mode 100644 index 0000000..3038487 --- /dev/null +++ b/multipart-file-mode/app/controller/home.js @@ -0,0 +1,9 @@ +'use strict'; + +const Controller = require('egg').Controller; + +module.exports = class extends Controller { + async render() { + await this.ctx.render('index.html'); + } +}; diff --git a/multipart-file-mode/app/controller/multiple.js b/multipart-file-mode/app/controller/multiple.js new file mode 100644 index 0000000..31ec0ef --- /dev/null +++ b/multipart-file-mode/app/controller/multiple.js @@ -0,0 +1,41 @@ +'use strict'; + +const fs = require('mz/fs'); +const path = require('path'); +const pump = require('mz-modules/pump'); +const Controller = require('egg').Controller; + +module.exports = class extends Controller { + async show() { + await this.ctx.render('page/multiple.html'); + } + + async upload() { + const { ctx } = this; + const files = ctx.request.files; + ctx.logger.warn('files: %j', files); + for (const file of files) { + const filename = file.filename.toLowerCase(); + const targetPath = path.join(this.config.baseDir, 'app/public', filename); + const source = fs.createReadStream(file.filepath); + const target = fs.createWriteStream(targetPath); + await pump(source, target); + ctx.logger.warn('save %s to %s', file.filepath, targetPath); + // delete tmp file + await fs.unlink(file.filepath); + } + + const fields = []; + for (const k in ctx.request.body) { + fields.push({ + key: k, + value: ctx.request.body[k], + }); + } + + await ctx.render('page/multiple_result.html', { + fields, + files, + }); + } +}; diff --git a/multipart-file-mode/app/router.js b/multipart-file-mode/app/router.js new file mode 100644 index 0000000..9b7e401 --- /dev/null +++ b/multipart-file-mode/app/router.js @@ -0,0 +1,14 @@ +'use strict'; + +module.exports = app => { + app.router.get('/', 'home.render'); + + app.router.get('/ajax', app.controller.ajax.show); + app.router.post('/ajax', app.controller.ajax.upload); + + app.router.get('/form', app.controller.form.show); + app.router.post('/form', app.controller.form.upload); + + app.router.get('/multiple-file', app.controller.multiple.show); + app.router.post('/multiple-file', app.controller.multiple.upload); +}; diff --git a/multipart-file-mode/app/view/index.html b/multipart-file-mode/app/view/index.html new file mode 100644 index 0000000..15799e5 --- /dev/null +++ b/multipart-file-mode/app/view/index.html @@ -0,0 +1,9 @@ +{% extends "layout.html" %} +{% block content %} +

Upload

+ +{% endblock %} diff --git a/multipart-file-mode/app/view/layout.html b/multipart-file-mode/app/view/layout.html new file mode 100644 index 0000000..a016e35 --- /dev/null +++ b/multipart-file-mode/app/view/layout.html @@ -0,0 +1,10 @@ + + + + + + +{% block content %} +{% endblock %} + + diff --git a/multipart-file-mode/app/view/page/ajax.html b/multipart-file-mode/app/view/page/ajax.html new file mode 100644 index 0000000..0187141 --- /dev/null +++ b/multipart-file-mode/app/view/page/ajax.html @@ -0,0 +1,43 @@ +{% extends "layout.html" %} + +{% block content %} +

Upload Image

+
+ +
+ + +{% endblock %} diff --git a/multipart-file-mode/app/view/page/form.html b/multipart-file-mode/app/view/page/form.html new file mode 100644 index 0000000..1dee9c2 --- /dev/null +++ b/multipart-file-mode/app/view/page/form.html @@ -0,0 +1,12 @@ +{% extends "layout.html" %} + +{% block content %} +

Upload Image

+
+ +
+{% endblock %} diff --git a/multipart-file-mode/app/view/page/multiple.html b/multipart-file-mode/app/view/page/multiple.html new file mode 100644 index 0000000..19c157a --- /dev/null +++ b/multipart-file-mode/app/view/page/multiple.html @@ -0,0 +1,14 @@ +{% extends "layout.html" %} +{% block content %} +

Upload Image

+
+ +
+{% endblock %} diff --git a/multipart-file-mode/app/view/page/multiple_result.html b/multipart-file-mode/app/view/page/multiple_result.html new file mode 100644 index 0000000..24278ce --- /dev/null +++ b/multipart-file-mode/app/view/page/multiple_result.html @@ -0,0 +1,13 @@ +{% extends "layout.html" %} +{% block content %} +

Upload Result

+ +{% endblock %} diff --git a/multipart-file-mode/config/config.default.js b/multipart-file-mode/config/config.default.js new file mode 100644 index 0000000..bfc6e31 --- /dev/null +++ b/multipart-file-mode/config/config.default.js @@ -0,0 +1,11 @@ +'use strict'; + +exports.keys = 'my keys'; + +exports.view = { + defaultViewEngine: 'nunjucks', +}; + +exports.multipart = { + mode: 'file', +}; diff --git a/multipart-file-mode/config/plugin.js b/multipart-file-mode/config/plugin.js new file mode 100644 index 0000000..1edbc89 --- /dev/null +++ b/multipart-file-mode/config/plugin.js @@ -0,0 +1,6 @@ +'use strict'; + +exports.nunjucks = { + enable: true, + package: 'egg-view-nunjucks', +}; diff --git a/multipart-file-mode/package.json b/multipart-file-mode/package.json new file mode 100644 index 0000000..1d86014 --- /dev/null +++ b/multipart-file-mode/package.json @@ -0,0 +1,19 @@ +{ + "name": "multipart-file-mode-example", + "dependencies": { + "egg": "^2.11.2", + "egg-view-nunjucks": "^2.1.4", + "mz": "^2.7.0", + "mz-modules": "^2.1.0" + }, + "devDependencies": { + "egg-bin": "^4.3.5", + "egg-mock": "^3.13.1" + }, + "scripts": { + "dev": "egg-bin dev", + "test": "egg-bin test", + "cov": "egg-bin cov" + }, + "private": true +} diff --git a/multipart-file-mode/test/index.test.js b/multipart-file-mode/test/index.test.js new file mode 100644 index 0000000..b7378be --- /dev/null +++ b/multipart-file-mode/test/index.test.js @@ -0,0 +1,83 @@ +'use strict'; + +const path = require('path'); +const assert = require('assert'); +const mm = require('egg-mock'); +const rimraf = require('mz-modules/rimraf'); + +describe('example multipart test', () => { + let app; + before(async () => { + app = mm.app(); + await app.ready(); + }); + after(() => app.close()); + after(() => rimraf(path.join(app.config.baseDir, 'app/public'))); + + describe('form', () => { + it('should upload', async () => { + app.mockCsrf(); + await app.httpRequest() + .post('/form') + .field('name', 'form') + .attach('file', path.join(__dirname, 'mc.jpeg')) + .expect('Location', '/public/form.jpeg') + .expect(302); + + await app.httpRequest() + .get('/public/form.jpeg') + .expect('content-length', '6635') + .expect(200); + }); + }); + + describe('multiple', () => { + it('should upload', async () => { + app.mockCsrf(); + await app.httpRequest() + .post('/multiple-file') + .field('name1', '1') + .attach('file1', path.join(__dirname, 'mc.jpeg')) + .field('name2', '2') + .attach('file2', path.join(__dirname, 'kfc.jpeg')) + .field('name3', '3') + .expect(res => { + assert(res.text.includes('name1: 1')); + assert(res.text.includes('name2: 2')); + assert(res.text.includes('name3: 3')); + assert(res.text.includes('href="/public/mc.jpeg"')); + assert(res.text.includes('href="/public/kfc.jpeg"')); + }) + .expect(200); + + await app.httpRequest() + .get('/public/mc.jpeg') + .expect('content-length', '6635') + .expect(200); + + await app.httpRequest() + .get('/public/kfc.jpeg') + .expect('content-length', '28810') + .expect(200); + }); + }); + + describe('ajax', () => { + it('should upload', async () => { + app.mockCsrf(); + await app.httpRequest() + .post('/ajax') + .field('name', 'ajax') + .attach('file', path.join(__dirname, 'mc.jpeg')) + .expect({ + url: '/public/ajax.jpeg', + }) + .expect(200); + + await app.httpRequest() + .get('/public/ajax.jpeg') + .expect('content-length', '6635') + .expect(200); + }); + }); +}); diff --git a/multipart-file-mode/test/kfc.jpeg b/multipart-file-mode/test/kfc.jpeg new file mode 100644 index 0000000..8a43190 Binary files /dev/null and b/multipart-file-mode/test/kfc.jpeg differ diff --git a/multipart-file-mode/test/mc.jpeg b/multipart-file-mode/test/mc.jpeg new file mode 100644 index 0000000..a1bedce Binary files /dev/null and b/multipart-file-mode/test/mc.jpeg differ diff --git a/package.json b/package.json index 20b0814..eb04cb1 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,9 @@ }, "ci": { "version": "8", + "license": { + "year": 2017 + }, "afterScript": false }, "license": "MIT", diff --git a/sequelize/README.md b/sequelize/README.md index b89f628..cfd8355 100644 --- a/sequelize/README.md +++ b/sequelize/README.md @@ -8,7 +8,7 @@ The [egg] example project that uses [egg-sequelize] plugin. It will show you how - install mysql and create database -``` +```bash brew install mysql # macOS brew service start mysql @@ -19,7 +19,7 @@ mysql - install dependencies -``` +```bash npm install ``` @@ -27,7 +27,7 @@ npm install - prepare database structure -``` +```bash # for develop npm run sequelize -- db:migrate # for unittest @@ -36,13 +36,13 @@ NODE_ENV=test npm run sequelize -- db:migrate - start project -``` +```bash npm run dev ``` - run test -``` +```bash npm test ``` diff --git a/sequelize/README.zh-CN.md b/sequelize/README.zh-CN.md index c229895..fa78397 100644 --- a/sequelize/README.zh-CN.md +++ b/sequelize/README.zh-CN.md @@ -8,7 +8,7 @@ - 安装 mysql 并建立数据库 -``` +```bash brew install mysql # macOS brew service start mysql @@ -19,7 +19,7 @@ mysql - 安装 node 依赖 -``` +```bash npm install ``` @@ -27,7 +27,7 @@ npm install - 执行 migration 执行数据变更 -``` +```bash # for develop npm run sequelize -- db:migrate # for unittest @@ -36,13 +36,13 @@ NODE_ENV=test npm run sequelize -- db:migrate - 启动项目 -``` +```bash npm run dev ``` - 运行测试 -``` +```bash npm test ``` diff --git a/sequelize/package.json b/sequelize/package.json index 05da784..5f4cea6 100644 --- a/sequelize/package.json +++ b/sequelize/package.json @@ -21,7 +21,7 @@ }, "scripts": { "dev": "egg-bin dev", - "test": "egg-bin test", + "test": "NODE_ENV=test npm run sequelize -- db:migrate && egg-bin test", "cov": "egg-bin cov", "ci": "npm run cov", "autod": "autod",