1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-06-28 20:37:46 +02:00
jfa-go/email.go
Harvey Tindall 961b9afa75 Functioning user creation, notifications,
Fixed password validation for new users, add invite route, couple other
fixes.
2020-07-31 12:48:37 +01:00

210 lines
6.1 KiB
Go

package main
import (
"bytes"
// "context"
"context"
"fmt"
"github.com/knz/strtime"
"github.com/mailgun/mailgun-go/v4"
"html/template"
"net/smtp"
"strings"
"time"
)
type Emailer struct {
smtpAuth smtp.Auth
sendType, sendMethod, fromAddr, fromName string
content Email
mg *mailgun.MailgunImpl
}
type Email struct {
subject string
html, text string
}
func (email *Emailer) formatExpiry(expiry time.Time, tzaware bool, datePattern, timePattern string) (d, t, expires_in string) {
d, _ = strtime.Strftime(expiry, datePattern)
t, _ = strtime.Strftime(expiry, timePattern)
current_time := time.Now()
if tzaware {
current_time = current_time.UTC()
}
_, _, days, hours, minutes, _ := timeDiff(expiry, current_time)
if days != 0 {
expires_in += fmt.Sprintf("%dd ", days)
}
if hours != 0 {
expires_in += fmt.Sprintf("%dh ", hours)
}
if minutes != 0 {
expires_in += fmt.Sprintf("%dm ", minutes)
}
expires_in = strings.TrimSuffix(expires_in, " ")
return
}
func (email *Emailer) init(ctx *appContext) {
email.fromAddr = ctx.config.Section("email").Key("address").String()
email.fromName = ctx.config.Section("email").Key("from").String()
email.sendMethod = ctx.config.Section("email").Key("method").String()
if email.sendMethod == "mailgun" {
email.mg = mailgun.NewMailgun(strings.Split(email.fromAddr, "@")[1], ctx.config.Section("mailgun").Key("api_key").String())
api_url := ctx.config.Section("mailgun").Key("api_url").String()
if strings.Contains(api_url, "messages") {
api_url = api_url[0:strings.LastIndex(api_url, "/")]
api_url = api_url[0:strings.LastIndex(api_url, "/")]
}
email.mg.SetAPIBase(api_url)
}
}
func (email *Emailer) constructInvite(code string, invite Invite, ctx *appContext) error {
email.content.subject = ctx.config.Section("invite_emails").Key("subject").String()
expiry := invite.ValidTill
d, t, expires_in := email.formatExpiry(expiry, false, ctx.datePattern, ctx.timePattern)
message := ctx.config.Section("email").Key("message").String()
invite_link := ctx.config.Section("invite_emails").Key("url_base").String()
invite_link = fmt.Sprintf("%s/%s", invite_link, code)
for _, key := range []string{"html", "text"} {
fpath := ctx.config.Section("invite_emails").Key("email_" + key).String()
tpl, err := template.ParseFiles(fpath)
if err != nil {
fmt.Println("failed email", err)
return err
}
var tplData bytes.Buffer
err = tpl.Execute(&tplData, map[string]string{
"expiry_date": d,
"expiry_time": t,
"expires_in": expires_in,
"invite_link": invite_link,
"message": message,
})
if err != nil {
fmt.Println("failed email", err)
return err
}
if key == "html" {
email.content.html = tplData.String()
} else {
email.content.text = tplData.String()
}
}
email.sendType = "invite"
return nil
}
func (email *Emailer) constructExpiry(code string, invite Invite, ctx *appContext) error {
email.content.subject = "Notice: Invite expired"
expiry := ctx.formatDatetime(invite.ValidTill)
for _, key := range []string{"html", "text"} {
fpath := ctx.config.Section("notifications").Key("expiry_" + key).String()
tpl, err := template.ParseFiles(fpath)
if err != nil {
fmt.Println("failed email", err)
return err
}
var tplData bytes.Buffer
err = tpl.Execute(&tplData, map[string]string{
"code": code,
"expiry": expiry,
})
if err != nil {
fmt.Println("failed email", err)
return err
}
if key == "html" {
email.content.html = tplData.String()
} else {
email.content.text = tplData.String()
}
}
email.sendType = "expiry"
return nil
}
func (email *Emailer) constructCreated(code, username, address string, invite Invite, ctx *appContext) error {
email.content.subject = "Notice: User created"
created := ctx.formatDatetime(invite.Created)
var tplAddress string
if ctx.config.Section("email").Key("no_username").MustBool(false) {
tplAddress = "n/a"
} else {
tplAddress = address
}
for _, key := range []string{"html", "text"} {
fpath := ctx.config.Section("notifications").Key("created_" + key).String()
tpl, err := template.ParseFiles(fpath)
if err != nil {
fmt.Println("failed email", err)
return err
}
var tplData bytes.Buffer
err = tpl.Execute(&tplData, map[string]string{
"code": code,
"username": username,
"address": tplAddress,
"time": created,
})
if err != nil {
fmt.Println("failed email", err)
return err
}
if key == "html" {
email.content.html = tplData.String()
} else {
email.content.text = tplData.String()
}
}
email.sendType = "created"
return nil
}
func (email *Emailer) send(address string, ctx *appContext) error {
if email.sendMethod == "mailgun" {
// reqData := map[string]string{
// "to": fmt.Sprintf("%s <%s>", "test", email.to),
// "from": email.fromAddr,
// "subject": email.subject,
// }
// if email.sendType == "invite" {
// reqData["text"] = email.invite.text
// reqData["html"] = email.invite.html
// }
// data := &bytes.Buffer{}
// encoder := json.NewEncoder(data)
// encoder.SetEscapeHTML(false)
// err := encoder.Encode(reqData)
// fmt.Println("marshaled:", data)
// if err != nil {
// fmt.Println("Failed marshal:", err, ">", data)
// return err
// }
// var req *http.Request
// req, err = http.NewRequest("POST", ctx.config.Section("mailgun").Key("api_url").String(), data)
// req.SetBasicAuth("api", ctx.config.Section("mailgun").Key("api_key").String())
// var resp *http.Response
// resp, err = email.httpClient.Do(req)
// if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 204) {
// fmt.Println("failed send:", err, resp.StatusCode)
// fmt.Println("resp:", resp.Header.Get("Content-Encoding"), resp.Body)
// }
message := email.mg.NewMessage(
fmt.Sprintf("%s <%s>", email.fromName, email.fromAddr),
email.content.subject,
email.content.text,
address)
message.SetHtml(email.content.html)
mgctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
_, id, err := email.mg.Send(mgctx, message)
fmt.Println("mailgun:", id, err)
}
return nil
}