aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/routers
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-12-24 12:18:08 +0200
committerGitHub <noreply@github.com>2025-12-24 10:18:08 +0000
commit314c363e5ca69a50626650ade8968feec583e5ce (patch)
tree2251691c2a79598b50b4417ee5632b602e5faf78 /packages/trpc/routers
parent3408e6e4854dc79b963eef455e9a69231de3cd28 (diff)
downloadkarakeep-314c363e5ca69a50626650ade8968feec583e5ce.tar.zst
feat: add support for user avatars (#2296)
* feat: add support for user avatars * more fixes * more fixes * more fixes * more fixes
Diffstat (limited to 'packages/trpc/routers')
-rw-r--r--packages/trpc/routers/users.test.ts75
-rw-r--r--packages/trpc/routers/users.ts10
2 files changed, 85 insertions, 0 deletions
diff --git a/packages/trpc/routers/users.test.ts b/packages/trpc/routers/users.test.ts
index 27d6c2d6..21f05f5b 100644
--- a/packages/trpc/routers/users.test.ts
+++ b/packages/trpc/routers/users.test.ts
@@ -942,6 +942,81 @@ describe("User Routes", () => {
});
});
+ describe("Update Avatar", () => {
+ test<CustomTestContext>("updateAvatar - promotes unknown asset", async ({
+ db,
+ unauthedAPICaller,
+ }) => {
+ const user = await unauthedAPICaller.users.create({
+ name: "Avatar Reject",
+ email: "avatar-reject@test.com",
+ password: "pass1234",
+ confirmPassword: "pass1234",
+ });
+ const caller = getApiCaller(db, user.id, user.email, user.role || "user");
+
+ await db.insert(assets).values({
+ id: "avatar-asset-2",
+ assetType: AssetTypes.UNKNOWN,
+ userId: user.id,
+ contentType: "image/png",
+ size: 12,
+ fileName: "avatar.png",
+ bookmarkId: null,
+ });
+
+ await caller.users.updateAvatar({ assetId: "avatar-asset-2" });
+
+ const updatedAsset = await db
+ .select()
+ .from(assets)
+ .where(eq(assets.id, "avatar-asset-2"))
+ .then((rows) => rows[0]);
+
+ expect(updatedAsset?.assetType).toBe(AssetTypes.AVATAR);
+ });
+
+ test<CustomTestContext>("updateAvatar - deletes avatar asset", async ({
+ db,
+ unauthedAPICaller,
+ }) => {
+ const user = await unauthedAPICaller.users.create({
+ name: "Avatar Delete",
+ email: "avatar-delete@test.com",
+ password: "pass1234",
+ confirmPassword: "pass1234",
+ });
+ const caller = getApiCaller(db, user.id, user.email, user.role || "user");
+
+ await db.insert(assets).values({
+ id: "avatar-asset-3",
+ assetType: AssetTypes.UNKNOWN,
+ userId: user.id,
+ contentType: "image/png",
+ size: 12,
+ fileName: "avatar.png",
+ bookmarkId: null,
+ });
+
+ await caller.users.updateAvatar({ assetId: "avatar-asset-3" });
+ await caller.users.updateAvatar({ assetId: null });
+
+ const updatedUser = await db
+ .select()
+ .from(users)
+ .where(eq(users.id, user.id))
+ .then((rows) => rows[0]);
+ const remainingAsset = await db
+ .select()
+ .from(assets)
+ .where(eq(assets.id, "avatar-asset-3"))
+ .then((rows) => rows[0]);
+
+ expect(updatedUser?.image).toBeNull();
+ expect(remainingAsset).toBeUndefined();
+ });
+ });
+
describe("Who Am I", () => {
test<CustomTestContext>("whoami - returns user info", async ({
db,
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts
index d3bc06d9..dbfbbc3c 100644
--- a/packages/trpc/routers/users.ts
+++ b/packages/trpc/routers/users.ts
@@ -148,6 +148,16 @@ export const usersAppRouter = router({
const user = await User.fromCtx(ctx);
await user.updateSettings(input);
}),
+ updateAvatar: authedProcedure
+ .input(
+ z.object({
+ assetId: z.string().nullable(),
+ }),
+ )
+ .mutation(async ({ input, ctx }) => {
+ const user = await User.fromCtx(ctx);
+ await user.updateAvatar(input.assetId);
+ }),
verifyEmail: publicProcedure
.use(
createRateLimitMiddleware({