notify.py 22 KB
Newer Older
1
#!/usr/bin/env python3
2
3
4
5
6
7

import email.mime.text
import subprocess
import sys
import textwrap

Lukas Fleischer's avatar
Lukas Fleischer committed
8
9
import aurweb.config
import aurweb.db
Lukas Fleischer's avatar
Lukas Fleischer committed
10
import aurweb.l10n
11

Lukas Fleischer's avatar
Lukas Fleischer committed
12
aur_location = aurweb.config.get('options', 'aur_location')
13
14


15
16
17
def headers_cc(cclist):
    return {'Cc': str.join(', ', cclist)}

18

19
20
21
def headers_msgid(thread_id):
    return {'Message-ID': thread_id}

22

23
24
25
def headers_reply(thread_id):
    return {'In-Reply-To': thread_id, 'References': thread_id}

26

Lukas Fleischer's avatar
Lukas Fleischer committed
27
28
def username_from_id(conn, uid):
    cur = conn.execute('SELECT UserName FROM Users WHERE ID = ?', [uid])
29
30
    return cur.fetchone()[0]

31

Lukas Fleischer's avatar
Lukas Fleischer committed
32
33
34
def pkgbase_from_id(conn, pkgbase_id):
    cur = conn.execute('SELECT Name FROM PackageBases WHERE ID = ?',
                       [pkgbase_id])
35
36
    return cur.fetchone()[0]

37

Lukas Fleischer's avatar
Lukas Fleischer committed
38
39
40
def pkgbase_from_pkgreq(conn, reqid):
    cur = conn.execute('SELECT PackageBaseID FROM PackageRequests ' +
                       'WHERE ID = ?', [reqid])
41
42
    return cur.fetchone()[0]

43

44
class Notification:
Lukas Fleischer's avatar
Lukas Fleischer committed
45
46
47
    def __init__(self):
        self._l10n = aurweb.l10n.Translator()

48
49
50
51
52
53
    def get_refs(self):
        return ()

    def get_headers(self):
        return {}

Lukas Fleischer's avatar
Lukas Fleischer committed
54
    def get_body_fmt(self, lang):
55
        body = ''
Lukas Fleischer's avatar
Lukas Fleischer committed
56
        for line in self.get_body(lang).splitlines():
57
58
59
            if line == '-- ':
                body += '-- \n'
                continue
60
61
62
            body += textwrap.fill(line, break_long_words=False) + '\n'
        for i, ref in enumerate(self.get_refs()):
            body += '\n' + '[%d] %s' % (i + 1, ref)
Lukas Fleischer's avatar
Lukas Fleischer committed
63
        return body.rstrip()
64

Lukas Fleischer's avatar
Lukas Fleischer committed
65
    def send(self):
66
67
68
        sendmail = aurweb.config.get('notifications', 'sendmail')
        sender = aurweb.config.get('notifications', 'sender')
        reply_to = aurweb.config.get('notifications', 'reply-to')
69
70
71
        reason = self.__class__.__name__
        if reason.endswith('Notification'):
            reason = reason[:-len('Notification')]
72
73

        for recipient in self.get_recipients():
Lukas Fleischer's avatar
Lukas Fleischer committed
74
75
76
77
            to, lang = recipient
            msg = email.mime.text.MIMEText(self.get_body_fmt(lang),
                                           'plain', 'utf-8')
            msg['Subject'] = self.get_subject(lang)
78
79
            msg['From'] = sender
            msg['Reply-to'] = reply_to
Lukas Fleischer's avatar
Lukas Fleischer committed
80
            msg['To'] = to
81
            msg['X-AUR-Reason'] = reason
82
83
84
85
86
87
88
89
90
91
92

            for key, value in self.get_headers().items():
                msg[key] = value

            p = subprocess.Popen([sendmail, '-t', '-oi'],
                                 stdin=subprocess.PIPE)
            p.communicate(msg.as_bytes())


class ResetKeyNotification(Notification):
    def __init__(self, conn, uid):
93
94
95
96
        cur = conn.execute('SELECT UserName, Email, BackupEmail, ' +
                           'LangPreference, ResetKey ' +
                           'FROM Users WHERE ID = ?', [uid])
        self._username, self._to, self._backup, self._lang, self._resetkey = cur.fetchone()
