2017-04-19 21:32:12 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"github.com/Masterminds/sprig"
|
|
|
|
"gopkg.in/gomail.v2"
|
|
|
|
"text/template"
|
|
|
|
)
|
|
|
|
|
|
|
|
type NotificationMail interface {
|
|
|
|
GetData() interface{}
|
|
|
|
GetTemplate() string
|
|
|
|
GetSubject() string
|
|
|
|
GetHeaders() map[string]string
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:58:22 +00:00
|
|
|
type VoterMail interface {
|
|
|
|
GetData() interface{}
|
|
|
|
GetTemplate() string
|
|
|
|
GetSubject() string
|
|
|
|
GetRecipient() (string, string)
|
|
|
|
}
|
|
|
|
|
2017-04-19 21:32:12 +00:00
|
|
|
var notifyMail = make(chan NotificationMail, 1)
|
2017-04-20 18:58:22 +00:00
|
|
|
var voterMail = make(chan VoterMail, 1)
|
2017-04-19 21:32:12 +00:00
|
|
|
var quitMailNotifier = make(chan int)
|
|
|
|
|
|
|
|
func CloseMailNotifier() {
|
|
|
|
quitMailNotifier <- 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func MailNotifier() {
|
|
|
|
logger.Println("Launched mail notifier")
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case notification := <-notifyMail:
|
|
|
|
mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
|
|
|
|
if err != nil {
|
|
|
|
logger.Println("ERROR building mail:", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
m := gomail.NewMessage()
|
|
|
|
m.SetHeader("From", config.NoticeSenderAddress)
|
|
|
|
m.SetHeader("To", config.BoardMailAddress)
|
|
|
|
m.SetHeader("Subject", notification.GetSubject())
|
|
|
|
for header, value := range notification.GetHeaders() {
|
|
|
|
m.SetHeader(header, value)
|
|
|
|
}
|
|
|
|
m.SetBody("text/plain", mailText.String())
|
|
|
|
|
2017-04-20 18:58:22 +00:00
|
|
|
d := gomail.NewDialer(config.MailServer.Host, config.MailServer.Port, "", "")
|
|
|
|
if err := d.DialAndSend(m); err != nil {
|
|
|
|
logger.Println("ERROR sending mail:", err)
|
|
|
|
}
|
|
|
|
case notification := <-voterMail:
|
|
|
|
mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
|
|
|
|
if err != nil {
|
|
|
|
logger.Println("ERROR building mail:", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
m := gomail.NewMessage()
|
|
|
|
m.SetHeader("From", config.ReminderSenderAddress)
|
|
|
|
address, name := notification.GetRecipient()
|
|
|
|
m.SetAddressHeader("To", address, name)
|
|
|
|
m.SetHeader("Subject", notification.GetSubject())
|
|
|
|
m.SetBody("text/plain", mailText.String())
|
|
|
|
|
2017-04-19 21:32:12 +00:00
|
|
|
d := gomail.NewDialer(config.MailServer.Host, config.MailServer.Port, "", "")
|
|
|
|
if err := d.DialAndSend(m); err != nil {
|
|
|
|
logger.Println("ERROR sending mail:", err)
|
|
|
|
}
|
|
|
|
case <-quitMailNotifier:
|
|
|
|
fmt.Println("Ending mail notifier")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildMail(templateName string, context interface{}) (mailText *bytes.Buffer, err error) {
|
|
|
|
t, err := template.New(templateName).Funcs(
|
|
|
|
sprig.GenericFuncMap()).ParseFiles(fmt.Sprintf("templates/%s", templateName))
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
mailText = bytes.NewBufferString("")
|
|
|
|
t.Execute(mailText, context)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
type NotificationClosedDecision struct {
|
|
|
|
decision Decision
|
|
|
|
voteSums VoteSums
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationClosedDecision) GetData() interface{} {
|
|
|
|
return struct {
|
|
|
|
*Decision
|
|
|
|
*VoteSums
|
|
|
|
}{&n.decision, &n.voteSums}
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:58:22 +00:00
|
|
|
func (n *NotificationClosedDecision) GetTemplate() string { return "closed_motion_mail.txt" }
|
2017-04-19 21:32:12 +00:00
|
|
|
|
|
|
|
func (n *NotificationClosedDecision) GetSubject() string {
|
|
|
|
return fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationClosedDecision) GetHeaders() map[string]string {
|
|
|
|
return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
|
|
|
|
}
|
|
|
|
|
|
|
|
type NotificationCreateMotion struct {
|
|
|
|
decision Decision
|
|
|
|
voter Voter
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationCreateMotion) GetData() interface{} {
|
|
|
|
voteURL := fmt.Sprintf("%s/vote", config.BaseURL)
|
|
|
|
unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
|
|
|
|
return struct {
|
|
|
|
*Decision
|
|
|
|
Name string
|
|
|
|
VoteURL string
|
|
|
|
UnvotedURL string
|
|
|
|
}{&n.decision, n.voter.Name, voteURL, unvotedURL}
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:58:22 +00:00
|
|
|
func (n *NotificationCreateMotion) GetTemplate() string { return "create_motion_mail.txt" }
|
2017-04-19 21:32:12 +00:00
|
|
|
|
|
|
|
func (n *NotificationCreateMotion) GetSubject() string {
|
|
|
|
return fmt.Sprintf("%s - %s", n.decision.Tag, n.decision.Title)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationCreateMotion) GetHeaders() map[string]string {
|
|
|
|
return map[string]string{"Message-ID": fmt.Sprintf("<%s>", n.decision.Tag)}
|
|
|
|
}
|
|
|
|
|
|
|
|
type NotificationUpdateMotion struct {
|
|
|
|
decision Decision
|
|
|
|
voter Voter
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationUpdateMotion) GetData() interface{} {
|
|
|
|
voteURL := fmt.Sprintf("%s/vote", config.BaseURL)
|
|
|
|
unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
|
|
|
|
return struct {
|
|
|
|
*Decision
|
|
|
|
Name string
|
|
|
|
VoteURL string
|
|
|
|
UnvotedURL string
|
|
|
|
}{&n.decision, n.voter.Name, voteURL, unvotedURL}
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:58:22 +00:00
|
|
|
func (n *NotificationUpdateMotion) GetTemplate() string { return "update_motion_mail.txt" }
|
2017-04-19 21:32:12 +00:00
|
|
|
|
|
|
|
func (n *NotificationUpdateMotion) GetSubject() string {
|
|
|
|
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationUpdateMotion) GetHeaders() map[string]string {
|
|
|
|
return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
|
|
|
|
}
|
|
|
|
|
|
|
|
type NotificationWithDrawMotion struct {
|
|
|
|
decision Decision
|
|
|
|
voter Voter
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationWithDrawMotion) GetData() interface{} {
|
|
|
|
return struct {
|
|
|
|
*Decision
|
|
|
|
Name string
|
|
|
|
}{&n.decision, n.voter.Name}
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:58:22 +00:00
|
|
|
func (n *NotificationWithDrawMotion) GetTemplate() string { return "withdraw_motion_mail.txt" }
|
2017-04-19 21:32:12 +00:00
|
|
|
|
|
|
|
func (n *NotificationWithDrawMotion) GetSubject() string {
|
|
|
|
return fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NotificationWithDrawMotion) GetHeaders() map[string]string {
|
|
|
|
return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
|
|
|
|
}
|
2017-04-20 18:58:22 +00:00
|
|
|
|
|
|
|
type RemindVoterNotification struct {
|
|
|
|
voter Voter
|
|
|
|
decisions []Decision
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *RemindVoterNotification) GetData() interface{} {
|
|
|
|
return struct {
|
|
|
|
Decisions []Decision
|
|
|
|
Name string
|
|
|
|
BaseURL string
|
|
|
|
}{n.decisions, n.voter.Name, config.BaseURL}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *RemindVoterNotification) GetTemplate() string { return "remind_voter_mail.txt" }
|
|
|
|
|
|
|
|
func (n *RemindVoterNotification) GetSubject() string { return "Outstanding CAcert board votes" }
|
|
|
|
|
|
|
|
func (n *RemindVoterNotification) GetRecipient() (address string, name string) {
|
|
|
|
address, name = n.voter.Reminder, n.voter.Name
|
|
|
|
return
|
|
|
|
}
|