mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 11:12:35 +02:00
180 lines
6.4 KiB
Python
180 lines
6.4 KiB
Python
"""API routes for notification template management."""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from backend.app.core.auth import RequirePermissionIfAuthEnabled
|
|
from backend.app.core.database import get_db
|
|
from backend.app.core.permissions import Permission
|
|
from backend.app.models.notification_template import DEFAULT_TEMPLATES, NotificationTemplate
|
|
from backend.app.models.user import User
|
|
from backend.app.schemas.notification_template import (
|
|
EVENT_VARIABLES,
|
|
SAMPLE_DATA,
|
|
EventVariablesResponse,
|
|
NotificationTemplateResponse,
|
|
NotificationTemplateUpdate,
|
|
TemplatePreviewRequest,
|
|
TemplatePreviewResponse,
|
|
)
|
|
from backend.app.services.notification_service import notification_service
|
|
|
|
router = APIRouter(prefix="/notification-templates", tags=["notification-templates"])
|
|
|
|
|
|
# Event type display names
|
|
EVENT_NAMES = {
|
|
"print_start": "Print Started",
|
|
"print_complete": "Print Completed",
|
|
"print_failed": "Print Failed",
|
|
"print_stopped": "Print Stopped",
|
|
"print_progress": "Print Progress",
|
|
"billing_charge_failed": "Billing Charge Failed",
|
|
"printer_offline": "Printer Offline",
|
|
"printer_error": "Printer Error",
|
|
"filament_low": "Filament Low",
|
|
"maintenance_due": "Maintenance Due",
|
|
"test": "Test Notification",
|
|
# Queue notifications
|
|
"queue_job_added": "Queue Job Added",
|
|
"queue_job_assigned": "Queue Job Assigned",
|
|
"queue_job_started": "Queue Job Started",
|
|
"queue_job_waiting": "Queue Job Waiting",
|
|
"queue_job_skipped": "Queue Job Skipped",
|
|
"queue_job_failed": "Queue Job Failed",
|
|
"queue_completed": "Queue Completed",
|
|
# User management
|
|
"user_created": "Welcome Email",
|
|
"password_reset": "Password Reset",
|
|
# User email print notifications
|
|
"user_print_start": "User Print Started Email",
|
|
"user_print_complete": "User Print Completed Email",
|
|
"user_print_failed": "User Print Failed Email",
|
|
"user_print_stopped": "User Print Stopped Email",
|
|
}
|
|
|
|
|
|
@router.get("", response_model=list[NotificationTemplateResponse])
|
|
@router.get("/", response_model=list[NotificationTemplateResponse])
|
|
async def get_templates(
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User | None = RequirePermissionIfAuthEnabled(Permission.NOTIFICATION_TEMPLATES_READ),
|
|
):
|
|
"""Get all notification templates."""
|
|
result = await db.execute(select(NotificationTemplate).order_by(NotificationTemplate.id))
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.get("/variables", response_model=list[EventVariablesResponse])
|
|
async def get_variables(
|
|
_: User | None = RequirePermissionIfAuthEnabled(Permission.NOTIFICATION_TEMPLATES_READ),
|
|
):
|
|
"""Get available variables for each event type."""
|
|
return [
|
|
EventVariablesResponse(
|
|
event_type=event_type,
|
|
event_name=EVENT_NAMES.get(event_type, event_type),
|
|
variables=variables,
|
|
)
|
|
for event_type, variables in EVENT_VARIABLES.items()
|
|
]
|
|
|
|
|
|
@router.get("/{template_id}", response_model=NotificationTemplateResponse)
|
|
async def get_template(
|
|
template_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User | None = RequirePermissionIfAuthEnabled(Permission.NOTIFICATION_TEMPLATES_READ),
|
|
):
|
|
"""Get a single notification template."""
|
|
result = await db.execute(select(NotificationTemplate).where(NotificationTemplate.id == template_id))
|
|
template = result.scalar_one_or_none()
|
|
if not template:
|
|
raise HTTPException(status_code=404, detail="Template not found")
|
|
return template
|
|
|
|
|
|
@router.put("/{template_id}", response_model=NotificationTemplateResponse)
|
|
async def update_template(
|
|
template_id: int,
|
|
update: NotificationTemplateUpdate,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User | None = RequirePermissionIfAuthEnabled(Permission.NOTIFICATION_TEMPLATES_UPDATE),
|
|
):
|
|
"""Update a notification template."""
|
|
result = await db.execute(select(NotificationTemplate).where(NotificationTemplate.id == template_id))
|
|
template = result.scalar_one_or_none()
|
|
if not template:
|
|
raise HTTPException(status_code=404, detail="Template not found")
|
|
|
|
if update.title_template is not None:
|
|
template.title_template = update.title_template
|
|
if update.body_template is not None:
|
|
template.body_template = update.body_template
|
|
|
|
await db.commit()
|
|
await db.refresh(template)
|
|
|
|
# Clear template cache so changes take effect immediately
|
|
notification_service.clear_template_cache()
|
|
|
|
return template
|
|
|
|
|
|
@router.post("/{template_id}/reset", response_model=NotificationTemplateResponse)
|
|
async def reset_template(
|
|
template_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User | None = RequirePermissionIfAuthEnabled(Permission.NOTIFICATION_TEMPLATES_UPDATE),
|
|
):
|
|
"""Reset a notification template to its default values."""
|
|
result = await db.execute(select(NotificationTemplate).where(NotificationTemplate.id == template_id))
|
|
template = result.scalar_one_or_none()
|
|
if not template:
|
|
raise HTTPException(status_code=404, detail="Template not found")
|
|
|
|
# Find the default template
|
|
default = next(
|
|
(t for t in DEFAULT_TEMPLATES if t["event_type"] == template.event_type),
|
|
None,
|
|
)
|
|
if not default:
|
|
raise HTTPException(status_code=500, detail="Default template not found")
|
|
|
|
template.title_template = default["title_template"]
|
|
template.body_template = default["body_template"]
|
|
|
|
await db.commit()
|
|
await db.refresh(template)
|
|
|
|
# Clear template cache so changes take effect immediately
|
|
notification_service.clear_template_cache()
|
|
|
|
return template
|
|
|
|
|
|
@router.post("/preview", response_model=TemplatePreviewResponse)
|
|
async def preview_template(
|
|
request: TemplatePreviewRequest,
|
|
_: User | None = RequirePermissionIfAuthEnabled(Permission.NOTIFICATION_TEMPLATES_READ),
|
|
):
|
|
"""Preview a template with sample data."""
|
|
sample = SAMPLE_DATA.get(request.event_type, {})
|
|
|
|
# Safe template rendering - replace missing vars with empty string
|
|
def safe_format(template: str, data: dict) -> str:
|
|
result = template
|
|
for key, value in data.items():
|
|
result = result.replace("{" + key + "}", str(value))
|
|
# Remove any remaining unreplaced placeholders
|
|
import re
|
|
|
|
result = re.sub(r"\{[a-z_]+\}", "", result)
|
|
return result
|
|
|
|
return TemplatePreviewResponse(
|
|
title=safe_format(request.title_template, sample),
|
|
body=safe_format(request.body_template, sample),
|
|
)
|