Lukas Fleischer's avatar
Lukas Fleischer committed
97
        super().__init__()
98
99

    def get_recipients(self):
100
101
102
103
        if self._backup:
            return [(self._to, self._lang), (self._backup, self._lang)]
        else:
            return [(self._to, self._lang)]
104

Lukas Fleischer's avatar
Lukas Fleischer committed
105
106
    def get_subject(self, lang):
        return self._l10n.translate('AUR Password Reset', lang)
107

Lukas Fleischer's avatar
Lukas Fleischer committed
108
109
    def get_body(self, lang):
        return self._l10n.translate(
110
111
112
113
114
                'A password reset request was submitted for the account '
                '{user} associated with your email address. If you wish to '
                'reset your password follow the link [1] below, otherwise '
                'ignore this message and nothing will happen.',
                lang).format(user=self._username)
115
116
117
118
119
120

    def get_refs(self):
        return (aur_location + '/passreset/?resetkey=' + self._resetkey,)


class WelcomeNotification(ResetKeyNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
121
122
123
    def get_subject(self, lang):
        return self._l10n.translate('Welcome to the Arch User Repository',
                                    lang)
124

Lukas Fleischer's avatar
Lukas Fleischer committed
125
126
127
128
129
130
    def get_body(self, lang):
        return self._l10n.translate(
                'Welcome to the Arch User Repository! In order to set an '
                'initial password for your new account, please click the '
                'link [1] below. If the link does not work, try copying and '
                'pasting it into your browser.', lang)
131
132
133
134
135
136


class CommentNotification(Notification):
    def __init__(self, conn, uid, pkgbase_id, comment_id):
        self._user = username_from_id(conn, uid)
        self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
Lukas Fleischer's avatar
Lukas Fleischer committed
137
138
        cur = conn.execute('SELECT DISTINCT Users.Email, Users.LangPreference '
                           'FROM Users INNER JOIN PackageNotifications ' +
139
140
141
142
143
                           'ON PackageNotifications.UserID = Users.ID WHERE ' +
                           'Users.CommentNotify = 1 AND ' +
                           'PackageNotifications.UserID != ? AND ' +
                           'PackageNotifications.PackageBaseID = ?',
                           [uid, pkgbase_id])
Lukas Fleischer's avatar
Lukas Fleischer committed
144
        self._recipients = cur.fetchall()
145
146
147
        cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?',
                           [comment_id])
        self._text = cur.fetchone()[0]
Lukas Fleischer's avatar
Lukas Fleischer committed
148
        super().__init__()
149
150

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
151
        return self._recipients
152

Lukas Fleischer's avatar
Lukas Fleischer committed
153
    def get_subject(self, lang):
154
155
        return self._l10n.translate('AUR Comment for {pkgbase}',
                                    lang).format(pkgbase=self._pkgbase)
156

Lukas Fleischer's avatar
Lukas Fleischer committed
157
158
    def get_body(self, lang):
        body = self._l10n.translate(
159
160
                '{user} [1] added the following comment to {pkgbase} [2]:',
                lang).format(user=self._user, pkgbase=self._pkgbase)
161
        body += '\n\n' + self._text + '\n\n-- \n'
Lukas Fleischer's avatar
Lukas Fleischer committed
162
163
164
165
        dnlabel = self._l10n.translate('Disable notifications', lang)
        body += self._l10n.translate(
                'If you no longer wish to receive notifications about this '
                'package, please go to the package page [2] and select '
166
                '"{label}".', lang).format(label=dnlabel)
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        return body

    def get_refs(self):
        return (aur_location + '/account/' + self._user + '/',
                aur_location + '/pkgbase/' + self._pkgbase + '/')

    def get_headers(self):
        thread_id = '<pkg-notifications-' + self._pkgbase + \
                    '@aur.archlinux.org>'
        return headers_reply(thread_id)


class UpdateNotification(Notification):
    def __init__(self, conn, uid, pkgbase_id):
        self._user = username_from_id(conn, uid)
        self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
Lukas Fleischer's avatar
Lukas Fleischer committed
183
184
        cur = conn.execute('SELECT DISTINCT Users.Email, ' +
                           'Users.LangPreference FROM Users ' +
185
186
187
188
189
190
                           'INNER JOIN PackageNotifications ' +
                           'ON PackageNotifications.UserID = Users.ID WHERE ' +
                           'Users.UpdateNotify = 1 AND ' +
                           'PackageNotifications.UserID != ? AND ' +
                           'PackageNotifications.PackageBaseID = ?',
                           [uid, pkgbase_id])
