"use server"; import { createElement } from "react"; import { headers } from "next/headers"; import { ContactConfirmationEmail } from "@/emails/ContactConfirmationEmail"; import { ContactRequestEmail } from "@/emails/ContactRequestEmail"; import { contactRequestSchema, contactRequestTypeLabels, type ContactSubmissionPayload, } from "@/lib/contact-schema"; import { getAppEmailConfigError, sendAppEmail } from "@/lib/mail"; import { rateLimit } from "@/lib/rate-limit"; const DEFAULT_ADMIN_EMAIL = "kontakt@kita-planer.local"; const RATE_LIMIT_MAX = 5; const RATE_LIMIT_WINDOW_SECONDS = 60 * 60; async function resolveClientIp(): Promise { const h = await headers(); const forwarded = h.get("x-forwarded-for"); if (forwarded) { return forwarded.split(",")[0]?.trim() || "unknown"; } return h.get("x-real-ip") ?? "unknown"; } export async function submitContactRequest(data: ContactSubmissionPayload) { // Honeypot: silently absorb bot submissions without informing them. if (data.website && data.website.trim().length > 0) { return { success: true }; } const ip = await resolveClientIp(); const limit = rateLimit( `contact:${ip}`, RATE_LIMIT_MAX, RATE_LIMIT_WINDOW_SECONDS, ); if (!limit.allowed) { const minutes = Math.max(1, Math.ceil(limit.retryAfterSeconds / 60)); return { success: false, error: `Zu viele Anfragen. Bitte versuche es in ${minutes} Minuten erneut.`, }; } const parsed = contactRequestSchema.safeParse(data); if (!parsed.success) { return { success: false, error: "Bitte prüfe deine Eingaben und versuche es erneut.", }; } const configError = getAppEmailConfigError(); if (configError) { return { success: false, error: configError, }; } const adminEmail = process.env.ADMIN_EMAIL || DEFAULT_ADMIN_EMAIL; const inquiryLabel = contactRequestTypeLabels[parsed.data.requestType]; const [adminResult, confirmationResult] = await Promise.all([ sendAppEmail({ to: adminEmail, subject: `Kontaktanfrage: ${inquiryLabel} von ${parsed.data.name}`, replyTo: parsed.data.email, react: createElement(ContactRequestEmail, parsed.data), }), sendAppEmail({ to: parsed.data.email, subject: "Wir haben deine Anfrage erhalten — Kita-Planer", replyTo: adminEmail, react: createElement(ContactConfirmationEmail, parsed.data), }), ]); if (!adminResult.success) { return { success: false, error: adminResult.error, }; } if (!confirmationResult.success) { console.error( "Bestätigungs-E-Mail konnte nicht zugestellt werden:", confirmationResult.error, ); } return { success: true }; }