Skip to content

Commit 0c2461f

Browse files
committed
Merge branch 'feature/validate-upload-file' into dev
2 parents 47de115 + 5274da3 commit 0c2461f

File tree

6 files changed

+61
-9
lines changed

6 files changed

+61
-9
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ configs/**/credential.*
1414
# Generated files
1515
/build
1616
/.deploy
17-
/src/public/uploads
17+
/src/public/tmp
1818
/src/public/users
1919
/src/native/styles/index.js
2020
my-release-key.keystore

configs/project/client.js

+11
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,15 @@ module.exports = {
99
},
1010
},
1111
recaptcha: require('./recaptcha/client'),
12+
fileUpload: {
13+
avatar: {
14+
maxSize: 1024 * 1024, // in bytes
15+
// MIME type
16+
validMIMETypes: [
17+
'image/jpeg',
18+
'image/png',
19+
'image/gif',
20+
],
21+
},
22+
},
1223
};

src/common/components/forms/user/AvatarForm.js

+24-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,33 @@ const initialValues = {
1616
storage: 'local',
1717
};
1818

19-
const validate = (values) => {
19+
/**
20+
* Test server side validation with Postman:
21+
* 1. Setup the method and url `POST http://localhost:3000/api/users/me/avatar`
22+
* 2. Select `Body` tab
23+
* 3. Select `form-data` type
24+
* 4. Add new key `avatar` and select some invalid file on purpose
25+
* 5. Send
26+
*/
27+
export let validate = (values) => {
2028
const errors = {};
29+
2130
if (!values.avatar || values.avatar.length !== 1) {
2231
errors.avatar = 'Required';
32+
} else {
33+
let { size, type, mimetype } = values.avatar[0];
34+
let { maxSize, validMIMETypes } = configs.fileUpload.avatar;
35+
36+
if (size > maxSize) {
37+
errors.avatar = (
38+
`Your file(${Math.floor(size / 1024)} Kb) ` +
39+
`exceeds the limit size(${Math.floor(maxSize / 1024)} Kb).`
40+
);
41+
}
42+
// we check the key `type` for client side and `mimetype` for server side
43+
if (validMIMETypes.indexOf(type || mimetype) < 0) {
44+
errors.avatar = 'Invalid type. Please upload .jpg, .png or .gif file.';
45+
}
2346
}
2447

2548
return errors;

src/server/controllers/user.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import mkdirp from 'mkdirp';
14
import assign from 'object-assign';
25
import configs from '../../../configs/project/server';
36
import Errors from '../../common/constants/Errors';
4-
import { handleDbError } from '../decorators/handleError';
7+
import handleError, { handleDbError } from '../decorators/handleError';
58
import User from '../models/User';
69
import filterAttribute from '../utils/filterAttribute';
710
import { loginUser } from '../../common/actions/userActions';
@@ -213,8 +216,19 @@ export default {
213216
uploadAvatar(req, res) {
214217
// use `req.file` to access the avatar file
215218
// and use `req.body` to access other fileds
216-
res.json({
217-
downloadURL: `/users/${req.user._id}/${req.file.filename}`,
218-
});
219+
let { filename } = req.files.avatar[0];
220+
let tmpPath = req.files.avatar[0].path;
221+
let targetDir = path.join(
222+
__dirname, '../../public', 'users', req.user._id.toString()
223+
);
224+
let targetPath = path.join(targetDir, filename);
225+
226+
mkdirp(targetDir, handleError(res)(() => {
227+
fs.rename(tmpPath, targetPath, handleError(res)(() => {
228+
res.json({
229+
downloadURL: `/users/${req.user._id}/${filename}`,
230+
});
231+
}));
232+
}));
219233
},
220234
};

src/server/middlewares/validate.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import User from '../models/User';
88
export default {
99
form: (formPath, onlyFields = []) => (req, res, next) => {
1010
let { validate } = require(`../../common/components/forms/${formPath}`);
11-
let errors = validate(req.body);
11+
let errors = validate({
12+
...req.body,
13+
...req.files,
14+
});
1215

1316
if (onlyFields.length > 0) {
1417
let newErrors = {};

src/server/routes/api.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ export default ({ app }) => {
7878
app.post('/api/users/me/avatar',
7979
authRequired,
8080
fileUpload.disk({
81-
destination: 'users/{userId}',
81+
destination: 'tmp/{userId}',
8282
filename: 'avatar.jpg',
83-
}).single('avatar'),
83+
}).fields([{ name: 'avatar' }]),
84+
validate.form('user/AvatarForm'),
8485
userController.uploadAvatar);
8586

8687
// form

0 commit comments

Comments
 (0)