From dec0da3455103b7999b3314adda0e88eb7563aa6 Mon Sep 17 00:00:00 2001 From: esteban Date: Sat, 8 Aug 2026 22:05:38 -0500 Subject: [PATCH] add email verification, add cf validation for debounce --- .gitignore | 1 + src/pages/api/formulario/send.ts | 10 ++++++++++ src/pages/api/lib/email.ts | 2 +- src/pages/api/lib/emailsRegistry.ts | 22 ++++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/pages/api/lib/emailsRegistry.ts diff --git a/.gitignore b/.gitignore index a31e3de..8ad93c8 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ pnpm-debug.log* /generated/prisma prisma/*.db prisma/dev.db +data/ # opencode - agentes y scripts locales (no subir a producción) opencode/ diff --git a/src/pages/api/formulario/send.ts b/src/pages/api/formulario/send.ts index fdb9b40..bbd90ca 100644 --- a/src/pages/api/formulario/send.ts +++ b/src/pages/api/formulario/send.ts @@ -1,6 +1,7 @@ import type { APIRoute } from "astro"; import { appendRegistrationToSheet } from "../lib/googleSheets"; import { sendEmailCf } from "../lib/email"; +import { emailExistsInRegistry, addEmailToRegistry } from "../lib/emailsRegistry"; export const prerender = false; const COLUMNS = [ @@ -101,6 +102,13 @@ export const POST: APIRoute = async ({ request }) => { timeZone: "America/Puerto_Rico", }); + if (emailExistsInRegistry(formData.correo)) { + return Response.json( + { success: false, message: "Este correo ya está registrado. No se permiten 2 registros." }, + { status: 409 } + ); + } + const row = COLUMNS.map((key) => flattenValue(formData[key])); row.push(timestamp); @@ -111,6 +119,8 @@ export const POST: APIRoute = async ({ request }) => { apellidos: formData.apellido, }, formData.correo, "CENTRO_DEL_REINO_PAZ_Y_JUSTICIA_POSTULACION"); + addEmailToRegistry(formData.correo); + return Response.json(result); } catch (error) { console.error("Error en /api/formulario/send:", error); diff --git a/src/pages/api/lib/email.ts b/src/pages/api/lib/email.ts index 3752377..27ab5aa 100644 --- a/src/pages/api/lib/email.ts +++ b/src/pages/api/lib/email.ts @@ -96,7 +96,7 @@ export async function sendEmailCf(data: Record, to: string, type text, }); - if (response.permanent_bounces.includes(to)) { + if (!response.delivered.includes(to)) { console.error("Cloudflare email not delivered", response); throw new Error("El correo no fue entregado"); } diff --git a/src/pages/api/lib/emailsRegistry.ts b/src/pages/api/lib/emailsRegistry.ts new file mode 100644 index 0000000..a4e4c4b --- /dev/null +++ b/src/pages/api/lib/emailsRegistry.ts @@ -0,0 +1,22 @@ +import fs from "node:fs"; +import path from "node:path"; + +const REGISTRY_PATH = path.resolve(process.cwd(), "data", "emails.txt"); + +export function emailExistsInRegistry(email: string): boolean { + try { + if (!fs.existsSync(REGISTRY_PATH)) return false; + const content = fs.readFileSync(REGISTRY_PATH, "utf-8"); + return content.split("\n").some((line) => line.trim().toLowerCase() === email.trim().toLowerCase()); + } catch { + return false; + } +} + +export function addEmailToRegistry(email: string): void { + const dir = path.dirname(REGISTRY_PATH); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.appendFileSync(REGISTRY_PATH, email.trim().toLowerCase() + "\n"); +}