2025-10-02 16:16:33 +00:00
package usecase
import (
2025-10-02 16:36:34 +00:00
"backend/pkg/notification/domain"
"backend/pkg/notification/domain/entity"
"backend/pkg/notification/domain/repository"
2025-10-02 16:16:33 +00:00
"backend/pkg/notification/domain/template"
"backend/pkg/notification/domain/usecase"
"context"
"fmt"
2025-10-02 16:36:34 +00:00
"strings"
"backend/pkg/library/errs"
"backend/pkg/library/errs/code"
"github.com/zeromicro/go-zero/core/logx"
2025-10-02 16:16:33 +00:00
)
2025-10-02 16:36:34 +00:00
type TemplateUseCaseParam struct {
TemplateRepo repository . TemplateRepository // 可選的資料庫模板 repository
}
2025-10-02 16:16:33 +00:00
type TemplateUseCase struct {
2025-10-02 16:36:34 +00:00
param TemplateUseCaseParam
2025-10-02 16:16:33 +00:00
}
func MustTemplateUseCase ( param TemplateUseCaseParam ) usecase . TemplateUseCase {
return & TemplateUseCase {
param ,
}
}
2025-10-02 16:36:34 +00:00
// GetEmailTemplateByStatic 從靜態模板獲取郵件模板
2025-10-02 16:16:33 +00:00
func ( use * TemplateUseCase ) GetEmailTemplateByStatic ( _ context . Context , language template . Language , templateID template . Type ) ( template . EmailTemplate , error ) {
// 查找指定語言的模板映射
templateByLang , exists := template . EmailTemplateMap [ language ]
if ! exists {
2025-10-02 16:36:34 +00:00
return template . EmailTemplate { } , errs . ResourceNotFoundWithScope (
code . CloudEPNotification ,
domain . FailedToGetTemplateErrorCode ,
fmt . Sprintf ( "email template not found for language: %s" , language ) )
2025-10-02 16:16:33 +00:00
}
// 查找指定類型的模板生成函數
templateFunc , exists := templateByLang [ templateID ]
if ! exists {
2025-10-02 16:36:34 +00:00
return template . EmailTemplate { } , errs . ResourceNotFoundWithScope (
code . CloudEPNotification ,
domain . FailedToGetTemplateErrorCode ,
fmt . Sprintf ( "email template not found for type ID: %s" , templateID ) )
2025-10-02 16:16:33 +00:00
}
// 執行模板生成函數
tmp , err := templateFunc ( )
if err != nil {
2025-10-02 16:36:34 +00:00
return template . EmailTemplate { } , errs . DatabaseErrorWithScope (
code . CloudEPNotification ,
domain . FailedToGetTemplateErrorCode ,
fmt . Sprintf ( "error generating email template: %v" , err ) )
2025-10-02 16:16:33 +00:00
}
return tmp , nil
}
2025-10-02 16:36:34 +00:00
// GetEmailTemplate 獲取郵件模板(優先從資料庫,回退到靜態模板)
func ( use * TemplateUseCase ) GetEmailTemplate ( ctx context . Context , language template . Language , templateID template . Type ) ( template . EmailTemplate , error ) {
// 1. 嘗試從資料庫獲取模板
if use . param . TemplateRepo != nil {
dbTemplate , err := use . param . TemplateRepo . GetTemplate ( ctx , "email" , string ( language ) , string ( templateID ) )
if err == nil && dbTemplate != nil && dbTemplate . IsActive {
logx . WithContext ( ctx ) . Infof ( "Using database template for %s/%s" , language , templateID )
return template . EmailTemplate {
Title : dbTemplate . Subject ,
Body : dbTemplate . Body ,
} , nil
}
// 記錄資料庫查詢失敗,但不返回錯誤,繼續使用靜態模板
if err != nil {
logx . WithContext ( ctx ) . WithFields ( logx . LogField { Key : "error" , Value : err . Error ( ) } ) . Error ( "Failed to get template from database, falling back to static" )
}
}
// 2. 回退到靜態模板
logx . WithContext ( ctx ) . Infof ( "Using static template for %s/%s" , language , templateID )
return use . GetEmailTemplateByStatic ( ctx , language , templateID )
}
// GetSMSTemplate 獲取 SMS 模板(優先從資料庫,回退到靜態模板)
func ( use * TemplateUseCase ) GetSMSTemplate ( ctx context . Context , language template . Language , templateID template . Type ) ( usecase . SMSTemplateResp , error ) {
// 1. 嘗試從資料庫獲取模板
if use . param . TemplateRepo != nil {
dbTemplate , err := use . param . TemplateRepo . GetTemplate ( ctx , "sms" , string ( language ) , string ( templateID ) )
if err == nil && dbTemplate != nil && dbTemplate . IsActive {
logx . WithContext ( ctx ) . Infof ( "Using database SMS template for %s/%s" , language , templateID )
return usecase . SMSTemplateResp {
Body : dbTemplate . Body ,
} , nil
}
// 記錄資料庫查詢失敗,但不返回錯誤,繼續使用靜態模板
if err != nil {
logx . WithContext ( ctx ) . WithFields ( logx . LogField { Key : "error" , Value : err . Error ( ) } ) . Error ( "Failed to get SMS template from database, falling back to static" )
}
}
// 2. 回退到靜態模板( SMS 暫時沒有靜態模板,返回默認)
logx . WithContext ( ctx ) . Infof ( "Using default SMS template for %s/%s" , language , templateID )
return use . getDefaultSMSTemplate ( templateID ) , nil
}
// RenderEmailTemplate 渲染郵件模板(替換變數)
func ( use * TemplateUseCase ) RenderEmailTemplate ( ctx context . Context , tmpl template . EmailTemplate , params entity . TemplateParams ) ( usecase . EmailTemplateResp , error ) {
renderedSubject := use . renderTemplate ( tmpl . Title , params )
renderedBody := use . renderTemplate ( tmpl . Body , params )
return usecase . EmailTemplateResp {
Subject : renderedSubject ,
Body : renderedBody ,
} , nil
}
// RenderSMSTemplate 渲染 SMS 模板(替換變數)
func ( use * TemplateUseCase ) RenderSMSTemplate ( ctx context . Context , tmpl usecase . SMSTemplateResp , params entity . TemplateParams ) ( usecase . SMSTemplateResp , error ) {
renderedBody := use . renderTemplate ( tmpl . Body , params )
return usecase . SMSTemplateResp {
Body : renderedBody ,
} , nil
}
// renderTemplate 渲染模板內容(簡單的字符串替換)
func ( use * TemplateUseCase ) renderTemplate ( content string , params entity . TemplateParams ) string {
result := content
// 替換基本參數
result = strings . ReplaceAll ( result , "{{.Username}}" , params . Username )
result = strings . ReplaceAll ( result , "{{.VerifyCode}}" , params . VerifyCode )
// 替換額外參數
for key , value := range params . Extra {
placeholder := fmt . Sprintf ( "{{.%s}}" , key )
result = strings . ReplaceAll ( result , placeholder , value )
}
return result
}
// getDefaultSMSTemplate 獲取默認 SMS 模板
func ( use * TemplateUseCase ) getDefaultSMSTemplate ( templateID template . Type ) usecase . SMSTemplateResp {
switch templateID {
case template . ForgetPasswordVerify :
return usecase . SMSTemplateResp {
Body : "您的密碼重設驗證碼是:{{.VerifyCode}}, 請在5分鐘內使用。如非本人操作請忽略此訊息。" ,
}
case template . BindingEmail :
return usecase . SMSTemplateResp {
Body : "您的綁定驗證碼是:{{.VerifyCode}}, 請在5分鐘內使用。如非本人操作請忽略此訊息。" ,
}
default :
return usecase . SMSTemplateResp {
Body : "您的驗證碼是:{{.VerifyCode}}, 請在5分鐘內使用。" ,
}
}
}