"""
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 = `
| Version |
Sprache |
Betreff |
Status |
Aktualisiert |
Aktionen |
${emailTemplateVersions.map(v => `
| ${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' ? `
` : ''}
|
`).join('')}
`;
}
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 = ``;
document.execCommand('insertHTML', false, buttonHtml);
}
}
"""