aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/routers/users.ts
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-03-11 20:09:32 +0000
committerMohamed Bassem <me@mbassem.com>2025-03-11 20:09:32 +0000
commitb8c587e3c3e717263da84522d59c7904715ae22a (patch)
treea26a67162118b4a629d33a833dd25be67d344855 /packages/trpc/routers/users.ts
parent59c444a503c0124988608c190342acc53c797107 (diff)
downloadkarakeep-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.ts77
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,
+ };
+ }),
});