From ccfe56c0d3d6780f08209710b569bfccd88c892c Mon Sep 17 00:00:00 2001 From: sliang-code Date: Sat, 24 Jan 2026 00:05:39 +0000 Subject: [PATCH] Refactor (src/user/picture.js): reduce complexity and improve export structure --- src/user/picture.js | 163 +++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 78 deletions(-) diff --git a/src/user/picture.js b/src/user/picture.js index fbff7fd225..6fb09cc394 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -10,19 +10,7 @@ const file = require('../file'); const image = require('../image'); const meta = require('../meta'); -module.exports = function (User) { - User.getAllowedProfileImageExtensions = function () { - const exts = User.getAllowedImageTypes().map(type => mime.getExtension(type)); - if (exts.includes('jpeg')) { - exts.push('jpg'); - } - return exts; - }; - - User.getAllowedImageTypes = function () { - return ['image/png', 'image/jpeg', 'image/bmp', 'image/gif']; - }; - +function initCoverMethods(User) { User.updateCoverPosition = async function (uid, position) { // Reject anything that isn't two percentages if (!/^[\d.]+%\s[\d.]+%$/.test(position)) { @@ -52,7 +40,7 @@ module.exports = function (User) { const filename = `${data.uid}-profilecover-${Date.now()}${extension}`; const uploadData = await image.uploadImage(filename, `profile/uid-${data.uid}`, picture); - await deleteCurrentPicture(data.uid, 'cover:url'); + await deleteCurrentPicture(User, data.uid, 'cover:url'); await User.setUserField(data.uid, 'cover:url', uploadData.url); if (data.position) { @@ -66,7 +54,13 @@ module.exports = function (User) { await file.delete(picture.path); } }; + User.removeCoverPicture = async function (data) { + await deletePicture(User, data.uid, 'cover:url'); + await db.deleteObjectFields(`user:${data.uid}`, ['cover:url', 'cover:position']); + }; +} +function initProfileImageMethods(User) { // uploads a image file as profile picture User.uploadCroppedPictureFile = async function (data) { const userPhoto = data.file; @@ -102,7 +96,7 @@ module.exports = function (User) { name: 'profileAvatar', }); - await deleteCurrentPicture(data.uid, 'uploadedpicture'); + await deleteCurrentPicture(User, data.uid, 'uploadedpicture'); await User.updateProfile(data.callerUid, { uid: data.uid, uploadedpicture: uploadedImage.url, @@ -110,7 +104,6 @@ module.exports = function (User) { }, ['uploadedpicture', 'picture']); return uploadedImage; }; - // uploads image data in base64 as profile picture User.uploadCroppedPicture = async function (data) { const picture = { @@ -142,7 +135,7 @@ module.exports = function (User) { const filename = generateProfileImageFilename(data.uid, extension); const uploadedImage = await image.uploadImage(filename, `profile/uid-${data.uid}`, picture); - await deleteCurrentPicture(data.uid, 'uploadedpicture'); + await deleteCurrentPicture(User, data.uid, 'uploadedpicture'); await User.updateProfile(data.callerUid, { uid: data.uid, uploadedpicture: uploadedImage.url, @@ -153,59 +146,9 @@ module.exports = function (User) { await file.delete(picture.path); } }; - - async function deleteCurrentPicture(uid, field) { - if (meta.config['profile:keepAllUserImages']) { - return; - } - await deletePicture(uid, field); - } - - async function deletePicture(uid, field) { - const uploadPath = await getPicturePath(uid, field); - if (uploadPath) { - await file.delete(uploadPath); - } - } - - function validateUpload(data, maxSize, allowedTypes) { - if (!data.imageData) { - throw new Error('[[error:invalid-data]]'); - } - const size = image.sizeFromBase64(data.imageData); - if (size > maxSize * 1024) { - throw new Error(`[[error:file-too-big, ${maxSize}]]`); - } - - const type = image.mimeFromBase64(data.imageData); - if (!type || !allowedTypes.includes(type)) { - throw new Error('[[error:invalid-image]]'); - } - } - - async function convertToPNG(path) { - const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1; - if (!convertToPNG) { - return path; - } - const newPath = await image.normalise(path); - await file.delete(path); - return newPath; - } - - function generateProfileImageFilename(uid, extension) { - const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1; - return `${uid}-profileavatar-${Date.now()}${convertToPNG ? '.png' : extension}`; - } - - User.removeCoverPicture = async function (data) { - await deletePicture(data.uid, 'cover:url'); - await db.deleteObjectFields(`user:${data.uid}`, ['cover:url', 'cover:position']); - }; - User.removeProfileImage = async function (uid) { const userData = await User.getUserFields(uid, ['uploadedpicture', 'picture']); - await deletePicture(uid, 'uploadedpicture'); + await deletePicture(User, uid, 'uploadedpicture'); await User.setUserFields(uid, { uploadedpicture: '', // if current picture is uploaded picture, reset to user icon @@ -213,21 +156,85 @@ module.exports = function (User) { }); return userData; }; +} +function initGetters(User) { + User.getAllowedProfileImageExtensions = function () { + const exts = User.getAllowedImageTypes().map(type => mime.getExtension(type)); + if (exts.includes('jpeg')) { + exts.push('jpg'); + } + return exts; + }; + + User.getAllowedImageTypes = function () { + return ['image/png', 'image/jpeg', 'image/bmp', 'image/gif']; + }; + User.getLocalCoverPath = async function (uid) { - return getPicturePath(uid, 'cover:url'); + return getPicturePath(User, uid, 'cover:url'); }; User.getLocalAvatarPath = async function (uid) { - return getPicturePath(uid, 'uploadedpicture'); + return getPicturePath(User, uid, 'uploadedpicture'); }; +} - async function getPicturePath(uid, field) { - const value = await User.getUserField(uid, field); - if (!value || !value.startsWith(`${nconf.get('relative_path')}/assets/uploads/profile/uid-${uid}`)) { - return false; - } - const filename = value.split('/').pop(); - return path.join(nconf.get('upload_path'), `profile/uid-${uid}`, filename); +function validateUpload(data, maxSize, allowedTypes) { + if (!data.imageData) { + throw new Error('[[error:invalid-data]]'); + } + const size = image.sizeFromBase64(data.imageData); + if (size > maxSize * 1024) { + throw new Error(`[[error:file-too-big, ${maxSize}]]`); + } + + const type = image.mimeFromBase64(data.imageData); + if (!type || !allowedTypes.includes(type)) { + throw new Error('[[error:invalid-image]]'); + } +} +function generateProfileImageFilename(uid, extension) { + const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1; + return `${uid}-profileavatar-${Date.now()}${convertToPNG ? '.png' : extension}`; +} + +async function getPicturePath(User, uid, field) { + const value = await User.getUserField(uid, field); + if (!value || !value.startsWith(`${nconf.get('relative_path')}/assets/uploads/profile/uid-${uid}`)) { + return false; + } + const filename = value.split('/').pop(); + return path.join(nconf.get('upload_path'), `profile/uid-${uid}`, filename); +} + + +async function deleteCurrentPicture(User, uid, field) { + if (meta.config['profile:keepAllUserImages']) { + return; + } + await deletePicture(User, uid, field); +} + +async function deletePicture(User, uid, field) { + const uploadPath = await getPicturePath(User, uid, field); + if (uploadPath) { + await file.delete(uploadPath); } -}; +} + +async function convertToPNG(path) { + const convertToPNG = meta.config['profile:convertProfileImageToPNG'] === 1; + if (!convertToPNG) { + return path; + } + const newPath = await image.normalise(path); + await file.delete(path); + return newPath; +} + +module.exports = function (User) { + initGetters(User); + initCoverMethods(User); + initProfileImageMethods(User); +}; \ No newline at end of file