Skip to content

Commit

Permalink
feat: move all user profile pics to folder, closes #12449 (#12450)
Browse files Browse the repository at this point in the history
* feat: move all user profile pics to folder

get rid of glob delete and just delete the uid-{uid} folder when deleting user images

* when exporting user uploads add all profile uploads

* uid check
  • Loading branch information
barisusakli committed Mar 28, 2024
1 parent aef3ea1 commit 8f9ac5c
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 17 deletions.
6 changes: 4 additions & 2 deletions src/api/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ const plugins = require('../plugins');
const events = require('../events');
const translator = require('../translator');
const sockets = require('../socket.io');

// const api = require('.');
const utils = require('../utils');

const usersAPI = module.exports;

Expand Down Expand Up @@ -686,6 +685,9 @@ usersAPI.generateExport = async (caller, { uid, type }) => {
if (!validTypes.includes(type)) {
throw new Error('[[error:invalid-data]]');
}
if (!utils.isNumber(uid) || !(parseInt(uid, 10) > 0)) {
throw new Error('[[error:invalid-uid]]');
}
const count = await db.incrObjectField('locks', `export:${uid}${type}`);
if (count > 1) {
throw new Error('[[error:already-exporting]]');
Expand Down
86 changes: 86 additions & 0 deletions src/upgrades/3.8.0/user-upload-folders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use strict';


const fs = require('fs');
const nconf = require('nconf');
const path = require('path');
const { mkdirp } = require('mkdirp');

const db = require('../../database');
const batch = require('../../batch');


module.exports = {
name: 'Create user upload folders',
timestamp: Date.UTC(2024, 4, 28),
method: async function () {
const { progress } = this;

const folder = path.join(nconf.get('upload_path'), 'profile');

const userPicRegex = /^\d+-profile/;
const files = (await fs.promises.readdir(folder, { withFileTypes: true }))
.filter(item => !item.isDirectory() && String(item.name).match(userPicRegex))
.map(item => item.name);

progress.total = files.length;
await batch.processArray(files, async (files) => {
progress.incr(files.length);
await Promise.all(files.map(async (file) => {
const uid = file.split('-')[0];
if (parseInt(uid, 10) > 0) {
await mkdirp(path.join(folder, `uid-${uid}`));
await fs.promises.rename(
path.join(folder, file),
path.join(folder, `uid-${uid}`, file),
);
}
}));
}, {
batch: 500,
});

await batch.processSortedSet('users:joindate', async (uids) => {
progress.incr(uids.length);
const usersData = await db.getObjects(uids.map(uid => `user:${uid}`));
const bulkSet = [];
usersData.forEach((userData) => {
const setObj = {};
if (userData && userData.picture &&
userData.picture.includes(`/uploads/profile/${userData.uid}-`) &&
!userData.picture.includes(`/uploads/profile/uid-${userData.uid}/${userData.uid}-`)) {
setObj.picture = userData.picture.replace(
`/uploads/profile/${userData.uid}-`,
`/uploads/profile/uid-${userData.uid}/${userData.uid}-`
);
}

if (userData && userData.uploadedpicture &&
userData.uploadedpicture.includes(`/uploads/profile/${userData.uid}-`) &&
!userData.uploadedpicture.includes(`/uploads/profile/uid-${userData.uid}/${userData.uid}-`)) {
setObj.uploadedpicture = userData.uploadedpicture.replace(
`/uploads/profile/${userData.uid}-`,
`/uploads/profile/uid-${userData.uid}/${userData.uid}-`
);
}

if (userData && userData['cover:url'] &&
userData['cover:url'].includes(`/uploads/profile/${userData.uid}-`) &&
!userData['cover:url'].includes(`/uploads/profile/uid-${userData.uid}/${userData.uid}-`)) {
setObj['cover:url'] = userData['cover:url'].replace(
`/uploads/profile/${userData.uid}-`,
`/uploads/profile/uid-${userData.uid}/${userData.uid}-`
);
}

if (Object.keys(setObj).length) {
bulkSet.push([`user:${userData.uid}`, setObj]);
}
});
await db.setObjectBulk(bulkSet);
}, {
batch: 500,
progress: progress,
});
},
};
4 changes: 2 additions & 2 deletions src/user/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ module.exports = function (User) {
}

async function deleteImages(uid) {
const folder = path.join(nconf.get('upload_path'), 'profile');
await rimraf(`${uid}-profile{avatar,cover}*`, { glob: { cwd: folder } });
const folder = path.join(nconf.get('upload_path'), 'profile', `uid-${uid}`);
await rimraf(folder);
}
};
10 changes: 2 additions & 8 deletions src/user/jobs/export-uploads.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,8 @@ process.on('message', async (msg) => {
winston.verbose(`[user/export/uploads] Collating uploads for uid ${targetUid}`);
await user.collateUploads(targetUid, archive);

const uploadedPicture = await user.getUserField(targetUid, 'uploadedpicture');
if (uploadedPicture) {
const filePath = uploadedPicture.replace(nconf.get('upload_url'), '');
archive.file(path.join(nconf.get('upload_path'), filePath), {
name: path.basename(filePath),
});
}

const profileUploadPath = path.join(nconf.get('upload_path'), `profile/uid-${targetUid}`);
archive.directory(profileUploadPath, 'profile');
archive.finalize();
}
});
10 changes: 5 additions & 5 deletions src/user/picture.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ module.exports = function (User) {

const extension = file.typeToExtension(image.mimeFromBase64(data.imageData));
const filename = `${data.uid}-profilecover-${Date.now()}${extension}`;
const uploadData = await image.uploadImage(filename, 'profile', picture);
const uploadData = await image.uploadImage(filename, `profile/uid-${data.uid}`, picture);

await deleteCurrentPicture(data.uid, 'cover:url');
await User.setUserField(data.uid, 'cover:url', uploadData.url);
Expand Down Expand Up @@ -96,7 +96,7 @@ module.exports = function (User) {
});

const filename = generateProfileImageFilename(data.uid, extension);
const uploadedImage = await image.uploadImage(filename, 'profile', {
const uploadedImage = await image.uploadImage(filename, `profile/uid-${data.uid}`, {
uid: data.uid,
path: newPath,
name: 'profileAvatar',
Expand Down Expand Up @@ -140,7 +140,7 @@ module.exports = function (User) {
});

const filename = generateProfileImageFilename(data.uid, extension);
const uploadedImage = await image.uploadImage(filename, 'profile', picture);
const uploadedImage = await image.uploadImage(filename, `profile/uid-${data.uid}`, picture);

await deleteCurrentPicture(data.uid, 'uploadedpicture');
await User.updateProfile(data.callerUid, {
Expand Down Expand Up @@ -224,10 +224,10 @@ module.exports = function (User) {

async function getPicturePath(uid, field) {
const value = await User.getUserField(uid, field);
if (!value || !value.startsWith(`${nconf.get('relative_path')}/assets/uploads/profile/`)) {
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', filename);
return path.join(nconf.get('upload_path'), `profile/uid-${uid}`, filename);
}
};

0 comments on commit 8f9ac5c

Please sign in to comment.