Lukas Fleischer's avatar
Lukas Fleischer committed
191
192
        self._recipients = cur.fetchall()
        super().__init__()
193
194

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
195
        return self._recipients
196

Lukas Fleischer's avatar
Lukas Fleischer committed
197
    def get_subject(self, lang):
198
199
        return self._l10n.translate('AUR Package Update: {pkgbase}',
                                    lang).format(pkgbase=self._pkgbase)
200

Lukas Fleischer's avatar
Lukas Fleischer committed
201
    def get_body(self, lang):
202
203
204
205
        body = self._l10n.translate('{user} [1] pushed a new commit to '
                                    '{pkgbase} [2].', lang).format(
                                            user=self._user,
                                            pkgbase=self._pkgbase)
206
        body += '\n\n-- \n'
Lukas Fleischer's avatar
Lukas Fleischer committed
207
208
209
210
        dnlabel = self._l10n.translate('Disable notifications', lang)
        body += self._l10n.translate(
                'If you no longer wish to receive notifications about this '
                'package, please go to the package page [2] and select '
211
                '"{label}".', lang).format(label=dnlabel)
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
        return body

    def get_refs(self):
        return (aur_location + '/account/' + self._user + '/',
                aur_location + '/pkgbase/' + self._pkgbase + '/')

    def get_headers(self):
        thread_id = '<pkg-notifications-' + self._pkgbase + \
                    '@aur.archlinux.org>'
        return headers_reply(thread_id)


class FlagNotification(Notification):
    def __init__(self, conn, uid, pkgbase_id):
        self._user = username_from_id(conn, uid)
        self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
Lukas Fleischer's avatar
Lukas Fleischer committed
228
229
        cur = conn.execute('SELECT DISTINCT Users.Email, ' +
                           'Users.LangPreference FROM Users ' +
230
231
232
233
234
235
                           'LEFT JOIN PackageComaintainers ' +
                           'ON PackageComaintainers.UsersID = Users.ID ' +
                           'INNER JOIN PackageBases ' +
                           'ON PackageBases.MaintainerUID = Users.ID OR ' +
                           'PackageBases.ID = PackageComaintainers.PackageBaseID ' +
                           'WHERE PackageBases.ID = ?', [pkgbase_id])
Lukas Fleischer's avatar
Lukas Fleischer committed
236
        self._recipients = cur.fetchall()
237
238
239
        cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' +
                           'ID = ?', [pkgbase_id])
        self._text = cur.fetchone()[0]
Lukas Fleischer's avatar
Lukas Fleischer committed
240
        super().__init__()
241
242

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
243
        return self._recipients
244

Lukas Fleischer's avatar
Lukas Fleischer committed
245
    def get_subject(self, lang):
246
247
248
        return self._l10n.translate('AUR Out-of-date Notification for '
                                    '{pkgbase}',
                                    lang).format(pkgbase=self._pkgbase)
249

Lukas Fleischer's avatar
Lukas Fleischer committed
250
251
    def get_body(self, lang):
        body = self._l10n.translate(
252
253
254
                'Your package {pkgbase} [1] has been flagged out-of-date by '
                '{user} [2]:', lang).format(pkgbase=self._pkgbase,
                                            user=self._user)
255
256
257
258
259
260
261
262
263
264
265
266
        body += '\n\n' + self._text
        return body

    def get_refs(self):
        return (aur_location + '/pkgbase/' + self._pkgbase + '/',
                aur_location + '/account/' + self._user + '/')


class OwnershipEventNotification(Notification):
    def __init__(self, conn, uid, pkgbase_id):
        self._user = username_from_id(conn, uid)
        self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
Lukas Fleischer's avatar
Lukas Fleischer committed
267
268
        cur = conn.execute('SELECT DISTINCT Users.Email, ' +
                           'Users.LangPreference FROM Users ' +
269
270
271
272
273
274
                           'INNER JOIN PackageNotifications ' +
                           'ON PackageNotifications.UserID = Users.ID WHERE ' +
                           'Users.OwnershipNotify = 1 AND ' +
                           'PackageNotifications.UserID != ? AND ' +
                           'PackageNotifications.PackageBaseID = ?',
                           [uid, pkgbase_id])
