Skip to content

Commit

Permalink
feat: add file mode example on multipart (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Sep 29, 2018
1 parent 11958bc commit 6a03a0b
Show file tree
Hide file tree
Showing 25 changed files with 361 additions and 27 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -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
Expand Down
14 changes: 0 additions & 14 deletions appveyor.yml

This file was deleted.

2 changes: 1 addition & 1 deletion bin/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions multipart-file-mode/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
upload_dirs
!upload_dirs/keepit
app/public
29 changes: 29 additions & 0 deletions multipart-file-mode/app/controller/ajax.js
Original file line number Diff line number Diff line change
@@ -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 };
}
};
29 changes: 29 additions & 0 deletions multipart-file-mode/app/controller/form.js
Original file line number Diff line number Diff line change
@@ -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);
}
};
9 changes: 9 additions & 0 deletions multipart-file-mode/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

const Controller = require('egg').Controller;

module.exports = class extends Controller {
async render() {
await this.ctx.render('index.html');
}
};
41 changes: 41 additions & 0 deletions multipart-file-mode/app/controller/multiple.js
Original file line number Diff line number Diff line change
@@ -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,
});
}
};
14 changes: 14 additions & 0 deletions multipart-file-mode/app/router.js
Original file line number Diff line number Diff line change
@@ -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);
};
9 changes: 9 additions & 0 deletions multipart-file-mode/app/view/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "layout.html" %}
{% block content %}
<h2>Upload</h2>
<ul>
<li><a href="/form">Upload with Form</a></li>
<li><a href="/ajax">Upload with Ajax</a></li>
<li><a href="/multiple-file">Upload Multiple Files</a></li>
</ul>
{% endblock %}
10 changes: 10 additions & 0 deletions multipart-file-mode/app/view/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
43 changes: 43 additions & 0 deletions multipart-file-mode/app/view/page/ajax.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{% extends "layout.html" %}

{% block content %}
<h2>Upload Image</h2>
<form>
<ul>
<li>Image Name: <input name="name" type="text" /></li>
<li><input name="file" type="file" /></li>
<li><input type="submit" value="Upload" /></li>
</ul>
</form>

<script>
$('form').submit(function(e) {
e.preventDefault();
var formData = new FormData();
formData.append('name', $('input[type=text]').val());
// Attach file
formData.append('image', $('input[type=file]')[0].files[0]);
// console.log(formData);

$.ajax({
url: '/ajax?_csrf=' + getCsrf(),
data: formData,
method: 'POST',
contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
processData: false, // NEEDED, DON'T OMIT THIS
success: function(result) {
console.log(result);
location.href = result.url;
},
error: function(responseStr) {
alert("error", responseStr);
}
});

function getCsrf() {
var keyValue = document.cookie.match('(^|;) ?csrfToken=([^;]*)(;|$)');
return keyValue ? keyValue[2] : null;
}
});
</script>
{% endblock %}
12 changes: 12 additions & 0 deletions multipart-file-mode/app/view/page/form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends "layout.html" %}

{% block content %}
<h2>Upload Image</h2>
<form action="/form?_csrf={{ ctx.csrf | safe }}" method="post" enctype="multipart/form-data">
<ul>
<li>Image Name: <input name="name" type="text" /></li>
<li><input name="file" type="file" /></li>
<li><input type="submit" value="Upload" /></li>
</ul>
</form>
{% endblock %}
14 changes: 14 additions & 0 deletions multipart-file-mode/app/view/page/multiple.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends "layout.html" %}
{% block content %}
<h2>Upload Image</h2>
<form action="/multiple-file?_csrf={{ ctx.csrf | safe }}" method="post" enctype="multipart/form-data">
<ul>
<li><input name="name1" type="text" /></li>
<li><input name="file1" type="file" /></li>
<li><input name="name2" type="text" /></li>
<li><input name="file2" type="file" /></li>
<li><input name="name3" type="text" /></li>
<li><input type="submit" value="Upload" /></li>
</ul>
</form>
{% endblock %}
13 changes: 13 additions & 0 deletions multipart-file-mode/app/view/page/multiple_result.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends "layout.html" %}
{% block content %}
<h2>Upload Result</h2>
<ul>
{% for field in fields %}
<li>{{ field.key }}: {{ field.value }}</li>
{% endfor %}

{% for file in files %}
<li><a href="/public/{{ file.filename }}" _target="blank">{{ file.filename }}</a></li>
{% endfor %}
</ul>
{% endblock %}
11 changes: 11 additions & 0 deletions multipart-file-mode/config/config.default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

exports.keys = 'my keys';

exports.view = {
defaultViewEngine: 'nunjucks',
};

exports.multipart = {
mode: 'file',
};
6 changes: 6 additions & 0 deletions multipart-file-mode/config/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict';

exports.nunjucks = {
enable: true,
package: 'egg-view-nunjucks',
};
19 changes: 19 additions & 0 deletions multipart-file-mode/package.json
Original file line number Diff line number Diff line change
@@ -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
}
83 changes: 83 additions & 0 deletions multipart-file-mode/test/index.test.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
Binary file added multipart-file-mode/test/kfc.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added multipart-file-mode/test/mc.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6a03a0b

Please sign in to comment.