import { protectProedure, publicProcedure, router } from '../trpc'; import { z } from 'zod'; import { authUser, authUserWithToken, changeUserPassword, createAdminUser, createUser, getUserCount, } from '../../model/user'; import { jwtSign } from '../../middleware/auth'; import { TRPCError } from '@trpc/server'; import { env } from '../../utils/env'; import { userInfoSchema } from '../../model/_schema/index'; import { OPENAPI_TAG } from '../../utils/const'; export const userRouter = router({ login: publicProcedure .meta({ openapi: { method: 'POST', path: '/login', tags: [OPENAPI_TAG.USER] }, }) .input( z.object({ username: z.string(), password: z.string(), }) ) .output( z.object({ info: userInfoSchema, token: z.string(), }) ) .mutation(async ({ input }) => { const { username, password } = input; const user = await authUser(username, password); const token = jwtSign(user); return { info: user, token }; }), loginWithToken: publicProcedure .meta({ openapi: { method: 'POST', path: '/loginWithToken', tags: [OPENAPI_TAG.USER], }, }) .input( z.object({ token: z.string(), }) ) .output( z.object({ info: userInfoSchema, token: z.string(), }) ) .mutation(async ({ input }) => { const { token } = input; if (!token) { throw new Error('Cannot get token'); } try { const user = await authUserWithToken(token); const newToken = jwtSign(user); return { info: user, token: newToken }; } catch (err) { throw new TRPCError({ code: 'FORBIDDEN', message: 'Invalid token' }); } }), register: publicProcedure .meta({ openapi: { enabled: env.allowRegister, method: 'POST', path: '/register', tags: [OPENAPI_TAG.USER], }, }) .input( z.object({ username: z.string(), password: z.string(), }) ) .output( z.object({ info: userInfoSchema, token: z.string(), }) ) .mutation(async ({ input }) => { if (!env.allowRegister) { throw new TRPCError({ code: 'FORBIDDEN', message: 'Not allow register', }); } const { username, password } = input; const userCount = await getUserCount(); if (userCount === 0) { const user = await createAdminUser(username, password); const token = jwtSign(user); return { info: user, token }; } else { const user = await createUser(username, password); const token = jwtSign(user); return { info: user, token }; } }), changePassword: protectProedure .input( z.object({ oldPassword: z.string(), newPassword: z.string(), }) ) .mutation(async ({ input, ctx }) => { const userId = ctx.user.id; const { oldPassword, newPassword } = input; return changeUserPassword(userId, oldPassword, newPassword); }), });