""" Admin Email Component - E-Mail Template Management """ def get_admin_email_css() -> str: """CSS für E-Mail Templates (inkludiert in admin_panel.css)""" return "" def get_admin_email_html() -> str: """HTML für E-Mail Templates (inkludiert in admin_panel.html)""" return "" def get_admin_email_js() -> str: """JavaScript für E-Mail Template Management zurückgeben""" return """ let emailTemplates = []; let emailTemplateVersions = []; let currentEmailTemplateId = null; let currentEmailVersionId = null; // E-Mail-Template-Typen mit deutschen Namen const emailTypeNames = { 'welcome': 'Willkommens-E-Mail', 'email_verification': 'E-Mail-Verifizierung', 'password_reset': 'Passwort zurücksetzen', 'password_changed': 'Passwort geändert', '2fa_enabled': '2FA aktiviert', '2fa_disabled': '2FA deaktiviert', 'new_device_login': 'Neues Gerät Login', 'suspicious_activity': 'Verdächtige Aktivität', 'account_locked': 'Account gesperrt', 'account_unlocked': 'Account entsperrt', 'deletion_requested': 'Löschung angefordert', 'deletion_confirmed': 'Löschung bestätigt', 'data_export_ready': 'Datenexport bereit', 'email_changed': 'E-Mail geändert', 'new_version_published': 'Neue Version veröffentlicht', 'consent_reminder': 'Consent Erinnerung', 'consent_deadline_warning': 'Consent Frist Warnung', 'account_suspended': 'Account suspendiert' }; // Load E-Mail Templates when tab is clicked document.querySelector('.admin-tab[data-tab="emails"]')?.addEventListener('click', loadEmailTemplates); async function loadEmailTemplates() { try { const res = await fetch('/api/consent/admin/email-templates'); if (!res.ok) throw new Error('Fehler beim Laden der Templates'); const data = await res.json(); emailTemplates = data.templates || []; populateEmailTemplateSelect(); } catch (e) { console.error('Error loading email templates:', e); showToast('Fehler beim Laden der E-Mail-Templates', 'error'); } } function populateEmailTemplateSelect() { const select = document.getElementById('email-template-select'); select.innerHTML = ''; emailTemplates.forEach(template => { const opt = document.createElement('option'); opt.value = template.id; opt.textContent = emailTypeNames[template.type] || template.name; select.appendChild(opt); }); } async function loadEmailTemplateVersions() { const select = document.getElementById('email-template-select'); const templateId = select.value; const newVersionBtn = document.getElementById('btn-new-email-version'); const infoCard = document.getElementById('email-template-info'); const container = document.getElementById('email-version-table-container'); if (!templateId) { newVersionBtn.disabled = true; infoCard.style.display = 'none'; container.innerHTML = '
Wählen Sie eine E-Mail-Vorlage aus, um deren Versionen anzuzeigen.
'; currentEmailTemplateId = null; return; } currentEmailTemplateId = templateId; newVersionBtn.disabled = false; // Finde das Template const template = emailTemplates.find(t => t.id === templateId); if (template) { infoCard.style.display = 'block'; document.getElementById('email-template-name').textContent = emailTypeNames[template.type] || template.name; document.getElementById('email-template-description').textContent = template.description || 'Keine Beschreibung'; document.getElementById('email-template-type-badge').textContent = template.type; // Variablen anzeigen (wird aus dem Default-Inhalt ermittelt) try { const defaultRes = await fetch(`/api/consent/admin/email-templates/default/${template.type}`); if (defaultRes.ok) { const defaultData = await defaultRes.json(); const variables = extractVariables(defaultData.body_html || ''); document.getElementById('email-template-variables').textContent = variables.join(', ') || 'Keine'; } } catch (e) { document.getElementById('email-template-variables').textContent = '-'; } } // Lade Versionen container.innerHTML = '
Lade Versionen...
'; try { const res = await fetch(`/api/consent/admin/email-templates/${templateId}/versions`); if (!res.ok) throw new Error('Fehler beim Laden'); const data = await res.json(); emailTemplateVersions = data.versions || []; renderEmailVersionsTable(); } catch (e) { container.innerHTML = '
Fehler beim Laden der Versionen.
'; } } function extractVariables(content) { const matches = content.match(/\\{\\{([^}]+)\\}\\}/g) || []; return [...new Set(matches.map(m => m.replace(/[{}]/g, '')))]; } function renderEmailVersionsTable() { const container = document.getElementById('email-version-table-container'); if (emailTemplateVersions.length === 0) { container.innerHTML = '
Keine Versionen vorhanden. Erstellen Sie eine neue Version.
'; return; } const statusColors = { 'draft': 'draft', 'review': 'review', 'approved': 'approved', 'published': 'published', 'archived': 'archived' }; const statusNames = { 'draft': 'Entwurf', 'review': 'In Prüfung', 'approved': 'Genehmigt', 'published': 'Veröffentlicht', 'archived': 'Archiviert' }; container.innerHTML = ` ${emailTemplateVersions.map(v => ` `).join('')}
Version Sprache Betreff Status Aktualisiert Aktionen
${v.version} ${v.language === 'de' ? '🇩🇪 DE' : '🇬🇧 EN'} ${v.subject} ${statusNames[v.status] || v.status} ${new Date(v.updated_at).toLocaleDateString('de-DE')} ${v.status === 'draft' ? ` ` : ''} ${v.status === 'review' ? ` ` : ''} ${v.status === 'approved' ? ` ` : ''}
`; } function showEmailVersionForm() { document.getElementById('email-version-form').style.display = 'block'; document.getElementById('email-version-form-title').textContent = 'Neue E-Mail-Version erstellen'; document.getElementById('email-version-id').value = ''; document.getElementById('email-version-number').value = ''; document.getElementById('email-version-subject').value = ''; document.getElementById('email-version-editor').innerHTML = ''; document.getElementById('email-version-text').value = ''; // Lade Default-Inhalt const template = emailTemplates.find(t => t.id === currentEmailTemplateId); if (template) { loadDefaultEmailContent(template.type); } } async function loadDefaultEmailContent(templateType) { try { const res = await fetch(`/api/consent/admin/email-templates/default/${templateType}`); if (res.ok) { const data = await res.json(); document.getElementById('email-version-subject').value = data.subject || ''; document.getElementById('email-version-editor').innerHTML = data.body_html || ''; document.getElementById('email-version-text').value = data.body_text || ''; } } catch (e) { console.error('Error loading default content:', e); } } function hideEmailVersionForm() { document.getElementById('email-version-form').style.display = 'none'; } async function saveEmailVersion() { const versionId = document.getElementById('email-version-id').value; const templateId = currentEmailTemplateId; const version = document.getElementById('email-version-number').value.trim(); const language = document.getElementById('email-version-lang').value; const subject = document.getElementById('email-version-subject').value.trim(); const bodyHtml = document.getElementById('email-version-editor').innerHTML; const bodyText = document.getElementById('email-version-text').value.trim(); if (!version || !subject || !bodyHtml) { showToast('Bitte füllen Sie alle Pflichtfelder aus', 'error'); return; } const data = { template_id: templateId, version: version, language: language, subject: subject, body_html: bodyHtml, body_text: bodyText || stripHtml(bodyHtml) }; try { let res; if (versionId) { // Update existing version res = await fetch(`/api/consent/admin/email-template-versions/${versionId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); } else { // Create new version res = await fetch('/api/consent/admin/email-template-versions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); } if (!res.ok) { const error = await res.json(); throw new Error(error.detail || 'Fehler beim Speichern'); } showToast('E-Mail-Version gespeichert!', 'success'); hideEmailVersionForm(); loadEmailTemplateVersions(); } catch (e) { showToast('Fehler: ' + e.message, 'error'); } } function stripHtml(html) { const div = document.createElement('div'); div.innerHTML = html; return div.textContent || div.innerText || ''; } async function editEmailVersion(versionId) { try { const res = await fetch(`/api/consent/admin/email-template-versions/${versionId}`); if (!res.ok) throw new Error('Version nicht gefunden'); const version = await res.json(); document.getElementById('email-version-form').style.display = 'block'; document.getElementById('email-version-form-title').textContent = 'E-Mail-Version bearbeiten'; document.getElementById('email-version-id').value = versionId; document.getElementById('email-version-number').value = version.version; document.getElementById('email-version-lang').value = version.language; document.getElementById('email-version-subject').value = version.subject; document.getElementById('email-version-editor').innerHTML = version.body_html; document.getElementById('email-version-text').value = version.body_text || ''; } catch (e) { showToast('Fehler beim Laden der Version', 'error'); } } async function deleteEmailVersion(versionId) { if (!confirm('Möchten Sie diese Version wirklich löschen?')) return; try { const res = await fetch(`/api/consent/admin/email-template-versions/${versionId}`, { method: 'DELETE' }); if (!res.ok) throw new Error('Fehler beim Löschen'); showToast('Version gelöscht', 'success'); loadEmailTemplateVersions(); } catch (e) { showToast('Fehler beim Löschen', 'error'); } } async function submitEmailForReview(versionId) { try { const res = await fetch(`/api/consent/admin/email-template-versions/${versionId}/submit`, { method: 'POST' }); if (!res.ok) throw new Error('Fehler'); showToast('Zur Prüfung eingereicht', 'success'); loadEmailTemplateVersions(); } catch (e) { showToast('Fehler beim Einreichen', 'error'); } } function showEmailApprovalDialogFor(versionId) { currentEmailVersionId = versionId; document.getElementById('email-approval-dialog').style.display = 'flex'; document.getElementById('email-approval-comment').value = ''; } function hideEmailApprovalDialog() { document.getElementById('email-approval-dialog').style.display = 'none'; currentEmailVersionId = null; } async function submitEmailApproval() { if (!currentEmailVersionId) return; const comment = document.getElementById('email-approval-comment').value.trim(); try { const res = await fetch(`/api/consent/admin/email-template-versions/${currentEmailVersionId}/approve`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ comment: comment }) }); if (!res.ok) throw new Error('Fehler'); showToast('Version genehmigt', 'success'); hideEmailApprovalDialog(); loadEmailTemplateVersions(); } catch (e) { showToast('Fehler bei der Genehmigung', 'error'); } } async function rejectEmailVersion(versionId) { const reason = prompt('Ablehnungsgrund:'); if (!reason) return; try { const res = await fetch(`/api/consent/admin/email-template-versions/${versionId}/reject`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason: reason }) }); if (!res.ok) throw new Error('Fehler'); showToast('Version abgelehnt', 'success'); loadEmailTemplateVersions(); } catch (e) { showToast('Fehler bei der Ablehnung', 'error'); } } async function publishEmailVersion(versionId) { if (!confirm('Möchten Sie diese Version veröffentlichen? Die vorherige Version wird archiviert.')) return; try { const res = await fetch(`/api/consent/admin/email-template-versions/${versionId}/publish`, { method: 'POST' }); if (!res.ok) throw new Error('Fehler'); showToast('Version veröffentlicht!', 'success'); loadEmailTemplateVersions(); } catch (e) { showToast('Fehler beim Veröffentlichen', 'error'); } } async function previewEmailVersionById(versionId) { try { const res = await fetch(`/api/consent/admin/email-template-versions/${versionId}/preview`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); if (!res.ok) throw new Error('Fehler'); const data = await res.json(); document.getElementById('email-preview-subject').textContent = data.subject; document.getElementById('email-preview-content').innerHTML = data.body_html; document.getElementById('email-preview-dialog').style.display = 'flex'; currentEmailVersionId = versionId; } catch (e) { showToast('Fehler bei der Vorschau', 'error'); } } function previewEmailVersion() { const subject = document.getElementById('email-version-subject').value; const bodyHtml = document.getElementById('email-version-editor').innerHTML; document.getElementById('email-preview-subject').textContent = subject; document.getElementById('email-preview-content').innerHTML = bodyHtml; document.getElementById('email-preview-dialog').style.display = 'flex'; } function hideEmailPreview() { document.getElementById('email-preview-dialog').style.display = 'none'; } async function sendTestEmail() { const email = document.getElementById('email-test-address').value.trim(); if (!email) { showToast('Bitte geben Sie eine E-Mail-Adresse ein', 'error'); return; } if (!currentEmailVersionId) { showToast('Keine Version ausgewählt', 'error'); return; } try { const res = await fetch(`/api/consent/admin/email-template-versions/${currentEmailVersionId}/send-test`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email }) }); if (!res.ok) throw new Error('Fehler'); showToast('Test-E-Mail gesendet!', 'success'); } catch (e) { showToast('Fehler beim Senden der Test-E-Mail', 'error'); } } async function initializeEmailTemplates() { if (!confirm('Möchten Sie alle Standard-E-Mail-Templates initialisieren?')) return; try { const res = await fetch('/api/consent/admin/email-templates/initialize', { method: 'POST' }); if (!res.ok) throw new Error('Fehler'); showToast('Templates initialisiert!', 'success'); loadEmailTemplates(); } catch (e) { showToast('Fehler bei der Initialisierung', 'error'); } } // E-Mail Editor Helpers function formatEmailDoc(command) { document.execCommand(command, false, null); document.getElementById('email-version-editor').focus(); } function formatEmailBlock(tag) { document.execCommand('formatBlock', false, '<' + tag + '>'); document.getElementById('email-version-editor').focus(); } function insertEmailVariable() { const variable = prompt('Variablenname eingeben (z.B. user_name, reset_link):'); if (variable) { document.execCommand('insertText', false, '{{' + variable + '}}'); } } function insertEmailLink() { const url = prompt('Link-URL:'); if (url) { const text = prompt('Link-Text:', url); document.execCommand('insertHTML', false, `${text}`); } } function insertEmailButton() { const url = prompt('Button-Link:'); if (url) { const text = prompt('Button-Text:', 'Klicken'); const buttonHtml = `
${text}
`; document.execCommand('insertHTML', false, buttonHtml); } } """