diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-03-11 20:09:32 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-03-11 20:09:32 +0000 |
| commit | b8c587e3c3e717263da84522d59c7904715ae22a (patch) | |
| tree | a26a67162118b4a629d33a833dd25be67d344855 /packages/trpc/routers/users.ts | |
| parent | 59c444a503c0124988608c190342acc53c797107 (diff) | |
| download | karakeep-b8c587e3c3e717263da84522d59c7904715ae22a.tar.zst | |
feat: Add endpoints for whoami and user stats. Fixes #1113
Diffstat (limited to 'packages/trpc/routers/users.ts')
| -rw-r--r-- | packages/trpc/routers/users.ts | 77 |
1 files changed, 68 insertions, 9 deletions
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts index ca46d9f7..a78ec9b4 100644 --- a/packages/trpc/routers/users.ts +++ b/packages/trpc/routers/users.ts @@ -4,10 +4,20 @@ import invariant from "tiny-invariant"; import { z } from "zod"; import { SqliteError } from "@hoarder/db"; -import { users } from "@hoarder/db/schema"; +import { + bookmarkLists, + bookmarks, + bookmarkTags, + highlights, + users, +} from "@hoarder/db/schema"; import { deleteUserAssets } from "@hoarder/shared/assetdb"; import serverConfig from "@hoarder/shared/config"; -import { zSignUpSchema } from "@hoarder/shared/types/users"; +import { + zSignUpSchema, + zUserStatsResponseSchema, + zWhoAmIResponseSchema, +} from "@hoarder/shared/types/users"; import { hashPassword, validatePassword } from "../auth"; import { @@ -160,13 +170,7 @@ export const usersAppRouter = router({ await deleteUserAssets({ userId: input.userId }); }), whoami: authedProcedure - .output( - z.object({ - id: z.string(), - name: z.string().nullish(), - email: z.string().nullish(), - }), - ) + .output(zWhoAmIResponseSchema) .query(async ({ ctx }) => { if (!ctx.user.email) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -179,4 +183,59 @@ export const usersAppRouter = router({ } return { id: ctx.user.id, name: ctx.user.name, email: ctx.user.email }; }), + stats: authedProcedure + .output(zUserStatsResponseSchema) + .query(async ({ ctx }) => { + const [ + [{ numBookmarks }], + [{ numFavorites }], + [{ numArchived }], + [{ numTags }], + [{ numLists }], + [{ numHighlights }], + ] = await Promise.all([ + ctx.db + .select({ numBookmarks: count() }) + .from(bookmarks) + .where(eq(bookmarks.userId, ctx.user.id)), + ctx.db + .select({ numFavorites: count() }) + .from(bookmarks) + .where( + and( + eq(bookmarks.userId, ctx.user.id), + eq(bookmarks.favourited, true), + ), + ), + ctx.db + .select({ numArchived: count() }) + .from(bookmarks) + .where( + and( + eq(bookmarks.userId, ctx.user.id), + eq(bookmarks.archived, true), + ), + ), + ctx.db + .select({ numTags: count() }) + .from(bookmarkTags) + .where(eq(bookmarkTags.userId, ctx.user.id)), + ctx.db + .select({ numLists: count() }) + .from(bookmarkLists) + .where(eq(bookmarkLists.userId, ctx.user.id)), + ctx.db + .select({ numHighlights: count() }) + .from(highlights) + .where(eq(highlights.userId, ctx.user.id)), + ]); + return { + numBookmarks, + numFavorites, + numArchived, + numTags, + numLists, + numHighlights, + }; + }), }); |
