diff options
| author | kamtschatka <simon.schatka@gmx.at> | 2024-10-19 23:48:14 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-19 22:48:14 +0100 |
| commit | 9a56e58bd54b2bfe11104e80c602493d720ff6be (patch) | |
| tree | bd5ac7c8dd386881f077519e40d911d8e07dbace /packages/trpc/routers/users.ts | |
| parent | 0debc6b415baa466245901fb52c009d09ef3ba15 (diff) | |
| download | karakeep-9a56e58bd54b2bfe11104e80c602493d720ff6be.tar.zst | |
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 <me@mbassem.com>
Diffstat (limited to 'packages/trpc/routers/users.ts')
| -rw-r--r-- | packages/trpc/routers/users.ts | 109 |
1 files changed, 66 insertions, 43 deletions
diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts index 87d0fa2d..ca46d9f7 100644 --- a/packages/trpc/routers/users.ts +++ b/packages/trpc/routers/users.ts @@ -13,10 +13,58 @@ import { hashPassword, validatePassword } from "../auth"; import { adminProcedure, authedProcedure, + Context, publicProcedure, router, } from "../index"; +export async function createUser( + input: z.infer<typeof zSignUpSchema>, + ctx: Context, + role?: "user" | "admin", +) { + return ctx.db.transaction(async (trx) => { + let userRole = role; + if (!userRole) { + const [{ count: userCount }] = await trx + .select({ count: count() }) + .from(users); + userRole = userCount == 0 ? "admin" : "user"; + } + + try { + const result = await trx + .insert(users) + .values({ + name: input.name, + email: input.email, + password: await hashPassword(input.password), + role: userRole, + }) + .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", + }); + } + }); +} + export const usersAppRouter = router({ create: publicProcedure .input(zSignUpSchema) @@ -41,40 +89,7 @@ export const usersAppRouter = router({ message: errorMessage, }); } - // 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", - }); - } + return createUser(input, ctx); }), list: adminProcedure .output( @@ -85,20 +100,28 @@ export const usersAppRouter = router({ name: z.string(), email: z.string(), role: z.enum(["user", "admin"]).nullable(), + localUser: z.boolean(), }), ), }), ) .query(async ({ ctx }) => { - const users = await ctx.db.query.users.findMany({ - columns: { - id: true, - name: true, - email: true, - role: true, - }, - }); - return { users }; + const dbUsers = await ctx.db + .select({ + id: users.id, + name: users.name, + email: users.email, + role: users.role, + password: users.password, + }) + .from(users); + + return { + users: dbUsers.map(({ password, ...user }) => ({ + ...user, + localUser: password !== null, + })), + }; }), changePassword: authedProcedure .input( |
