diff --git a/apps/notification/backend/business/template_message_manager.py b/apps/notification/backend/business/template_message_manager.py
index 017de66..d002b24 100644
--- a/apps/notification/backend/business/template_message_manager.py
+++ b/apps/notification/backend/business/template_message_manager.py
@@ -44,10 +44,9 @@ class TemplateMessageManager:
)
result = await self.template_message_service.create_global_template(template)
- action = "skipped" if hasattr(result, "_is_existing") and result._is_existing else "created"
await self.module_logger.log_info(
- info=f"Global template {action}",
- properties={"template_id": template_id, "region": region, "action": action}
+ info="Global template created",
+ properties={"template_id": template_id, "region": region}
)
return result
@@ -156,15 +155,12 @@ class TemplateMessageManager:
)
result = await self.template_message_service.create_tenant_template(tenant_id, template)
-
- action = "skipped" if hasattr(result, "_is_existing") and result._is_existing else "created"
await self.module_logger.log_info(
- info=f"Tenant template {action}",
+ info="Tenant template created",
properties={
"tenant_id": tenant_id,
"template_id": template_id,
- "region": region,
- "action": action
+ "region": region
}
)
diff --git a/apps/notification/backend/infra/template_message_handler.py b/apps/notification/backend/infra/template_message_handler.py
index 44fa4d3..a951374 100644
--- a/apps/notification/backend/infra/template_message_handler.py
+++ b/apps/notification/backend/infra/template_message_handler.py
@@ -9,6 +9,15 @@ from common.constants.region import UserRegion
class TemplateMessageHandler:
def __init__(self):
self.module_logger = ModuleLogger(sender_id="TemplateMessageHandler")
+
+ @staticmethod
+ def _normalize_placeholders(text: str) -> str:
+ """Convert Handlebars-like placeholders {{name}} into Python str.format style {name}.
+ Does not touch CSS double braces like `.class {{ ... }}` because those won't match \w+.
+ """
+ if not isinstance(text, str):
+ return text
+ return re.sub(r"\{\{(\w+)\}\}", r"{\1}", text)
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:
@@ -52,21 +61,16 @@ class TemplateMessageHandler:
})
if existing_template:
- # if template already exists, skip creation
await self.module_logger.log_info(
- info="Global template already exists, skipping creation",
+ info="Global template already exists",
properties={
"template_id": template.template_id,
"tenant_id": template.tenant_id,
"region": template.region
}
)
-
- # mark as existing template
- existing_template._is_existing = True
- return existing_template
+ raise ValueError("Global template already exists")
else:
- # if template does not exist, create new template
await template.create()
await self.module_logger.log_info(
info="Template created in database",
@@ -76,8 +80,6 @@ class TemplateMessageHandler:
"region": template.region
}
)
- # mark as new template
- template._is_existing = False
return template
except Exception as e:
@@ -294,21 +296,16 @@ class TemplateMessageHandler:
})
if existing_template:
- # if template already exists, skip creation
await self.module_logger.log_info(
- info="Tenant template already exists, skipping creation",
+ info="Tenant Template already exists",
properties={
"template_id": template.template_id,
"tenant_id": template.tenant_id,
"region": template.region
}
)
-
- # mark as existing template
- existing_template._is_existing = True
- return existing_template
+ raise ValueError("Template already exists")
else:
- # if template does not exist, create new template
await template.create()
await self.module_logger.log_info(
info="Template created in database",
@@ -318,8 +315,6 @@ class TemplateMessageHandler:
"region": template.region
}
)
- # mark as new template
- template._is_existing = False
return template
except Exception as e:
@@ -412,8 +407,12 @@ class TemplateMessageHandler:
async def validate_template_parameters(self, template: MessageTemplateDoc, properties: dict) -> list:
"""validate template parameters"""
try:
- subject_placeholders = re.findall(r'\{(\w+)\}', template.subject)
- body_placeholders = re.findall(r'\{(\w+)\}', template.body)
+ # Normalize double-curly placeholders to single-curly for extraction
+ normalized_subject = self._normalize_placeholders(template.subject)
+ normalized_body = self._normalize_placeholders(template.body)
+
+ subject_placeholders = re.findall(r'\{(\w+)\}', normalized_subject)
+ body_placeholders = re.findall(r'\{(\w+)\}', normalized_body)
all_placeholders = list(set(subject_placeholders + body_placeholders))
missing_params = set(all_placeholders) - set(properties.keys())
@@ -461,10 +460,23 @@ class TemplateMessageHandler:
async def render_template(self, template: MessageTemplateDoc, properties: dict) -> dict:
"""render template"""
try:
- required_params = await self.validate_template_parameters(template, properties)
+ # Build normalized copies for rendering
+ normalized_subject = self._normalize_placeholders(template.subject)
+ normalized_body = self._normalize_placeholders(template.body)
- subject = template.subject.format(**properties)
- body = template.body.format(**properties)
+ # Validate using normalized content
+ temp_for_validation = MessageTemplateDoc(
+ template_id=template.template_id,
+ tenant_id=template.tenant_id,
+ region=template.region,
+ subject=normalized_subject,
+ body=normalized_body,
+ is_active=template.is_active,
+ )
+ required_params = await self.validate_template_parameters(temp_for_validation, properties)
+
+ subject = normalized_subject.format(**properties)
+ body = normalized_body.format(**properties)
await self.module_logger.log_info(
info="Template rendered",
diff --git a/apps/notification/backend/models/models.py b/apps/notification/backend/models/models.py
index 49c3cf2..542aa64 100644
--- a/apps/notification/backend/models/models.py
+++ b/apps/notification/backend/models/models.py
@@ -12,7 +12,6 @@ class MessageTemplateDoc(Document):
subject: str
body: str
is_active: bool = True
- is_existing: bool = False
created_at: datetime = datetime.utcnow()
updated_at: Optional[datetime] = None
@@ -52,7 +51,7 @@ class EmailSendStatusDoc(Document):
updated_at: Optional[datetime] = None
class Settings:
- name = "email_sender_status_doc"
+ name = "email_send_status_doc"
indexes = [
"email_id",
"tenant_id"
diff --git a/apps/notification/backend/services/template_message_service.py b/apps/notification/backend/services/template_message_service.py
index b3b5053..ecd1bd2 100644
--- a/apps/notification/backend/services/template_message_service.py
+++ b/apps/notification/backend/services/template_message_service.py
@@ -183,7 +183,7 @@ class TemplateMessageService:
continue
# copy template to tenant, use unique template_id
- tenant_template_id = f"{global_template.template_id}_tenant_{tenant_id}"
+ tenant_template_id = f"{tenant_id}_{global_template.template_id}"
new_template = MessageTemplateDoc(
template_id=tenant_template_id,
tenant_id=tenant_id,
diff --git a/apps/notification/create_global_templates.py b/apps/notification/create_global_templates.py
index 90b2547..c71e73b 100644
--- a/apps/notification/create_global_templates.py
+++ b/apps/notification/create_global_templates.py
@@ -33,7 +33,6 @@ class GlobalTemplateCreator:
# generate admin token
admin_payload = {
- "id": "test_admin_user",
"role": 8, # ADMINISTRATOR = 8
"tenant_id": None,
"exp": datetime.now(timezone.utc) + timedelta(hours=1)
@@ -42,9 +41,8 @@ class GlobalTemplateCreator:
# generate tenant token
tenant_payload = {
- "id": "test_tenant_user",
"role": 2, # BUSINESS = 2
- "tenant_id": "test_tenant_user",
+ "tenant_id": "magicleaps",
"exp": datetime.now(timezone.utc) + timedelta(hours=1)
}
tenant_token = jwt.encode(tenant_payload, secret_key, algorithm=algorithm)
@@ -109,57 +107,57 @@ class GlobalTemplateCreator:
template_data_cn = {
"template_id": "assessment_result_notification",
"region": 1,
- "subject": "笔试结果 - {candidate_name}",
+ "subject": "笔试结果 - {{candidate_name}}",
"body": """
-

+
-
尊敬的 {candidate_name},
+
尊敬的 {{candidate_name}},
感谢您参加我们的笔试考核。以下是您的评估结果:
📊 评估详情
- - 候选人姓名:{candidate_name}
- - 评估日期:{assessment_date}
- - 评估时长:{duration_minutes} 分钟
+ - 候选人姓名:{{candidate_name}}
+ - 评估日期:{{assessment_date}}
+ - 评估时长:{{duration_minutes}} 分钟
🔍 执行结果
- - 执行状态:{execution_status}
- - 执行时间:{execution_time} 毫秒
- - 测试用例通过率:{test_cases_passed}/{total_test_cases} ({pass_rate}%)
+ - 执行状态:{{execution_status}}
+ - 执行时间:{{execution_time}} 毫秒
+ - 测试用例通过率:{{test_cases_passed}}/{{total_test_cases}} ({{pass_rate}}%)
⚠️ 执行错误信息
-
{execution_errors}
+
{{execution_errors}}
📈 详细结果
-
{detailed_results}
+
{{detailed_results}}
🎯 评估结论
-
{assessment_conclusion}
+
{{assessment_conclusion}}
如有任何疑问,请联系我们的技术团队:
-
邮箱:{tech_support_email}
-
电话:{tech_support_phone}
+
邮箱:{{tech_support_email}}
+
电话:{{tech_support_phone}}
-
祝好!
{company_name} 技术团队
+
祝好!
{{company_name}} 技术团队
"""
}
@@ -168,57 +166,57 @@ class GlobalTemplateCreator:
template_data_en = {
"template_id": "assessment_result_notification",
"region": 0,
- "subject": "Assessment Result - {candidate_name}",
+ "subject": "Assessment Result - {{candidate_name}}",
"body": """
-

+
-
Dear {candidate_name},
+
Dear {{candidate_name}},
Thank you for participating in our assessment. Here are your evaluation results:
📊 Assessment Details
- - Candidate Name: {candidate_name}
- - Assessment Date: {assessment_date}
- - Duration: {duration_minutes} minutes
+ - Candidate Name: {{candidate_name}}
+ - Assessment Date: {{assessment_date}}
+ - Duration: {{duration_minutes}} minutes
🔍 Execution Results
- - Execution Status: {execution_status}
- - Execution Time: {execution_time} milliseconds
- - Test Cases Passed: {test_cases_passed}/{total_test_cases} ({pass_rate}%)
+ - Execution Status: {{execution_status}}
+ - Execution Time: {{execution_time}} milliseconds
+ - Test Cases Passed: {{test_cases_passed}}/{{total_test_cases}} ({{pass_rate}}%)
⚠️ Execution Errors
-
{execution_errors}
+
{{execution_errors}}
📈 Detailed Results
-
{detailed_results}
+
{{detailed_results}}
🎯 Assessment Conclusion
-
{assessment_conclusion}
+
{{assessment_conclusion}}
If you have any questions, please contact our technical team:
-
Email: {tech_support_email}
-
Phone: {tech_support_phone}
+
Email: {{tech_support_email}}
+
Phone: {{tech_support_phone}}
-
Best regards,
{company_name} Technical Team
+
Best regards,
{{company_name}} Technical Team
"""
}
@@ -236,13 +234,13 @@ class GlobalTemplateCreator:
template_data_cn = {
"template_id": "deadline_reminder",
"region": 1,
- "subject": "截止期限提醒 - {task_name}",
+ "subject": "截止期限提醒 - {{task_name}}",
"body": """
-

+
-
尊敬的 {recipient_name},
+
尊敬的 {{recipient_name}},
⚠️ 截止期限提醒
@@ -252,42 +250,42 @@ class GlobalTemplateCreator:
📋 任务详情
- - 任务名称:{task_name}
- - 任务描述:{task_description}
- - 截止日期:{deadline_date}
- - 剩余时间:{remaining_time}
+ - 任务名称:{{task_name}}
+ - 任务描述:{{task_description}}
+ - 截止日期:{{deadline_date}}
+ - 剩余时间:{{remaining_time}}
⏰ 时间信息
- - 当前时间:{current_time}
- - 截止时间:{deadline_time}
- - 剩余天数:{days_remaining} 天
+ - 当前时间:{{current_time}}
+ - 截止时间:{{deadline_time}}
+ - 剩余天数:{{days_remaining}} 天
📝 任务要求
-
{task_requirements}
+
{{task_requirements}}
请务必在截止日期前完成相关任务。如有任何问题,请联系:
-
邮箱:{contact_email}
+
邮箱:{{contact_email}}
-
谢谢!
{company_name} 团队
+
谢谢!
{{company_name}} 团队
"""
}
@@ -296,13 +294,13 @@ class GlobalTemplateCreator:
template_data_en = {
"template_id": "deadline_reminder",
"region": 0,
- "subject": "Deadline Reminder - {task_name}",
+ "subject": "Deadline Reminder - {{task_name}}",
"body": """
-

+
-
Dear {recipient_name},
+
Dear {{recipient_name}},
⚠️ Deadline Reminder
@@ -312,42 +310,42 @@ class GlobalTemplateCreator:
📋 Task Details
- - Task Name: {task_name}
- - Task Description: {task_description}
- - Deadline Date: {deadline_date}
- - Time Remaining: {remaining_time}
+ - Task Name: {{task_name}}
+ - Task Description: {{task_description}}
+ - Deadline Date: {{deadline_date}}
+ - Time
⏰ Time Information
- - Current Time: {current_time}
- - Deadline Time: {deadline_time}
- - Days Remaining: {days_remaining} days
+ - Current Time: {{current_time}}
+ - Deadline Time: {{deadline_time}}
+ - Days Remaining: {{days_remaining}} days
📝 Task Requirements
-
{task_requirements}
+
{{task_requirements}}
Please ensure to complete the related task before the deadline. If you have any questions, please contact:
-
Email: {contact_email}
+
Email: {{contact_email}}
-
Thank you!
{company_name} Team
+
Thank you!
{{company_name}} Team
"""
}
@@ -365,59 +363,59 @@ class GlobalTemplateCreator:
template_data_cn = {
"template_id": "interview_status_update",
"region": 1,
- "subject": "面试状态更新 - {candidate_name}",
+ "subject": "面试状态更新 - {{candidate_name}}",
"body": """
-

+
-
尊敬的 {candidate_name},
+
尊敬的 {{candidate_name}},
您的面试状态已更新:
👤 候选人信息
- - 姓名:{candidate_name}
- - 应聘职位:{position_name}
- - 申请编号:{application_id}
+ - 姓名:{{candidate_name}}
+ - 应聘职位:{{position_name}}
+ - 申请编号:{{application_id}}
📊 状态更新
- - 当前状态:{current_status}
- - 更新日期:{update_date}
- - 更新时间:{update_time}
+ - 当前状态:{{current_status}}
+ - 更新日期:{{update_date}}
+ - 更新时间:{{update_time}}
📋 状态详情
-
{status_details}
+
{{status_details}}
📅 下一步安排
-
{next_steps}
+
{{next_steps}}
⏰ 重要时间
- - 面试时间:{interview_time}
- - 面试地点:{interview_location}
- - 面试官:{interviewer_name}
+ - 面试时间:{{interview_time}}
+ - 面试地点:{{interview_location}}
+ - 面试官:{{interviewer_name}}
📞 联系方式
- - 面试官邮箱:{interviewer_email}
- - 面试官电话:{interviewer_phone}
- - 公司地址:{company_address}
+ - 面试官邮箱:{{interviewer_email}}
+ - 面试官电话:{{interviewer_phone}}
+ - 公司地址:{{company_address}}
@@ -426,7 +424,7 @@ class GlobalTemplateCreator:
-
祝面试顺利!
{company_name} 人力资源部
+
祝面试顺利!
{{company_name}} 人力资源部
"""
}
@@ -435,59 +433,59 @@ class GlobalTemplateCreator:
template_data_en = {
"template_id": "interview_status_update",
"region": 0,
- "subject": "Interview Status Update - {candidate_name}",
+ "subject": "Interview Status Update - {{candidate_name}}",
"body": """
-

+
-
Dear {candidate_name},
+
Dear {{candidate_name}},
Your interview status has been updated:
👤 Candidate Information
- - Name: {candidate_name}
- - Position Applied: {position_name}
- - Application ID: {application_id}
+ - Name: {{candidate_name}}
+ - Position Applied: {{position_name}}
+ - Application ID: {{application_id}}
📊 Status Update
- - Current Status: {current_status}
- - Update Date: {update_date}
- - Update Time: {update_time}
+ - Current Status: {{current_status}}
+ - Update Date: {{update_date}}
+ - Update Time: {{update_time}}
📋 Status Details
-
{status_details}
+
{{status_details}}
📅 Next Steps
-
{next_steps}
+
{{next_steps}}
⏰ Important Times
- - Interview Time: {interview_time}
- - Interview Location: {interview_location}
- - Interviewer: {interviewer_name}
+ - Interview Time: {{interview_time}}
+ - Interview Location: {{interview_location}}
+ - Interviewer: {{interviewer_name}}
📞 Contact Information
- - Interviewer Email: {interviewer_email}
- - Interviewer Phone: {interviewer_phone}
- - Company Address: {company_address}
+ - Interviewer Email: {{interviewer_email}}
+ - Interviewer Phone: {{interviewer_phone}}
+ - Company Address: {{company_address}}
@@ -496,7 +494,7 @@ class GlobalTemplateCreator:
-
Good luck with your interview!
{company_name} Human Resources Department
+
Good luck with your interview!
{{company_name}} Human Resources Department
"""
}
@@ -514,16 +512,16 @@ class GlobalTemplateCreator:
template_data_cn = {
"template_id": "welcome_email",
"region": 1,
- "subject": "欢迎加入 {company_name} - {new_employee_name}",
+ "subject": "欢迎加入 {{company_name}} - {{new_employee_name}}",
"body": """
-

+
-
亲爱的 {new_employee_name},
+
亲爱的 {{new_employee_name}},
-
🎉 欢迎加入 {company_name}!
+ 🎉 欢迎加入 {{company_name}}!
我们很高兴地通知您,您已成功加入我们的团队。以下是您的入职信息:
@@ -531,58 +529,58 @@ class GlobalTemplateCreator:
👤 员工信息
- - 姓名:{new_employee_name}
- - 员工编号:{employee_id}
- - 部门:{department}
- - 职位:{position}
- - 入职日期:{start_date}
+ - 姓名:{{new_employee_name}}
+ - 员工编号:{{employee_id}}
+ - 部门:{{department}}
+ - 职位:{{position}}
+ - 入职日期:{{start_date}}
🏢 公司信息
- - 公司名称:{company_name}
- - 公司地址:{company_address}
- - 联系电话:{company_phone}
+ - 公司名称:{{company_name}}
+ - 公司地址:{{company_address}}
+ - 联系电话:{{company_phone}}
📋 入职安排
-
{onboarding_schedule}
+
{{onboarding_schedule}}
👥 联系人
- - 直属经理:{manager_name} ({manager_email})
- - HR联系人:{hr_contact_name} ({hr_contact_email})
- - IT支持:{it_support_email}
+ - 直属经理:{{manager_name}} ({{manager_email}})
+ - HR联系人:{{hr_contact_name}} ({{hr_contact_email}})
+ - IT支持:{{it_support_email}}
🎯 第一周安排
-
{first_week_schedule}
+
{{first_week_schedule}}
@@ -590,7 +588,7 @@ class GlobalTemplateCreator:
-
再次欢迎您的加入!
{company_name} 团队
+
再次欢迎您的加入!
{{company_name}} 团队
"""
}
@@ -599,16 +597,16 @@ class GlobalTemplateCreator:
template_data_en = {
"template_id": "welcome_email",
"region": 0,
- "subject": "Welcome to {company_name} - {new_employee_name}",
+ "subject": "Welcome to {{company_name}} - {{new_employee_name}}",
"body": """
-

+
-
Dear {new_employee_name},
+
Dear {{new_employee_name}},
-
🎉 Welcome to {company_name}!
+ 🎉 Welcome to {{company_name}}!
We are pleased to inform you that you have successfully joined our team. Here is your onboarding information:
@@ -616,58 +614,58 @@ class GlobalTemplateCreator:
👤 Employee Information
- - Name: {new_employee_name}
- - Employee ID: {employee_id}
- - Department: {department}
- - Position: {position}
- - Start Date: {start_date}
+ - Name: {{new_employee_name}}
+ - Employee ID: {{employee_id}}
+ - Department: {{department}}
+ - Position: {{position}}
+ - Start Date: {{start_date}}
🏢 Company Information
- - Company Name: {company_name}
- - Company Address: {company_address}
- - Contact Phone: {company_phone}
+ - Company Name: {{company_name}}
+ - Company Address: {{company_address}}
+ - Contact Phone: {{company_phone}}
📋 Onboarding Schedule
-
{onboarding_schedule}
+
{{onboarding_schedule}}
🔑 System Access Information
- - Email: {email_address}
- - Initial Password: {initial_password}
- - System Login URL: {system_login_url}
+ - Email: {{email_address}}
+ - Initial Password: {{initial_password}}
+ - System Login URL: {{system_login_url}}
👥 Contacts
- - Direct Manager: {manager_name} ({manager_email})
- - HR Contact: {hr_contact_name} ({hr_contact_email})
- - IT Support: {it_support_email}
+ - Direct Manager: {{manager_name}} ({{manager_email}})
+ - HR Contact: {{hr_contact_name}} ({{hr_contact_email}})
+ - IT Support: {{it_support_email}}
🎯 First Week Schedule
-
{first_week_schedule}
+
{{first_week_schedule}}
@@ -675,7 +673,7 @@ class GlobalTemplateCreator:
-
Welcome aboard!
{company_name} Team
+
Welcome aboard!
{{company_name}} Team
"""
}
@@ -693,36 +691,36 @@ class GlobalTemplateCreator:
template_data_cn = {
"template_id": "password_reset_email",
"region": 1,
- "subject": "密码重置请求 - {user_name}",
+ "subject": "密码重置请求 - {{user_name}}",
"body": """
-

+
-
尊敬的 {user_name},
+
尊敬的 {{user_name}},
我们收到了您的密码重置请求。
🔐 重置信息
- - 用户名:{user_name}
- - 邮箱:{email_address}
- - 请求时间:{request_time}
- - 请求IP:{request_ip}
+ - 用户名:{{user_name}}
+ - 邮箱:{{email_address}}
+ - 请求时间:{{request_time}}
+ - 请求IP:{{request_ip}}
🔗 重置链接
-
点击重置密码
-
或复制链接:{reset_link}
+
点击重置密码
+
或复制链接:{{reset_link}}
⚠️ 重要提醒
- - • 此链接将在 {expiry_hours} 小时后失效
+ - • 此链接将在 {{expiry_hours}} 小时后失效
- • 请勿将此链接分享给他人
- • 如果您没有请求重置密码,请忽略此邮件
@@ -730,7 +728,7 @@ class GlobalTemplateCreator:
📱 验证码
-
{verification_code}
+
{{verification_code}}
@@ -744,12 +742,12 @@ class GlobalTemplateCreator:
如有任何问题,请联系技术支持:
-
邮箱:{support_email}
-
电话:{support_phone}
+
邮箱:{{support_email}}
+
电话:{{support_phone}}
-
谢谢!
{company_name} 技术支持团队
+
谢谢!
{{company_name}} 技术支持团队
"""
}
@@ -758,36 +756,36 @@ class GlobalTemplateCreator:
template_data_en = {
"template_id": "password_reset_email",
"region": 0,
- "subject": "Password Reset Request - {user_name}",
+ "subject": "Password Reset Request - {{user_name}}",
"body": """
-

+
-
Dear {user_name},
+
Dear {{user_name}},
We have received your password reset request.
🔐 Reset Information
- - Username: {user_name}
- - Email: {email_address}
- - Request Time: {request_time}
- - Request IP: {request_ip}
+ - Username: {{user_name}}
+ - Email: {{email_address}}
+ - Request Time: {{request_time}}
+ - Request IP: {{request_ip}}
⚠️ Important Reminder
- - • This link will expire in {expiry_hours} hours
+ - • This link will expire in {{expiry_hours}} hours
- • Please do not share this link with others
- • If you did not request a password reset, please ignore this email
@@ -795,7 +793,7 @@ class GlobalTemplateCreator:
📱 Verification Code
-
{verification_code}
+
{{verification_code}}
@@ -809,12 +807,12 @@ class GlobalTemplateCreator:
If you have any questions, please contact technical support:
-
Email: {support_email}
-
Phone: {support_phone}
+
Email: {{support_email}}
+
Phone: {{support_phone}}
-
Thank you!
{company_name} Technical Support Team
+
Thank you!
{{company_name}} Technical Support Team
"""
}
@@ -832,41 +830,41 @@ class GlobalTemplateCreator:
template_data_cn = {
"template_id": "account_verification_email",
"region": 1,
- "subject": "账号验证 - {user_name}",
+ "subject": "账号验证 - {{user_name}}",
"body": """
-

+
-
尊敬的 {user_name},
+
尊敬的 {{user_name}},
-
感谢您注册 {company_name} 的账户。请验证您的邮箱地址以完成注册。
+
感谢您注册 {{company_name}} 的账户。请验证您的邮箱地址以完成注册。
👤 账户信息
- - 用户名:{user_name}
- - 邮箱地址:{email_address}
- - 注册时间:{registration_time}
+ - 用户名:{{user_name}}
+ - 邮箱地址:{{email_address}}
+ - 注册时间:{{registration_time}}
🔗 验证链接
-
点击验证邮箱
-
或复制链接:{verification_link}
+
点击验证邮箱
+
或复制链接:{{verification_link}}
📱 验证码
-
{verification_code}
+
{{verification_code}}
⏰ 验证期限
- - 验证链接有效期:{expiry_hours} 小时
- - 请在 {expiry_time} 前完成验证
+ - 验证链接有效期:{{expiry_hours}} 小时
+ - 请在 {{expiry_time}} 前完成验证
@@ -874,7 +872,7 @@ class GlobalTemplateCreator:
✅ 验证步骤
- 点击上面的验证链接,或
- - 在登录页面输入验证码:{verification_code}
+ - 在登录页面输入验证码:{{verification_code}}
@@ -890,8 +888,8 @@ class GlobalTemplateCreator:
📞 需要帮助?
- - 技术支持:{support_email}
- - 客服热线:{support_phone}
+ - 技术支持:{{support_email}}
+ - 客服热线:{{support_phone}}
@@ -905,7 +903,7 @@ class GlobalTemplateCreator:
-
谢谢!
{company_name} 团队
+
谢谢!
{{company_name}} 团队
"""
}
@@ -914,41 +912,41 @@ class GlobalTemplateCreator:
template_data_en = {
"template_id": "account_verification_email",
"region": 0,
- "subject": "Account Verification - {user_name}",
+ "subject": "Account Verification - {{user_name}}",
"body": """
-

+
-
Dear {user_name},
+
Dear {{user_name}},
-
Thank you for registering an account with {company_name}. Please verify your email address to complete your registration.
+
Thank you for registering an account with {{company_name}}. Please verify your email address to complete your registration.
👤 Account Information
- - Username: {user_name}
- - Email Address: {email_address}
- - Registration Time: {registration_time}
+ - Username: {{user_name}}
+ - Email Address: {{email_address}}
+ - Registration Time: {{registration_time}}
📱 Verification Code
-
{verification_code}
+
{{verification_code}}
⏰ Verification Period
- - Verification Link Valid: {expiry_hours} hours
- - Please complete verification before {expiry_time}
+ - Verification Link Valid: {{expiry_hours}} hours
+ - Please complete verification before {{expiry_time}}
@@ -956,7 +954,7 @@ class GlobalTemplateCreator:
✅ Verification Steps
- Click the verification link above, or
- - Enter the verification code on the login page: {verification_code}
+ - Enter the verification code on the login page: {{verification_code}}
@@ -972,8 +970,8 @@ class GlobalTemplateCreator:
📞 Need Help?
- - Technical Support: {support_email}
- - Customer Service: {support_phone}
+ - Technical Support: {{support_email}}
+ - Customer Service: {{support_phone}}
@@ -987,7 +985,7 @@ class GlobalTemplateCreator:
-
Thank you!
{company_name} Team
+
Thank you!
{{company_name}} Team
"""
}
diff --git a/apps/notification/webapi/routes/template_massege.py b/apps/notification/webapi/routes/template_massege.py
index 202de43..cea767b 100644
--- a/apps/notification/webapi/routes/template_massege.py
+++ b/apps/notification/webapi/routes/template_massege.py
@@ -139,18 +139,12 @@ async def create_global_template(request: TemplateCreateRequest):
body=request.body,
is_active=request.is_active
)
- # check if the template is created or skipped (already exists)
- is_skipped = hasattr(result, '_is_existing') and result._is_existing
-
return JSONResponse(
- content={
- "message": f"Global template {'skipped (already exists)' if is_skipped else 'created'} successfully",
- "template_id": request.template_id,
- "action": "skipped" if is_skipped else "created"
- },
- status_code=200 if is_skipped else 201
+ content={"message": "Global template created successfully", "template_id": request.template_id},
+ status_code=201
)
except ValueError as e:
+ # duplicate or validation error
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
import traceback
@@ -286,37 +280,19 @@ async def create_tenant_template(request: TemplateCreateRequest, payload: dict =
tenant_id=tenant_id,
is_active=request.is_active
)
-
- # check if the template is created or skipped (already exists)
- is_skipped = hasattr(result, '_is_existing') and result._is_existing
-
+ # normalize minimal response
if hasattr(result, 'dict'):
result_dict = result.dict()
- for key, value in result_dict.items():
- if hasattr(value, 'isoformat'):
- result_dict[key] = value.isoformat()
- elif hasattr(value, 'value'):
- result_dict[key] = value.value
else:
- result_dict = {
- "template_id": getattr(result, 'template_id', request.template_id),
- "tenant_id": getattr(result, 'tenant_id', tenant_id),
- "region": getattr(result, 'region', request.region),
- "subject": getattr(result, 'subject', request.subject),
- "body": getattr(result, 'body', request.body),
- "is_active": getattr(result, 'is_active', request.is_active)
- }
-
+ result_dict = {"template_id": request.template_id, "tenant_id": tenant_id, "region": request.region}
+
return JSONResponse(
- content={
- "message": f"Tenant template {'skipped (already exists)' if is_skipped else 'created'} successfully",
- "result": result_dict,
- "action": "skipped" if is_skipped else "created"
- },
- status_code=200 if is_skipped else 201,
+ content={"message": "Tenant template created successfully", "result": result_dict},
+ status_code=201,
media_type="application/json"
)
except ValueError as e:
+ # duplicate or validation error
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
import traceback