From 4f4587893af49233a7b4728cf4762b43c152bcb2 Mon Sep 17 00:00:00 2001 From: YuehuCao Date: Fri, 25 Jul 2025 19:05:29 +0800 Subject: [PATCH] feat(api): add CRUD interfaces for message templates and email senders --- .../webapi/routes/email_sender.py | 56 +++++++++ .../webapi/routes/template_massege.py | 106 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 apps/notification/webapi/routes/email_sender.py create mode 100644 apps/notification/webapi/routes/template_massege.py diff --git a/apps/notification/webapi/routes/email_sender.py b/apps/notification/webapi/routes/email_sender.py new file mode 100644 index 0000000..3a7e1e3 --- /dev/null +++ b/apps/notification/webapi/routes/email_sender.py @@ -0,0 +1,56 @@ +from fastapi import APIRouter, Depends, HTTPException +from backend.services.email_sender_service import EmailSenderService +from common.token.token_manager import TokenManager +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials + +router = APIRouter() +email_sender_service = EmailSenderService() +token_manager = TokenManager() +security = HTTPBearer() + + +def get_current_tenant_id( + credentials: HTTPAuthorizationCredentials = Depends(security) +) -> str: + try: + payload = token_manager.decode_token(credentials.credentials) + tenant_id = payload.get("tenant_id") + if not tenant_id: + raise HTTPException(status_code=401, detail="No tenant_id in token") + return tenant_id + except Exception: + raise HTTPException(status_code=401, detail="Invalid token") + + +@router.get("/email_senders") +async def get_email_senders(tenant_id: str = Depends(get_current_tenant_id)): + return await email_sender_service.get_email_sender(tenant_id) + +@router.post("/email_sender/set") +async def set_email_senders( + email_senders: list[str], + tenant_id: str = Depends(get_current_tenant_id) +): + return await email_sender_service.set_email_sender(tenant_id, email_senders) + +@router.post("/email_senders/add") +async def add_email_senders( + new_senders: list[str], + tenant_id: str = Depends(get_current_tenant_id) +): + return await email_sender_service.add_email_senders(tenant_id, new_senders) + +@router.delete("/email_senders/remove") +async def remove_email_senders( + emails_to_remove: list[str], + tenant_id: str = Depends(get_current_tenant_id) +): + return await email_sender_service.remove_email_senders(tenant_id, emails_to_remove) + +@router.delete("/email_senders/clear") +async def clear_email_senders(tenant_id: str = Depends(get_current_tenant_id)): + return await email_sender_service.clear_email_senders(tenant_id) + +@router.delete("/email_senders/delete") +async def delete_email_sender(tenant_id: str = Depends(get_current_tenant_id)): + return await email_sender_service.delete_email_sender(tenant_id) \ No newline at end of file diff --git a/apps/notification/webapi/routes/template_massege.py b/apps/notification/webapi/routes/template_massege.py new file mode 100644 index 0000000..bf4f3ba --- /dev/null +++ b/apps/notification/webapi/routes/template_massege.py @@ -0,0 +1,106 @@ +from fastapi import APIRouter, Depends, HTTPException +from backend.models.models import MessageTemplateDoc +from backend.services.template_message_service import TemplateMessageService +from common.token.token_manager import TokenManager +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials + +router = APIRouter() +template_service = TemplateMessageService() + +token_manager = TokenManager() +security = HTTPBearer() + +""" +# token payload example +{ + "user_id": "...", + "tenant_id": "...", + "role": "...", + "exp": ... +} +""" + +def get_current_tenant_id( + credentials: HTTPAuthorizationCredentials = Depends(security) +) -> str: + try: + payload = token_manager.decode_token(credentials.credentials) + tenant_id = payload.get("tenant_id") + if not tenant_id: + raise HTTPException(status_code=401, detail="No tenant_id in token") + return tenant_id + except Exception: + raise HTTPException(status_code=401, detail="Invalid token") + ... +def admin_only( + credentials: HTTPAuthorizationCredentials = Depends(security) +): + try: + payload = token_manager.decode_token(credentials.credentials) + role = payload.get("role") + if role != "admin": + raise HTTPException(status_code=403, detail="Not a platform admin") + except Exception: + raise HTTPException(status_code=401, detail="Invalid token") + +# interface for platform admin(management of global templates) +@router.post("/global_templates", dependencies=[Depends(admin_only)]) +async def create_global_template(template: MessageTemplateDoc): + return await template_service.create_global_template(template) + +@router.put("/global_templates/{id}", dependencies=[Depends(admin_only)]) +async def update_global_template(id: str, data: dict): + try: + return await template_service.update_global_template(id, data) + except PermissionError: + raise HTTPException(status_code=403, detail="Not a global template") + +@router.delete("/global_templates/{id}", dependencies=[Depends(admin_only)]) +async def delete_global_template(id: str): + try: + return await template_service.delete_global_template(id) + except PermissionError: + raise HTTPException(status_code=403, detail="Not a global template") + +@router.get("/global_templates") +async def list_global_templates(region: int): + return await template_service.list_global_templates(region) + + +# interface for tenant(management of tenant's templates) +@router.get("/templates") +async def list_tenant_templates(region: int, tenant_id: str = Depends(get_current_tenant_id)): + return await template_service.list_tenant_templates(tenant_id, region) + +@router.post("/templates/assign") +async def assign_templates(template_ids: list[str], region: int, tenant_id: str = Depends(get_current_tenant_id)): + return await template_service.assign_template_to_tenant(template_ids, region, tenant_id) + +@router.post("/templates") +async def create_template(template: MessageTemplateDoc, tenant_id: str = Depends(get_current_tenant_id)): + return await template_service.create_template(template, tenant_id) + +@router.put("/templates/{id}") +async def update_template(id: str, data: dict, tenant_id: str = Depends(get_current_tenant_id)): + try: + return await template_service.update_template(id, tenant_id, data) + except PermissionError: + raise HTTPException(status_code=403, detail="Forbidden") + +@router.delete("/templates/{id}") +async def delete_template(id: str, tenant_id: str = Depends(get_current_tenant_id)): + try: + return await template_service.delete_template(id, tenant_id) + except PermissionError: + raise HTTPException(status_code=403, detail="Forbidden") + +@router.post("/templates/{id}/render") +async def render_template(id: str, properties: dict, tenant_id: str = Depends(get_current_tenant_id)): + template = await template_service.get_template(id, tenant_id) + if not template: + raise HTTPException(status_code=404, detail="Template not found") + try: + subject, body = await template_service.render_template(template, properties) + return {"subject": subject, "body": body} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) \ No newline at end of file