Skip to content

Commit

Permalink
feat(server): support upload
Browse files Browse the repository at this point in the history
  • Loading branch information
chuangker committed Nov 29, 2017
1 parent c2232dc commit af0827a
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -27,3 +27,4 @@ yarn-error.log*
dist
config
views/config.json
public/upload
4 changes: 4 additions & 0 deletions config/default.json
Expand Up @@ -22,6 +22,10 @@
"collection": "tokens",
"secret": "shared-secret"
},
"upload": {
"types": [".jpg", ".jpeg", ".png", ".gif", ".json", ".yml"],
"size": 5242880
},
"publicAPIs": [
"/api/proxy",
"/api/u/login",
Expand Down
57 changes: 57 additions & 0 deletions controllers/util.js
@@ -1,8 +1,16 @@
'use strict'

const fs = require('fs')
const path = require('path')
const { URL } = require('url')
const axios = require('axios')
const moment = require('moment')
const mkdirp = require('mkdirp')
const crypto = require('crypto')
const LRU = require('lru-cache')
const config = require('config')
const parse = require('co-busboy')
const concat = require('concat-stream')
const unsplashClientId = config.get('unsplashClientId')
const unsplashCache = LRU({
max: 1,
Expand Down Expand Up @@ -48,3 +56,52 @@ exports.wallpaper = function * () {
}
unsplashCache.set('one', this.body)
}

exports.upload = function * () {
const origin = this.request.origin
const conf = config.get('upload')
const hash = crypto.createHash('md5')
const day = moment().format('YYYY/MM/DD')
const uploadDir = path.join(__dirname, '../public/upload', day)
const handleLimit = function () {
limitError = new Error('上传失败,超过限定大小')
part && part.removeListener('limit', handleLimit)
}
const parts = parse(this, {
limits: {
fileSize: conf.size
},
checkFile: function (fieldname, file, filename) {
const suffix = path.extname(filename).toLowerCase()
file.on('limit', handleLimit)
if (conf.types.indexOf(suffix) === -1) {
return new Error(`上传失败,仅支持 ${conf.types.join('/').replace(/\./g, '')} 文件类型`)
}
}
})
let part, limitError, body

if (!fs.existsSync(uploadDir)) mkdirp.sync(uploadDir)

try {
while ((part = yield parts)) {
part.pipe(concat((fileContent) => {
const suffix = path.extname(part.filename).toLowerCase()
const fileName = hash.update(fileContent).digest('hex') + suffix
const filePath = path.join(uploadDir, fileName)
if (limitError) {
body = this.util.refail(limitError.message)
} else {
fs.writeFileSync(filePath, fileContent)
body = this.util.resuccess({
path: new URL(filePath.replace(path.join(__dirname, '..'), ''), origin)
})
}
}))
}
} catch (error) {
body = this.util.refail(error && error.message)
}

this.body = body || this.util.refail('无文件上传')
}
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -29,6 +29,8 @@
"bunyan": "^1.8.5",
"clipboard": "^1.7.1",
"co": "^4.6.0",
"co-busboy": "^1.4.0",
"concat-stream": "^1.6.0",
"config": "^1.26.1",
"cross-env": "^5.0.1",
"iview": "^2.3.2",
Expand Down
1 change: 1 addition & 0 deletions router-config.js
Expand Up @@ -19,6 +19,7 @@ exports.mock = router({ prefix: routerPrefix.mock })
exports.api = router({ prefix: routerPrefix.api })
.get('/proxy', util.proxy)
.get('/wallpaper', util.wallpaper)
.post('/upload', util.upload)

.get('/realtime', realtime.list)
.get('/realtime/top/project', realtime.topProject)
Expand Down
55 changes: 55 additions & 0 deletions test/controllers/util.js
Expand Up @@ -2,9 +2,21 @@

require('should')

const path = require('path')
const support = require('../support')

describe('test/controllers/util.test.js', () => {
let user

before((done) => {
support.createUser().then((data) => {
user = data
done()
})
})

after(() => support.cleanCollections())

describe('#proxy', () => {
const url = encodeURIComponent('http://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1484223823846&pid=hp&video=1')

Expand All @@ -21,4 +33,47 @@ describe('test/controllers/util.test.js', () => {
support.r('get', `/proxy?url=${url}`).then(done())
})
})

describe('#upload', () => {
it('空文件', (done) => {
support.request
.post('/api/upload')
.set('Authorization', `Bearer ${user.token || ''}`)
.set('Content-Type', 'multipart/form-data; boundary=----WebKitFormBoundaryl8pytbOxkyNIdRgC')
.expect(200, function (err, res) {
if (!err) {
res.body.success.should.not.be.ok()
res.body.message.should.be.eql('无文件上传')
done()
}
})
})

it('正常上传', (done) => {
support.request
.post('/api/upload')
.set('Authorization', `Bearer ${user.token || ''}`)
.attach('file', path.join(__dirname, '../support/swagger.json'))
.expect(200, function (err, res) {
if (!err) {
res.body.success.should.be.ok()
res.body.data.path.should.not.empty()
done()
}
})
})

it('错误的文件类型', (done) => {
support.request
.post('/api/upload')
.set('Authorization', `Bearer ${user.token || ''}`)
.attach('file', path.join(__dirname, '../support/index.js'))
.expect(200, function (err, res) {
if (!err) {
res.body.success.should.not.be.ok()
done()
}
})
})
})
})
1 change: 1 addition & 0 deletions test/support/index.js
Expand Up @@ -27,6 +27,7 @@ function createRequest (prefix) {
}
}

exports.request = request
exports.r = createRequest(routerPrefix.api)
exports.m = createRequest(routerPrefix.mock)

Expand Down
18 changes: 17 additions & 1 deletion yarn.lock
Expand Up @@ -955,6 +955,10 @@ binary-extensions@^1.0.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0"

black-hole-stream@~0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/black-hole-stream/-/black-hole-stream-0.0.1.tgz#33b7a06b9f1e7453d6041b82974481d2152aea42"

block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
Expand Down Expand Up @@ -1145,7 +1149,7 @@ bunyan@~1.5.0:
mv "~2"
safe-json-stringify "~1"

busboy@^0.2.11:
busboy@^0.2.11, busboy@^0.2.8:
version "0.2.14"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
dependencies:
Expand Down Expand Up @@ -1237,6 +1241,10 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"

chan@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/chan/-/chan-0.6.1.tgz#ec0ad132e5bc62c27ef10ccbfc4d8dcd8ca00640"

cheerio@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.20.0.tgz#5c710f2bab95653272842ba01c6ea61b3545ec35"
Expand Down Expand Up @@ -1328,6 +1336,14 @@ co-body@^5.1.0:
raw-body "^2.2.0"
type-is "^1.6.14"

co-busboy@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/co-busboy/-/co-busboy-1.4.0.tgz#ac9b85c4a966f03b7df55d53746a0dc9c93fa741"
dependencies:
black-hole-stream "~0.0.1"
busboy "^0.2.8"
chan "^0.6.1"

co-render@1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/co-render/-/co-render-1.1.0.tgz#90f465fab9dc5e236117c5804c9fcf0724e6d160"
Expand Down

0 comments on commit af0827a

Please sign in to comment.