feat: Add email settings management and templates functionality
- Implemented email settings configuration in the admin panel, allowing for SMTP settings and notification preferences. - Created a new template for email settings with fields for SMTP host, port, username, password, sender address, and recipients. - Added JavaScript functionality to handle loading, saving, and validating email settings. - Introduced email templates management, enabling the listing, editing, and saving of email templates. - Updated navigation to include links to email settings and templates. - Added tests for email settings and templates to ensure proper functionality and validation.
This commit is contained in:
86
server/services/email_templates.py
Normal file
86
server/services/email_templates.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""Email template management helpers."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List
|
||||
|
||||
from ..database import get_app_settings, update_app_setting
|
||||
from .. import settings
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EmailTemplateDefinition:
|
||||
"""Definition metadata describing an editable email template."""
|
||||
|
||||
id: str
|
||||
setting_key: str
|
||||
name: str
|
||||
description: str
|
||||
default_content: str
|
||||
|
||||
|
||||
EMAIL_TEMPLATE_DEFINITIONS: Dict[str, EmailTemplateDefinition] = {
|
||||
"newsletter_confirmation": EmailTemplateDefinition(
|
||||
id="newsletter_confirmation",
|
||||
setting_key="newsletter_confirmation_template",
|
||||
name="Newsletter Confirmation",
|
||||
description="HTML email sent to subscribers immediately after they confirm their newsletter signup.",
|
||||
default_content=getattr(
|
||||
settings, "NEWSLETTER_CONFIRMATION_TEMPLATE", "").strip(),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def list_templates() -> List[dict]:
|
||||
"""Return a list of metadata describing available email templates."""
|
||||
return [
|
||||
{
|
||||
"id": definition.id,
|
||||
"name": definition.name,
|
||||
"description": definition.description,
|
||||
}
|
||||
for definition in EMAIL_TEMPLATE_DEFINITIONS.values()
|
||||
]
|
||||
|
||||
|
||||
def _load_stored_templates() -> dict:
|
||||
"""Return stored template values keyed by their setting key."""
|
||||
return get_app_settings()
|
||||
|
||||
|
||||
def load_template(template_id: str) -> dict:
|
||||
"""Return template metadata and content for the requested template."""
|
||||
if template_id not in EMAIL_TEMPLATE_DEFINITIONS:
|
||||
raise KeyError(template_id)
|
||||
|
||||
definition = EMAIL_TEMPLATE_DEFINITIONS[template_id]
|
||||
stored = _load_stored_templates()
|
||||
content = stored.get(definition.setting_key, definition.default_content)
|
||||
|
||||
return {
|
||||
"id": definition.id,
|
||||
"name": definition.name,
|
||||
"description": definition.description,
|
||||
"content": content,
|
||||
}
|
||||
|
||||
|
||||
def persist_template(template_id: str, content: str) -> dict:
|
||||
"""Persist template content and return the updated template payload."""
|
||||
if template_id not in EMAIL_TEMPLATE_DEFINITIONS:
|
||||
raise KeyError(template_id)
|
||||
|
||||
definition = EMAIL_TEMPLATE_DEFINITIONS[template_id]
|
||||
content = (content or "").strip()
|
||||
update_app_setting(definition.setting_key, content)
|
||||
return load_template(template_id)
|
||||
|
||||
|
||||
def get_template_content(template_id: str) -> str:
|
||||
"""Return just the template body, falling back to defaults when unset."""
|
||||
if template_id not in EMAIL_TEMPLATE_DEFINITIONS:
|
||||
raise KeyError(template_id)
|
||||
|
||||
definition = EMAIL_TEMPLATE_DEFINITIONS[template_id]
|
||||
stored = _load_stored_templates()
|
||||
return stored.get(definition.setting_key, definition.default_content)
|
||||
Reference in New Issue
Block a user