Implement vote closing, refactor notifications
[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 var notifyMail = make(chan NotificationMail, 1)
19 var quitMailNotifier = make(chan int)
20
21 func CloseMailNotifier() {
22 quitMailNotifier <- 1
23 }
24
25 func MailNotifier() {
26 logger.Println("Launched mail notifier")
27 for {
28 select {
29 case notification := <-notifyMail:
30 mailText, err := buildMail(notification.GetTemplate(), notification.GetData())
31 if err != nil {
32 logger.Println("ERROR building mail:", err)
33 continue
34 }
35
36 m := gomail.NewMessage()
37 m.SetHeader("From", config.NoticeSenderAddress)
38 m.SetHeader("To", config.BoardMailAddress)
39 m.SetHeader("Subject", notification.GetSubject())
40 for header, value := range notification.GetHeaders() {
41 m.SetHeader(header, value)
42 }
43 m.SetBody("text/plain", mailText.String())
44
45 d := gomail.NewDialer(config.MailServer.Host, config.MailServer.Port, "", "")
46 if err := d.DialAndSend(m); err != nil {
47 logger.Println("ERROR sending mail:", err)
48 }
49 case <-quitMailNotifier:
50 fmt.Println("Ending mail notifier")
51 return
52 }
53 }
54 }
55
56 func buildMail(templateName string, context interface{}) (mailText *bytes.Buffer, err error) {
57 t, err := template.New(templateName).Funcs(
58 sprig.GenericFuncMap()).ParseFiles(fmt.Sprintf("templates/%s", templateName))
59 if err != nil {
60 return
61 }
62
63 mailText = bytes.NewBufferString("")
64 t.Execute(mailText, context)
65
66 return
67 }
68
69 type NotificationClosedDecision struct {
70 decision Decision
71 voteSums VoteSums
72 }
73
74 func (n *NotificationClosedDecision) GetData() interface{} {
75 return struct {
76 *Decision
77 *VoteSums
78 }{&n.decision, &n.voteSums}
79 }
80
81 func (n *NotificationClosedDecision) GetTemplate() string {
82 return "closed_motion_mail.txt"
83 }
84
85 func (n *NotificationClosedDecision) GetSubject() string {
86 return fmt.Sprintf("Re: %s - %s - finalised", n.decision.Tag, n.decision.Title)
87 }
88
89 func (n *NotificationClosedDecision) GetHeaders() map[string]string {
90 return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
91 }
92
93 type NotificationCreateMotion struct {
94 decision Decision
95 voter Voter
96 }
97
98 func (n *NotificationCreateMotion) GetData() interface{} {
99 voteURL := fmt.Sprintf("%s/vote", config.BaseURL)
100 unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
101 return struct {
102 *Decision
103 Name string
104 VoteURL string
105 UnvotedURL string
106 }{&n.decision, n.voter.Name, voteURL, unvotedURL}
107 }
108
109 func (n *NotificationCreateMotion) GetTemplate() string {
110 return "create_motion_mail.txt"
111 }
112
113 func (n *NotificationCreateMotion) GetSubject() string {
114 return fmt.Sprintf("%s - %s", n.decision.Tag, n.decision.Title)
115 }
116
117 func (n *NotificationCreateMotion) GetHeaders() map[string]string {
118 return map[string]string{"Message-ID": fmt.Sprintf("<%s>", n.decision.Tag)}
119 }
120
121 type NotificationUpdateMotion struct {
122 decision Decision
123 voter Voter
124 }
125
126 func (n *NotificationUpdateMotion) GetData() interface{} {
127 voteURL := fmt.Sprintf("%s/vote", config.BaseURL)
128 unvotedURL := fmt.Sprintf("%s/motions/?unvoted=1", config.BaseURL)
129 return struct {
130 *Decision
131 Name string
132 VoteURL string
133 UnvotedURL string
134 }{&n.decision, n.voter.Name, voteURL, unvotedURL}
135 }
136
137 func (n *NotificationUpdateMotion) GetTemplate() string {
138 return "update_motion_mail.txt"
139 }
140
141 func (n *NotificationUpdateMotion) GetSubject() string {
142 return fmt.Sprintf("Re: %s - %s", n.decision.Tag, n.decision.Title)
143 }
144
145 func (n *NotificationUpdateMotion) GetHeaders() map[string]string {
146 return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
147 }
148
149 type NotificationWithDrawMotion struct {
150 decision Decision
151 voter Voter
152 }
153
154 func (n *NotificationWithDrawMotion) GetData() interface{} {
155 return struct {
156 *Decision
157 Name string
158 }{&n.decision, n.voter.Name}
159 }
160
161 func (n *NotificationWithDrawMotion) GetTemplate() string {
162 return "withdraw_motion_mail.txt"
163 }
164
165 func (n *NotificationWithDrawMotion) GetSubject() string {
166 return fmt.Sprintf("Re: %s - %s - withdrawn", n.decision.Tag, n.decision.Title)
167 }
168
169 func (n *NotificationWithDrawMotion) GetHeaders() map[string]string {
170 return map[string]string{"References": fmt.Sprintf("<%s>", n.decision.Tag)}
171 }