2022-08-28 12:43:25 +03:00
// Copyright 2022 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2022-08-28 12:43:25 +03:00
package templates
import (
"context"
"html/template"
"strings"
texttmpl "text/template"
2023-04-08 16:15:22 +03:00
"code.gitea.io/gitea/modules/base"
2022-08-28 12:43:25 +03:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
2023-04-08 16:15:22 +03:00
// mailSubjectTextFuncMap returns functions for injecting to text templates, it's only used for mail subject
func mailSubjectTextFuncMap ( ) texttmpl . FuncMap {
return texttmpl . FuncMap {
"dict" : dict ,
"Eval" : Eval ,
"EllipsisString" : base . EllipsisString ,
"AppName" : func ( ) string {
return setting . AppName
} ,
"AppDomain" : func ( ) string { // documented in mail-templates.md
return setting . Domain
} ,
}
}
func buildSubjectBodyTemplate ( stpl * texttmpl . Template , btpl * template . Template , name string , content [ ] byte ) {
// Split template into subject and body
var subjectContent [ ] byte
bodyContent := content
loc := mailSubjectSplit . FindIndex ( content )
if loc != nil {
subjectContent = content [ 0 : loc [ 0 ] ]
bodyContent = content [ loc [ 1 ] : ]
}
if _ , err := stpl . New ( name ) .
Parse ( string ( subjectContent ) ) ; err != nil {
log . Warn ( "Failed to parse template [%s/subject]: %v" , name , err )
}
if _ , err := btpl . New ( name ) .
Parse ( string ( bodyContent ) ) ; err != nil {
log . Warn ( "Failed to parse template [%s/body]: %v" , name , err )
}
}
2022-08-28 12:43:25 +03:00
// Mailer provides the templates required for sending notification mails.
func Mailer ( ctx context . Context ) ( * texttmpl . Template , * template . Template ) {
2023-04-08 16:15:22 +03:00
subjectTemplates := texttmpl . New ( "" )
bodyTemplates := template . New ( "" )
subjectTemplates . Funcs ( mailSubjectTextFuncMap ( ) )
2022-08-28 12:43:25 +03:00
for _ , funcs := range NewFuncMap ( ) {
bodyTemplates . Funcs ( funcs )
}
2023-04-12 13:16:45 +03:00
assetFS := AssetFS ( )
2022-08-28 12:43:25 +03:00
refreshTemplates := func ( ) {
2023-04-12 13:16:45 +03:00
assetPaths , err := ListMailTemplateAssetNames ( assetFS )
if err != nil {
log . Error ( "Failed to list mail templates: %v" , err )
return
2022-08-28 12:43:25 +03:00
}
2023-04-12 13:16:45 +03:00
for _ , assetPath := range assetPaths {
content , layerName , err := assetFS . ReadLayeredFile ( assetPath )
2022-08-28 12:43:25 +03:00
if err != nil {
2023-04-12 13:16:45 +03:00
log . Warn ( "Failed to read mail template %s by %s: %v" , assetPath , layerName , err )
continue
2022-08-28 12:43:25 +03:00
}
2023-04-12 13:16:45 +03:00
tmplName := strings . TrimPrefix ( strings . TrimSuffix ( assetPath , ".tmpl" ) , "mail/" )
log . Trace ( "Adding mail template %s: %s by %s" , tmplName , assetPath , layerName )
buildSubjectBodyTemplate ( subjectTemplates , bodyTemplates , tmplName , content )
2022-08-28 12:43:25 +03:00
}
}
refreshTemplates ( )
if ! setting . IsProd {
// Now subjectTemplates and bodyTemplates are both synchronized
// thus it is safe to call refresh from a different goroutine
2023-04-12 13:16:45 +03:00
go assetFS . WatchLocalChanges ( ctx , refreshTemplates )
2022-08-28 12:43:25 +03:00
}
return subjectTemplates , bodyTemplates
}