Skip to content

Commit 5b1b240

Browse files
nanzmJacksonTian
authored andcommitted
fix: upload file (#101)
* fix: upload file (#99) * test: add upload test (#99) * fix: del sync code * fix:move qnUpload hepler into service * snyk pass * lint * fix: some specifics
1 parent 782c164 commit 5b1b240

File tree

9 files changed

+95
-26
lines changed

9 files changed

+95
-26
lines changed

.snyk

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
2+
version: v1.10.2
3+
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
4+
ignore:
5+
'npm:hoek:20180212':
6+
- loader-builder > less > request > hawk > hoek:
7+
reason: None given
8+
expires: '2018-04-24T12:22:34.546Z'
9+
- loader-builder > less > request > hawk > boom > hoek:
10+
reason: i dont know how to fix this.
11+
expires: '2018-04-24T12:22:34.546Z'
12+
- loader-builder > less > request > hawk > sntp > hoek:
13+
reason: None given
14+
expires: '2018-04-24T12:22:34.546Z'
15+
- loader-builder > less > request > hawk > cryptiles > boom > hoek:
16+
reason: None given
17+
expires: '2018-04-24T12:22:34.546Z'
18+
- loader-koa > less > request > hawk > boom > hoek:
19+
reason: None given
20+
expires: '2018-04-24T12:22:34.547Z'
21+
- loader-koa > less > request > hawk > sntp > hoek:
22+
reason: None given
23+
expires: '2018-04-24T12:22:34.547Z'
24+
- loader-koa > less > request > hawk > cryptiles > boom > hoek:
25+
reason: None given
26+
expires: '2018-04-24T12:22:34.547Z'
27+
'npm:mime:20170907':
28+
- qiniu > mime:
29+
reason: None given
30+
expires: '2018-04-24T12:22:34.547Z'
31+
patch: {}

app/controller/topic.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Controller = require('egg').Controller;
44
const _ = require('lodash');
55
const path = require('path');
66
const fs = require('fs');
7+
const uuidv1 = require('uuid/v1');
78
const awaitWriteStream = require('await-stream-ready').write;
89
const sendToWormhole = require('stream-wormhole');
910

@@ -415,26 +416,25 @@ class TopicController extends Controller {
415416
* 上传
416417
*/
417418
async upload() {
418-
const { ctx, config } = this;
419+
const { ctx, config, service } = this;
420+
const uid = uuidv1();
419421
const stream = await ctx.getFileStream();
420-
const filename = encodeURIComponent(stream.fields.name) +
421-
path.extname(stream.filename).toLowerCase();
422-
const target = path.join(config.upload.path, filename);
422+
const filename = uid + path.extname(stream.filename).toLowerCase();
423423

424424
// 如果有七牛云的配置,优先上传七牛云
425-
if (config.qn_access) {
425+
if (config.qn_access && config.qn_access.secretKey !== 'your secret key') {
426426
try {
427-
const upload = this.ctx.helper.qnUpload(config.qn_access);
428-
const result = await upload(stream);
427+
const result = await service.topic.qnUpload(stream, filename);
429428
ctx.body = {
430429
success: true,
431-
url: result.url,
430+
url: config.qn_access.origin + '/' + result.key,
432431
};
433432
} catch (err) {
434433
await sendToWormhole(stream);
435434
throw err;
436435
}
437436
} else {
437+
const target = path.join(config.upload.path, filename);
438438
const writeStream = fs.createWriteStream(target);
439439
try {
440440
await awaitWriteStream(stream.pipe(writeStream));

app/extend/helper.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ const validator = require('validator');
55
const jsxss = require('xss');
66
const moment = require('moment');
77
const bcrypt = require('bcryptjs');
8-
const util = require('util');
9-
const qn = require('qn');
108

119
moment.locale('zh-cn'); // 使用中文
1210

@@ -114,16 +112,3 @@ exports.bhash = str => {
114112
exports.bcompare = (str, hash) => {
115113
return bcrypt.compareSync(str, hash);
116114
};
117-
118-
let qnClientUpload;
119-
120-
exports.qnUpload = options => {
121-
// 7牛 client
122-
if (qnClientUpload) return qnClientUpload;
123-
let qnClient;
124-
if (options.qn_access && options.qn_access.secretKey !== 'your secret key') {
125-
qnClient = qn.create(options.qn_access);
126-
}
127-
qnClientUpload = util.promisify(qnClient.upload);
128-
return qnClientUpload;
129-
};

app/public/upload/.gitkeep

Whitespace-only changes.

app/router.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ module.exports = app => {
9595
router.post('/reply/:reply_id/edit', userRequired, reply.update); // 修改某评论
9696
router.post('/reply/:reply_id/delete', userRequired, reply.delete); // 删除某评论
9797
router.post('/reply/:reply_id/up', userRequired, reply.up); // 为评论点赞
98-
// router.post('/upload', auth.userRequired, topic.upload); // 上传图片
98+
router.post('/upload', userRequired, topic.upload); // 上传图片
9999
// static page
100100
router.get('/about', page.about);
101101
router.get('/faq', page.faq);

app/service/topic.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const Service = require('egg').Service;
4+
const qiniu = require('qiniu');
45

56
class TopicService extends Service {
67
/*
@@ -179,6 +180,38 @@ class TopicService extends Service {
179180

180181
return topic.save();
181182
}
183+
184+
/*
185+
* 七牛上传
186+
* @param {Stream} readableStream 流
187+
* @param {String} key 文件名key
188+
* @param {Function} callback 回调函数
189+
*/
190+
qnUpload(readableStream, key) {
191+
const { accessKey, secretKey, bucket } = this.config.qn_access;
192+
193+
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
194+
const putPolicy = new qiniu.rs.PutPolicy({ scope: bucket });
195+
const uploadToken = putPolicy.uploadToken(mac);
196+
197+
const config = new qiniu.conf.Config();
198+
const formUploader = new qiniu.form_up.FormUploader(config);
199+
const putExtra = new qiniu.form_up.PutExtra();
200+
201+
return new Promise(function(resolve, reject) {
202+
formUploader.putStream(uploadToken, key, readableStream, putExtra, function(respErr, respBody, respInfo) {
203+
if (respErr) {
204+
reject(respErr);
205+
return;
206+
}
207+
if (respInfo.statusCode === 200) {
208+
resolve(respBody);
209+
} else {
210+
reject(new Error('上传失败:statusCode !== 200'));
211+
}
212+
});
213+
});
214+
}
182215
}
183216

184217
module.exports = TopicService;

config/config.default.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ module.exports = appInfo => {
6767
// 文件上传配置
6868
// 注:如果填写 qn_access,则会上传到 7牛,以下配置无效
6969
config.upload = {
70-
path: path.join(__dirname, 'public/upload/'),
70+
path: path.join(__dirname, '../app/public/upload/'),
7171
url: '/public/upload/',
7272
};
7373

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"markdown-it": "^8.4.1",
2525
"nodemailer": "^4.6.2",
2626
"nodemailer-smtp-transport": "^2.7.4",
27-
"qn": "^1.3.0",
27+
"qiniu": "^7.1.3",
2828
"stream-wormhole": "^1.0.3",
2929
"uuid": "^3.2.1",
3030
"validator": "^9.4.1",

test/app/controller/topic.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const { app, assert } = require('egg-mock/bootstrap');
4+
const path = require('path');
45

56
function randomInt() {
67
return (Math.random() * 10000).toFixed(0);
@@ -287,4 +288,23 @@ describe('test/app/controller/topic.test.js', () => {
287288
await app.httpRequest().post(`/topic/${topicId}/delete`).expect(200);
288289
await app.httpRequest().post(`/topic/${objectId}/delete`).expect(422);
289290
});
291+
292+
it('should POST /upload ok', async () => {
293+
const file = path.resolve(__dirname, '../../../app/public/images/logo.png');
294+
mockUser();
295+
await app
296+
.httpRequest()
297+
.post('/upload')
298+
.attach('logo', file)
299+
.expect(200);
300+
});
301+
302+
it('should POST /upload forbidden', async () => {
303+
const file = path.resolve(__dirname, '../../../app/public/images/logo.png');
304+
await app
305+
.httpRequest()
306+
.post('/upload')
307+
.attach('logo', file)
308+
.expect(403);
309+
});
290310
});

0 commit comments

Comments
 (0)