Refactor notifications to use a cleaner interface

debian
Jan Dittberner 7 years ago committed by Jan Dittberner
parent 8d1f18e16d
commit 12dd0717ad

@ -8,12 +8,27 @@ import (
"text/template" "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 { type NotificationMail interface {
GetData() interface{} GetNotificationContent() *notificationContent
GetTemplate() string
GetSubject() string
GetHeaders() map[string]string
GetRecipient() (string, string)
} }
var NotifyMailChannel = make(chan NotificationMail, 1) var NotifyMailChannel = make(chan NotificationMail, 1)
@ -23,19 +38,21 @@ func MailNotifier(quitMailNotifier chan int) {
for { for {
select { select {
case notification := <-NotifyMailChannel: case notification := <-NotifyMailChannel:
mailText, err := buildMail(notification.GetTemplate(), notification.GetData()) content := notification.GetNotificationContent()
mailText, err := buildMail(content.template, content.data)
if err != nil { if err != nil {
logger.Println("ERROR building mail:", err) logger.Println("ERROR building mail:", err)
continue continue
} }
m := gomail.NewMessage() m := gomail.NewMessage()
m.SetHeader("From", config.NotificationSenderAddress) m.SetAddressHeader("From", config.NotificationSenderAddress, "CAcert board voting system")
address, name := notification.GetRecipient() for _, recipient := range content.recipients {
m.SetAddressHeader("To", address, name) m.SetAddressHeader(recipient.field, recipient.address, recipient.name)
m.SetHeader("Subject", notification.GetSubject()) }
for header, value := range notification.GetHeaders() { m.SetHeader("Subject", content.subject)
m.SetHeader(header, value) for _, header := range content.headers {
m.SetHeader(header.name, header.value...)
} }
m.SetBody("text/plain", mailText.String()) m.SetBody("text/plain", mailText.String())
@ -65,45 +82,52 @@ func buildMail(templateName string, context interface{}) (mailText *bytes.Buffer
type notificationBase struct{} type notificationBase struct{}
func (n *notificationBase) GetRecipient() (address string, name string) { func (n *notificationBase) getRecipient() recipientData {
address, name = config.BoardMailAddress, "CAcert board mailing list" return recipientData{field: "To", address: config.BoardMailAddress, name: "CAcert board mailing list"}
return
} }
type decisionReplyBase struct { type decisionReplyBase struct {
decision Decision decision Decision
} }
func (n *decisionReplyBase) GetHeaders() map[string]string { func (n *decisionReplyBase) getHeaders() headerList {
return map[string]string{ headers := make(headerList, 0)
"References": fmt.Sprintf("<%s>", n.decision.Tag), headers = append(headers, headerData{
"In-Reply-To": fmt.Sprintf("<%s>", n.decision.Tag), 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 notificationBase
decisionReplyBase decisionReplyBase
voteSums VoteSums voteSums VoteSums
} }
func NewNotificationClosedDecision(decision *Decision, voteSums *VoteSums) *NotificationClosedDecision { func NewNotificationClosedDecision(decision *Decision, voteSums *VoteSums) NotificationMail {
notification := &NotificationClosedDecision{voteSums: *voteSums} notification := &notificationClosedDecision{voteSums: *voteSums}
notification.decision = *decision notification.decision = *decision
return notification return notification
} }
func (n *NotificationClosedDecision) GetData() interface{} { func (n *notificationClosedDecision) GetNotificationContent() *notificationContent {
return struct { return &notificationContent{
*Decision template: "closed_motion_mail.txt",
*VoteSums data: struct {
}{&n.decision, &n.voteSums} *Decision
} *VoteSums
}{&n.decision, &n.voteSums},
func (n *NotificationClosedDecision) GetTemplate() string { return "closed_motion_mail.txt" } subject: fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title),
headers: n.decisionReplyBase.getHeaders(),
func (n *NotificationClosedDecision) GetSubject() string { recipients: []recipientData{n.notificationBase.getRecipient()},
return fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title) }
} }
type NotificationCreateMotion struct { type NotificationCreateMotion struct {
@ -112,79 +136,75 @@ type NotificationCreateMotion struct {
voter Voter voter Voter
} }
func (n *NotificationCreateMotion) GetData() interface{} { func (n *NotificationCreateMotion) GetNotificationContent() *notificationContent {
voteURL := fmt.Sprintf("%s/vote/%s", config.BaseURL, n.decision.Tag) voteURL := fmt.Sprintf("%s/vote/%s", config.BaseURL, n.decision.Tag)
unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL) unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
return struct { return &notificationContent{
*Decision template: "create_motion_mail.txt",
Name string data: struct {
VoteURL string *Decision
UnvotedURL string Name string
}{&n.decision, n.voter.Name, voteURL, unvotedURL} VoteURL string
} UnvotedURL string
}{&n.decision, n.voter.Name, voteURL, unvotedURL},
func (n *NotificationCreateMotion) GetTemplate() string { return "create_motion_mail.txt" } subject: fmt.Sprintf("%s - %s", n.decision.Tag, n.decision.Title),
headers: headerList{headerData{"Message-ID", []string{fmt.Sprintf("<%s>", n.decision.Tag)}}},
func (n *NotificationCreateMotion) GetSubject() string { recipients: []recipientData{n.notificationBase.getRecipient()},
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 { type notificationUpdateMotion struct {
notificationBase notificationBase
decisionReplyBase decisionReplyBase
voter Voter voter Voter
} }
func NewNotificationUpdateMotion(decision Decision, voter Voter) *NotificationUpdateMotion { func NewNotificationUpdateMotion(decision Decision, voter Voter) NotificationMail {
notification := NotificationUpdateMotion{voter: voter} notification := notificationUpdateMotion{voter: voter}
notification.decision = decision notification.decision = decision
return &notification return &notification
} }
func (n *NotificationUpdateMotion) GetData() interface{} { func (n *notificationUpdateMotion) GetNotificationContent() *notificationContent {
voteURL := fmt.Sprintf("%s/vote/%s", config.BaseURL, n.decision.Tag) voteURL := fmt.Sprintf("%s/vote/%s", config.BaseURL, n.decision.Tag)
unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL) unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
return struct { return &notificationContent{
*Decision template: "update_motion_mail.txt",
Name string data: struct {
VoteURL string *Decision
UnvotedURL string Name string
}{&n.decision, n.voter.Name, voteURL, unvotedURL} VoteURL string
} UnvotedURL string
}{&n.decision, n.voter.Name, voteURL, unvotedURL},
func (n *NotificationUpdateMotion) GetTemplate() string { return "update_motion_mail.txt" } subject: n.decisionReplyBase.getSubject(),
headers: n.decisionReplyBase.getHeaders(),
func (n *NotificationUpdateMotion) GetSubject() string { recipients: []recipientData{n.notificationBase.getRecipient()},
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title) }
} }
type NotificationWithDrawMotion struct { type notificationWithDrawMotion struct {
notificationBase notificationBase
decisionReplyBase decisionReplyBase
voter Voter voter Voter
} }
func NewNotificationWithDrawMotion(decision *Decision, voter *Voter) *NotificationWithDrawMotion { func NewNotificationWithDrawMotion(decision *Decision, voter *Voter) NotificationMail {
notification := &NotificationWithDrawMotion{voter: *voter} notification := &notificationWithDrawMotion{voter: *voter}
notification.decision = *decision notification.decision = *decision
return notification return notification
} }
func (n *NotificationWithDrawMotion) GetData() interface{} { func (n *notificationWithDrawMotion) GetNotificationContent() *notificationContent {
return struct { return &notificationContent{
*Decision template: "withdraw_motion_mail.txt",
Name string data: struct {
}{&n.decision, n.voter.Name} *Decision
} Name string
}{&n.decision, n.voter.Name},
func (n *NotificationWithDrawMotion) GetTemplate() string { return "withdraw_motion_mail.txt" } subject: fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title),
headers: n.decisionReplyBase.getHeaders(),
func (n *NotificationWithDrawMotion) GetSubject() string { recipients: []recipientData{n.notificationBase.getRecipient()},
return fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title) }
} }
type RemindVoterNotification struct { type RemindVoterNotification struct {
@ -192,35 +212,26 @@ type RemindVoterNotification struct {
decisions []Decision decisions []Decision
} }
func (n *RemindVoterNotification) GetData() interface{} { func (n *RemindVoterNotification) GetNotificationContent() *notificationContent {
return struct { return &notificationContent{
Decisions []Decision template: "remind_voter_mail.txt",
Name string data: struct {
BaseURL string Decisions []Decision
}{n.decisions, n.voter.Name, config.BaseURL} Name string
} BaseURL string
}{n.decisions, n.voter.Name, config.BaseURL},
func (n *RemindVoterNotification) GetTemplate() string { return "remind_voter_mail.txt" } subject: "Outstanding CAcert board votes",
recipients: []recipientData{{"To", n.voter.Reminder, n.voter.Name}},
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{} type voteNotificationBase struct{}
func (n *voteNotificationBase) GetRecipient() (address string, name string) { func (n *voteNotificationBase) getRecipient() recipientData {
address, name = config.VoteNoticeAddress, "CAcert board votes mailing list" return recipientData{"To", config.VoteNoticeAddress, "CAcert board votes mailing list"}
return
} }
type NotificationProxyVote struct { type notificationProxyVote struct {
voteNotificationBase voteNotificationBase
decisionReplyBase decisionReplyBase
proxy Voter proxy Voter
@ -229,51 +240,51 @@ type NotificationProxyVote struct {
justification string justification string
} }
func NewNotificationProxyVote(decision *Decision, proxy *Voter, voter *Voter, vote *Vote, justification string) *NotificationProxyVote { func NewNotificationProxyVote(decision *Decision, proxy *Voter, voter *Voter, vote *Vote, justification string) NotificationMail {
notification := &NotificationProxyVote{proxy: *proxy, voter: *voter, vote: *vote, justification: justification} notification := &notificationProxyVote{proxy: *proxy, voter: *voter, vote: *vote, justification: justification}
notification.decision = *decision notification.decision = *decision
return notification return notification
} }
func (n *NotificationProxyVote) GetData() interface{} { func (n *notificationProxyVote) GetNotificationContent() *notificationContent {
return struct { return &notificationContent{
Proxy string template: "proxy_vote_mail.txt",
Vote VoteChoice data: struct {
Voter string Proxy string
Decision *Decision Vote VoteChoice
Justification string Voter string
}{n.proxy.Name, n.vote.Vote, n.voter.Name, &n.decision, n.justification} 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" } subject: n.decisionReplyBase.getSubject(),
headers: n.decisionReplyBase.getHeaders(),
func (n *NotificationProxyVote) GetSubject() string { recipients: []recipientData{n.voteNotificationBase.getRecipient()},
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title) }
} }
type NotificationDirectVote struct { type notificationDirectVote struct {
voteNotificationBase voteNotificationBase
decisionReplyBase decisionReplyBase
voter Voter voter Voter
vote Vote vote Vote
} }
func NewNotificationDirectVote(decision *Decision, voter *Voter, vote *Vote) *NotificationDirectVote { func NewNotificationDirectVote(decision *Decision, voter *Voter, vote *Vote) NotificationMail {
notification := &NotificationDirectVote{voter: *voter, vote: *vote} notification := &notificationDirectVote{voter: *voter, vote: *vote}
notification.decision = *decision notification.decision = *decision
return notification return notification
} }
func (n *NotificationDirectVote) GetData() interface{} { func (n *notificationDirectVote) GetNotificationContent() *notificationContent {
return struct { return &notificationContent{
Vote VoteChoice template: "direct_vote_mail.txt",
Voter string data: struct {
Decision *Decision Vote VoteChoice
}{n.vote.Vote, n.voter.Name, &n.decision} Voter string
} Decision *Decision
}{n.vote.Vote, n.voter.Name, &n.decision},
func (n *NotificationDirectVote) GetTemplate() string { return "direct_vote_mail.txt" } subject: n.decisionReplyBase.getSubject(),
headers: n.decisionReplyBase.getHeaders(),
func (n *NotificationDirectVote) GetSubject() string { recipients: []recipientData{n.voteNotificationBase.getRecipient()},
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title) }
} }

Loading…
Cancel
Save