cms.c2sgmbh/src/collections/Tenants.ts

249 lines
7 KiB
TypeScript

import type { CollectionConfig, FieldHook } from 'payload'
import { invalidateEmailCacheHook } from '../hooks/invalidateEmailCache'
import { auditTenantAfterChange, auditTenantAfterDelete } from '../hooks/auditTenantChanges'
/**
* Validiert SMTP Host Format
*/
const validateSmtpHost: FieldHook = ({ value }) => {
// Nur validieren, wenn ein Wert gesetzt ist
if (!value) return value
// Basis-Validierung: Keine Protokoll-Präfixe erlaubt
if (value.includes('://')) {
throw new Error('SMTP Host ohne Protokoll angeben (z.B. smtp.example.com)')
}
return value
}
/**
* Validiert SMTP Port
*/
const validateSmtpPort: FieldHook = ({ value }) => {
if (!value) return value
const port = Number(value)
if (port && (port < 1 || port > 65535)) {
throw new Error('Port muss zwischen 1 und 65535 liegen')
}
return value
}
export const Tenants: CollectionConfig = {
slug: 'tenants',
admin: {
useAsTitle: 'name',
},
hooks: {
afterChange: [invalidateEmailCacheHook, auditTenantAfterChange],
afterDelete: [auditTenantAfterDelete],
},
fields: [
{
name: 'name',
type: 'text',
required: true,
},
{
name: 'slug',
type: 'text',
required: true,
unique: true,
},
{
name: 'domains',
type: 'array',
fields: [
{
name: 'domain',
type: 'text',
required: true,
},
],
},
// E-Mail Konfiguration
{
name: 'email',
type: 'group',
label: 'E-Mail Konfiguration',
admin: {
description: 'SMTP-Einstellungen für diesen Tenant. Leer = globale Einstellungen.',
},
fields: [
{
type: 'row',
fields: [
{
name: 'fromAddress',
type: 'email',
label: 'Absender E-Mail',
admin: {
placeholder: 'info@domain.de',
width: '50%',
description:
'Tipp: Verwenden Sie eine E-Mail-Adresse der Domain, für die SPF/DKIM konfiguriert ist.',
},
},
{
name: 'fromName',
type: 'text',
label: 'Absender Name',
admin: {
placeholder: 'Firmenname',
width: '50%',
},
},
],
},
{
name: 'replyTo',
type: 'email',
label: 'Antwort-Adresse (Reply-To)',
admin: {
placeholder: 'kontakt@domain.de (optional)',
},
},
// SPF/DKIM Info-Block
{
name: 'emailDeliverabilityInfo',
type: 'ui',
admin: {
components: {
Field: '@/components/admin/EmailDeliverabilityInfo#EmailDeliverabilityInfo',
},
},
},
{
name: 'useCustomSmtp',
type: 'checkbox',
label: 'Eigenen SMTP-Server verwenden',
defaultValue: false,
admin: {
description:
'Aktivieren Sie diese Option, um einen eigenen SMTP-Server statt der globalen Einstellungen zu verwenden.',
},
},
{
name: 'smtp',
type: 'group',
label: 'SMTP Einstellungen',
admin: {
condition: (_, siblingData) => siblingData?.useCustomSmtp,
description:
'Hinweis: Stellen Sie sicher, dass SPF- und DKIM-Einträge für Ihre Domain konfiguriert sind, um eine optimale E-Mail-Zustellung zu gewährleisten.',
},
validate: (value, { siblingData }) => {
const emailData = siblingData as { useCustomSmtp?: boolean }
if (!emailData?.useCustomSmtp) return true
const smtpData = (value || {}) as { host?: string; user?: string }
if (!smtpData.host?.trim()) {
return 'SMTP Host ist erforderlich'
}
if (!smtpData.user?.trim()) {
return 'SMTP Benutzername ist erforderlich'
}
return true
},
fields: [
{
type: 'row',
fields: [
{
name: 'host',
type: 'text',
label: 'SMTP Host',
admin: {
placeholder: 'smtp.example.com',
width: '50%',
description: 'Hostname ohne Protokoll (z.B. smtp.gmail.com)',
},
hooks: {
beforeValidate: [validateSmtpHost],
},
},
{
name: 'port',
type: 'number',
label: 'Port',
defaultValue: 587,
admin: {
width: '25%',
description: '587 (STARTTLS) oder 465 (SSL)',
},
hooks: {
beforeValidate: [validateSmtpPort],
},
min: 1,
max: 65535,
},
{
name: 'secure',
type: 'checkbox',
label: 'SSL/TLS (Port 465)',
defaultValue: false,
admin: {
width: '25%',
description: 'Für Port 465 aktivieren',
},
},
],
},
{
type: 'row',
fields: [
{
name: 'user',
type: 'text',
label: 'SMTP Benutzername',
admin: {
width: '50%',
description: 'Meist die E-Mail-Adresse',
},
},
{
name: 'pass',
type: 'text',
label: 'SMTP Passwort',
admin: {
width: '50%',
description: 'Leer lassen um bestehendes Passwort zu behalten',
},
access: {
read: ({ req }) => !!req.user, // Admin kann lesen, API ohne Auth nicht
},
hooks: {
beforeChange: [
({ value, originalDoc }) => {
// Behalte altes Passwort wenn Feld leer
if (!value && originalDoc?.email?.smtp?.pass) {
return originalDoc.email.smtp.pass
}
return value
},
],
},
},
],
},
// Test-Email Button
{
name: 'testEmailButton',
type: 'ui',
admin: {
components: {
Field: '@/components/admin/TestEmailButton#TestEmailButton',
},
},
},
],
},
],
},
],
}