cacert-boardvoting/notifications.go

279 lines
7.5 KiB
Go

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
GetRecipient() (string, string)
}
var NotifyMailChannel = make(chan NotificationMail, 1)
func MailNotifier(quitMailNotifier chan int) {
logger.Println("Launched mail notifier")
for {
select {
case notification := <-NotifyMailChannel:
mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
if err != nil {
logger.Println("ERROR building mail:", err)
continue
}
m := gomail.NewMessage()
m.SetHeader("From", config.NotificationSenderAddress)
address, name := notification.GetRecipient()
m.SetAddressHeader("To", address, name)
m.SetHeader("Subject", notification.GetSubject())
for header, value := range notification.GetHeaders() {
m.SetHeader(header, value)
}
m.SetBody("text/plain", mailText.String())
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 notificationBase struct{}
func (n *notificationBase) GetRecipient() (address string, name string) {
address, name = config.BoardMailAddress, "CAcert board mailing list"
return
}
type decisionReplyBase struct {
decision Decision
}
func (n *decisionReplyBase) GetHeaders() map[string]string {
return map[string]string{
"References": fmt.Sprintf("<%s>", n.decision.Tag),
"In-Reply-To": fmt.Sprintf("<%s>", n.decision.Tag),
}
}
type NotificationClosedDecision struct {
notificationBase
decisionReplyBase
voteSums VoteSums
}
func NewNotificationClosedDecision(decision *Decision, voteSums *VoteSums) *NotificationClosedDecision {
notification := &NotificationClosedDecision{voteSums: *voteSums}
notification.decision = *decision
return notification
}
func (n *NotificationClosedDecision) GetData() interface{} {
return struct {
*Decision
*VoteSums
}{&n.decision, &n.voteSums}
}
func (n *NotificationClosedDecision) GetTemplate() string { return "closed_motion_mail.txt" }
func (n *NotificationClosedDecision) GetSubject() string {
return fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title)
}
type NotificationCreateMotion struct {
notificationBase
decision Decision
voter Voter
}
func (n *NotificationCreateMotion) GetData() interface{} {
voteURL := fmt.Sprintf("%s/vote/%s", config.BaseURL, n.decision.Tag)
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}
}
func (n *NotificationCreateMotion) GetTemplate() string { return "create_motion_mail.txt" }
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 {
notificationBase
decisionReplyBase
voter Voter
}
func NewNotificationUpdateMotion(decision Decision, voter Voter) *NotificationUpdateMotion {
notification := NotificationUpdateMotion{voter: voter}
notification.decision = decision
return &notification
}
func (n *NotificationUpdateMotion) GetData() interface{} {
voteURL := fmt.Sprintf("%s/vote/%s", config.BaseURL, n.decision.Tag)
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}
}
func (n *NotificationUpdateMotion) GetTemplate() string { return "update_motion_mail.txt" }
func (n *NotificationUpdateMotion) GetSubject() string {
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
}
type NotificationWithDrawMotion struct {
notificationBase
decisionReplyBase
voter Voter
}
func NewNotificationWithDrawMotion(decision *Decision, voter *Voter) *NotificationWithDrawMotion {
notification := &NotificationWithDrawMotion{voter: *voter}
notification.decision = *decision
return notification
}
func (n *NotificationWithDrawMotion) GetData() interface{} {
return struct {
*Decision
Name string
}{&n.decision, n.voter.Name}
}
func (n *NotificationWithDrawMotion) GetTemplate() string { return "withdraw_motion_mail.txt" }
func (n *NotificationWithDrawMotion) GetSubject() string {
return fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title)
}
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) GetHeaders() map[string]string {
return map[string]string{}
}
func (n *RemindVoterNotification) GetRecipient() (address string, name string) {
address, name = n.voter.Reminder, n.voter.Name
return
}
type voteNotificationBase struct{}
func (n *voteNotificationBase) GetRecipient() (address string, name string) {
address, name = config.VoteNoticeAddress, "CAcert board votes mailing list"
return
}
type NotificationProxyVote struct {
voteNotificationBase
decisionReplyBase
proxy Voter
voter Voter
vote Vote
justification string
}
func NewNotificationProxyVote(decision *Decision, proxy *Voter, voter *Voter, vote *Vote, justification string) *NotificationProxyVote {
notification := &NotificationProxyVote{proxy: *proxy, voter: *voter, vote: *vote, justification: justification}
notification.decision = *decision
return notification
}
func (n *NotificationProxyVote) GetData() interface{} {
return struct {
Proxy string
Vote VoteChoice
Voter string
Decision *Decision
Justification string
}{n.proxy.Name, n.vote.Vote, n.voter.Name, &n.decision, n.justification}
}
func (n *NotificationProxyVote) GetTemplate() string { return "proxy_vote_mail.txt" }
func (n *NotificationProxyVote) GetSubject() string {
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
}
type NotificationDirectVote struct {
voteNotificationBase
decisionReplyBase
voter Voter
vote Vote
}
func NewNotificationDirectVote(decision *Decision, voter *Voter, vote *Vote) *NotificationDirectVote {
notification := &NotificationDirectVote{voter: *voter, vote: *vote}
notification.decision = *decision
return notification
}
func (n *NotificationDirectVote) GetData() interface{} {
return struct {
Vote VoteChoice
Voter string
Decision *Decision
}{n.vote.Vote, n.voter.Name, &n.decision}
}
func (n *NotificationDirectVote) GetTemplate() string { return "direct_vote_mail.txt" }
func (n *NotificationDirectVote) GetSubject() string {
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
}