From e53a18f219858dd44cba4941f6c5ac7841580d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 24 Jun 2020 23:04:24 -0400 Subject: [PATCH] fix: #8437, #8433 --- public/src/client/account/edit.js | 3 +- src/controllers/accounts/edit.js | 27 +++++++++++++++++ src/routes/api.js | 2 ++ src/user/picture.js | 48 +++++++++++++++++++++++++++++-- 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index c6f99d733b..aeb63b7561 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -206,7 +206,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' updateHeader(urlOnServer); - if (ajaxify.data.picture.length) { + if (ajaxify.data.picture && ajaxify.data.picture.length) { $('#user-current-picture, img.avatar').attr('src', urlOnServer); ajaxify.data.uploadedpicture = urlOnServer; } else { @@ -228,6 +228,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' pictureCropper.show({ socketMethod: 'user.uploadCroppedPicture', + route: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/uploadpicture', aspectRatio: 1 / 1, paramName: 'uid', paramValue: ajaxify.data.theirid, diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 9e23d736fd..0f81163391 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -7,6 +7,7 @@ const helpers = require('../helpers'); const groups = require('../../groups'); const accountHelpers = require('./helpers'); const privileges = require('../../privileges'); +const file = require('../../file'); const editController = module.exports; @@ -124,3 +125,29 @@ async function getUserData(req) { userData.hasPassword = await user.hasPassword(userData.uid); return userData; } + +editController.uploadPicture = async function (req, res, next) { + const userPhoto = req.files.files[0]; + try { + const updateUid = await user.getUidByUserslug(req.params.userslug); + const isAllowed = await privileges.users.canEdit(req.uid, updateUid); + if (!isAllowed) { + return helpers.notAllowed(req, res); + } + await user.checkMinReputation(req.uid, updateUid, 'min:rep:profile-picture'); + + const image = await user.uploadCroppedPictureFile({ + uid: updateUid, + file: userPhoto, + }); + + res.json([{ + name: userPhoto.name, + url: image.url, + }]); + } catch (err) { + next(err); + } finally { + await file.delete(userPhoto.path); + } +}; diff --git a/src/routes/api.js b/src/routes/api.js index 1e94de1d96..bc66050358 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -34,4 +34,6 @@ module.exports = function (app, middleware, controllers) { var middlewares = [middleware.maintenanceMode, multipartMiddleware, middleware.validateFiles, middleware.applyCSRF]; router.post('/post/upload', middlewares, uploadsController.uploadPost); router.post('/topic/thumb/upload', middlewares, uploadsController.uploadThumb); + + router.post('/user/:userslug/uploadpicture', middlewares.concat([middleware.exposeUid, middleware.authenticate, middleware.canViewUsers, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadPicture); }; diff --git a/src/user/picture.js b/src/user/picture.js index 5419b062e5..b1ae0f72e2 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -61,10 +61,52 @@ module.exports = function (User) { url: uploadData.url, }; } finally { - file.delete(picture.path); + await file.delete(picture.path); } }; + // uploads a image file as profile picture + User.uploadCroppedPictureFile = async function (data) { + const userPhoto = data.file; + if (!meta.config.allowProfileImageUploads) { + throw new Error('[[error:profile-image-uploads-disabled]]'); + } + + if (userPhoto.size > meta.config.maximumProfileImageSize * 1024) { + throw new Error('[[error:file-too-big, ' + meta.config.maximumProfileImageSize + ']]'); + } + + if (!userPhoto.type || !User.getAllowedImageTypes().includes(userPhoto.type)) { + throw new Error('[[error:invalid-image]]'); + } + + const extension = file.typeToExtension(userPhoto.type); + if (!extension) { + throw new Error('[[error:invalid-image-extension]]'); + } + + const newPath = await convertToPNG(userPhoto.path); + + await image.resizeImage({ + path: newPath, + width: meta.config.profileImageDimension, + height: meta.config.profileImageDimension, + }); + + const filename = generateProfileImageFilename(data.uid, extension); + const uploadedImage = await image.uploadImage(filename, 'profile', { + uid: data.uid, + path: newPath, + }); + + await User.setUserFields(data.uid, { + uploadedpicture: uploadedImage.url, + picture: uploadedImage.url, + }); + return uploadedImage; + }; + + // uploads image data in base64 as profile picture User.uploadCroppedPicture = async function (data) { const picture = { name: 'profileAvatar', @@ -101,7 +143,7 @@ module.exports = function (User) { }); return uploadedImage; } finally { - file.delete(picture.path); + await file.delete(picture.path); } }; @@ -126,7 +168,7 @@ module.exports = function (User) { return path; } const newPath = await image.normalise(path); - file.delete(path); + await file.delete(path); return newPath; }