Lukas Fleischer's avatar
Lukas Fleischer committed
275
        self._recipients = cur.fetchall()
276
277
278
        cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' +
                           'ID = ?', [pkgbase_id])
        self._text = cur.fetchone()[0]
Lukas Fleischer's avatar
Lukas Fleischer committed
279
        super().__init__()
280
281

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
282
        return self._recipients
283

Lukas Fleischer's avatar
Lukas Fleischer committed
284
    def get_subject(self, lang):
285
286
        return self._l10n.translate('AUR Ownership Notification for {pkgbase}',
                                    lang).format(pkgbase=self._pkgbase)
287
288
289
290
291
292
293

    def get_refs(self):
        return (aur_location + '/pkgbase/' + self._pkgbase + '/',
                aur_location + '/account/' + self._user + '/')


class AdoptNotification(OwnershipEventNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
294
295
    def get_body(self, lang):
        return self._l10n.translate(
296
297
                'The package {pkgbase} [1] was adopted by {user} [2].',
                lang).format(pkgbase=self._pkgbase, user=self._user)
298
299
300


class DisownNotification(OwnershipEventNotification):
301
    def get_body(self, lang):
Lukas Fleischer's avatar
Lukas Fleischer committed
302
        return self._l10n.translate(
303
304
305
                'The package {pkgbase} [1] was disowned by {user} '
                '[2].', lang).format(pkgbase=self._pkgbase,
                                     user=self._user)
306
307
308
309
310


class ComaintainershipEventNotification(Notification):
    def __init__(self, conn, uid, pkgbase_id):
        self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
Lukas Fleischer's avatar
Lukas Fleischer committed
311
312
313
314
        cur = conn.execute('SELECT Email, LangPreference FROM Users ' +
                           'WHERE ID = ?', [uid])
        self._to, self._lang = cur.fetchone()
        super().__init__()
315
316

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
317
        return [(self._to, self._lang)]
318

Lukas Fleischer's avatar
Lukas Fleischer committed
319
    def get_subject(self, lang):
320
321
322
        return self._l10n.translate('AUR Co-Maintainer Notification for '
                                    '{pkgbase}',
                                    lang).format(pkgbase=self._pkgbase)
323
324
325
326
327
328

    def get_refs(self):
        return (aur_location + '/pkgbase/' + self._pkgbase + '/',)


class ComaintainerAddNotification(ComaintainershipEventNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
329
330
    def get_body(self, lang):
        return self._l10n.translate(
331
332
                'You were added to the co-maintainer list of {pkgbase} [1].',
                lang).format(pkgbase=self._pkgbase)
333
334
335


class ComaintainerRemoveNotification(ComaintainershipEventNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
336
337
    def get_body(self, lang):
        return self._l10n.translate(
338
339
                'You were removed from the co-maintainer list of {pkgbase} '
                '[1].', lang).format(pkgbase=self._pkgbase)
340
341
342
343
344
345
346
347
348
349


class DeleteNotification(Notification):
    def __init__(self, conn, uid, old_pkgbase_id, new_pkgbase_id=None):
        self._user = username_from_id(conn, uid)
        self._old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id)
        if new_pkgbase_id:
            self._new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id)
        else:
            self._new_pkgbase = None
Lukas Fleischer's avatar
Lukas Fleischer committed
350
351
        cur = conn.execute('SELECT DISTINCT Users.Email, ' +
                           'Users.LangPreference FROM Users ' +
352
353
354
355
356
                           'INNER JOIN PackageNotifications ' +
                           'ON PackageNotifications.UserID = Users.ID WHERE ' +
                           'PackageNotifications.UserID != ? AND ' +
                           'PackageNotifications.PackageBaseID = ?',
                           [uid, old_pkgbase_id])
Lukas Fleischer's avatar
Lukas Fleischer committed
357
358
        self._recipients = cur.fetchall()
        super().__init__()
359
360

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
361
        return self._recipients
362

Lukas Fleischer's avatar
Lukas Fleischer committed
363
    def get_subject(self, lang):
364
365
        return self._l10n.translate('AUR Package deleted: {pkgbase}',
                                    lang).format(pkgbase=self._old_pkgbase)
366

Lukas Fleischer's avatar
Lukas Fleischer committed
367
    def get_body(self, lang):
368
        if self._new_pkgbase:
Lukas Fleischer's avatar
Lukas Fleischer committed
369
370
            dnlabel = self._l10n.translate('Disable notifications', lang)
            return self._l10n.translate(
371
                    '{user} [1] merged {old} [2] into {new} [3].\n\n'
372
                    '-- \n'
Lukas Fleischer's avatar
Lukas Fleischer committed
373
                    'If you no longer wish receive notifications about the '
374
375
376
                    'new package, please go to [3] and click "{label}".',
                    lang).format(user=self._user, old=self._old_pkgbase,
                                 new=self._new_pkgbase, label=dnlabel)
377
        else:
Lukas Fleischer's avatar
Lukas Fleischer committed
378
            return self._l10n.translate(
379
                    '{user} [1] deleted {pkgbase} [2].\n\n'
Lukas Fleischer's avatar
Lukas Fleischer committed
380
                    'You will no longer receive notifications about this '
381
382
                    'package.', lang).format(user=self._user,
                                             pkgbase=self._old_pkgbase)
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

    def get_refs(self):
        refs = (aur_location + '/account/' + self._user + '/',
                aur_location + '/pkgbase/' + self._old_pkgbase + '/')
        if self._new_pkgbase:
            refs += (aur_location + '/pkgbase/' + self._new_pkgbase + '/',)
        return refs


class RequestOpenNotification(Notification):
    def __init__(self, conn, uid, reqid, reqtype, pkgbase_id, merge_into=None):
        self._user = username_from_id(conn, uid)
        self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
        cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' +
                           'INNER JOIN PackageBases ' +
                           'ON PackageBases.ID = PackageRequests.PackageBaseID ' +
                           'INNER JOIN Users ' +
                           'ON Users.ID = PackageRequests.UsersID ' +
                           'OR Users.ID = PackageBases.MaintainerUID ' +
                           'WHERE PackageRequests.ID = ?', [reqid])
        self._to = aurweb.config.get('options', 'aur_request_ml')
        self._cc = [row[0] for row in cur.fetchall()]
        cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?',
                           [reqid])
        self._text = cur.fetchone()[0]
        self._reqid = int(reqid)
        self._reqtype = reqtype
        self._merge_into = merge_into

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
413
        return [(self._to, 'en')]
