Skip to content

Commit 6a03a0b

Browse files
authored
feat: add file mode example on multipart (#86)
deps on eggjs/multipart#19
1 parent 11958bc commit 6a03a0b

25 files changed

+361
-27
lines changed

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) Alibaba Group Holding Limited and other contributors.
3+
Copyright (c) 2017-present Alibaba Group Holding Limited and other contributors.
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

appveyor.yml

-14
This file was deleted.

bin/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class Test extends Command {
3939
);
4040
try {
4141
const flag = argv.c ? ' -c' : '';
42-
await this.runscript(`npminstall${flag}`, { cwd: dir });
42+
await this.runscript(`npmupdate${flag}`, { cwd: dir });
4343
await this.runscript('npm test', { cwd: dir });
4444
console.info('%s success\n', chalk.green('✔'));
4545
success.add(dir);

multipart-file-mode/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
upload_dirs
2+
!upload_dirs/keepit
3+
app/public
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
const fs = require('mz/fs');
4+
const path = require('path');
5+
const Controller = require('egg').Controller;
6+
const pump = require('mz-modules/pump');
7+
8+
module.exports = class extends Controller {
9+
async show() {
10+
await this.ctx.render('page/ajax.html');
11+
}
12+
13+
async upload() {
14+
const { ctx } = this;
15+
const file = ctx.request.files[0];
16+
if (!file) return ctx.throw(404);
17+
18+
const filename = encodeURIComponent(ctx.request.body.name) + path.extname(file.filename).toLowerCase();
19+
const targetPath = path.join(this.config.baseDir, 'app/public', filename);
20+
const source = fs.createReadStream(file.filepath);
21+
const target = fs.createWriteStream(targetPath);
22+
await pump(source, target);
23+
ctx.logger.warn('save %s to %s', file.filepath, targetPath);
24+
// delete tmp file
25+
await fs.unlink(file.filepath);
26+
27+
ctx.body = { url: '/public/' + filename };
28+
}
29+
};
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
const fs = require('mz/fs');
4+
const path = require('path');
5+
const pump = require('mz-modules/pump');
6+
const Controller = require('egg').Controller;
7+
8+
module.exports = class extends Controller {
9+
async show() {
10+
await this.ctx.render('page/form.html');
11+
}
12+
13+
async upload() {
14+
const { ctx } = this;
15+
const file = ctx.request.files[0];
16+
if (!file) return ctx.throw(404);
17+
18+
const filename = encodeURIComponent(ctx.request.body.name) + path.extname(file.filename).toLowerCase();
19+
const targetPath = path.join(this.config.baseDir, 'app/public', filename);
20+
const source = fs.createReadStream(file.filepath);
21+
const target = fs.createWriteStream(targetPath);
22+
await pump(source, target);
23+
ctx.logger.warn('save %s to %s', file.filepath, targetPath);
24+
// delete tmp file
25+
await fs.unlink(file.filepath);
26+
27+
ctx.redirect('/public/' + filename);
28+
}
29+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict';
2+
3+
const Controller = require('egg').Controller;
4+
5+
module.exports = class extends Controller {
6+
async render() {
7+
await this.ctx.render('index.html');
8+
}
9+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
3+
const fs = require('mz/fs');
4+
const path = require('path');
5+
const pump = require('mz-modules/pump');
6+
const Controller = require('egg').Controller;
7+
8+
module.exports = class extends Controller {
9+
async show() {
10+
await this.ctx.render('page/multiple.html');
11+
}
12+
13+
async upload() {
14+
const { ctx } = this;
15+
const files = ctx.request.files;
16+
ctx.logger.warn('files: %j', files);
17+
for (const file of files) {
18+
const filename = file.filename.toLowerCase();
19+
const targetPath = path.join(this.config.baseDir, 'app/public', filename);
20+
const source = fs.createReadStream(file.filepath);
21+
const target = fs.createWriteStream(targetPath);
22+
await pump(source, target);
23+
ctx.logger.warn('save %s to %s', file.filepath, targetPath);
24+
// delete tmp file
25+
await fs.unlink(file.filepath);
26+
}
27+
28+
const fields = [];
29+
for (const k in ctx.request.body) {
30+
fields.push({
31+
key: k,
32+
value: ctx.request.body[k],
33+
});
34+
}
35+
36+
await ctx.render('page/multiple_result.html', {
37+
fields,
38+
files,
39+
});
40+
}
41+
};

multipart-file-mode/app/router.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
3+
module.exports = app => {
4+
app.router.get('/', 'home.render');
5+
6+
app.router.get('/ajax', app.controller.ajax.show);
7+
app.router.post('/ajax', app.controller.ajax.upload);
8+
9+
app.router.get('/form', app.controller.form.show);
10+
app.router.post('/form', app.controller.form.upload);
11+
12+
app.router.get('/multiple-file', app.controller.multiple.show);
13+
app.router.post('/multiple-file', app.controller.multiple.upload);
14+
};
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% extends "layout.html" %}
2+
{% block content %}
3+
<h2>Upload</h2>
4+
<ul>
5+
<li><a href="/form">Upload with Form</a></li>
6+
<li><a href="/ajax">Upload with Ajax</a></li>
7+
<li><a href="/multiple-file">Upload Multiple Files</a></li>
8+
</ul>
9+
{% endblock %}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
5+
</head>
6+
<body>
7+
{% block content %}
8+
{% endblock %}
9+
</body>
10+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{% extends "layout.html" %}
2+
3+
{% block content %}
4+
<h2>Upload Image</h2>
5+
<form>
6+
<ul>
7+
<li>Image Name: <input name="name" type="text" /></li>
8+
<li><input name="file" type="file" /></li>
9+
<li><input type="submit" value="Upload" /></li>
10+
</ul>
11+
</form>
12+
13+
<script>
14+
$('form').submit(function(e) {
15+
e.preventDefault();
16+
var formData = new FormData();
17+
formData.append('name', $('input[type=text]').val());
18+
// Attach file
19+
formData.append('image', $('input[type=file]')[0].files[0]);
20+
// console.log(formData);
21+
22+
$.ajax({
23+
url: '/ajax?_csrf=' + getCsrf(),
24+
data: formData,
25+
method: 'POST',
26+
contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
27+
processData: false, // NEEDED, DON'T OMIT THIS
28+
success: function(result) {
29+
console.log(result);
30+
location.href = result.url;
31+
},
32+
error: function(responseStr) {
33+
alert("error", responseStr);
34+
}
35+
});
36+
37+
function getCsrf() {
38+
var keyValue = document.cookie.match('(^|;) ?csrfToken=([^;]*)(;|$)');
39+
return keyValue ? keyValue[2] : null;
40+
}
41+
});
42+
</script>
43+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends "layout.html" %}
2+
3+
{% block content %}
4+
<h2>Upload Image</h2>
5+
<form action="/form?_csrf={{ ctx.csrf | safe }}" method="post" enctype="multipart/form-data">
6+
<ul>
7+
<li>Image Name: <input name="name" type="text" /></li>
8+
<li><input name="file" type="file" /></li>
9+
<li><input type="submit" value="Upload" /></li>
10+
</ul>
11+
</form>
12+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% extends "layout.html" %}
2+
{% block content %}
3+
<h2>Upload Image</h2>
4+
<form action="/multiple-file?_csrf={{ ctx.csrf | safe }}" method="post" enctype="multipart/form-data">
5+
<ul>
6+
<li><input name="name1" type="text" /></li>
7+
<li><input name="file1" type="file" /></li>
8+
<li><input name="name2" type="text" /></li>
9+
<li><input name="file2" type="file" /></li>
10+
<li><input name="name3" type="text" /></li>
11+
<li><input type="submit" value="Upload" /></li>
12+
</ul>
13+
</form>
14+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{% extends "layout.html" %}
2+
{% block content %}
3+
<h2>Upload Result</h2>
4+
<ul>
5+
{% for field in fields %}
6+
<li>{{ field.key }}: {{ field.value }}</li>
7+
{% endfor %}
8+
9+
{% for file in files %}
10+
<li><a href="/public/{{ file.filename }}" _target="blank">{{ file.filename }}</a></li>
11+
{% endfor %}
12+
</ul>
13+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
exports.keys = 'my keys';
4+
5+
exports.view = {
6+
defaultViewEngine: 'nunjucks',
7+
};
8+
9+
exports.multipart = {
10+
mode: 'file',
11+
};

