perf: call getIconbackgrounds once

instead of 20x on topic/topic list load
This commit is contained in:
Barış Soner Uşaklı
2024-06-11 17:20:31 -04:00
parent 1c44f55d3c
commit 1dadd16f4b
9 changed files with 41 additions and 38 deletions

View File

@@ -331,6 +331,12 @@ UserObjectFull:
example:
- administrators
- Staff
iconBackgrounds:
type: array
items:
type: string
description: A valid CSS colour code
example: '#fff'
muted:
type: boolean
description: Whether or not the user has been muted.

View File

@@ -152,12 +152,6 @@ get:
type: boolean
enableQuickReply:
type: boolean
iconBackgrounds:
type: array
items:
type: string
description: A valid CSS colour code
example: '#fff'
emailPrompt:
type: number
useragent:

View File

@@ -152,12 +152,6 @@ get:
type: boolean
enableQuickReply:
type: boolean
iconBackgrounds:
type: array
items:
type: string
description: A valid CSS colour code
example: '#fff'
emailPrompt:
type: number
useragent:

View File

@@ -27,7 +27,7 @@ define('accounts/picture', [
icon: { text: ajaxify.data['icon:text'], bgColor: ajaxify.data['icon:bgColor'] },
defaultAvatar: ajaxify.data.defaultAvatar,
allowProfileImageUploads: ajaxify.data.allowProfileImageUploads,
iconBackgrounds: config.iconBackgrounds,
iconBackgrounds: ajaxify.data.iconBackgrounds,
user: {
uid: ajaxify.data.uid,
username: ajaxify.data.username,

View File

@@ -656,7 +656,7 @@ usersAPI.changePicture = async (caller, data) => {
picture = returnData && returnData.picture;
}
const validBackgrounds = await user.getIconBackgrounds(caller.uid);
const validBackgrounds = await user.getIconBackgrounds();
if (!validBackgrounds.includes(data.bgColor)) {
data.bgColor = validBackgrounds[0];
}

View File

@@ -32,11 +32,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {})
await parseAboutMe(results.userData);
let { userData } = results;
const { userSettings } = results;
const { isAdmin } = results;
const { isGlobalModerator } = results;
const { isModerator } = results;
const { canViewInfo } = results;
const { userSettings, isAdmin, isGlobalModerator, isModerator, canViewInfo } = results;
const isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10);
if (meta.config['reputation:disabled']) {
@@ -84,6 +80,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {})
userData.isFollowing = results.isFollowing;
userData.canChat = results.canChat;
userData.hasPrivateChat = results.hasPrivateChat;
userData.iconBackgrounds = results.iconBackgrounds;
userData.showHidden = results.canEdit; // remove in v1.19.0
userData.allowProfilePicture = !userData.isSelf || !!meta.config['reputation:disabled'] || userData.reputation >= meta.config['min:rep:profile-picture'];
userData.allowCoverPicture = !userData.isSelf || !!meta.config['reputation:disabled'] || userData.reputation >= meta.config['min:rep:cover-picture'];
@@ -160,6 +157,7 @@ async function getAllData(uid, callerUID) {
canViewInfo: privileges.global.can('view:users:info', callerUID),
canChat: canChat(callerUID, uid),
hasPrivateChat: messaging.hasPrivateChat(callerUID, uid),
iconBackgrounds: user.getIconBackgrounds(),
});
}

View File

