infoalloggi-monorepo/apps/infoalloggi/src/server/controllers/invites.controller.ts

121 lines
2.7 KiB
TypeScript

import crypto from "node:crypto";
import { TRPCError } from "@trpc/server";
import type { UserInvites } from "~/schemas/public/UserInvites";
import type { UsersId } from "~/schemas/public/Users";
import { db } from "~/server/db";
import { NewMail } from "../services/mailer";
const INVITE_EXPIRY_HOURS = 48;
export async function createInviteToken(email: string) {
// Generate a secure random token
const token = crypto.randomBytes(32).toString("hex");
const expiresAt = new Date(Date.now() + INVITE_EXPIRY_HOURS * 60 * 60 * 1000);
try {
// Store in database
await db
.insertInto("user_invites")
.values({
email,
token,
expires_at: expiresAt,
})
.execute();
} catch (e) {
console.error("Error creating invite token:", e);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Errore durante la creazione del token di invito.: ${(e as Error).message}`,
});
}
return token;
}
type VerifyInviteResult =
| {
status: true;
invite: UserInvites;
}
| {
status: false;
reason: "not_found" | "expired";
};
export async function verifyInviteToken(
token: string,
): Promise<VerifyInviteResult> {
try {
const invite = await db
.selectFrom("user_invites")
.selectAll("user_invites")
.where("token", "=", token)
//.where("expires_at", ">", new Date())
.executeTakeFirst();
if (!invite) {
return { status: false, reason: "not_found" };
}
if (invite.expires_at < new Date()) {
return { status: false, reason: "expired" };
}
return { status: true, invite };
} catch (e) {
console.error("Error verifying invite token:", e);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Errore durante la verifica del token di invito.: ${(e as Error).message}`,
});
}
}
export async function consumeInviteToken(token: string) {
try {
await db.deleteFrom("user_invites").where("token", "=", token).execute();
} catch (e) {
console.error("Error consuming invite token:", e);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Errore durante il consumo del token di invito.: ${(e as Error).message}`,
});
}
}
export const sendInvitoEmail = async ({
userId,
email,
//password,
nome,
inviteUrl,
}: {
userId: UsersId;
email: string;
//password: string;
nome: string;
inviteUrl: string;
}) => {
try {
await NewMail({
template: {
mailType: "invito",
props: {
//email,
nome,
//password,
inviteUrl,
},
},
mail: {
subject: "Procedi ora su Infoalloggi.it",
to: email,
},
userId,
});
return true;
} catch (e) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error sending email: ${(e as Error).message}`,
});
}
};