Skip to content

Commit

Permalink
Merge branch 'feature/validate-upload-file' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
gocreating committed Oct 31, 2016
2 parents 47de115 + 5274da3 commit 0c2461f
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ configs/**/credential.*
# Generated files
/build
/.deploy
/src/public/uploads
/src/public/tmp
/src/public/users
/src/native/styles/index.js
my-release-key.keystore
Expand Down
11 changes: 11 additions & 0 deletions configs/project/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,15 @@ module.exports = {
},
},
recaptcha: require('./recaptcha/client'),
fileUpload: {
avatar: {
maxSize: 1024 * 1024, // in bytes
// MIME type
validMIMETypes: [
'image/jpeg',
'image/png',
'image/gif',
],
},
},
};
25 changes: 24 additions & 1 deletion src/common/components/forms/user/AvatarForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,33 @@ const initialValues = {
storage: 'local',
};

const validate = (values) => {
/**
* Test server side validation with Postman:
* 1. Setup the method and url `POST http://localhost:3000/api/users/me/avatar`
* 2. Select `Body` tab
* 3. Select `form-data` type
* 4. Add new key `avatar` and select some invalid file on purpose
* 5. Send
*/
export let validate = (values) => {
const errors = {};

if (!values.avatar || values.avatar.length !== 1) {
errors.avatar = 'Required';
} else {
let { size, type, mimetype } = values.avatar[0];
let { maxSize, validMIMETypes } = configs.fileUpload.avatar;

if (size > maxSize) {
errors.avatar = (
`Your file(${Math.floor(size / 1024)} Kb) ` +
`exceeds the limit size(${Math.floor(maxSize / 1024)} Kb).`
);
}
// we check the key `type` for client side and `mimetype` for server side
if (validMIMETypes.indexOf(type || mimetype) < 0) {
errors.avatar = 'Invalid type. Please upload .jpg, .png or .gif file.';
}
}

return errors;
Expand Down
22 changes: 18 additions & 4 deletions src/server/controllers/user.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import assign from 'object-assign';
import configs from '../../../configs/project/server';
import Errors from '../../common/constants/Errors';
import { handleDbError } from '../decorators/handleError';
import handleError, { handleDbError } from '../decorators/handleError';
import User from '../models/User';
import filterAttribute from '../utils/filterAttribute';
import { loginUser } from '../../common/actions/userActions';
Expand Down Expand Up @@ -213,8 +216,19 @@ export default {
uploadAvatar(req, res) {
// use `req.file` to access the avatar file
// and use `req.body` to access other fileds
res.json({
downloadURL: `/users/${req.user._id}/${req.file.filename}`,
});
let { filename } = req.files.avatar[0];
let tmpPath = req.files.avatar[0].path;
let targetDir = path.join(
__dirname, '../../public', 'users', req.user._id.toString()
);
let targetPath = path.join(targetDir, filename);

mkdirp(targetDir, handleError(res)(() => {
fs.rename(tmpPath, targetPath, handleError(res)(() => {
res.json({
downloadURL: `/users/${req.user._id}/${filename}`,
});
}));
}));
},
};
5 changes: 4 additions & 1 deletion src/server/middlewares/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import User from '../models/User';
export default {
form: (formPath, onlyFields = []) => (req, res, next) => {
let { validate } = require(`../../common/components/forms/${formPath}`);
let errors = validate(req.body);
let errors = validate({
...req.body,
...req.files,
});

if (onlyFields.length > 0) {
let newErrors = {};
Expand Down
5 changes: 3 additions & 2 deletions src/server/routes/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ export default ({ app }) => {
app.post('/api/users/me/avatar',
authRequired,
fileUpload.disk({
destination: 'users/{userId}',
destination: 'tmp/{userId}',
filename: 'avatar.jpg',
}).single('avatar'),
}).fields([{ name: 'avatar' }]),
validate.form('user/AvatarForm'),
userController.uploadAvatar);

// form
Expand Down

0 comments on commit 0c2461f

Please sign in to comment.