121 lines
2.7 KiB
TypeScript
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}`,
|
|
});
|
|
}
|
|
};
|