summaryrefslogtreecommitdiff
path: root/notifications.go
diff options
context:
space:
mode:
authorJan Dittberner <jandd@cacert.org>2017-04-21 12:50:29 +0200
committerJan Dittberner <jan@dittberner.info>2017-04-22 00:14:11 +0200
commit12dd0717ad0bb2389b38161f9fd6ff71e4cc0c62 (patch)
tree6d3ba7c40865e880a3e55e6bef2150e4499c5d45 /notifications.go
parent8d1f18e16dcf44001155e8dff273f82900899d76 (diff)
downloadcacert-boardvoting-12dd0717ad0bb2389b38161f9fd6ff71e4cc0c62.tar.gz
cacert-boardvoting-12dd0717ad0bb2389b38161f9fd6ff71e4cc0c62.tar.xz
cacert-boardvoting-12dd0717ad0bb2389b38161f9fd6ff71e4cc0c62.zip
Refactor notifications to use a cleaner interface
Diffstat (limited to 'notifications.go')
-rw-r--r--notifications.go281
1 files changed, 146 insertions, 135 deletions
diff --git a/notifications.go b/notifications.go
index 4a76710..d4c405a 100644
--- a/notifications.go
+++ b/notifications.go
@@ -8,12 +8,27 @@ import (
"text/template"
)
+type headerData struct {
+ name string
+ value []string
+}
+
+type headerList []headerData
+
+type recipientData struct {
+ field, address, name string
+}
+
+type notificationContent struct {
+ template string
+ data interface{}
+ subject string
+ headers headerList
+ recipients []recipientData
+}
+
type NotificationMail interface {
- GetData() interface{}
- GetTemplate() string
- GetSubject() string
- GetHeaders() map[string]string
- GetRecipient() (string, string)
+ GetNotificationContent() *notificationContent
}
var NotifyMailChannel = make(chan NotificationMail, 1)
@@ -23,19 +38,21 @@ func MailNotifier(quitMailNotifier chan int) {
for {
select {
case notification := <-NotifyMailChannel:
- mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
+ content := notification.GetNotificationContent()
+ mailText, err := buildMail(content.template, content.data)
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.SetAddressHeader("From", config.NotificationSenderAddress, "CAcert board voting system")
+ for _, recipient := range content.recipients {
+ m.SetAddressHeader(recipient.field, recipient.address, recipient.name)
+ }
+ m.SetHeader("Subject", content.subject)
+ for _, header := range content.headers {
+ m.SetHeader(header.name, header.value...)
}
m.SetBody("text/plain", mailText.String())
@@ -65,45 +82,52 @@ func buildMail(templateName string, context interface{}) (mailText *bytes.Buffer
type notificationBase struct{}
-func (n *notificationBase) GetRecipient() (address string, name string) {
- address, name = config.BoardMailAddress, "CAcert board mailing list"
- return
+func (n *notificationBase) getRecipient() recipientData {
+ return recipientData{field: "To", address: config.BoardMailAddress, name: "CAcert board mailing list"}
}
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),
- }
+func (n *decisionReplyBase) getHeaders() headerList {
+ headers := make(headerList, 0)
+ headers = append(headers, headerData{
+ name: "References", value: []string{fmt.Sprintf("<%s>", n.decision.Tag)},
+ })
+ headers = append(headers, headerData{
+ name: "In-Reply-To", value: []string{fmt.Sprintf("<%s>", n.decision.Tag)},
+ })
+ return headers
+}
+
+func (n *decisionReplyBase) getSubject() string {
+ return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
}
-type NotificationClosedDecision struct {
+type notificationClosedDecision struct {
notificationBase
decisionReplyBase
voteSums VoteSums
}
-func NewNotificationClosedDecision(decision *Decision, voteSums *VoteSums) *NotificationClosedDecision {
- notification := &NotificationClosedDecision{voteSums: *voteSums}
+func NewNotificationClosedDecision(decision *Decision, voteSums *VoteSums) NotificationMail {
+ 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)
+func (n *notificationClosedDecision) GetNotificationContent() *notificationContent {
+ return &notificationContent{
+ template: "closed_motion_mail.txt",
+ data: struct {
+ *Decision
+ *VoteSums
+ }{&n.decision, &n.voteSums},
+ subject: fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title),
+ headers: n.decisionReplyBase.getHeaders(),
+ recipients: []recipientData{n.notificationBase.getRecipient()},
+ }
}
type NotificationCreateMotion struct {
@@ -112,79 +136,75 @@ type NotificationCreateMotion struct {
voter Voter
}
-func (n *NotificationCreateMotion) GetData() interface{} {
+func (n *NotificationCreateMotion) GetNotificationContent() *notificationContent {
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)}
+ return &notificationContent{
+ template: "create_motion_mail.txt",
+ data: struct {
+ *Decision
+ Name string
+ VoteURL string
+ UnvotedURL string
+ }{&n.decision, n.voter.Name, voteURL, unvotedURL},
+ subject: fmt.Sprintf("%s - %s", n.decision.Tag, n.decision.Title),
+ headers: headerList{headerData{"Message-ID", []string{fmt.Sprintf("<%s>", n.decision.Tag)}}},
+ recipients: []recipientData{n.notificationBase.getRecipient()},
+ }
}
-type NotificationUpdateMotion struct {
+type notificationUpdateMotion struct {
notificationBase
decisionReplyBase
voter Voter
}
-func NewNotificationUpdateMotion(decision Decision, voter Voter) *NotificationUpdateMotion {
- notification := NotificationUpdateMotion{voter: voter}
+func NewNotificationUpdateMotion(decision Decision, voter Voter) NotificationMail {
+ notification := notificationUpdateMotion{voter: voter}
notification.decision = decision
return &notification
}
-func (n *NotificationUpdateMotion) GetData() interface{} {
+func (n *notificationUpdateMotion) GetNotificationContent() *notificationContent {
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)
+ return &notificationContent{
+ template: "update_motion_mail.txt",
+ data: struct {
+ *Decision
+ Name string
+ VoteURL string
+ UnvotedURL string
+ }{&n.decision, n.voter.Name, voteURL, unvotedURL},
+ subject: n.decisionReplyBase.getSubject(),
+ headers: n.decisionReplyBase.getHeaders(),
+ recipients: []recipientData{n.notificationBase.getRecipient()},
+ }
}
-type NotificationWithDrawMotion struct {
+type notificationWithDrawMotion struct {
notificationBase
decisionReplyBase
voter Voter
}
-func NewNotificationWithDrawMotion(decision *Decision, voter *Voter) *NotificationWithDrawMotion {
- notification := &NotificationWithDrawMotion{voter: *voter}
+func NewNotificationWithDrawMotion(decision *Decision, voter *Voter) NotificationMail {
+ 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)
+func (n *notificationWithDrawMotion) GetNotificationContent() *notificationContent {
+ return &notificationContent{
+ template: "withdraw_motion_mail.txt",
+ data: struct {
+ *Decision
+ Name string
+ }{&n.decision, n.voter.Name},
+ subject: fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title),
+ headers: n.decisionReplyBase.getHeaders(),
+ recipients: []recipientData{n.notificationBase.getRecipient()},
+ }
}
type RemindVoterNotification struct {
@@ -192,35 +212,26 @@ type RemindVoterNotification struct {
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
+func (n *RemindVoterNotification) GetNotificationContent() *notificationContent {
+ return &notificationContent{
+ template: "remind_voter_mail.txt",
+ data: struct {
+ Decisions []Decision
+ Name string
+ BaseURL string
+ }{n.decisions, n.voter.Name, config.BaseURL},
+ subject: "Outstanding CAcert board votes",
+ recipients: []recipientData{{"To", n.voter.Reminder, n.voter.Name}},
+ }
}
type voteNotificationBase struct{}
-func (n *voteNotificationBase) GetRecipient() (address string, name string) {
- address, name = config.VoteNoticeAddress, "CAcert board votes mailing list"
- return
+func (n *voteNotificationBase) getRecipient() recipientData {
+ return recipientData{"To", config.VoteNoticeAddress, "CAcert board votes mailing list"}
}
-type NotificationProxyVote struct {
+type notificationProxyVote struct {
voteNotificationBase
decisionReplyBase
proxy Voter
@@ -229,51 +240,51 @@ type NotificationProxyVote struct {
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}
+func NewNotificationProxyVote(decision *Decision, proxy *Voter, voter *Voter, vote *Vote, justification string) NotificationMail {
+ 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)
+func (n *notificationProxyVote) GetNotificationContent() *notificationContent {
+ return &notificationContent{
+ template: "proxy_vote_mail.txt",
+ data: struct {
+ Proxy string
+ Vote VoteChoice
+ Voter string
+ Decision *Decision
+ Justification string
+ }{n.proxy.Name, n.vote.Vote, n.voter.Name, &n.decision, n.justification},
+ subject: n.decisionReplyBase.getSubject(),
+ headers: n.decisionReplyBase.getHeaders(),
+ recipients: []recipientData{n.voteNotificationBase.getRecipient()},
+ }
}
-type NotificationDirectVote struct {
+type notificationDirectVote struct {
voteNotificationBase
decisionReplyBase
voter Voter
vote Vote
}
-func NewNotificationDirectVote(decision *Decision, voter *Voter, vote *Vote) *NotificationDirectVote {
- notification := &NotificationDirectVote{voter: *voter, vote: *vote}
+func NewNotificationDirectVote(decision *Decision, voter *Voter, vote *Vote) NotificationMail {
+ 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)
+func (n *notificationDirectVote) GetNotificationContent() *notificationContent {
+ return &notificationContent{
+ template: "direct_vote_mail.txt",
+ data: struct {
+ Vote VoteChoice
+ Voter string
+ Decision *Decision
+ }{n.vote.Vote, n.voter.Name, &n.decision},
+ subject: n.decisionReplyBase.getSubject(),
+ headers: n.decisionReplyBase.getHeaders(),
+ recipients: []recipientData{n.voteNotificationBase.getRecipient()},
+ }
}