import { BookingError, emailPattern } from "./booking-service.js"; // Prüft und normalisiert die vom Browser übermittelten Kontaktangaben. function normalizeInput(input) { if (!input || typeof input !== "object" || Array.isArray(input)) { throw new BookingError( 400, "INVALID_INPUT", "Bitte alle Pflichtfelder prüfen.", ); } // Legt die zulässige Höchstlänge für jedes Formularfeld fest. const limits = { name: 120, email: 254, subject: 160, message: 5000 }; const fields = {}; const data = { consent: true }; if (input.consent !== true) fields.consent = "Bitte die Datenschutzbestimmungen akzeptieren."; for (const [field, max] of Object.entries(limits)) { const value = input[field]; if (typeof value !== "string") { fields[field] = "Dieses Feld ist erforderlich."; continue; } const trimmed = value.trim(); if (!trimmed) fields[field] = "Dieses Feld ist erforderlich."; else if (trimmed.length > max) fields[field] = `Maximal ${max} Zeichen eingeben.`; else if ( (field === "message" ? /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/ : /[\x00-\x1f\x7f]/ ).test(trimmed) ) fields[field] = "Bitte entferne ungültige Steuerzeichen."; else data[field] = trimmed; } // Prüft zusätzlich das E-Mail-Format und die Mindestlänge der Nachricht. if ( data.email && (!emailPattern.test(data.email) || data.email.split("@")[0].length > 64) ) { fields.email = "Bitte eine gültige E-Mail-Adresse eingeben."; } if (data.message && [...data.message].length < 10) { fields.message = "Deine Nachricht muss mindestens 10 Zeichen enthalten."; } // Gibt alle gefundenen Feldfehler gesammelt an die Route zurück. if (Object.keys(fields).length) { throw new BookingError( 400, "INVALID_INPUT", "Bitte prüfe deine Eingaben.", fields, ); } return data; } // Verbindet Validierung, CSV-Speicherung und anschließenden E-Mail-Versand. export function createContactFormService({ storage, sendContactForm }) { return { async submit(input) { const data = normalizeInput(input); // Ergänzt einen Zeitstempel, damit die Anfrage zeitlich nachvollziehbar bleibt. const record = { createdAt: new Date().toISOString(), ...data }; // Speichert vor dem Versand, damit die Anfrage bei SMTP-Problemen erhalten bleibt. try { await storage.append(record); } catch { throw new BookingError( 503, "CONTACT_NOT_SAVED", "Deine Nachricht konnte gerade nicht gespeichert werden. Bitte versuche es erneut.", ); } // Sendet die beiden Mails erst nach erfolgreichem Speichern der Anfrage. try { await sendContactForm(record); } catch (error) { if (error instanceof BookingError) throw error; throw new BookingError( 502, "CONTACT_EMAIL_FAILED", "Deine Nachricht wurde gespeichert, aber die E-Mails konnten nicht vollständig gesendet werden. Bitte versuche es später erneut oder melde dich direkt bei Tri-Hub.", ); } return { saved: true, emailStatus: "accepted" }; }, }; }