multipart-file-mode/config/plugin.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use strict';
2+
3+
exports.nunjucks = {
4+
enable: true,
5+
package: 'egg-view-nunjucks',
6+
};

multipart-file-mode/package.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "multipart-file-mode-example",
3+
"dependencies": {
4+
"egg": "^2.11.2",
5+
"egg-view-nunjucks": "^2.1.4",
6+
"mz": "^2.7.0",
7+
"mz-modules": "^2.1.0"
8+
},
9+
"devDependencies": {
10+
"egg-bin": "^4.3.5",
11+
"egg-mock": "^3.13.1"
12+
},
13+
"scripts": {
14+
"dev": "egg-bin dev",
15+
"test": "egg-bin test",
16+
"cov": "egg-bin cov"
17+
},
18+
"private": true
19+
}
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const assert = require('assert');
5+
const mm = require('egg-mock');
6+
const rimraf = require('mz-modules/rimraf');
7+
8+
describe('example multipart test', () => {
9+
let app;
10+
before(async () => {
11+
app = mm.app();
12+
await app.ready();
13+
});
14+
after(() => app.close());
15+
after(() => rimraf(path.join(app.config.baseDir, 'app/public')));
16+
17+
describe('form', () => {
18+
it('should upload', async () => {
19+
app.mockCsrf();
20+
await app.httpRequest()
21+
.post('/form')
22+
.field('name', 'form')
23+
.attach('file', path.join(__dirname, 'mc.jpeg'))
24+
.expect('Location', '/public/form.jpeg')
25+
.expect(302);
26+
27+
await app.httpRequest()
28+
.get('/public/form.jpeg')
29+
.expect('content-length', '6635')
30+
.expect(200);
31+
});
32+
});
33+
34+
describe('multiple', () => {
35+
it('should upload', async () => {
36+
app.mockCsrf();
37+
await app.httpRequest()
38+
.post('/multiple-file')
39+
.field('name1', '1')
40+
.attach('file1', path.join(__dirname, 'mc.jpeg'))
41+
.field('name2', '2')
42+
.attach('file2', path.join(__dirname, 'kfc.jpeg'))
43+
.field('name3', '3')
44+
.expect(res => {
45+
assert(res.text.includes('name1: 1'));
46+
assert(res.text.includes('name2: 2'));
47+
assert(res.text.includes('name3: 3'));
48+
assert(res.text.includes('href="/public/mc.jpeg"'));
49+
assert(res.text.includes('href="/public/kfc.jpeg"'));
50+
})
51+
.expect(200);
52+
53+
await app.httpRequest()
54+
.get('/public/mc.jpeg')
55+
.expect('content-length', '6635')
56+
.expect(200);
57+
58+
await app.httpRequest()
59+
.get('/public/kfc.jpeg')
60+
.expect('content-length', '28810')
61+
.expect(200);
62+
});
63+
});
64+
65+
describe('ajax', () => {
66+
it('should upload', async () => {
67+
app.mockCsrf();
68+
await app.httpRequest()
69+
.post('/ajax')
70+
.field('name', 'ajax')
71+
.attach('file', path.join(__dirname, 'mc.jpeg'))
72+
.expect({
73+
url: '/public/ajax.jpeg',
74+
})
75+
.expect(200);
76+
77+
await app.httpRequest()
78+
.get('/public/ajax.jpeg')
79+
.expect('content-length', '6635')
80+
.expect(200);
81+
});
82+
});
83+
});

multipart-file-mode/test/kfc.jpeg

28.1 KB
Loading

multipart-file-mode/test/mc.jpeg

6.48 KB
Loading

0 commit comments

Comments
 (0)