aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-07-13 09:54:51 +0000
committerMohamed Bassem <me@mbassem.com>2025-07-13 09:54:51 +0000
commit845ccf1ad46c8635782f8e10280b07c48c08eaf5 (patch)
treeb6b257d07532ff2b1a300c28d6f57623d9f1cdc0 /packages/trpc
parentf8ae986692f82efe8c1f3940907aab553e4f5a49 (diff)
downloadkarakeep-845ccf1ad46c8635782f8e10280b07c48c08eaf5.tar.zst
feat: Add delete account support
Diffstat (limited to 'packages/trpc')
-rw-r--r--packages/trpc/routers/users.ts53
1 files changed, 52 insertions, 1 deletions
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts
index 8d6db6c7..4531875c 100644
--- a/packages/trpc/routers/users.ts
+++ b/packages/trpc/routers/users.ts
@@ -289,6 +289,52 @@ export const usersAppRouter = router({
}
await deleteUserAssets({ userId: input.userId });
}),
+ deleteAccount: authedProcedure
+ .input(
+ z.object({
+ password: z.string().optional(),
+ }),
+ )
+ .mutation(async ({ input, ctx }) => {
+ invariant(ctx.user.email, "A user always has an email specified");
+
+ // Check if user has a password (local account)
+ const user = await ctx.db.query.users.findFirst({
+ where: eq(users.id, ctx.user.id),
+ });
+
+ if (!user) {
+ throw new TRPCError({ code: "NOT_FOUND" });
+ }
+
+ // If user has a password, verify it before allowing account deletion
+ if (user.password) {
+ if (!input.password) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Password is required for local accounts",
+ });
+ }
+
+ try {
+ await validatePassword(ctx.user.email, input.password);
+ } catch {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "Invalid password",
+ });
+ }
+ }
+
+ // Delete the user account
+ const res = await ctx.db.delete(users).where(eq(users.id, ctx.user.id));
+ if (res.changes == 0) {
+ throw new TRPCError({ code: "NOT_FOUND" });
+ }
+
+ // Delete user assets
+ await deleteUserAssets({ userId: ctx.user.id });
+ }),
whoami: authedProcedure
.output(zWhoAmIResponseSchema)
.query(async ({ ctx }) => {
@@ -301,7 +347,12 @@ export const usersAppRouter = router({
if (!userDb) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
- return { id: ctx.user.id, name: ctx.user.name, email: ctx.user.email };
+ return {
+ id: ctx.user.id,
+ name: ctx.user.name,
+ email: ctx.user.email,
+ localUser: userDb.password !== null,
+ };
}),
stats: authedProcedure
.output(zUserStatsResponseSchema)