Implement reminder job
[cacert-boardvoting.git] / notifications.go
1 package main
2
3 import (
4 "bytes"
5 "fmt"
6 "github.com/Masterminds/sprig"
7 "gopkg.in/gomail.v2"
8 "text/template"
9 )
10
11 type NotificationMail interface {
12 GetData() interface{}
13 GetTemplate() string
14 GetSubject() string
15 GetHeaders() map[string]string
16 }
17
18 type VoterMail interface {
19 GetData() interface{}
20 GetTemplate() string
21 GetSubject() string
22 GetRecipient() (string, string)
23 }
24
25 var notifyMail = make(chan NotificationMail, 1)
26 var voterMail = make(chan VoterMail, 1)
27 var quitMailNotifier = make(chan int)
28
29 func CloseMailNotifier() {
30 quitMailNotifier <- 1
31 }
32
33 func MailNotifier() {
34 logger.Println("Launched mail notifier")
35 for {
36 select {
37 case notification := <-notifyMail:
38 mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
39 if err != nil {
40 logger.Println("ERROR building mail:", err)
41 continue
42 }
43
44 m := gomail.NewMessage()
45 m.SetHeader("From", config.NoticeSenderAddress)
46 m.SetHeader("To", config.BoardMailAddress)
47 m.SetHeader("Subject", notification.GetSubject())
48 for header, value := range notification.GetHeaders() {
49 m.SetHeader(header, value)
50 }
51 m.SetBody("text/plain", mailText.String())
52
53 d := gomail.NewDialer(config.MailServer.Host, config.MailServer.Port, "", "")
54 if err := d.DialAndSend(m); err != nil {
55 logger.Println("ERROR sending mail:", err)
56 }
57 case notification := <-voterMail:
58 mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
59 if err != nil {
60 logger.Println("ERROR building mail:", err)
61 continue
62 }
63
64 m := gomail.NewMessage()
65 m.SetHeader("From", config.ReminderSenderAddress)
66 address, name := notification.GetRecipient()
67 m.SetAddressHeader("To", address, name)
68 m.SetHeader("Subject", notification.GetSubject())
69 m.SetBody("text/plain", mailText.String())
70
71 d := gomail.NewDialer(config.MailServer.Host, config.MailServer.Port, "", "")
72 if err := d.DialAndSend(m); err != nil {
73 logger.Println("ERROR sending mail:", err)
74 }
75 case <-quitMailNotifier:
76 fmt.Println("Ending mail notifier")
77 return
78 }
79 }
80 }
81
82 func buildMail(templateName string, context interface{}) (mailText *bytes.Buffer, err error) {
83 t, err := template.New(templateName).Funcs(
84 sprig.GenericFuncMap()).ParseFiles(fmt.Sprintf("templates/%s", templateName))
85 if err != nil {
86 return
87 }
88
89 mailText = bytes.NewBufferString("")
90 t.Execute(mailText, context)
91
92 return
93 }
94
95 type NotificationClosedDecision struct {
96 decision Decision
97 voteSums VoteSums
98 }
99
100 func (n *NotificationClosedDecision) GetData() interface{} {
101 return struct {
102 *Decision
103 *VoteSums
104 }{&n.decision, &n.voteSums}
105 }
106
107 func (n *NotificationClosedDecision) GetTemplate() string { return "closed_motion_mail.txt" }
108
109 func (n *NotificationClosedDecision) GetSubject() string {
110 return fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title)
111 }
112
113 func (n *NotificationClosedDecision) GetHeaders() map[string]string {
114 return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
115 }
116
117 type NotificationCreateMotion struct {
118 decision Decision
119 voter Voter
120 }
121
122 func (n *NotificationCreateMotion) GetData() interface{} {
123 voteURL := fmt.Sprintf("%s/vote", config.BaseURL)
124 unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
125 return struct {
126 *Decision
127 Name string
128 VoteURL string
129 UnvotedURL string
130 }{&n.decision, n.voter.Name, voteURL, unvotedURL}
131 }
132
133 func (n *NotificationCreateMotion) GetTemplate() string { return "create_motion_mail.txt" }
134
135 func (n *NotificationCreateMotion) GetSubject() string {
136 return fmt.Sprintf("%s - %s", n.decision.Tag, n.decision.Title)
137 }
138
139 func (n *NotificationCreateMotion) GetHeaders() map[string]string {
140 return map[string]string{"Message-ID": fmt.Sprintf("<%s>", n.decision.Tag)}
141 }
142
143 type NotificationUpdateMotion struct {
144 decision Decision
145 voter Voter
146 }
147
148 func (n *NotificationUpdateMotion) GetData() interface{} {
149 voteURL := fmt.Sprintf("%s/vote", config.BaseURL)
150 unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
151 return struct {
152 *Decision
153 Name string
154 VoteURL string
155 UnvotedURL string
156 }{&n.decision, n.voter.Name, voteURL, unvotedURL}
157 }
158
159 func (n *NotificationUpdateMotion) GetTemplate() string { return "update_motion_mail.txt" }
160
161 func (n *NotificationUpdateMotion) GetSubject() string {
162 return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
163 }
164
165 func (n *NotificationUpdateMotion) GetHeaders() map[string]string {
166 return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
167 }
168
169 type NotificationWithDrawMotion struct {
170 decision Decision
171 voter Voter
172 }
173
174 func (n *NotificationWithDrawMotion) GetData() interface{} {
175 return struct {
176 *Decision
177 Name string
178 }{&n.decision, n.voter.Name}
179 }
180
181 func (n *NotificationWithDrawMotion) GetTemplate() string { return "withdraw_motion_mail.txt" }
182
183 func (n *NotificationWithDrawMotion) GetSubject() string {
184 return fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title)
185 }
186
187 func (n *NotificationWithDrawMotion) GetHeaders() map[string]string {
188 return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
189 }
190
191 type RemindVoterNotification struct {
192 voter Voter
193 decisions []Decision
194 }
195
196 func (n *RemindVoterNotification) GetData() interface{} {
197 return struct {
198 Decisions []Decision
199 Name string
200 BaseURL string
201 }{n.decisions, n.voter.Name, config.BaseURL}
202 }
203
204 func (n *RemindVoterNotification) GetTemplate() string { return "remind_voter_mail.txt" }
205
206 func (n *RemindVoterNotification) GetSubject() string { return "Outstanding CAcert board votes" }
207
208 func (n *RemindVoterNotification) GetRecipient() (address string, name string) {
209 address, name = n.voter.Reminder, n.voter.Name
210 return
211 }