This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { corsHeaders } from "./cors.ts";
|
||||
|
||||
const respond = (body: unknown, status = 200) => new Response(JSON.stringify(body), {
|
||||
status,
|
||||
headers: { ...corsHeaders, "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
const escapeHtml = (value: string) => value.replace(/[&<>"']/g, (character) => ({
|
||||
"&": "&", "<": "<", ">": ">", '"': """, "'": "'",
|
||||
}[character] || character));
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
if (req.method === "OPTIONS") {
|
||||
return new Response("ok", { headers: corsHeaders });
|
||||
}
|
||||
if (req.method !== "POST") {
|
||||
return respond({ success: false, error: "Método no permitido." }, 405);
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = await req.json();
|
||||
const record = payload?.record || payload;
|
||||
if (!record || typeof record !== "object") {
|
||||
return respond({ success: false, error: "Datos de contacto no válidos." }, 400);
|
||||
}
|
||||
|
||||
const fields = ["name", "email", "phone", "subject", "message"];
|
||||
if (fields.some((field) => record[field] != null && typeof record[field] !== "string")) {
|
||||
return respond({ success: false, error: "Datos de contacto no válidos." }, 400);
|
||||
}
|
||||
const name = (record.name || "").trim();
|
||||
const email = (record.email || "").trim();
|
||||
const phone = (record.phone || "").trim();
|
||||
const subject = (record.subject || "").trim();
|
||||
const message = (record.message || "").trim();
|
||||
if (!name || name.length > 200 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || email.length > 320 || phone.length > 100 || subject.length > 300 || message.length < 10 || message.length > 10000) {
|
||||
return respond({ success: false, error: "Revisa los datos de contacto." }, 400);
|
||||
}
|
||||
|
||||
// Configura estos secretos solo en Supabase, nunca en Coolify ni en VITE_*.
|
||||
const apiKey = Deno.env.get("RESEND_API_KEY");
|
||||
const sender = Deno.env.get("RESEND_FROM_EMAIL");
|
||||
if (!apiKey || !sender) {
|
||||
// Estado explícito, no una simulación de entrega: el formulario ya está guardado.
|
||||
return respond({ success: false, status: "not_configured", message: "La notificación por correo no está configurada." });
|
||||
}
|
||||
|
||||
const response = await fetch("https://api.resend.com/emails", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
||||
body: JSON.stringify({
|
||||
from: sender,
|
||||
to: ["info@infinitustx.com"],
|
||||
subject: `Nuevo mensaje de contacto: ${name.replace(/[\r\n]/g, " ")}`,
|
||||
html: `<h2>Nuevo mensaje de contacto</h2><p><strong>Nombre:</strong> ${escapeHtml(name)}</p><p><strong>Correo:</strong> ${escapeHtml(email)}</p><p><strong>Teléfono:</strong> ${escapeHtml(phone)}</p><p><strong>Asunto:</strong> ${escapeHtml(subject)}</p><p>${escapeHtml(message).replace(/\n/g, "<br/>")}</p>`,
|
||||
reply_to: email,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.error("El proveedor de correo rechazó la solicitud:", response.status);
|
||||
return respond({ success: false, error: "No se pudo enviar la notificación por correo." }, 502);
|
||||
}
|
||||
return respond({ success: true });
|
||||
} catch {
|
||||
return respond({ success: false, error: "No se pudo procesar la notificación." }, 400);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user