From 3b05f7859f100ca32eeb9dd06a00c63f83cdcd49 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 30 Jun 2025 18:20:54 +0200 Subject: [PATCH] fix(users): refresh initials avatar refresh after name change (#1047) --- frontend/src/models/user.ts | 20 ++++++++++++++++++++ frontend/src/stores/auth.ts | 15 ++++++++++++--- pkg/routes/api/v1/user_settings.go | 6 ++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/frontend/src/models/user.ts b/frontend/src/models/user.ts index 8fb418b15..d106d6a99 100644 --- a/frontend/src/models/user.ts +++ b/frontend/src/models/user.ts @@ -25,6 +25,8 @@ export async function fetchAvatarBlobUrl(user: IUser, size = 50) { return await pendingRequests.get(key) as string } + invalidateAvatarCache(user) + // Create a new request const requestPromise = avatarService.getBlobUrl(`/avatar/${user.username}?size=${size}`) .then(url => { @@ -41,6 +43,24 @@ export async function fetchAvatarBlobUrl(user: IUser, size = 50) { return await requestPromise } +export function invalidateAvatarCache(user: IUser) { + if (!user || !user.username) { + return + } + + for (const key of Array.from(avatarCache.keys())) { + if (key.startsWith(`${user.username}-`)) { + avatarCache.delete(key) + } + } + + for (const key of Array.from(pendingRequests.keys())) { + if (key.startsWith(`${user.username}-`)) { + pendingRequests.delete(key) + } + } +} + export function getDisplayName(user: IUser) { if (user.name !== '') { return user.name diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts index 51cd2e7e3..df12fa589 100644 --- a/frontend/src/stores/auth.ts +++ b/frontend/src/stores/auth.ts @@ -4,7 +4,8 @@ import {acceptHMRUpdate, defineStore} from 'pinia' import {AuthenticatedHTTPFactory, HTTPFactory} from '@/helpers/fetcher' import {getBrowserLanguage, i18n, setLanguage} from '@/i18n' import {objectToSnakeCase} from '@/helpers/case' -import UserModel, {getDisplayName, fetchAvatarBlobUrl} from '@/models/user' +import UserModel, {getDisplayName, fetchAvatarBlobUrl, invalidateAvatarCache} from '@/models/user' +import AvatarService from '@/services/avatar' import UserSettingsService from '@/services/userSettings' import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth' import {setModuleLoading} from '@/stores/helper' @@ -149,6 +150,7 @@ export const useAuthStore = defineStore('auth', () => { if (!info.value || !info.value.username) { return } + invalidateAvatarCache(info.value) avatarUrl.value = await fetchAvatarBlobUrl(info.value, 40) } @@ -370,13 +372,14 @@ export const useAuthStore = defineStore('auth', () => { settings, showMessage = true, }: { - settings: IUserSettings - showMessage : boolean + settings: IUserSettings, + showMessage: boolean, }) { const userSettingsService = new UserSettingsService() const cancel = setModuleLoading(setIsLoadingGeneralSettings) try { + const oldName = info.value?.name let settingsUpdate = {...settings} if (configStore.demoModeEnabled) { settingsUpdate = { @@ -388,6 +391,12 @@ export const useAuthStore = defineStore('auth', () => { setUserSettings(settingsUpdate) await setLanguage(settings.language) await updateSettingsPromise + if (oldName !== undefined && oldName !== settingsUpdate.name) { + const {avatarProvider} = await (new AvatarService()).get({}) + if (avatarProvider === 'initials') { + await reloadAvatar() + } + } if (showMessage) { success({message: i18n.global.t('user.settings.general.savedSuccess')}) } diff --git a/pkg/routes/api/v1/user_settings.go b/pkg/routes/api/v1/user_settings.go index e2c70d7b6..45ae5a60c 100644 --- a/pkg/routes/api/v1/user_settings.go +++ b/pkg/routes/api/v1/user_settings.go @@ -201,6 +201,8 @@ func UpdateGeneralUserSettings(c echo.Context) error { return handler.HandleHTTPError(err) } + invalidateAvatar := user.AvatarProvider == "initials" && user.Name != us.Name + user.Name = us.Name user.EmailRemindersEnabled = us.EmailRemindersEnabled user.DiscoverableByEmail = us.DiscoverableByEmail @@ -224,6 +226,10 @@ func UpdateGeneralUserSettings(c echo.Context) error { return handler.HandleHTTPError(err) } + if invalidateAvatar { + avatar.FlushAllCaches(user) + } + return c.JSON(http.StatusOK, &models.Message{Message: "The settings were updated successfully."}) }