414

Lukas Fleischer's avatar
Lukas Fleischer committed
415
    def get_subject(self, lang):
416
417
418
        return '[PRQ#%d] %s Request for %s' % \
               (self._reqid, self._reqtype.title(), self._pkgbase)

Lukas Fleischer's avatar
Lukas Fleischer committed
419
    def get_body(self, lang):
420
421
422
423
424
        if self._merge_into:
            body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \
                   (self._user, self._pkgbase, self._merge_into)
            body += '\n\n' + self._text
        else:
425
426
427
            an = 'an' if self._reqtype[0] in 'aeiou' else 'a'
            body = '%s [1] filed %s %s request for %s [2]:' % \
                   (self._user, an, self._reqtype, self._pkgbase)
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
            body += '\n\n' + self._text
        return body

    def get_refs(self):
        refs = (aur_location + '/account/' + self._user + '/',
                aur_location + '/pkgbase/' + self._pkgbase + '/')
        if self._merge_into:
            refs += (aur_location + '/pkgbase/' + self._merge_into + '/',)
        return refs

    def get_headers(self):
        thread_id = '<pkg-request-' + str(self._reqid) + '@aur.archlinux.org>'
        # Use a deterministic Message-ID for the first email referencing a
        # request.
        headers = headers_msgid(thread_id)
        headers.update(headers_cc(self._cc))
        return headers


class RequestCloseNotification(Notification):
    def __init__(self, conn, uid, reqid, reason):
        self._user = username_from_id(conn, uid) if int(uid) else None
        cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' +
                           'INNER JOIN PackageBases ' +
                           'ON PackageBases.ID = PackageRequests.PackageBaseID ' +
                           'INNER JOIN Users ' +
                           'ON Users.ID = PackageRequests.UsersID ' +
                           'OR Users.ID = PackageBases.MaintainerUID ' +
                           'WHERE PackageRequests.ID = ?', [reqid])
        self._to = aurweb.config.get('options', 'aur_request_ml')
        self._cc = [row[0] for row in cur.fetchall()]