@@ -88,7 +88,6 @@ apiController.loadConfig = async function (req) {
thumbs: {
size: meta.config.topicThumbSize,
},
iconBackgrounds: await user.getIconBackgrounds(req.uid),
emailPrompt: meta.config.emailPrompt,
useragent: req.useragent,
fontawesome: {

View File

@@ -44,6 +44,8 @@ module.exports = function (User) {
'email:confirmed': 0,
};
let iconBackgrounds;
User.getUsersFields = async function (uids, fields) {
if (!Array.isArray(uids) || !uids.length) {
return [];
@@ -187,8 +189,11 @@ module.exports = function (User) {
['showfullname']
));
}
if (!iconBackgrounds) {
iconBackgrounds = await User.getIconBackgrounds();
}
await Promise.all(users.map(async (user) => {
users.forEach((user) => {
if (!user) {
return;
}
@@ -204,7 +209,7 @@ module.exports = function (User) {
user.email = validator.escape(user.email ? user.email.toString() : '');
}
if (!parseInt(user.uid, 10)) {
if (!user.uid) {
for (const [key, value] of Object.entries(User.guestData)) {
user[key] = value;
}
@@ -234,15 +239,12 @@ module.exports = function (User) {
}
// User Icons
if (requestedFields.includes('picture') && user.username && parseInt(user.uid, 10) && !meta.config.defaultAvatar) {
const iconBackgrounds = await User.getIconBackgrounds(user.uid);
let bgColor = await User.getUserField(user.uid, 'icon:bgColor');
if (!iconBackgrounds.includes(bgColor)) {
bgColor = Array.prototype.reduce.call(user.username, (cur, next) => cur + next.charCodeAt(), 0);
bgColor = iconBackgrounds[bgColor % iconBackgrounds.length];
if (requestedFields.includes('picture') && user.username && user.uid && !meta.config.defaultAvatar) {
if (!iconBackgrounds.includes(user['icon:bgColor'])) {
const nameAsIndex = Array.from(user.username).reduce((cur, next) => cur + next.charCodeAt(), 0);
user['icon:bgColor'] = iconBackgrounds[nameAsIndex % iconBackgrounds.length];
}
user['icon:text'] = (user.username[0] || '').toUpperCase();
user['icon:bgColor'] = bgColor;
}
if (user.hasOwnProperty('joindate')) {
@@ -253,6 +255,14 @@ module.exports = function (User) {
user.lastonlineISO = utils.toISOString(user.lastonline) || user.joindateISO;
}
if (user.hasOwnProperty('mutedUntil')) {
user.muted = user.mutedUntil > Date.now();
}
});
// TODO get rid of single calls
// dont do anything if user is not banned?
await Promise.all(users.map(async (user) => {
if (user.hasOwnProperty('banned') || user.hasOwnProperty('banned:expire')) {
const result = await User.bans.calcExpiredFromUserData(user);
user.banned = result.banned;
@@ -264,10 +274,6 @@ module.exports = function (User) {
user.banned = false;
}
}
if (user.hasOwnProperty('mutedUntil')) {
user.muted = user.mutedUntil > Date.now();
}
}));
return await plugins.hooks.fire('filter:users.get', users);
@@ -313,14 +319,20 @@ module.exports = function (User) {
}
}
User.getIconBackgrounds = async (uid = 0) => {
let iconBackgrounds = [
User.getIconBackgrounds = async () => {
if (iconBackgrounds) {
return iconBackgrounds;
}
const _iconBackgrounds = [
'#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3',
'#009688', '#1b5e20', '#33691e', '#827717', '#e65100', '#ff5722',
'#795548', '#607d8b',
];
({ iconBackgrounds } = await plugins.hooks.fire('filter:user.iconBackgrounds', { uid, iconBackgrounds }));
const data = await plugins.hooks.fire('filter:user.iconBackgrounds', { iconBackgrounds: _iconBackgrounds });
iconBackgrounds = data.iconBackgrounds;
return iconBackgrounds;
};

View File

@@ -607,7 +607,7 @@ describe('User', () => {
it('should return an icon text and valid background if username and picture is explicitly requested', async () => {
const payload = await User.getUserFields(testUid, ['username', 'picture']);
const validBackgrounds = await User.getIconBackgrounds(testUid);
const validBackgrounds = await User.getIconBackgrounds();
assert.strictEqual(payload['icon:text'], userData.username.slice(0, 1).toUpperCase());
assert(payload['icon:bgColor']);
assert(validBackgrounds.includes(payload['icon:bgColor']));
@@ -616,7 +616,7 @@ describe('User', () => {
it('should return a valid background, even if an invalid background colour is set', async () => {
await User.setUserField(testUid, 'icon:bgColor', 'teal');
const payload = await User.getUserFields(testUid, ['username', 'picture']);
const validBackgrounds = await User.getIconBackgrounds(testUid);
const validBackgrounds = await User.getIconBackgrounds();
assert(payload['icon:bgColor']);
assert(validBackgrounds.includes(payload['icon:bgColor']));