refactor(architecture): implement 5-layer separation
for both template message and email senders, their workflow will follow: api->application->business->service->infra
This commit is contained in:
parent
9449f0e99b
commit
2f10275493
65
apps/notification/backend/application/email_sender_hub.py
Normal file
65
apps/notification/backend/application/email_sender_hub.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from typing import List
|
||||||
|
from backend.business.email_sender_manager import EmailSenderManager
|
||||||
|
|
||||||
|
|
||||||
|
class EmailSenderHub:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def get_email_senders(self, tenant_id: str):
|
||||||
|
"""get email senders for tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
email_sender_manager = EmailSenderManager()
|
||||||
|
return await email_sender_manager.get_email_senders(tenant_id)
|
||||||
|
|
||||||
|
async def set_email_senders(self, tenant_id: str, email_senders: List[str]):
|
||||||
|
"""set email senders for tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
if not email_senders or not isinstance(email_senders, list):
|
||||||
|
raise ValueError("email_senders must be a non-empty list")
|
||||||
|
|
||||||
|
email_sender_manager = EmailSenderManager()
|
||||||
|
return await email_sender_manager.set_email_senders(tenant_id, email_senders)
|
||||||
|
|
||||||
|
async def add_email_senders(self, tenant_id: str, new_senders: List[str]):
|
||||||
|
"""add email senders to tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
if not new_senders or not isinstance(new_senders, list):
|
||||||
|
raise ValueError("new_senders must be a non-empty list")
|
||||||
|
|
||||||
|
email_sender_manager = EmailSenderManager()
|
||||||
|
return await email_sender_manager.add_email_senders(tenant_id, new_senders)
|
||||||
|
|
||||||
|
async def remove_email_senders(self, tenant_id: str, emails_to_remove: List[str]):
|
||||||
|
"""remove email senders from tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
if not emails_to_remove or not isinstance(emails_to_remove, list):
|
||||||
|
raise ValueError("emails_to_remove must be a non-empty list")
|
||||||
|
|
||||||
|
email_sender_manager = EmailSenderManager()
|
||||||
|
return await email_sender_manager.remove_email_senders(tenant_id, emails_to_remove)
|
||||||
|
|
||||||
|
async def clear_email_senders(self, tenant_id: str):
|
||||||
|
"""clear email senders for tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
email_sender_manager = EmailSenderManager()
|
||||||
|
return await email_sender_manager.clear_email_senders(tenant_id)
|
||||||
|
|
||||||
|
async def delete_email_sender(self, tenant_id: str):
|
||||||
|
"""delete email sender for tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
email_sender_manager = EmailSenderManager()
|
||||||
|
return await email_sender_manager.delete_email_sender(tenant_id)
|
||||||
|
|
||||||
150
apps/notification/backend/application/template_message_hub.py
Normal file
150
apps/notification/backend/application/template_message_hub.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
from typing import Dict, List, Optional
|
||||||
|
from backend.business.template_message_manager import TemplateMessageManager
|
||||||
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateMessageHub:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def verify_tenant_access(self, template_id: str, tenant_id: str, region: int):
|
||||||
|
"""get template by tenant and template ids with region"""
|
||||||
|
if not template_id or not tenant_id:
|
||||||
|
raise ValueError("template_id and tenant_id are required")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.verify_tenant_access(template_id, tenant_id, region)
|
||||||
|
|
||||||
|
# ==================== global templates ====================
|
||||||
|
async def create_global_template(
|
||||||
|
self,
|
||||||
|
template_id: str,
|
||||||
|
region: int,
|
||||||
|
subject: str,
|
||||||
|
body: str,
|
||||||
|
is_active: bool = True
|
||||||
|
):
|
||||||
|
"""create global template"""
|
||||||
|
if not template_id or not subject or not body:
|
||||||
|
raise ValueError("template_id, subject, and body are required")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.create_global_template_from_data(
|
||||||
|
template_id=template_id,
|
||||||
|
region=region,
|
||||||
|
subject=subject,
|
||||||
|
body=body,
|
||||||
|
is_active=is_active
|
||||||
|
)
|
||||||
|
|
||||||
|
async def update_global_template(self, template_id: str, data: dict, region: int):
|
||||||
|
"""update global template"""
|
||||||
|
if not template_id:
|
||||||
|
raise ValueError("template_id is required")
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
raise ValueError("Update data cannot be empty")
|
||||||
|
|
||||||
|
allowed_fields = {"subject", "body", "is_active"}
|
||||||
|
invalid_fields = set(data.keys()) - allowed_fields
|
||||||
|
if invalid_fields:
|
||||||
|
raise ValueError(f"Invalid update fields: {invalid_fields}")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.update_global_template(template_id, data, region)
|
||||||
|
|
||||||
|
async def delete_global_template(self, template_id: str):
|
||||||
|
"""delete global template"""
|
||||||
|
if not template_id:
|
||||||
|
raise ValueError("template_id is required")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.delete_global_template(template_id)
|
||||||
|
|
||||||
|
async def list_global_templates(self, region: int):
|
||||||
|
"""list global templates"""
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.list_global_templates(region)
|
||||||
|
|
||||||
|
# ==================== TENANT templates ====================
|
||||||
|
|
||||||
|
async def list_tenant_templates(self, tenant_id: str, region: int):
|
||||||
|
"""list tenant templates"""
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.list_tenant_templates(tenant_id, region)
|
||||||
|
|
||||||
|
async def assign_templates_to_tenant(self, tenant_id: str, template_ids: List[str], region: int):
|
||||||
|
"""assign templates to tenant"""
|
||||||
|
if not template_ids:
|
||||||
|
raise ValueError("template_ids cannot be empty")
|
||||||
|
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.assign_templates_to_tenant(tenant_id, template_ids, region)
|
||||||
|
|
||||||
|
async def create_tenant_template(
|
||||||
|
self,
|
||||||
|
template_id: str,
|
||||||
|
region: int,
|
||||||
|
subject: str,
|
||||||
|
body: str,
|
||||||
|
tenant_id: str,
|
||||||
|
is_active: bool = True
|
||||||
|
):
|
||||||
|
"""create tenant template"""
|
||||||
|
if not template_id or not subject or not body or not tenant_id:
|
||||||
|
raise ValueError("template_id, subject, body, and tenant_id are required")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.create_tenant_template_from_data(
|
||||||
|
template_id=template_id,
|
||||||
|
region=region,
|
||||||
|
subject=subject,
|
||||||
|
body=body,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
is_active=is_active
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def update_tenant_template(self, tenant_id: str, template_id: str, data: dict, region: int):
|
||||||
|
"""update tenant template"""
|
||||||
|
if not template_id or not tenant_id:
|
||||||
|
raise ValueError("template_id and tenant_id are required")
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
raise ValueError("Update data cannot be empty")
|
||||||
|
|
||||||
|
allowed_fields = {"subject", "body", "is_active"}
|
||||||
|
invalid_fields = set(data.keys()) - allowed_fields
|
||||||
|
if invalid_fields:
|
||||||
|
raise ValueError(f"Invalid update fields: {invalid_fields}")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.update_tenant_template(tenant_id, template_id, data, region)
|
||||||
|
|
||||||
|
async def delete_tenant_template(self, tenant_id: str, template_id: str, region: int):
|
||||||
|
"""delete tenant template"""
|
||||||
|
if not template_id or not tenant_id:
|
||||||
|
raise ValueError("template_id and tenant_id are required")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.delete_tenant_template(tenant_id, template_id, region)
|
||||||
|
|
||||||
|
async def render_template(
|
||||||
|
self,
|
||||||
|
tenant_id: str,
|
||||||
|
template_id: str,
|
||||||
|
properties: dict,
|
||||||
|
region: int
|
||||||
|
):
|
||||||
|
"""render template"""
|
||||||
|
if not template_id or not tenant_id:
|
||||||
|
raise ValueError("template_id and tenant_id are required")
|
||||||
|
|
||||||
|
if not properties:
|
||||||
|
raise ValueError("properties cannot be empty")
|
||||||
|
|
||||||
|
template_message_manager = TemplateMessageManager()
|
||||||
|
return await template_message_manager.render_template(tenant_id, template_id, properties, region)
|
||||||
127
apps/notification/backend/business/email_sender_manager.py
Normal file
127
apps/notification/backend/business/email_sender_manager.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
from typing import List
|
||||||
|
from backend.services.email_sender_service import EmailSenderService
|
||||||
|
from backend.models.models import EmailSenderDoc
|
||||||
|
from common.log.module_logger import ModuleLogger
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
class EmailSenderManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.email_sender_service = EmailSenderService()
|
||||||
|
self.module_logger = ModuleLogger(sender_id="EmailSenderManager")
|
||||||
|
|
||||||
|
async def get_email_senders(self, tenant_id: str):
|
||||||
|
"""get email senders for tenant"""
|
||||||
|
email_senders = await self.email_sender_service.get_email_senders(tenant_id)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders retrieved",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"sender_count": len(email_senders)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return email_senders
|
||||||
|
|
||||||
|
async def set_email_senders(self, tenant_id: str, email_senders: List[str]):
|
||||||
|
"""set email senders for tenant"""
|
||||||
|
if not email_senders:
|
||||||
|
raise ValueError("Email senders list cannot be empty")
|
||||||
|
|
||||||
|
for email in email_senders:
|
||||||
|
if not self._is_valid_email(email):
|
||||||
|
raise ValueError(f"Invalid email format: {email}")
|
||||||
|
|
||||||
|
result = await self.email_sender_service.set_email_senders(tenant_id, email_senders)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders set",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"sender_count": len(email_senders)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def add_email_senders(self, tenant_id: str, new_senders: List[str]):
|
||||||
|
"""add email senders to tenant"""
|
||||||
|
if not new_senders:
|
||||||
|
raise ValueError("New senders list cannot be empty")
|
||||||
|
|
||||||
|
for email in new_senders:
|
||||||
|
if not self._is_valid_email(email):
|
||||||
|
raise ValueError(f"Invalid email format: {email}")
|
||||||
|
|
||||||
|
result = await self.email_sender_service.add_email_senders(tenant_id, new_senders)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders added",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"new_sender_count": len(new_senders),
|
||||||
|
"success": result.get("success", False)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def remove_email_senders(self, tenant_id: str, emails_to_remove: List[str]):
|
||||||
|
"""remove email senders from tenant"""
|
||||||
|
if not emails_to_remove:
|
||||||
|
raise ValueError("Emails to remove list cannot be empty")
|
||||||
|
|
||||||
|
result = await self.email_sender_service.remove_email_senders(tenant_id, emails_to_remove)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders removed",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"removed_count": len(emails_to_remove),
|
||||||
|
"success": result.get("success", False)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def clear_email_senders(self, tenant_id: str):
|
||||||
|
"""clear email senders for tenant"""
|
||||||
|
result = await self.email_sender_service.clear_email_senders(tenant_id)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders cleared",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"success": result.get("success", False)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def delete_email_sender(self, tenant_id: str):
|
||||||
|
"""delete email sender for tenant"""
|
||||||
|
result = await self.email_sender_service.delete_email_sender(tenant_id)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email sender configuration deleted",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"success": result.get("success", False)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _is_valid_email(self, email: str) -> bool:
|
||||||
|
"""validate email format"""
|
||||||
|
# TODO: add more complex email format validation if needed
|
||||||
|
import re
|
||||||
|
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
||||||
|
return re.match(pattern, email) is not None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
217
apps/notification/backend/business/template_message_manager.py
Normal file
217
apps/notification/backend/business/template_message_manager.py
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
from typing import Optional, List, Dict
|
||||||
|
from backend.services.template_message_service import TemplateMessageService
|
||||||
|
from backend.models.models import MessageTemplateDoc
|
||||||
|
from common.log.module_logger import ModuleLogger
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateMessageManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.template_message_service = TemplateMessageService()
|
||||||
|
self.module_logger = ModuleLogger(sender_id="TemplateMessageManager")
|
||||||
|
|
||||||
|
async def verify_tenant_access(self, template_id: str, tenant_id: str, region: int) -> Optional[MessageTemplateDoc]:
|
||||||
|
"""get template by tenant and template ids with region"""
|
||||||
|
if not template_id or not tenant_id:
|
||||||
|
raise ValueError("template_id and tenant_id are required")
|
||||||
|
|
||||||
|
template = await self.template_message_service.verify_tenant_access(template_id, tenant_id, region)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template retrieved by tenant and ID",
|
||||||
|
properties={"template_id": template_id, "tenant_id": tenant_id, "region": region}
|
||||||
|
)
|
||||||
|
|
||||||
|
return template
|
||||||
|
# ==================== global templates ====================
|
||||||
|
async def create_global_template_from_data(
|
||||||
|
self,
|
||||||
|
template_id: str,
|
||||||
|
region: int,
|
||||||
|
subject: str,
|
||||||
|
body: str,
|
||||||
|
is_active: bool = True
|
||||||
|
):
|
||||||
|
"""create global template from data"""
|
||||||
|
template = MessageTemplateDoc(
|
||||||
|
template_id=template_id,
|
||||||
|
tenant_id=None,
|
||||||
|
region=region,
|
||||||
|
subject=subject,
|
||||||
|
body=body,
|
||||||
|
is_active=is_active,
|
||||||
|
created_at=datetime.now(timezone.utc)
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await self.template_message_service.create_global_template(template)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template created",
|
||||||
|
properties={"template_id": template_id, "region": region}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def update_global_template(self, template_id: str, data: dict, region: int):
|
||||||
|
"""update global template"""
|
||||||
|
if not data.get("subject") and not data.get("body"):
|
||||||
|
raise ValueError("At least subject or body must be provided")
|
||||||
|
|
||||||
|
result = await self.template_message_service.update_global_template(template_id, data, region)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template updated",
|
||||||
|
properties={"template_id": template_id, "updated_fields": list(data.keys())}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def delete_global_template(self, template_id: str):
|
||||||
|
"""delete global template"""
|
||||||
|
|
||||||
|
result = await self.template_message_service.delete_global_template(template_id)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template deleted",
|
||||||
|
properties={"template_id": template_id}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def list_global_templates(self, region: int):
|
||||||
|
"""list global templates"""
|
||||||
|
templates = await self.template_message_service.list_global_templates(region)
|
||||||
|
|
||||||
|
formatted_templates = []
|
||||||
|
for template in templates:
|
||||||
|
formatted_templates.append({
|
||||||
|
"id": str(template.id),
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"subject": template.subject,
|
||||||
|
"region": template.region.value if hasattr(template.region, 'value') else template.region,
|
||||||
|
"is_active": template.is_active,
|
||||||
|
"created_at": template.created_at.isoformat() if template.created_at else None
|
||||||
|
})
|
||||||
|
|
||||||
|
return formatted_templates
|
||||||
|
|
||||||
|
# ==================== TENANT templates ====================
|
||||||
|
|
||||||
|
async def list_tenant_templates(self, tenant_id: str, region: int):
|
||||||
|
"""list tenant templates"""
|
||||||
|
|
||||||
|
templates = await self.template_message_service.list_tenant_templates(tenant_id, region)
|
||||||
|
|
||||||
|
formatted_templates = []
|
||||||
|
for template in templates:
|
||||||
|
formatted_templates.append({
|
||||||
|
"id": str(template.id),
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"subject": template.subject,
|
||||||
|
"region": template.region.value if hasattr(template.region, 'value') else template.region,
|
||||||
|
"is_active": template.is_active,
|
||||||
|
"created_at": template.created_at.isoformat() if template.created_at else None
|
||||||
|
})
|
||||||
|
|
||||||
|
return formatted_templates
|
||||||
|
|
||||||
|
async def assign_templates_to_tenant(self, tenant_id: str, template_ids: List[str], region: int):
|
||||||
|
"""assign templates to tenant"""
|
||||||
|
if not template_ids:
|
||||||
|
raise ValueError("Template IDs cannot be empty")
|
||||||
|
|
||||||
|
results = await self.template_message_service.assign_template_to_tenant(tenant_id, template_ids, region)
|
||||||
|
|
||||||
|
success_count = sum(1 for r in results if r.get("success"))
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Templates assigned to tenant",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"total_requested": len(template_ids),
|
||||||
|
"success_count": success_count
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
async def create_tenant_template_from_data(
|
||||||
|
self,
|
||||||
|
template_id: str,
|
||||||
|
region: int,
|
||||||
|
subject: str,
|
||||||
|
body: str,
|
||||||
|
tenant_id: str,
|
||||||
|
is_active: bool = True
|
||||||
|
):
|
||||||
|
"""create tenant template from data"""
|
||||||
|
template = MessageTemplateDoc(
|
||||||
|
template_id=template_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
region=region,
|
||||||
|
subject=subject,
|
||||||
|
body=body,
|
||||||
|
is_active=is_active,
|
||||||
|
created_at=datetime.now(timezone.utc)
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await self.template_message_service.create_tenant_template(tenant_id, template)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template created",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def update_tenant_template(self, tenant_id: str, template_id: str, data: dict, region: int):
|
||||||
|
"""update tenant template"""
|
||||||
|
if not data.get("subject") and not data.get("body"):
|
||||||
|
raise ValueError("At least subject or body must be provided")
|
||||||
|
|
||||||
|
result = await self.template_message_service.update_tenant_template(tenant_id, template_id, data, region)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template updated",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"updated_fields": list(data.keys())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
async def delete_tenant_template(self, tenant_id: str, template_id: str, region: int):
|
||||||
|
"""delete tenant template"""
|
||||||
|
result = await self.template_message_service.delete_tenant_template(tenant_id, template_id, region)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template deleted",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def render_template(self, tenant_id: str, template_id: str, properties: dict, region: int):
|
||||||
|
"""render template"""
|
||||||
|
result = await self.template_message_service.render_template(tenant_id, template_id, properties, region)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template rendered",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"properties_count": len(properties)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
176
apps/notification/backend/infra/email_sender_handler.py
Normal file
176
apps/notification/backend/infra/email_sender_handler.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
from backend.models.models import EmailSenderDoc
|
||||||
|
from common.log.module_logger import ModuleLogger
|
||||||
|
|
||||||
|
|
||||||
|
class EmailSenderHandler:
|
||||||
|
def __init__(self):
|
||||||
|
self.module_logger = ModuleLogger(sender_id="EmailSenderHandler")
|
||||||
|
|
||||||
|
async def get_email_senders(self, tenant_id: str) -> List[str]:
|
||||||
|
"""get email senders for tenant"""
|
||||||
|
try:
|
||||||
|
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
||||||
|
return doc.email_senders if doc else []
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to get email senders",
|
||||||
|
properties={"tenant_id": tenant_id, "error": str(e)}
|
||||||
|
)
|
||||||
|
return []
|
||||||
|
|
||||||
|
async def set_email_senders(self, tenant_id: str, email_senders: List[str]):
|
||||||
|
"""set email senders for tenant"""
|
||||||
|
try:
|
||||||
|
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id})
|
||||||
|
if doc:
|
||||||
|
await doc.set({"email_senders": email_senders})
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders set in database",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"sender_count": len(email_senders)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True, "email_senders": email_senders}
|
||||||
|
else:
|
||||||
|
doc = EmailSenderDoc(tenant_id=tenant_id, email_senders=email_senders)
|
||||||
|
await doc.create()
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email sender doc created with senders",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"sender_count": len(email_senders)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True, "email_senders": doc.email_senders}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to set email senders",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def add_email_senders(self, tenant_id: str, new_senders: List[str]):
|
||||||
|
"""add email senders to tenant"""
|
||||||
|
try:
|
||||||
|
if not new_senders or not isinstance(new_senders, list):
|
||||||
|
return {"success": False, "msg": "No sender provided"}
|
||||||
|
|
||||||
|
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
||||||
|
if doc:
|
||||||
|
original_set = set(doc.email_senders)
|
||||||
|
new_set = set(new_senders)
|
||||||
|
to_add = new_set - original_set
|
||||||
|
if not to_add:
|
||||||
|
return {"success": False, "msg": "All senders already exist"}
|
||||||
|
updated_list = list(original_set | new_set)
|
||||||
|
await doc.set({"email_senders": updated_list})
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders added to database",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"added_count": len(to_add),
|
||||||
|
"total_count": len(updated_list)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True, "email_senders": updated_list}
|
||||||
|
else:
|
||||||
|
doc = EmailSenderDoc(tenant_id=tenant_id, email_senders=new_senders)
|
||||||
|
await doc.create()
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email sender doc created with new senders",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"sender_count": len(new_senders)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True, "email_senders": doc.email_senders}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to add email senders",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def remove_email_senders(self, tenant_id: str, emails_to_remove: List[str]):
|
||||||
|
"""remove email senders from tenant"""
|
||||||
|
try:
|
||||||
|
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
||||||
|
if not doc or not doc.email_senders:
|
||||||
|
return {"success": False, "msg": "No sender found"}
|
||||||
|
|
||||||
|
original_count = len(doc.email_senders)
|
||||||
|
doc.email_senders = [s for s in doc.email_senders if s not in emails_to_remove]
|
||||||
|
if len(doc.email_senders) == original_count:
|
||||||
|
return {"success": False, "msg": "No sender matched for removal"}
|
||||||
|
|
||||||
|
await doc.set({"email_senders": doc.email_senders})
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders removed from database",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"removed_count": original_count - len(doc.email_senders),
|
||||||
|
"remaining_count": len(doc.email_senders)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True, "remaining": doc.email_senders}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to remove email senders",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def clear_email_senders(self, tenant_id: str):
|
||||||
|
"""clear up email senders for tenant"""
|
||||||
|
try:
|
||||||
|
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
||||||
|
if doc:
|
||||||
|
await doc.set({"email_senders": []})
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email senders cleared from database",
|
||||||
|
properties={"tenant_id": tenant_id}
|
||||||
|
)
|
||||||
|
return {"success": True}
|
||||||
|
return {"success": False, "msg": "No sender config found"}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to clear email senders",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def delete_email_sender(self, tenant_id: str):
|
||||||
|
"""delete email sender for tenant"""
|
||||||
|
try:
|
||||||
|
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id})
|
||||||
|
if doc:
|
||||||
|
await doc.delete()
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Email sender configuration deleted from database",
|
||||||
|
properties={"tenant_id": tenant_id}
|
||||||
|
)
|
||||||
|
return {"success": True}
|
||||||
|
return {"success": False, "msg": "No sender config found"}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to delete email sender",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
396
apps/notification/backend/infra/template_message_handler.py
Normal file
396
apps/notification/backend/infra/template_message_handler.py
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
from backend.models.models import MessageTemplateDoc
|
||||||
|
from common.log.module_logger import ModuleLogger
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import List, Optional
|
||||||
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateMessageHandler:
|
||||||
|
def __init__(self):
|
||||||
|
self.module_logger = ModuleLogger(sender_id="TemplateMessageHandler")
|
||||||
|
async def verify_tenant_access(self, template_id: str, tenant_id: str, region: int) -> Optional[MessageTemplateDoc]:
|
||||||
|
"""get template by tenant and template ids with region"""
|
||||||
|
try:
|
||||||
|
template = await MessageTemplateDoc.find_one({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
})
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template retrieved from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return template
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to get tenant template from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== global templates ====================
|
||||||
|
async def create_global_template(self, template: MessageTemplateDoc) -> MessageTemplateDoc:
|
||||||
|
"""create global template"""
|
||||||
|
try:
|
||||||
|
await template.create()
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template created in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"tenant_id": template.tenant_id,
|
||||||
|
"region": template.region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return template
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to create template in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def update_global_template(self, template_id: str, data: dict, region: int) -> dict:
|
||||||
|
"""update global template"""
|
||||||
|
try:
|
||||||
|
template = await MessageTemplateDoc.find_one({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": None,
|
||||||
|
"region": region
|
||||||
|
})
|
||||||
|
|
||||||
|
if not template:
|
||||||
|
raise ValueError(f"Template not found for template_id: {template_id}, region: {data.get('region')}")
|
||||||
|
|
||||||
|
data["updated_at"] = datetime.utcnow()
|
||||||
|
|
||||||
|
# remove fields that are not allowed to be updated
|
||||||
|
if "id" in data:
|
||||||
|
del data["id"]
|
||||||
|
if "template_id" in data:
|
||||||
|
del data["template_id"]
|
||||||
|
if "tenant_id" in data:
|
||||||
|
del data["tenant_id"]
|
||||||
|
if "region" in data:
|
||||||
|
del data["region"]
|
||||||
|
|
||||||
|
await template.set(data)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template updated in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": data.get("tenant_id"),
|
||||||
|
"region": data.get("region"),
|
||||||
|
"updated_fields": list(data.keys())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to update template in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": data.get("region"),
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def delete_global_template(self, template_id: str) -> dict:
|
||||||
|
"""delete global template"""
|
||||||
|
try:
|
||||||
|
# find all global templates named as template_id
|
||||||
|
templates = await MessageTemplateDoc.find({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": None
|
||||||
|
}).to_list()
|
||||||
|
|
||||||
|
if not templates:
|
||||||
|
raise ValueError("Global template not found")
|
||||||
|
|
||||||
|
# delete all found templates
|
||||||
|
deleted_count = 0
|
||||||
|
for template in templates:
|
||||||
|
await template.delete()
|
||||||
|
deleted_count += 1
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global templates deleted from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"deleted_count": deleted_count,
|
||||||
|
"total_found": len(templates)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True, "deleted_count": deleted_count}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to delete global templates from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def list_global_templates(self, region: int) -> List[MessageTemplateDoc]:
|
||||||
|
"""list global templates"""
|
||||||
|
try:
|
||||||
|
templates = await MessageTemplateDoc.find({
|
||||||
|
"tenant_id": None,
|
||||||
|
"region": region
|
||||||
|
}).to_list()
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global templates retrieved from database",
|
||||||
|
properties={"region": region, "count": len(templates)}
|
||||||
|
)
|
||||||
|
return templates
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to get global templates from database",
|
||||||
|
properties={
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def find_global_template(self, template_id: str, region: int) -> Optional[MessageTemplateDoc]:
|
||||||
|
"""find global template"""
|
||||||
|
try:
|
||||||
|
template = await MessageTemplateDoc.find_one({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": None,
|
||||||
|
"region": region
|
||||||
|
})
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template retrieved from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return template
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to get global template from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
# ==================== tenant templates ====================
|
||||||
|
async def list_tenant_templates(self, tenant_id: str, region: int) -> List[MessageTemplateDoc]:
|
||||||
|
"""list tenant templates"""
|
||||||
|
try:
|
||||||
|
templates = await MessageTemplateDoc.find({
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
}).to_list()
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant templates retrieved from database",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"count": len(templates)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return templates
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to get tenant templates from database",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def find_tenant_template(self, tenant_id: str, template_id: str, region: int) -> Optional[MessageTemplateDoc]:
|
||||||
|
"""find tenant template"""
|
||||||
|
try:
|
||||||
|
template = await MessageTemplateDoc.find_one({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
})
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template retrieved from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return template
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to get tenant template from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def create_tenant_template(self, tenant_id: str, template: MessageTemplateDoc) -> MessageTemplateDoc:
|
||||||
|
"""create tenant template"""
|
||||||
|
try:
|
||||||
|
await template.create()
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template created in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"tenant_id": template.tenant_id,
|
||||||
|
"region": template.region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return template
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to create template in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def update_tenant_template(self, tenant_id: str, template_id: str, data: dict, region: int) -> dict:
|
||||||
|
"""update template"""
|
||||||
|
try:
|
||||||
|
template = await MessageTemplateDoc.find_one({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
})
|
||||||
|
|
||||||
|
if not template:
|
||||||
|
raise ValueError(f"Template not found for template_id: {template_id}, tenant_id: {data.get('tenant_id')}, region: {data.get('region')}")
|
||||||
|
|
||||||
|
data["updated_at"] = datetime.utcnow()
|
||||||
|
|
||||||
|
# remove fields that are not allowed to be updated
|
||||||
|
if "id" in data:
|
||||||
|
del data["id"]
|
||||||
|
if "template_id" in data:
|
||||||
|
del data["template_id"]
|
||||||
|
if "tenant_id" in data:
|
||||||
|
del data["tenant_id"]
|
||||||
|
if "region" in data:
|
||||||
|
del data["region"]
|
||||||
|
|
||||||
|
await template.set(data)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template updated in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": data.get("tenant_id"),
|
||||||
|
"region": data.get("region"),
|
||||||
|
"updated_fields": list(data.keys())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"success": True}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to update template in database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": data.get("tenant_id"),
|
||||||
|
"region": data.get("region"),
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def delete_tenant_template(self, tenant_id: str, template_id: str, region: int) -> dict:
|
||||||
|
"""delete tenant template"""
|
||||||
|
try:
|
||||||
|
template = await MessageTemplateDoc.find_one({
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
})
|
||||||
|
if not template:
|
||||||
|
raise ValueError("Template not found")
|
||||||
|
|
||||||
|
await template.delete()
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template deleted from database",
|
||||||
|
properties={"template_id": template_id}
|
||||||
|
)
|
||||||
|
return {"success": True}
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to delete template from database",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def render_template(self, template: MessageTemplateDoc, properties: dict) -> dict:
|
||||||
|
"""render template"""
|
||||||
|
try:
|
||||||
|
subject = template.subject.format(**properties)
|
||||||
|
body = template.body.format(**properties)
|
||||||
|
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template rendered",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"tenant_id": template.tenant_id,
|
||||||
|
"region": template.region,
|
||||||
|
"properties_count": len(properties)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"subject": subject, "body": body}
|
||||||
|
except KeyError as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Missing template parameter",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"tenant_id": template.tenant_id,
|
||||||
|
"region": template.region,
|
||||||
|
"missing_parameter": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise ValueError(f"Missing template parameter: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Template rendering error",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"tenant_id": template.tenant_id,
|
||||||
|
"region": template.region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise ValueError(f"Template rendering error: {str(e)}")
|
||||||
@ -1,66 +1,59 @@
|
|||||||
|
from typing import List
|
||||||
|
from backend.infra.email_sender_handler import EmailSenderHandler
|
||||||
from backend.models.models import EmailSenderDoc
|
from backend.models.models import EmailSenderDoc
|
||||||
|
|
||||||
|
|
||||||
class EmailSenderService:
|
class EmailSenderService:
|
||||||
# get the email sender list for the tenant
|
def __init__(self):
|
||||||
async def get_email_sender(self, tenant_id: str):
|
self.email_sender_handler = EmailSenderHandler()
|
||||||
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
|
||||||
return doc.email_senders if doc else []
|
|
||||||
|
|
||||||
# set the email sender list for the tenant
|
async def get_email_senders(self, tenant_id: str) -> List[str]:
|
||||||
async def set_email_sender(self, tenant_id: str, email_senders: list):
|
"""get email senders for tenant"""
|
||||||
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id})
|
if not tenant_id:
|
||||||
if doc:
|
raise ValueError("tenant_id is required")
|
||||||
await doc.set({"email_senders": email_senders})
|
|
||||||
return {"success": True, "email_senders": doc.email_senders}
|
return await self.email_sender_handler.get_email_senders(tenant_id)
|
||||||
else:
|
|
||||||
doc = EmailSenderDoc(tenant_id=tenant_id, email_senders=email_senders)
|
async def set_email_senders(self, tenant_id: str, email_senders: List[str]):
|
||||||
await doc.create()
|
"""set email senders for tenant"""
|
||||||
return {"success": True, "email_senders": doc.email_senders}
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
|
if not email_senders or not isinstance(email_senders, list):
|
||||||
|
raise ValueError("email_senders must be a non-empty list")
|
||||||
|
|
||||||
|
return await self.email_sender_handler.set_email_senders(tenant_id, email_senders)
|
||||||
|
|
||||||
|
async def add_email_senders(self, tenant_id: str, new_senders: List[str]):
|
||||||
|
"""add email senders to tenant"""
|
||||||
|
if not tenant_id:
|
||||||
|
raise ValueError("tenant_id is required")
|
||||||
|
|
||||||
# add new email senders to the tenant
|
|
||||||
async def add_email_senders(self, tenant_id: str, new_senders: list):
|
|
||||||
if not new_senders or not isinstance(new_senders, list):
|
if not new_senders or not isinstance(new_senders, list):
|
||||||
return {"success": False, "msg": "No sender provided"}
|
return {"success": False, "msg": "No sender provided"}
|
||||||
|
|
||||||
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
return await self.email_sender_handler.add_email_senders(tenant_id, new_senders)
|
||||||
if doc:
|
|
||||||
original_set = set(doc.email_senders)
|
|
||||||
new_set = set(new_senders)
|
|
||||||
to_add = new_set - original_set
|
|
||||||
if not to_add:
|
|
||||||
return {"success": False, "msg": "All senders already exist"}
|
|
||||||
updated_list = list(original_set | new_set)
|
|
||||||
await doc.set({"email_senders": updated_list})
|
|
||||||
return {"success": True, "email_senders": updated_list}
|
|
||||||
else:
|
|
||||||
result = await self.set_email_sender(tenant_id, new_senders)
|
|
||||||
return result
|
|
||||||
|
|
||||||
# remove the email sender from the list
|
async def remove_email_senders(self, tenant_id: str, emails_to_remove: List[str]):
|
||||||
async def remove_email_senders(self, tenant_id: str, emails_to_remove: list):
|
"""remove email senders from tenant"""
|
||||||
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
if not tenant_id:
|
||||||
if not doc or not doc.email_senders:
|
raise ValueError("tenant_id is required")
|
||||||
return {"success": False, "msg": "No sender found"}
|
|
||||||
|
|
||||||
original_count = len(doc.email_senders)
|
if not emails_to_remove or not isinstance(emails_to_remove, list):
|
||||||
doc.email_senders = [s for s in doc.email_senders if s not in emails_to_remove]
|
raise ValueError("emails_to_remove must be a non-empty list")
|
||||||
if len(doc.email_senders) == original_count:
|
|
||||||
return {"success": False, "msg": "No sender matched for removal"}
|
return await self.email_sender_handler.remove_email_senders(tenant_id, emails_to_remove)
|
||||||
await doc.set({"email_senders": doc.email_senders})
|
|
||||||
return {"success": True, "remaining": doc.email_senders}
|
|
||||||
|
|
||||||
# clear the email sender list for the tenant
|
|
||||||
async def clear_email_senders(self, tenant_id: str):
|
async def clear_email_senders(self, tenant_id: str):
|
||||||
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id, "is_active": True})
|
"""clear email senders for tenant"""
|
||||||
if doc:
|
if not tenant_id:
|
||||||
await doc.set({"email_senders": []})
|
raise ValueError("tenant_id is required")
|
||||||
return {"success": True}
|
|
||||||
return {"success": False, "msg": "No sender config found"}
|
return await self.email_sender_handler.clear_email_senders(tenant_id)
|
||||||
|
|
||||||
# delete the email sender list for the tenant
|
|
||||||
async def delete_email_sender(self, tenant_id: str):
|
async def delete_email_sender(self, tenant_id: str):
|
||||||
doc = await EmailSenderDoc.find_one({"tenant_id": tenant_id})
|
"""delete email sender for tenant"""
|
||||||
if doc:
|
if not tenant_id:
|
||||||
await doc.delete()
|
raise ValueError("tenant_id is required")
|
||||||
return {"success": True}
|
|
||||||
return {"success": False, "msg": "No sender config found"}
|
return await self.email_sender_handler.delete_email_sender(tenant_id)
|
||||||
|
|||||||
@ -1,112 +1,363 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
from backend.infra.template_message_handler import TemplateMessageHandler
|
||||||
from backend.models.models import MessageTemplateDoc
|
from backend.models.models import MessageTemplateDoc
|
||||||
|
from common.log.module_logger import ModuleLogger
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
class TemplateMessageService:
|
class TemplateMessageService:
|
||||||
## operations for global templates, conducted by platform admin
|
def __init__(self):
|
||||||
# Create global template operated by platform admin
|
self.template_message_handler = TemplateMessageHandler()
|
||||||
async def create_global_template(self, template: MessageTemplateDoc):
|
self.module_logger = ModuleLogger(sender_id="TemplateMessageService")
|
||||||
template.tenant_id = None
|
|
||||||
return await template.create()
|
|
||||||
|
|
||||||
# Update global template operated by platform admin
|
async def verify_tenant_access(self, template_id: str, tenant_id: str, region: int):
|
||||||
async def update_global_template(self, id: str, data: dict):
|
"""verify tenant access"""
|
||||||
template = await MessageTemplateDoc.get(id)
|
|
||||||
if not template or template.tenant_id is not None:
|
|
||||||
raise PermissionError("Not a global template")
|
|
||||||
await template.set(data)
|
|
||||||
return {"success": True}
|
|
||||||
|
|
||||||
# Delete global template operated by platform admin
|
|
||||||
async def delete_global_template(self, id: str):
|
|
||||||
template = await MessageTemplateDoc.get(id)
|
|
||||||
if not template or template.tenant_id is not None:
|
|
||||||
raise PermissionError("Not a global template")
|
|
||||||
await template.delete()
|
|
||||||
return {"success": True}
|
|
||||||
|
|
||||||
|
|
||||||
# Just for Facilitating later addition of permissions, logging, and exception handling, etc.
|
|
||||||
async def get_template(self, template_id, tenant_id, region):
|
|
||||||
return await MessageTemplateDoc.find_one({
|
|
||||||
"template_id": template_id,
|
|
||||||
"tenant_id": tenant_id,
|
|
||||||
"region": region,
|
|
||||||
"is_active": True
|
|
||||||
})
|
|
||||||
|
|
||||||
# Query global template
|
|
||||||
async def list_global_templates(self, region):
|
|
||||||
return await MessageTemplateDoc.find({"tenant_id": None, "region": region}).to_list()
|
|
||||||
|
|
||||||
# Look up templates belonging to the tenant
|
|
||||||
async def list_tenant_templates(self, tenant_id, region):
|
|
||||||
return await MessageTemplateDoc.find({"tenant_id": tenant_id, "region": region}).to_list()
|
|
||||||
|
|
||||||
# Tenant selects template(s) (copies one or more global templates as their own)
|
|
||||||
async def assign_template_to_tenant(self, template_ids: list, region, tenant_id: str):
|
|
||||||
results = []
|
|
||||||
# assign a global template to a tenant
|
|
||||||
for template_id in template_ids:
|
|
||||||
# lookup global template
|
|
||||||
global_template = await MessageTemplateDoc.find_one({
|
|
||||||
"template_id": template_id,
|
|
||||||
"tenant_id": None,
|
|
||||||
"region": region
|
|
||||||
})
|
|
||||||
if not global_template:
|
|
||||||
results.append({"template_id": template_id, "success": False, "msg": "Template not found"})
|
|
||||||
continue
|
|
||||||
|
|
||||||
# check if the tenant already has the template
|
|
||||||
existing = await MessageTemplateDoc.find_one({
|
|
||||||
"template_id": template_id,
|
|
||||||
"tenant_id": tenant_id,
|
|
||||||
"region": region
|
|
||||||
})
|
|
||||||
if existing:
|
|
||||||
results.append({"template_id": template_id, "success": False, "msg": "Template already assigned"})
|
|
||||||
continue
|
|
||||||
|
|
||||||
# copy the template
|
|
||||||
new_template = MessageTemplateDoc(
|
|
||||||
template_id=global_template.template_id,
|
|
||||||
tenant_id=tenant_id,
|
|
||||||
region=global_template.region,
|
|
||||||
subject=global_template.subject,
|
|
||||||
body=global_template.body,
|
|
||||||
created_at=datetime.utcnow()
|
|
||||||
)
|
|
||||||
await new_template.create()
|
|
||||||
results.append({"template_id": template_id, "success": True, "template_db_id": str(new_template.id)})
|
|
||||||
return results
|
|
||||||
|
|
||||||
# Custom templates by tenant
|
|
||||||
async def create_template(self, template:MessageTemplateDoc, tenant_id: str):
|
|
||||||
template.tenant_id = tenant_id
|
|
||||||
return await template.create()
|
|
||||||
|
|
||||||
# Update template under certain tenant
|
|
||||||
async def update_template(self, id: str, tenant_id: str, data: dict):
|
|
||||||
template = await MessageTemplateDoc.get(id)
|
|
||||||
if not template or template.tenant_id != tenant_id:
|
|
||||||
raise PermissionError("Forbidden")
|
|
||||||
await template.set(data)
|
|
||||||
return {"success": True}
|
|
||||||
|
|
||||||
# Delete template under certain tenant
|
|
||||||
async def delete_template(self, id: str, tenant_id: str):
|
|
||||||
template = await MessageTemplateDoc.get(id)
|
|
||||||
if not template or template.tenant_id != tenant_id:
|
|
||||||
raise PermissionError("Forbidden")
|
|
||||||
await template.delete()
|
|
||||||
return {"success": True}
|
|
||||||
|
|
||||||
# Render template
|
|
||||||
async def render_template(self, template: MessageTemplateDoc, properties: dict):
|
|
||||||
# Use properties to replace the placeholders in the template, and return the rendered body
|
|
||||||
try:
|
try:
|
||||||
subject = template.subject.format(**properties)
|
result = await self.template_message_handler.verify_tenant_access(template_id, tenant_id, region)
|
||||||
body = template.body.format(**properties)
|
await self.module_logger.log_info(
|
||||||
except KeyError as e:
|
info="Tenant access verified",
|
||||||
raise ValueError(f"Missing template parameter: {e}")
|
properties={
|
||||||
return subject, body
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to verify tenant access",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
# ==================== global templates ====================
|
||||||
|
async def create_global_template(self, template: MessageTemplateDoc):
|
||||||
|
"""create global template"""
|
||||||
|
try:
|
||||||
|
# Check if template already exists with same template_id and region
|
||||||
|
existing_template = await self.template_message_handler.find_global_template(template.template_id, template.region)
|
||||||
|
if existing_template:
|
||||||
|
raise ValueError(f"Global template with template_id '{template.template_id}' and region '{template.region}' already exists")
|
||||||
|
|
||||||
|
result = await self.template_message_handler.create_global_template(template)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template created",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"region": template.region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except ValueError as e:
|
||||||
|
# Re-raise ValueError for duplicate template
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to create global template",
|
||||||
|
properties={
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def update_global_template(self, template_id: str, data: dict, region: int):
|
||||||
|
"""update global template"""
|
||||||
|
try:
|
||||||
|
# check if template exists
|
||||||
|
template = await self.template_message_handler.find_global_template(template_id, region)
|
||||||
|
if not template:
|
||||||
|
raise ValueError(f"Global template not found for template_id: {template_id}, region: {region}")
|
||||||
|
|
||||||
|
result = await self.template_message_handler.update_global_template(template_id, data, region)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template updated",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"updated_fields": list(data.keys())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to update global template",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def delete_global_template(self, template_id: str):
|
||||||
|
"""delete global template"""
|
||||||
|
try:
|
||||||
|
|
||||||
|
result = await self.template_message_handler.delete_global_template(template_id)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global template deleted",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"deleted_count": result.get("deleted_count", 0) if result else 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to delete global template",
|
||||||
|
properties={
|
||||||
|
"template_id": template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def list_global_templates(self, region: int):
|
||||||
|
"""list global templates"""
|
||||||
|
try:
|
||||||
|
result = await self.template_message_handler.list_global_templates(region)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Global templates listed",
|
||||||
|
properties={
|
||||||
|
"region": region,
|
||||||
|
"count": len(result) if result else 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to list global templates",
|
||||||
|
properties={
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
# ==================== TENANT templates ====================
|
||||||
|
async def list_tenant_templates(self, tenant_id: str, region: int):
|
||||||
|
"""list tenant templates"""
|
||||||
|
try:
|
||||||
|
result = await self.template_message_handler.list_tenant_templates(tenant_id, region)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant templates listed",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"count": len(result) if result else 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to list tenant templates",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def assign_template_to_tenant(self, tenant_id: str, template_ids: List[str], region: int):
|
||||||
|
"""assign templates to tenant"""
|
||||||
|
try:
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for template_id in template_ids:
|
||||||
|
try:
|
||||||
|
global_template = await self.template_message_handler.find_global_template(template_id, region)
|
||||||
|
if not global_template:
|
||||||
|
results.append({
|
||||||
|
"template_id": template_id,
|
||||||
|
"success": False,
|
||||||
|
"msg": "Global template not found"
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
|
||||||
|
# check if tenant already has this template
|
||||||
|
existing = await self.template_message_handler.find_tenant_template(tenant_id, template_id, region)
|
||||||
|
if existing:
|
||||||
|
results.append({
|
||||||
|
"template_id": template_id,
|
||||||
|
"success": False,
|
||||||
|
"msg": "Template already assigned to tenant"
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
|
||||||
|
# copy template to tenant, use unique template_id
|
||||||
|
tenant_template_id = f"{global_template.template_id}_tenant_{tenant_id}"
|
||||||
|
new_template = MessageTemplateDoc(
|
||||||
|
template_id=tenant_template_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
region=global_template.region,
|
||||||
|
subject=global_template.subject,
|
||||||
|
body=global_template.body,
|
||||||
|
is_active=global_template.is_active,
|
||||||
|
created_at=datetime.utcnow()
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.template_message_handler.create_tenant_template(tenant_id, new_template)
|
||||||
|
results.append({
|
||||||
|
"template_id": template_id,
|
||||||
|
"success": True,
|
||||||
|
"template_db_id": str(new_template.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
results.append({
|
||||||
|
"template_id": template_id,
|
||||||
|
"success": False,
|
||||||
|
"msg": f"Error: {str(e)}"
|
||||||
|
})
|
||||||
|
|
||||||
|
success_count = sum(1 for r in results if r.get("success"))
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Templates assigned to tenant",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"total_requested": len(template_ids),
|
||||||
|
"success_count": success_count
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return results
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to assign templates to tenant",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def create_tenant_template(self, tenant_id: str, template: MessageTemplateDoc):
|
||||||
|
"""create tenant template"""
|
||||||
|
try:
|
||||||
|
template.tenant_id = tenant_id
|
||||||
|
|
||||||
|
# Check if template already exists with same template_id, tenant_id and region
|
||||||
|
existing_template = await self.template_message_handler.find_tenant_template(tenant_id, template.template_id, template.region)
|
||||||
|
if existing_template:
|
||||||
|
raise ValueError(f"Tenant template with template_id '{template.template_id}', tenant_id '{tenant_id}' and region '{template.region}' already exists")
|
||||||
|
|
||||||
|
result = await self.template_message_handler.create_tenant_template(tenant_id, template)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template created",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"region": template.region
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except ValueError as e:
|
||||||
|
# Re-raise ValueError for duplicate template
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to create tenant template",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template.template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def update_tenant_template(self, tenant_id: str, template_id: str, data: dict, region: int):
|
||||||
|
"""update tenant template"""
|
||||||
|
try:
|
||||||
|
template = await self.template_message_handler.find_tenant_template(tenant_id, template_id, region)
|
||||||
|
if not template:
|
||||||
|
raise ValueError("Template not found")
|
||||||
|
|
||||||
|
result = await self.template_message_handler.update_tenant_template(tenant_id, template_id, data, region)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template updated",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"updated_fields": list(data.keys())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to update tenant template",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def delete_tenant_template(self, tenant_id: str, template_id: str, region: int):
|
||||||
|
"""delete tenant template"""
|
||||||
|
try:
|
||||||
|
template = await self.template_message_handler.find_tenant_template(tenant_id, template_id, region)
|
||||||
|
if not template:
|
||||||
|
raise ValueError("Template not found")
|
||||||
|
|
||||||
|
result = await self.template_message_handler.delete_tenant_template(tenant_id, template_id, region)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Tenant template deleted",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to delete tenant template",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
async def render_template(self, tenant_id: str, template_id: str, properties: dict, region: int):
|
||||||
|
"""render template"""
|
||||||
|
try:
|
||||||
|
template = await self.template_message_handler.find_tenant_template(tenant_id, template_id, region)
|
||||||
|
if not template:
|
||||||
|
raise ValueError("Template not found")
|
||||||
|
|
||||||
|
result = await self.template_message_handler.render_template(template, properties)
|
||||||
|
await self.module_logger.log_info(
|
||||||
|
info="Template rendered successfully",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"properties_count": len(properties)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
await self.module_logger.log_error(
|
||||||
|
error="Failed to render template",
|
||||||
|
properties={
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"template_id": template_id,
|
||||||
|
"region": region,
|
||||||
|
"error": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user