mirror of
https://github.com/lukevella/rallly.git
synced 2025-05-07 06:06:08 +02:00
149 lines
3.4 KiB
TypeScript
149 lines
3.4 KiB
TypeScript
import { prisma } from "@rallly/database";
|
|
import { z } from "zod";
|
|
|
|
import { createToken, decryptToken } from "../../session";
|
|
import { generateOtp } from "../../utils/nanoid";
|
|
import { publicProcedure, router } from "../trpc";
|
|
import { RegistrationTokenPayload } from "../types";
|
|
|
|
// assigns participants and comments created by guests to a user
|
|
// we could have multiple guests because a login might be triggered from one device
|
|
// and opened in another one.
|
|
const mergeGuestsIntoUser = async (userId: string, guestIds: string[]) => {
|
|
await prisma.poll.updateMany({
|
|
where: {
|
|
userId: {
|
|
in: guestIds,
|
|
},
|
|
},
|
|
data: {
|
|
userId: userId,
|
|
},
|
|
});
|
|
|
|
await prisma.participant.updateMany({
|
|
where: {
|
|
userId: {
|
|
in: guestIds,
|
|
},
|
|
},
|
|
data: {
|
|
userId: userId,
|
|
},
|
|
});
|
|
|
|
await prisma.comment.updateMany({
|
|
where: {
|
|
userId: {
|
|
in: guestIds,
|
|
},
|
|
},
|
|
data: {
|
|
userId: userId,
|
|
},
|
|
});
|
|
};
|
|
|
|
export const auth = router({
|
|
// @deprecated
|
|
requestRegistration: publicProcedure
|
|
.input(
|
|
z.object({
|
|
name: z.string(),
|
|
email: z.string(),
|
|
}),
|
|
)
|
|
.mutation(
|
|
async ({
|
|
input,
|
|
ctx,
|
|
}): Promise<
|
|
| { ok: true; token: string }
|
|
| { ok: false; reason: "userAlreadyExists" | "emailNotAllowed" }
|
|
> => {
|
|
if (ctx.isEmailBlocked?.(input.email)) {
|
|
return { ok: false, reason: "emailNotAllowed" };
|
|
}
|
|
|
|
const user = await prisma.user.findUnique({
|
|
select: {
|
|
id: true,
|
|
},
|
|
where: {
|
|
email: input.email,
|
|
},
|
|
});
|
|
|
|
if (user) {
|
|
return { ok: false, reason: "userAlreadyExists" };
|
|
}
|
|
|
|
const code = generateOtp();
|
|
|
|
const token = await createToken<RegistrationTokenPayload>({
|
|
name: input.name,
|
|
email: input.email,
|
|
code,
|
|
});
|
|
|
|
await ctx.emailClient.sendTemplate("RegisterEmail", {
|
|
to: input.email,
|
|
subject: `${input.name}, please verify your email address`,
|
|
props: {
|
|
code,
|
|
name: input.name,
|
|
},
|
|
});
|
|
|
|
return { ok: true, token };
|
|
},
|
|
),
|
|
authenticateRegistration: publicProcedure
|
|
.input(
|
|
z.object({
|
|
token: z.string(),
|
|
code: z.string(),
|
|
timeZone: z.string().optional(),
|
|
locale: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const payload = await decryptToken<RegistrationTokenPayload>(input.token);
|
|
|
|
if (!payload) {
|
|
return { user: null };
|
|
}
|
|
|
|
const { name, email, code } = payload;
|
|
if (input.code !== code) {
|
|
return { ok: false };
|
|
}
|
|
|
|
const user = await prisma.user.create({
|
|
select: { id: true, name: true, email: true },
|
|
data: {
|
|
name,
|
|
email,
|
|
timeZone: input.timeZone,
|
|
locale: input.locale,
|
|
},
|
|
});
|
|
|
|
if (ctx.user.isGuest) {
|
|
await mergeGuestsIntoUser(user.id, [ctx.user.id]);
|
|
}
|
|
|
|
return { ok: true, user };
|
|
}),
|
|
getUserPermission: publicProcedure
|
|
.input(z.object({ token: z.string() }))
|
|
.query(async ({ input }) => {
|
|
const res = await decryptToken<{ userId: string }>(input.token);
|
|
|
|
if (!res) {
|
|
return null;
|
|
}
|
|
|
|
return res;
|
|
}),
|
|
});
|