Refactor notifications to use a cleaner interface
This commit is contained in:
parent
8d1f18e16d
commit
12dd0717ad
1 changed files with 146 additions and 135 deletions
281
notifications.go
281
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
|
||||
}
|
||||
|
||||
type NotificationClosedDecision struct {
|
||||
func (n *decisionReplyBase) getSubject() string {
|
||||
return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
|
||||
}
|
||||
|
||||
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 := ¬ificationClosedDecision{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 ¬ificationContent{
|
||||
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}
|
||||
return ¬ificationContent{
|
||||
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()},
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 ¬ification
|
||||
}
|
||||
|
||||
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}
|
||||
return ¬ificationContent{
|
||||
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()},
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 := ¬ificationWithDrawMotion{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 ¬ificationContent{
|
||||
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 ¬ificationContent{
|
||||
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 := ¬ificationProxyVote{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) GetNotificationContent() *notificationContent {
|
||||
return ¬ificationContent{
|
||||
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()},
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 := ¬ificationDirectVote{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 ¬ificationContent{
|
||||
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()},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue