aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/routers/users.ts
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-03-05 13:11:06 +0000
committerMohamedBassem <me@mbassem.com>2024-03-05 13:11:06 +0000
commit8a46ecb7373d6c5e7300861169ea51a7917cd2b4 (patch)
tree4ad318c3b5fc8b7a74cba6d0e37b6ade24db829a /packages/trpc/routers/users.ts
parent224aa38d5976523f213e2860b6addc7630d472ba (diff)
downloadkarakeep-8a46ecb7373d6c5e7300861169ea51a7917cd2b4.tar.zst
refactor: Extract trpc logic into its package
Diffstat (limited to 'packages/trpc/routers/users.ts')
-rw-r--r--packages/trpc/routers/users.ts93
1 files changed, 93 insertions, 0 deletions
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts
new file mode 100644
index 00000000..b5334f99
--- /dev/null
+++ b/packages/trpc/routers/users.ts
@@ -0,0 +1,93 @@
+import { zSignUpSchema } from "../types/users";
+import { adminProcedure, publicProcedure, router } from "../index";
+import { SqliteError } from "@hoarder/db";
+import { z } from "zod";
+import { hashPassword } from "../auth";
+import { TRPCError } from "@trpc/server";
+import { users } from "@hoarder/db/schema";
+import { count, eq } from "drizzle-orm";
+
+export const usersAppRouter = router({
+ create: publicProcedure
+ .input(zSignUpSchema)
+ .output(
+ z.object({
+ id: z.string(),
+ name: z.string(),
+ email: z.string(),
+ role: z.enum(["user", "admin"]).nullable(),
+ }),
+ )
+ .mutation(async ({ input, ctx }) => {
+ // TODO: This is racy, but that's probably fine.
+ const [{ count: userCount }] = await ctx.db
+ .select({ count: count() })
+ .from(users);
+ try {
+ const result = await ctx.db
+ .insert(users)
+ .values({
+ name: input.name,
+ email: input.email,
+ password: await hashPassword(input.password),
+ role: userCount == 0 ? "admin" : "user",
+ })
+ .returning({
+ id: users.id,
+ name: users.name,
+ email: users.email,
+ role: users.role,
+ });
+ return result[0];
+ } catch (e) {
+ if (e instanceof SqliteError) {
+ if (e.code == "SQLITE_CONSTRAINT_UNIQUE") {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Email is already taken",
+ });
+ }
+ }
+ throw new TRPCError({
+ code: "INTERNAL_SERVER_ERROR",
+ message: "Something went wrong",
+ });
+ }
+ }),
+ list: adminProcedure
+ .output(
+ z.object({
+ users: z.array(
+ z.object({
+ id: z.string(),
+ name: z.string(),
+ email: z.string(),
+ role: z.enum(["user", "admin"]).nullable(),
+ }),
+ ),
+ }),
+ )
+ .query(async ({ ctx }) => {
+ const users = await ctx.db.query.users.findMany({
+ columns: {
+ id: true,
+ name: true,
+ email: true,
+ role: true,
+ },
+ });
+ return { users };
+ }),
+ delete: adminProcedure
+ .input(
+ z.object({
+ userId: z.string(),
+ }),
+ )
+ .mutation(async ({ input, ctx }) => {
+ const res = await ctx.db.delete(users).where(eq(users.id, input.userId));
+ if (res.changes == 0) {
+ throw new TRPCError({ code: "NOT_FOUND" });
+ }
+ }),
+});