From ea36016d87118f259efd7c7add6ac20df276acf4 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 10 Feb 2022 17:12:39 -0500 Subject: [PATCH] refactor: fix user uploads paths, and associate uid with user uploads --- src/upgrades/1.19.3/fix_user_uploads_zset.js | 49 ++++++++++++++++++++ src/user/uploads.js | 7 ++- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/upgrades/1.19.3/fix_user_uploads_zset.js diff --git a/src/upgrades/1.19.3/fix_user_uploads_zset.js b/src/upgrades/1.19.3/fix_user_uploads_zset.js new file mode 100644 index 0000000000..2c34ac947c --- /dev/null +++ b/src/upgrades/1.19.3/fix_user_uploads_zset.js @@ -0,0 +1,49 @@ +'use strict'; + +const crypto = require('crypto'); + +const db = require('../../database'); +const batch = require('../../batch'); +const user = require('../../user'); + +const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); + +module.exports = { + name: 'Fix paths in user uploads sorted sets', + timestamp: Date.UTC(2022, 1, 10), + method: async function () { + const { progress } = this; + + await batch.processSortedSet('users:joindate', async (uids) => { + let keys = uids.map(uid => `uid:${uid}:uploads`); + const exists = await db.exists(keys); + keys = keys.filter((key, idx) => exists[idx]); + + progress.incr(uids.length - keys.length); + + await Promise.all(keys.map(async (key, idx) => { + // Rename the paths within + let uploads = await db.getSortedSetRangeWithScores(key, 0, -1); + + // Don't process those that have already the right format + uploads = uploads.filter(upload => upload.value.startsWith('/files/')); + + await db.sortedSetRemove(key, uploads.map(upload => upload.value)); + await db.sortedSetAdd( + key, + uploads.map(upload => upload.score), + uploads.map(upload => upload.value.slice(1)) + ); + + // Add uid to the upload's hash object + uploads = await db.getSortedSetMembers(key); + await db.setObjectBulk(uploads.map(relativePath => [`upload:${md5(relativePath)}`, { uid: uids[idx] }])); + + progress.incr(); + })); + }, { + batch: 100, + progress: progress, + }); + }, +}; diff --git a/src/user/uploads.js b/src/user/uploads.js index d3bca805f7..076bbf7866 100644 --- a/src/user/uploads.js +++ b/src/user/uploads.js @@ -3,11 +3,13 @@ const path = require('path'); const nconf = require('nconf'); const winston = require('winston'); +const crypto = require('crypto'); const db = require('../database'); const file = require('../file'); const batch = require('../batch'); +const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); const _getFullPath = relativePath => path.resolve(nconf.get('upload_path'), relativePath); const _validatePath = async (relativePath) => { const fullPath = _getFullPath(relativePath); @@ -21,7 +23,10 @@ const _validatePath = async (relativePath) => { module.exports = function (User) { User.associateUpload = async (uid, relativePath) => { await _validatePath(relativePath); - await db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath); + await Promise.all([ + db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), + db.setObjectField(`upload:${md5(relativePath)}:uid`, uid), + ]); }; User.deleteUpload = async function (callerUid, uid, uploadName) {