459
460
461
462
463
464
465
466
        cur = conn.execute('SELECT PackageRequests.ClosureComment, ' +
                           'RequestTypes.Name, ' +
                           'PackageRequests.PackageBaseName ' +
                           'FROM PackageRequests ' +
                           'INNER JOIN RequestTypes ' +
                           'ON RequestTypes.ID = PackageRequests.ReqTypeID ' +
                           'WHERE PackageRequests.ID = ?', [reqid])
        self._text, self._reqtype, self._pkgbase = cur.fetchone()
467
468
469
470
        self._reqid = int(reqid)
        self._reason = reason

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
471
        return [(self._to, 'en')]
472

Lukas Fleischer's avatar
Lukas Fleischer committed
473
    def get_subject(self, lang):
474
475
476
477
        return '[PRQ#%d] %s Request for %s %s' % (self._reqid,
                                                  self._reqtype.title(),
                                                  self._pkgbase,
                                                  self._reason.title())
478

Lukas Fleischer's avatar
Lukas Fleischer committed
479
    def get_body(self, lang):
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
        if self._user:
            body = 'Request #%d has been %s by %s [1]' % \
                   (self._reqid, self._reason, self._user)
        else:
            body = 'Request #%d has been %s automatically by the Arch User ' \
                   'Repository package request system' % \
                   (self._reqid, self._reason)
        if self._text.strip() == '':
            body += '.'
        else:
            body += ':\n\n' + self._text
        return body

    def get_refs(self):
        if self._user:
            return (aur_location + '/account/' + self._user + '/',)
        else:
            return ()

    def get_headers(self):
        thread_id = '<pkg-request-' + str(self._reqid) + '@aur.archlinux.org>'
        headers = headers_reply(thread_id)
        headers.update(headers_cc(self._cc))
        return headers


class TUVoteReminderNotification(Notification):
    def __init__(self, conn, vote_id):
        self._vote_id = int(vote_id)
Lukas Fleischer's avatar
Lukas Fleischer committed
509
        cur = conn.execute('SELECT Email, LangPreference FROM Users ' +
510
511
512
                           'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' +
                           '(SELECT UserID FROM TU_Votes ' +
                           'WHERE TU_Votes.VoteID = ?)', [vote_id])
Lukas Fleischer's avatar
Lukas Fleischer committed
513
514
        self._recipients = cur.fetchall()
        super().__init__()
515
516

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
517
        return self._recipients
518

Lukas Fleischer's avatar
Lukas Fleischer committed
519
    def get_subject(self, lang):
520
521
        return self._l10n.translate('TU Vote Reminder: Proposal {id}',
                                    lang).format(id=self._vote_id)
522

Lukas Fleischer's avatar
Lukas Fleischer committed
523
524
    def get_body(self, lang):
        return self._l10n.translate(
525
526
527
                'Please remember to cast your vote on proposal {id} [1]. '
                'The voting period ends in less than 48 hours.',
                lang).format(id=self._vote_id)
528
529
530

    def get_refs(self):
        return (aur_location + '/tu/?id=' + str(self._vote_id),)
531
532


533
def main():
534
535
    action = sys.argv[1]
    action_map = {
536
537
538
539
540
541
542
543
544
545
546
547
548
        'send-resetkey': ResetKeyNotification,
        'welcome': WelcomeNotification,
        'comment': CommentNotification,
        'update': UpdateNotification,
        'flag': FlagNotification,
        'adopt': AdoptNotification,
        'disown': DisownNotification,
        'comaintainer-add': ComaintainerAddNotification,
        'comaintainer-remove': ComaintainerRemoveNotification,
        'delete': DeleteNotification,
        'request-open': RequestOpenNotification,
        'request-close': RequestCloseNotification,
        'tu-vote-reminder': TUVoteReminderNotification,
549
550
    }

Lukas Fleischer's avatar
Lukas Fleischer committed
551
    conn = aurweb.db.Connection()
552

553
554
    notification = action_map[action](conn, *sys.argv[2:])
    notification.send()
555

Lukas Fleischer's avatar
Lukas Fleischer committed
556
557
    conn.commit()
    conn.close()
558
559
560
561


if __name__ == '__main__':
    main()