Template
Fix avatar crash when users.image is an IdP URL
Authentik sign-ins write the picture claim URL to users.image, and both avatar components cast that value to a storage ID and passed it to files:getImageUrl, which failed argument validation and took the layout down after sign-in. getUser now returns imageUrl resolved from either a storage ID or a URL, and updateUser only deletes the previous avatar when it was an uploaded file. getImageUrl stays until the new Next image is live.
This commit is contained in:
1 parent
7d1884be41
commit
2d4f5b23b5
3 files changed
+20
-15
No files matched your search
@@ -45,12 +45,24 @@ export const getUserProvider = query({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* `users.image` holds either a Convex storage ID (avatar uploaded in-app) or a
|
||||
* plain URL (the `picture` claim Authentik writes on every OAuth sign-in).
|
||||
* Resolves either form to a URL the client can render directly.
|
||||
*/
|
||||
const resolveImageUrl = async (ctx: QueryCtx, image: string | undefined) => {
|
||||
if (!image) return null;
|
||||
const storageId = ctx.db.system.normalizeId('_storage', image);
|
||||
return storageId ? await ctx.storage.getUrl(storageId) : image;
|
||||
};
|
||||
|
||||
export const getUser = query({
|
||||
args: { userId: v.optional(v.id('users')) },
|
||||
handler: async (ctx, args) => {
|
||||
const userId = args.userId ?? (await getAuthUserId(ctx));
|
||||
if (!userId) return null;
|
||||
return getUserById(ctx, userId);
|
||||
const user = await getUserById(ctx, userId);
|
||||
return { ...user, imageUrl: await resolveImageUrl(ctx, user.image) };
|
||||
},
|
||||
});
|
||||
|
||||
@@ -73,7 +85,10 @@ export const updateUser = mutation({
|
||||
if (args.name !== undefined) patch.name = args.name;
|
||||
if (args.email !== undefined) patch.email = args.email;
|
||||
if (args.image !== undefined) {
|
||||
const oldImage = user.image as Id<'_storage'> | undefined;
|
||||
// Only delete the previous avatar when it was an uploaded file, not an IdP URL.
|
||||
const oldImage = user.image
|
||||
? ctx.db.system.normalizeId('_storage', user.image)
|
||||
: null;
|
||||
patch.image = args.image;
|
||||
if (oldImage && oldImage !== args.image) {
|
||||
await ctx.storage.delete(oldImage);
|
||||
|
||||
Reference in new issue
Block a user