diff --git a/api/users_test.go b/api/users_test.go index 8a13bda..b8da079 100644 --- a/api/users_test.go +++ b/api/users_test.go @@ -22,7 +22,7 @@ func init() { // create a regex to find the verification code in the email codeRgx := fmt.Sprintf(`(.{%d})`, VerificationCodeLength*2) // load the email templates - if err := mailtemplates.Load("../assets"); err != nil { + if err := mailtemplates.Load(); err != nil { panic(err) } // wrap the mail template execution to force plain body and set the regex diff --git a/cmd/service/main.go b/cmd/service/main.go index c87c560..9192549 100644 --- a/cmd/service/main.go +++ b/cmd/service/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "os" "os/signal" "syscall" @@ -30,7 +29,6 @@ func main() { flag.StringP("mongoDB", "d", "saasdb", "The name of the MongoDB database") flag.StringP("privateKey", "k", "", "private key for the Vocdoni account") flag.BoolP("fullTransparentMode", "a", false, "allow all transactions and do not modify any of them") - flag.String("emailTemplatesPath", "./assets", "path to the email templates") flag.String("smtpServer", "", "SMTP server") flag.Int("smtpPort", 587, "SMTP port") flag.String("smtpUsername", "", "SMTP username") @@ -60,7 +58,6 @@ func main() { mongoURL := viper.GetString("mongoURL") mongoDB := viper.GetString("mongoDB") // email vars - emailTemplatesPath := viper.GetString("emailTemplatesPath") smtpServer := viper.GetString("smtpServer") smtpPort := viper.GetInt("smtpPort") smtpUsername := viper.GetString("smtpUsername") @@ -136,16 +133,12 @@ func main() { }); err != nil { log.Fatalf("could not create the email service: %v", err) } - // load email templates if the path is set - if emailTemplatesPath != "" { - if err := mailtemplates.Load(emailTemplatesPath); err != nil { - log.Fatalf("could not load email templates: %v", err) - } - log.Infow("email templates loaded", - "path", emailTemplatesPath, - "templates", len(mailtemplates.AvailableTemplates)) + // load email templates + if err := mailtemplates.Load(); err != nil { + log.Fatalf("could not load email templates: %v", err) } - log.Infow("email service created", "from", fmt.Sprintf("%s <%s>", emailFromName, emailFromAddress)) + log.Infow("email templates loaded", + "templates", len(mailtemplates.Available())) } subscriptions := subscriptions.New(&subscriptions.SubscriptionsConfig{ DB: database, diff --git a/notifications/mailtemplates/templates.go b/notifications/mailtemplates/templates.go index d85ba6d..d01835d 100644 --- a/notifications/mailtemplates/templates.go +++ b/notifications/mailtemplates/templates.go @@ -4,17 +4,16 @@ import ( "bytes" "fmt" htmltemplate "html/template" - "os" - "path/filepath" "strings" texttemplate "text/template" + root "github.com/vocdoni/saas-backend" "github.com/vocdoni/saas-backend/notifications" ) -// AvailableTemplates is a map that stores the filename and the absolute path +// availableTemplates is a map that stores the filename and the absolute path // of the email templates. The filename is the key and the path is the value. -var AvailableTemplates map[TemplateFile]string +var availableTemplates map[TemplateFile]string // TemplateFile represents an email template key. Every email template should // have a key that identifies it, which is the filename without the extension. @@ -31,34 +30,33 @@ type MailTemplate struct { WebAppURI string } +// Available function returns the available email templates. It returns a map +// with the filename and the absolute path of the email templates. The filename +// is the key and the path is the value. +func Available() map[TemplateFile]string { + return availableTemplates +} + // Load function reads the email templates from the specified directory. // Returns a map with the filename and file absolute path. The filename is // the key and the path is the value. -func Load(path string) error { - // create a map to store the filename and file content - htmlFiles := make(map[TemplateFile]string) +func Load() error { + // reset the map to store the filename and file paths + availableTemplates = make(map[TemplateFile]string) + // read files from embedded assets + entries, err := root.Assets.ReadDir("assets") + if err != nil { + return err + } // walk through the directory and read each file - if err := filepath.Walk(path, func(fPath string, info os.FileInfo, err error) error { - if err != nil { - return err - } + for _, entry := range entries { // only process regular files and files with a ".html" extension - if !info.IsDir() && strings.HasSuffix(info.Name(), ".html") { - // get the absolute path of the file - absPath, err := filepath.Abs(fPath) - if err != nil { - return err - } - // remove the ".html" extension from the filename - filename := strings.TrimSuffix(info.Name(), ".html") - // store the filename and content in the map - htmlFiles[TemplateFile(filename)] = absPath + if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".html") { + // store the filename and the path in the map + name := strings.TrimSuffix(entry.Name(), ".html") + availableTemplates[TemplateFile(name)] = "assets/" + entry.Name() } - return nil - }); err != nil { - return err } - AvailableTemplates = htmlFiles return nil } @@ -69,7 +67,7 @@ func Load(path string) error { // data provided. It returns the notification with the body and plain body // filled with the data provided. func (mt MailTemplate) ExecTemplate(data any) (*notifications.Notification, error) { - path, ok := AvailableTemplates[mt.File] + path, ok := availableTemplates[mt.File] if !ok { return nil, fmt.Errorf("template not found") } @@ -81,7 +79,11 @@ func (mt MailTemplate) ExecTemplate(data any) (*notifications.Notification, erro // set the mail subject n.Subject = mt.Placeholder.Subject // parse the html template file - tmpl, err := htmltemplate.ParseFiles(path) + content, err := root.Assets.ReadFile(path) + if err != nil { + return nil, err + } + tmpl, err := htmltemplate.New(string(mt.File)).Parse(string(content)) if err != nil { return nil, err }