138 lines
3.1 KiB
TypeScript
138 lines
3.1 KiB
TypeScript
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);
|
|
}),
|
|
});
|