From 9a56e58bd54b2bfe11104e80c602493d720ff6be Mon Sep 17 00:00:00 2001 From: kamtschatka Date: Sat, 19 Oct 2024 23:48:14 +0200 Subject: feature: Allow reseting user password, change their roles and create new users. Fixes #495 (#567) * How do I set the variable "user" or "system" for AI inference #262 changed from system to user * Make Myself an Admin #560 added user management functionality to the admin page * A bunch of UI fixes and simplifications --------- Co-authored-by: Mohamed Bassem --- packages/trpc/routers/admin.ts | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'packages/trpc/routers/admin.ts') diff --git a/packages/trpc/routers/admin.ts b/packages/trpc/routers/admin.ts index d8ffe9d3..38aa0031 100644 --- a/packages/trpc/routers/admin.ts +++ b/packages/trpc/routers/admin.ts @@ -1,3 +1,4 @@ +import { TRPCError } from "@trpc/server"; import { count, eq, sum } from "drizzle-orm"; import { z } from "zod"; @@ -9,8 +10,15 @@ import { TidyAssetsQueue, triggerSearchReindex, } from "@hoarder/shared/queues"; +import { + changeRoleSchema, + resetPasswordSchema, + zAdminCreateUserSchema, +} from "@hoarder/shared/types/admin"; +import { hashPassword } from "../auth"; import { adminProcedure, router } from "../index"; +import { createUser } from "./users"; export const adminAppRouter = router({ stats: adminProcedure @@ -213,4 +221,60 @@ export const adminAppRouter = router({ return results; }), + createUser: adminProcedure + .input(zAdminCreateUserSchema) + .output( + z.object({ + id: z.string(), + name: z.string(), + email: z.string(), + role: z.enum(["user", "admin"]).nullable(), + }), + ) + .mutation(async ({ input, ctx }) => { + return createUser(input, ctx, input.role); + }), + changeRole: adminProcedure + .input(changeRoleSchema) + .mutation(async ({ input, ctx }) => { + if (ctx.user.id == input.userId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Cannot change own role", + }); + } + const result = await ctx.db + .update(users) + .set({ role: input.role }) + .where(eq(users.id, input.userId)); + + if (!result.changes) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + }), + resetPassword: adminProcedure + .input(resetPasswordSchema) + .mutation(async ({ input, ctx }) => { + if (ctx.user.id == input.userId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Cannot reset own password", + }); + } + const hashedPassword = await hashPassword(input.newPassword); + const result = await ctx.db + .update(users) + .set({ password: hashedPassword }) + .where(eq(users.id, input.userId)); + + if (result.changes == 0) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + }), }); -- cgit v1.2.3-70-g09d2