diff --git a/comms/email.go b/comms/email.go
index 4c9de747..cd1e930e 100644
--- a/comms/email.go
+++ b/comms/email.go
@@ -2,6 +2,7 @@ package comms
import (
"bytes"
+ "embed"
"encoding/json"
"fmt"
"io"
@@ -11,12 +12,46 @@ import (
"github.com/rs/zerolog/log"
)
-type AttachmentRequest struct {
+func SendEmailReportConfirmation(to string, report_id string) error {
+ content := contentEmailReportConfirmation{
+ URLLogo: "https://dev-sync.nidus.cloud/static/img/nidus-logo-no-lettering-64.png",
+ URLReportStatus: fmt.Sprintf("https://dev-sync.nidus.cloud/report/%s", report_id),
+ URLReportUnsubscribe: fmt.Sprintf("https://dev-sync.nidus.cloud/report/%s/unsubscribe", report_id),
+ URLViewInBrowser: fmt.Sprintf("https://dev-sync.nidus.cloud/report/%s/subscribe-confirmation", report_id),
+ }
+ text, html, err := renderEmailTemplates(reportConfirmationT, content)
+ if err != nil {
+ return fmt.Errorf("Failed to render template %s: %w", reportConfirmationT.name, err)
+ }
+ return sendEmail(emailRequest{
+ From: config.ForwardEmailReportAddress,
+ HTML: html,
+ Subject: fmt.Sprintf("Mosquito Report %s Submission", report_id),
+ Text: text,
+ To: to,
+ })
+}
+
+var (
+ reportConfirmationT = buildTemplate("report-subscription-confirmation")
+)
+
+//go:embed template/*
+var embeddedFiles embed.FS
+
+type attachmentRequest struct {
Filename string `json:"filename"`
Content string `json:"content"`
}
-type EmailRequest struct {
+type contentEmailReportConfirmation struct {
+ URLLogo string
+ URLReportStatus string
+ URLReportUnsubscribe string
+ URLViewInBrowser string
+}
+
+type emailRequest struct {
From string `json:"from"`
To string `json:"to"`
CC []string `json:"cc,omitempty"`
@@ -24,18 +59,18 @@ type EmailRequest struct {
Subject string `json:"subject"`
Text string `json:"text"`
HTML string `json:"html,omitempty"`
- Attachments []AttachmentRequest `json:"attachments,omitempty"`
+ Attachments []attachmentRequest `json:"attachments,omitempty"`
Sender string `json:"sender"`
ReplyTo string `json:"replyTo,omitempty"`
InReplyTo string `json:"inReplyTo,omitempty"`
References []string `json:"references,omitempty"`
}
-type EmailResponse struct {
+type emailResponse struct {
Message string `json:"message"`
}
-func SendEmail(email EmailRequest) error {
+func sendEmail(email emailRequest) error {
url := "https://api.forwardemail.net/v1/emails"
payload, err := json.Marshal(email)
diff --git a/comms/template.go b/comms/template.go
new file mode 100644
index 00000000..0ec5e8cd
--- /dev/null
+++ b/comms/template.go
@@ -0,0 +1,146 @@
+package comms
+
+import (
+ "bytes"
+ "embed"
+ "errors"
+ "fmt"
+ templatehtml "html/template"
+ "io"
+ "os"
+ "path"
+ "strings"
+ templatetxt "text/template"
+
+ "github.com/Gleipnir-Technology/nidus-sync/config"
+ "github.com/rs/zerolog/log"
+)
+
+type builtTemplate struct {
+ name string
+ templateHTML *templatehtml.Template
+ templateTXT *templatetxt.Template
+}
+
+func (bt *builtTemplate) executeTemplateHTML(w io.Writer, content any) error {
+ if bt.templateHTML == nil {
+ file := templateFileHTML(bt.name)
+ templ, err := parseFromDiskHTML(file)
+ if err != nil {
+ return fmt.Errorf("Failed to parse template file: %w", err)
+ }
+ if templ == nil {
+ w.Write([]byte("Failed to read from disk: "))
+ return errors.New("Template parsing failed")
+ }
+ //log.Debug().Str("name", templ.Name()).Msg("Parsed template")
+ return templ.ExecuteTemplate(w, bt.name+".html", content)
+ } else {
+ return bt.templateHTML.ExecuteTemplate(w, bt.name+".html", content)
+ }
+}
+func (bt *builtTemplate) executeTemplateTXT(w io.Writer, content any) error {
+ if bt.templateTXT == nil {
+ file := templateFileTXT(bt.name)
+ templ, err := parseFromDiskTXT(file)
+ if err != nil {
+ return fmt.Errorf("Failed to parse template file: %w", err)
+ }
+ if templ == nil {
+ w.Write([]byte("Failed to read from disk: "))
+ return errors.New("Template parsing failed")
+ }
+ //log.Debug().Str("name", templ.Name()).Msg("Parsed template")
+ return templ.ExecuteTemplate(w, bt.name+".txt", content)
+ } else {
+ return bt.templateTXT.ExecuteTemplate(w, bt.name+".txt", content)
+ }
+}
+func templateFileHTML(name string) string {
+ return fmt.Sprintf("comms/template/%s.html", name)
+}
+func templateFileTXT(name string) string {
+ return fmt.Sprintf("comms/template/%s.txt", name)
+}
+
+func buildTemplate(name string) *builtTemplate {
+ files_on_disk := true
+ file_html := templateFileHTML(name)
+ file_txt := templateFileTXT(name)
+ for _, f := range []string{file_html, file_txt} {
+ _, err := os.Stat(f)
+ if err != nil {
+ files_on_disk = false
+ if !config.IsProductionEnvironment() {
+ log.Warn().Str("file", f).Msg("email template file is not on disk")
+ }
+ break
+ }
+ }
+ var result builtTemplate
+ if files_on_disk {
+ result = builtTemplate{
+ name: name,
+ templateHTML: nil,
+ templateTXT: nil,
+ }
+ } else {
+ result = builtTemplate{
+ name: name,
+ templateHTML: parseEmbeddedHTML(embeddedFiles, "comms", file_html),
+ templateTXT: parseEmbeddedTXT(embeddedFiles, "comms", file_txt),
+ }
+ }
+ return &result
+}
+
+func parseEmbeddedHTML(embeddedFiles embed.FS, subdir string, file string) *templatehtml.Template {
+ // Remap the file names to embedded paths
+ embeddedFilePaths := []string{strings.TrimPrefix(file, subdir)}
+ name := path.Base(embeddedFilePaths[0])
+ log.Debug().Str("name", name).Strs("paths", embeddedFilePaths).Msg("Parsing embedded template")
+ return templatehtml.Must(
+ templatehtml.New(name).ParseFS(embeddedFiles, embeddedFilePaths...))
+}
+func parseEmbeddedTXT(embeddedFiles embed.FS, subdir string, file string) *templatetxt.Template {
+ // Remap the file names to embedded paths
+ embeddedFilePaths := []string{strings.TrimPrefix(file, subdir)}
+ name := path.Base(embeddedFilePaths[0])
+ log.Debug().Str("name", name).Strs("paths", embeddedFilePaths).Msg("Parsing embedded template")
+ return templatetxt.Must(
+ templatetxt.New(name).ParseFS(embeddedFiles, embeddedFilePaths...))
+}
+
+func parseFromDiskHTML(file string) (*templatehtml.Template, error) {
+ name := path.Base(file)
+ //log.Debug().Str("name", name).Strs("files", files).Msg("parsing from disk")
+ templ, err := templatehtml.New(name).ParseFiles(file)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to parse %s: %w", file, err)
+ }
+ return templ, nil
+}
+
+func parseFromDiskTXT(file string) (*templatetxt.Template, error) {
+ name := path.Base(file)
+ //log.Debug().Str("name", name).Strs("files", files).Msg("parsing from disk")
+ templ, err := templatetxt.New(name).ParseFiles(file)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to parse %s: %w", file, err)
+ }
+ return templ, nil
+}
+
+func renderEmailTemplates(t *builtTemplate, content interface{}) (text string, html string, err error) {
+ buf_txt := &bytes.Buffer{}
+ err = t.executeTemplateTXT(buf_txt, content)
+ if err != nil {
+ return "", "", fmt.Errorf("Failed to render TXT template: %w", err)
+ }
+ buf_html := &bytes.Buffer{}
+ err = t.executeTemplateHTML(buf_html, content)
+ if err != nil {
+ return "", "", fmt.Errorf("Failed to render HTML template: %w", err)
+ }
+ return buf_txt.String(), buf_html.String(), nil
+}
diff --git a/comms/template/report-subscription-confirmation.html b/comms/template/report-subscription-confirmation.html
new file mode 100644
index 00000000..8fe723b1
--- /dev/null
+++ b/comms/template/report-subscription-confirmation.html
@@ -0,0 +1,99 @@
+
+
+
+
+
+ Thank You for Your Mosquito Report
+
+
+
+
+
+
+
+
+
+
Thank You for Your Report
+
+
We've received your mosquito report. Thanks! We appreciate you taking the time to submit it.
+
+
You can check the current status of your report at any time by clicking the button below:
+
+
+
+
We'll send you additional updates as work is scheduled and completed.
+
+
If you have any questions or need further assistance, please don't hesitate to contact us by replying to this email.
+
+
+
+
+
+
diff --git a/comms/template/report-subscription-confirmation.txt b/comms/template/report-subscription-confirmation.txt
new file mode 100644
index 00000000..31df8a44
--- /dev/null
+++ b/comms/template/report-subscription-confirmation.txt
@@ -0,0 +1,9 @@
+We've received your mosquito report. Thanks! We appreciate you taking the time to submit it.
+
+You can check the current status of your report at any time at {{.URLReportStatus}}
+
+We'll send you additional updates as work is scheduled and completed.
+
+If you have any questions or need further assistance, please don't hesitate to contact us by replying to this email.
+
+If you no longer wish to receive these updates, navigate your browser to {{.URLReportUnsubscribe}} to unsubscribe.
diff --git a/public-report/quick.go b/public-report/quick.go
index eadda73e..a3cb41e8 100644
--- a/public-report/quick.go
+++ b/public-report/quick.go
@@ -7,7 +7,6 @@ import (
"time"
"github.com/Gleipnir-Technology/nidus-sync/comms"
- "github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
@@ -182,12 +181,10 @@ func postRegisterNotifications(w http.ResponseWriter, r *http.Request) {
return
}
if email != "" {
- comms.SendEmail(comms.EmailRequest{
- From: config.ForwardEmailReportAddress,
- To: email,
- Subject: "test email",
- Text: "This is just testing that I can send email",
- })
+ err := comms.SendEmailReportConfirmation(email, report_id)
+ if err != nil {
+ log.Error().Err(err).Msg("Failed to send email")
+ }
}
if phone != "" {
//err := comms.SendSMS(phone, "testing 1 2 3")