diff --git a/src/upgrades/3.2.0/fix_username_zsets.js b/src/upgrades/3.2.0/fix_username_zsets.js new file mode 100644 index 0000000000..22ab35c152 --- /dev/null +++ b/src/upgrades/3.2.0/fix_username_zsets.js @@ -0,0 +1,31 @@ +'use strict'; + + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Fix username zsets', + timestamp: Date.UTC(2023, 5, 5), + method: async function () { + const { progress } = this; + + await db.deleteAll(['username:uid', 'username:sorted']); + await batch.processSortedSet('users:joindate', async (uids) => { + progress.incr(uids.length); + const usersData = await db.getObjects(uids.map(uid => `user:${uid}`)); + const bulkAdd = []; + usersData.forEach((userData) => { + if (userData && userData.username) { + bulkAdd.push(['username:uid', userData.uid, userData.username]); + bulkAdd.push(['username:sorted', 0, `${String(userData.username).toLowerCase()}:${userData.uid}`]); + } + }); + await db.sortedSetAddBulk(bulkAdd); + }, { + batch: 500, + progress: progress, + }); + }, +}; diff --git a/src/user/profile.js b/src/user/profile.js index fc238ff87c..09c4814410 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -232,7 +232,7 @@ module.exports = function (User) { }; async function updateEmail(uid, newEmail) { - let oldEmail = await User.getUserField(uid, 'email'); + let oldEmail = await db.getObjectField(`user:${uid}`, 'email'); oldEmail = oldEmail || ''; if (oldEmail === newEmail) { return; @@ -251,7 +251,7 @@ module.exports = function (User) { if (!newUsername) { return; } - const userData = await User.getUserFields(uid, ['username', 'userslug']); + const userData = await db.getObjectFields(`user:${uid}`, ['username', 'userslug']); if (userData.username === newUsername) { return; } @@ -278,7 +278,7 @@ module.exports = function (User) { } async function updateFullname(uid, newFullname) { - const fullname = await User.getUserField(uid, 'fullname'); + const fullname = await db.getObjectField(`user:${uid}`, 'fullname'); await updateUidMapping('fullname', uid, newFullname, fullname); if (newFullname !== fullname) { if (fullname) { diff --git a/test/user.js b/test/user.js index 21e28f5b3a..066f6f13ae 100644 --- a/test/user.js +++ b/test/user.js @@ -912,6 +912,23 @@ describe('User', () => { } }); + it('should properly change username and clean up old sorted sets', async () => { + const uid = await User.create({ username: 'DennyO', password: '123456' }); + let usernames = await db.getSortedSetRevRangeWithScores('username:uid', 0, -1); + usernames = usernames.filter(d => d.score === uid); + assert.deepStrictEqual(usernames, [{ value: 'DennyO', score: uid }]); + + await apiUser.update({ uid: uid }, { uid: uid, username: 'DennyO\'s', password: '123456' }); + usernames = await db.getSortedSetRevRangeWithScores('username:uid', 0, -1); + usernames = usernames.filter(d => d.score === uid); + assert.deepStrictEqual(usernames, [{ value: 'DennyO\'s', score: uid }]); + + await apiUser.update({ uid: uid }, { uid: uid, username: 'Denny O', password: '123456' }); + usernames = await db.getSortedSetRevRangeWithScores('username:uid', 0, -1); + usernames = usernames.filter(d => d.score === uid); + assert.deepStrictEqual(usernames, [{ value: 'Denny O', score: uid }]); + }); + it('should send validation email', async () => { const uid = await User.create({ username: 'pooremailupdate', email: 'poor@update.me', password: '123456' }); await User.email.expireValidation(uid);