diff --git a/public/language/en-GB/admin/settings/uploads.json b/public/language/en-GB/admin/settings/uploads.json index b08d56a5f8..9cd7b7d8f2 100644 --- a/public/language/en-GB/admin/settings/uploads.json +++ b/public/language/en-GB/admin/settings/uploads.json @@ -40,7 +40,7 @@ "default-avatar": "Custom Default Avatar", "upload": "Upload", "profile-image-dimension": "Profile Image Dimension", - "profile-image-dimension-help": "(in pixels, default: 128 pixels)", + "profile-image-dimension-help": "(in pixels, default: 200 pixels)", "max-profile-image-size": "Maximum Profile Image File Size", "max-profile-image-size-help": "(in kibibytes, default: 256 KiB)", "max-cover-image-size": "Maximum Cover Image File Size", diff --git a/public/openapi/components/schemas/UserObject.yaml b/public/openapi/components/schemas/UserObject.yaml index 61d98b1f80..7ebb831b84 100644 --- a/public/openapi/components/schemas/UserObject.yaml +++ b/public/openapi/components/schemas/UserObject.yaml @@ -450,6 +450,10 @@ UserObjectFull: type: boolean allowProfileImageUploads: type: number + maximumProfileImageSize: + type: number + profileImageDimension: + type: number allowedProfileImageExtensions: type: string groups: diff --git a/public/openapi/read/user/userslug/edit.yaml b/public/openapi/read/user/userslug/edit.yaml index 32c476c99f..0832943fbe 100644 --- a/public/openapi/read/user/userslug/edit.yaml +++ b/public/openapi/read/user/userslug/edit.yaml @@ -23,8 +23,6 @@ get: type: number maximumAboutMeLength: type: number - maximumProfileImageSize: - type: number allowProfilePicture: type: boolean allowCoverPicture: @@ -41,8 +39,6 @@ get: type: boolean allowSignature: type: boolean - profileImageDimension: - type: number defaultAvatar: type: string sso: diff --git a/public/src/modules/accounts/picture.js b/public/src/modules/accounts/picture.js index 6fe37df734..0bec1a24a9 100644 --- a/public/src/modules/accounts/picture.js +++ b/public/src/modules/accounts/picture.js @@ -169,15 +169,16 @@ define('accounts/picture', [ modal.modal('hide'); pictureCropper.show({ - socketMethod: 'user.uploadCroppedPicture', - route: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/uploadpicture', - aspectRatio: 1 / 1, - paramName: 'uid', - paramValue: ajaxify.data.theirid, - fileSize: ajaxify.data.maximumProfileImageSize, - allowSkippingCrop: false, title: '[[user:upload-picture]]', description: '[[user:upload-a-picture]]', + socketMethod: 'user.uploadCroppedPicture', + route: `${config.relative_path}/api/user/${ajaxify.data.userslug}/uploadpicture`, + aspectRatio: 1 / 1, + allowSkippingCrop: false, + paramName: 'uid', + paramValue: ajaxify.data.theirid, + restrictImageDimension: true, + imageDimension: ajaxify.data.profileImageDimension, accept: ajaxify.data.allowedProfileImageExtensions, }, function (url) { onUploadComplete(url); diff --git a/public/src/modules/pictureCropper.js b/public/src/modules/pictureCropper.js index ce69c6b6c3..9dbb34af22 100644 --- a/public/src/modules/pictureCropper.js +++ b/public/src/modules/pictureCropper.js @@ -101,12 +101,11 @@ define('pictureCropper', ['alerts'], function (alerts) { }); cropperModal.find('.crop-btn').on('click', function () { - $(this).addClass('disabled'); const imageData = checkCORS(cropperTool, data); if (!imageData) { return; } - + $(this).addClass('disabled'); cropperModal.find('#upload-progress-bar').css('width', '0%'); cropperModal.find('#upload-progress-box').show().removeClass('hide'); @@ -160,7 +159,7 @@ define('pictureCropper', ['alerts'], function (alerts) { params: socketData, }, function (err, result) { if (err) { - return alerts.error(err); + return callback(err); } if (socketData.progress + chunkSize < socketData.size) { @@ -178,9 +177,14 @@ define('pictureCropper', ['alerts'], function (alerts) { function checkCORS(cropperTool, data) { let imageData; try { + const opts = {}; + if (data.restrictImageDimension) { + opts.width = data.imageDimension; + opts.height = data.imageDimension; + } imageData = data.imageType ? - cropperTool.getCroppedCanvas().toDataURL(data.imageType) : - cropperTool.getCroppedCanvas().toDataURL(); + cropperTool.getCroppedCanvas(opts).toDataURL(data.imageType) : + cropperTool.getCroppedCanvas(opts).toDataURL(); } catch (err) { const corsErrors = [ 'The operation is insecure.', @@ -209,7 +213,7 @@ define('pictureCropper', ['alerts'], function (alerts) { } const file = fileInput[0].files[0]; - const fileSize = data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false; + const fileSize = data.hasOwnProperty('fileSize') && data.fileSize ? parseInt(data.fileSize, 10) : false; if (fileSize && file.size > fileSize * 1024) { return showAlert('error', '[[error:file-too-big, ' + fileSize + ']]'); } diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 1192687a5f..6c1c977e0d 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -35,12 +35,10 @@ editController.get = async function (req, res, next) { userData.customUserFields = customUserFields; userData.maximumSignatureLength = meta.config.maximumSignatureLength; userData.maximumAboutMeLength = meta.config.maximumAboutMeLength; - userData.maximumProfileImageSize = meta.config.maximumProfileImageSize; userData.allowMultipleBadges = meta.config.allowMultipleBadges === 1; userData.allowAccountDelete = meta.config.allowAccountDelete === 1; userData.allowAboutMe = !isSelf || !!meta.config['reputation:disabled'] || reputation >= meta.config['min:rep:aboutme']; userData.allowSignature = canUseSignature && (!isSelf || !!meta.config['reputation:disabled'] || reputation >= meta.config['min:rep:signature']); - userData.profileImageDimension = meta.config.profileImageDimension; userData.defaultAvatar = user.getDefaultAvatar(); userData.groups = _groups.filter(g => g && g.userTitleEnabled && !groups.isPrivilegeGroup(g.name) && g.name !== 'registered-users'); diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index af5963002e..ba08f7187b 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -97,6 +97,8 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {}) userData.allowCoverPicture = !userData.isSelf || !!meta.config['reputation:disabled'] || userData.reputation >= meta.config['min:rep:cover-picture']; userData.allowProfileImageUploads = meta.config.allowProfileImageUploads; userData.allowedProfileImageExtensions = user.getAllowedProfileImageExtensions().map(ext => `.${ext}`).join(', '); + userData.maximumProfileImageSize = meta.config.maximumProfileImageSize; + userData.profileImageDimension = meta.config.profileImageDimension; userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : []; userData.selectedGroup = userData.groups.filter(group => group && userData.groupTitleArray.includes(group.name)) .sort((a, b) => userData.groupTitleArray.indexOf(a.name) - userData.groupTitleArray.indexOf(b.name)); diff --git a/src/image.js b/src/image.js index 0d60fddc6a..b2a69d7e3f 100644 --- a/src/image.js +++ b/src/image.js @@ -51,7 +51,10 @@ image.resizeImage = async function (data) { const metadata = await sharpImage.metadata(); sharpImage.rotate(); // auto-orients based on exif data - sharpImage.resize(data.hasOwnProperty('width') ? data.width : null, data.hasOwnProperty('height') ? data.height : null); + // don't resize if width/height not changing or not specificied + if ((data.width && metadata.width !== data.width) || (data.height && metadata.height !== data.height)) { + sharpImage.resize(data.width || null, data.height || null); + } if (data.quality) { switch (metadata.format) {