2023-07-29 10:05:05 +02:00
|
|
|
import { TRPCError } from '@trpc/server';
|
|
|
|
|
import bcrypt from 'bcrypt';
|
|
|
|
|
import { z } from 'zod';
|
|
|
|
|
import { hashPassword } from '~/utils/security';
|
2023-07-29 11:19:40 +02:00
|
|
|
import { colorSchemeParser, signUpFormSchema } from '~/validations/user';
|
2023-07-29 10:05:05 +02:00
|
|
|
|
2023-07-29 11:35:34 +02:00
|
|
|
import { COOKIE_COLOR_SCHEME_KEY, COOKIE_LOCALE_KEY } from '../../../../data/constants';
|
2023-07-29 11:19:40 +02:00
|
|
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
2023-07-29 10:05:05 +02:00
|
|
|
|
|
|
|
|
export const userRouter = createTRPCRouter({
|
|
|
|
|
register: publicProcedure
|
|
|
|
|
.input(
|
|
|
|
|
signUpFormSchema.and(
|
|
|
|
|
z.object({
|
|
|
|
|
registerToken: z.string(),
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
.mutation(async ({ ctx, input }) => {
|
|
|
|
|
const token = await ctx.prisma.registrationToken.findUnique({
|
|
|
|
|
where: {
|
|
|
|
|
token: input.registerToken,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!token || token.expires < new Date()) {
|
|
|
|
|
throw new TRPCError({
|
|
|
|
|
code: 'FORBIDDEN',
|
|
|
|
|
message: 'Invalid registration token',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const existingUser = await ctx.prisma.user.findFirst({
|
|
|
|
|
where: {
|
|
|
|
|
name: input.username,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (existingUser) {
|
|
|
|
|
throw new TRPCError({
|
|
|
|
|
code: 'CONFLICT',
|
|
|
|
|
message: 'User already exists',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const salt = bcrypt.genSaltSync(10);
|
|
|
|
|
const hashedPassword = hashPassword(input.password, salt);
|
|
|
|
|
|
|
|
|
|
const user = await ctx.prisma.user.create({
|
|
|
|
|
data: {
|
|
|
|
|
name: input.username,
|
|
|
|
|
password: hashedPassword,
|
|
|
|
|
salt: salt,
|
2023-07-29 11:19:40 +02:00
|
|
|
settings: {
|
|
|
|
|
create: {
|
2023-07-29 11:35:34 +02:00
|
|
|
colorScheme: colorSchemeParser.parse(ctx.cookies[COOKIE_COLOR_SCHEME_KEY]),
|
|
|
|
|
language: ctx.cookies[COOKIE_LOCALE_KEY] ?? 'en',
|
2023-07-29 11:19:40 +02:00
|
|
|
},
|
|
|
|
|
},
|
2023-07-29 10:05:05 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
await ctx.prisma.registrationToken.delete({
|
|
|
|
|
where: {
|
|
|
|
|
id: token.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
id: user.id,
|
|
|
|
|
name: user.name,
|
|
|
|
|
};
|
|
|
|
|
}),
|
2023-07-29 11:19:40 +02:00
|
|
|
changeColorScheme: protectedProcedure
|
|
|
|
|
.input(
|
|
|
|
|
z.object({
|
|
|
|
|
colorScheme: colorSchemeParser,
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
.mutation(async ({ ctx, input }) => {
|
|
|
|
|
await ctx.prisma.user.update({
|
|
|
|
|
where: {
|
|
|
|
|
id: ctx.session?.user?.id,
|
|
|
|
|
},
|
|
|
|
|
data: {
|
|
|
|
|
settings: {
|
|
|
|
|
update: {
|
|
|
|
|
colorScheme: input.colorScheme,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}),
|
2023-07-29 11:35:34 +02:00
|
|
|
changeLanguage: protectedProcedure
|
|
|
|
|
.input(
|
|
|
|
|
z.object({
|
|
|
|
|
language: z.string(),
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
.mutation(async ({ ctx, input }) => {
|
|
|
|
|
await ctx.prisma.user.update({
|
|
|
|
|
where: {
|
|
|
|
|
id: ctx.session?.user?.id,
|
|
|
|
|
},
|
|
|
|
|
data: {
|
|
|
|
|
settings: {
|
|
|
|
|
update: {
|
|
|
|
|
language: input.language,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}),
|
2023-07-29 14:30:19 +02:00
|
|
|
getWithSettings: protectedProcedure.query(async ({ ctx }) => {
|
|
|
|
|
const user = await ctx.prisma.user.findUnique({
|
|
|
|
|
where: {
|
|
|
|
|
id: ctx.session?.user?.id,
|
|
|
|
|
},
|
|
|
|
|
include: {
|
|
|
|
|
settings: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!user || !user.settings) {
|
|
|
|
|
throw new TRPCError({
|
|
|
|
|
code: 'NOT_FOUND',
|
|
|
|
|
message: 'User not found',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
id: user.id,
|
|
|
|
|
name: user.name,
|
|
|
|
|
settings: user.settings,
|
|
|
|
|
};
|
|
|
|
|
}),
|
2023-07-29 10:05:05 +02:00
|
|
|
});
|