notify.py 23.9 KB
Newer Older
1
#!/usr/bin/env python3
2
3

import email.mime.text
4
5
import email.utils
import smtplib
6
7
8
9
import subprocess
import sys
import textwrap

10
11
from sqlalchemy import and_, or_

Lukas Fleischer's avatar
Lukas Fleischer committed
12
13
import aurweb.config
import aurweb.db
Lukas Fleischer's avatar
Lukas Fleischer committed
14
import aurweb.l10n
15

16
17
18
19
from aurweb import db
from aurweb.models import (PackageBase, PackageComaintainer, PackageComment, PackageNotification, PackageRequest, RequestType,
                           TUVote, User)

Lukas Fleischer's avatar
Lukas Fleischer committed
20
aur_location = aurweb.config.get('options', 'aur_location')
21
22


23
24
25
def headers_msgid(thread_id):
    return {'Message-ID': thread_id}

26

27
28
29
def headers_reply(thread_id):
    return {'In-Reply-To': thread_id, 'References': thread_id}

30

31
32
33
34
35
36
37
class Notification:
    def get_refs(self):
        return ()

    def get_headers(self):
        return {}

38
39
40
    def get_cc(self):
        return []

Lukas Fleischer's avatar
Lukas Fleischer committed
41
    def get_body_fmt(self, lang):
42
        body = ''
Lukas Fleischer's avatar
Lukas Fleischer committed
43
        for line in self.get_body(lang).splitlines():
44
45
            if line == '--':
                body += '--\n'
46
                continue
47
48
49
            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
50
        return body.rstrip()
51

Lukas Fleischer's avatar
Lukas Fleischer committed
52
    def send(self):
53
        sendmail = aurweb.config.get('notifications', 'sendmail')
54
55
        sender = aurweb.config.get('notifications', 'sender')
        reply_to = aurweb.config.get('notifications', 'reply-to')
56
57
58
        reason = self.__class__.__name__
        if reason.endswith('Notification'):
            reason = reason[:-len('Notification')]
59
60

        for recipient in self.get_recipients():
Lukas Fleischer's avatar
Lukas Fleischer committed
61
62
63
64
            to, lang = recipient
            msg = email.mime.text.MIMEText(self.get_body_fmt(lang),
                                           'plain', 'utf-8')
            msg['Subject'] = self.get_subject(lang)
65
66
            msg['From'] = sender
            msg['Reply-to'] = reply_to
Lukas Fleischer's avatar
Lukas Fleischer committed
67
            msg['To'] = to
68
69
            if self.get_cc():
                msg['Cc'] = str.join(', ', self.get_cc())
70
            msg['X-AUR-Reason'] = reason
71
            msg['Date'] = email.utils.formatdate(localtime=True)
72
73
74
75

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

76
77
78
79
80
81
82
83
84
85
            sendmail = aurweb.config.get('notifications', 'sendmail')
            if sendmail:
                # send email using the sendmail binary specified in the
                # configuration file
                p = subprocess.Popen([sendmail, '-t', '-oi'],
                                     stdin=subprocess.PIPE)
                p.communicate(msg.as_bytes())
            else:
                # send email using smtplib; no local MTA required
                server_addr = aurweb.config.get('notifications', 'smtp-server')
86
87
88
89
90
91
                server_port = aurweb.config.getint('notifications',
                                                   'smtp-port')
                use_ssl = aurweb.config.getboolean('notifications',
                                                   'smtp-use-ssl')
                use_starttls = aurweb.config.getboolean('notifications',
                                                        'smtp-use-starttls')
92
93
94
                user = aurweb.config.get('notifications', 'smtp-user')
                passwd = aurweb.config.get('notifications', 'smtp-password')

95
96
97
98
99
                classes = {
                    False: smtplib.SMTP,
                    True: smtplib.SMTP_SSL,
                }
                server = classes[use_ssl](server_addr, server_port)
100
101
102
103
104
105
106
107

                if use_starttls:
                    server.ehlo()
                    server.starttls()
                    server.ehlo()

                if user and passwd:
                    server.login(user, passwd)
108
109

                server.set_debuglevel(0)
110
                deliver_to = [to] + self.get_cc()
111
                server.sendmail(sender, deliver_to, msg.as_bytes())
112
                server.quit()
113
114
115


class ResetKeyNotification(Notification):
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    def __init__(self, uid):

        user = db.query(User).filter(
            and_(User.ID == uid, User.Suspended == 0)
        ).with_entities(
            User.Username,
            User.Email,
            User.BackupEmail,
            User.LangPreference,
            User.ResetKey
        ).order_by(User.Username.asc()).first()

        self._username = user.Username
        self._to = user.Email
        self._backup = user.BackupEmail
        self._lang = user.LangPreference
        self._resetkey = user.ResetKey

Lukas Fleischer's avatar
Lukas Fleischer committed
134
        super().__init__()
135
136

    def get_recipients(self):
137
138
139
140
        if self._backup:
            return [(self._to, self._lang), (self._backup, self._lang)]
        else:
            return [(self._to, self._lang)]
141

Lukas Fleischer's avatar
Lukas Fleischer committed
142
    def get_subject(self, lang):
143
        return aurweb.l10n.translator.translate('AUR Password Reset', lang)
144

Lukas Fleischer's avatar
Lukas Fleischer committed
145
    def get_body(self, lang):
146
147
148
149
150
151
        return aurweb.l10n.translator.translate(
            '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)
152
153
154
155
156
157

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


class WelcomeNotification(ResetKeyNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
158
    def get_subject(self, lang):
159
160
161
        return aurweb.l10n.translator.translate(
            'Welcome to the Arch User Repository',
            lang)
162

Lukas Fleischer's avatar
Lukas Fleischer committed
163
    def get_body(self, lang):
164
165
166
167
168
        return aurweb.l10n.translator.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)
169
170
171


class CommentNotification(Notification):
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    def __init__(self, uid, pkgbase_id, comment_id):

        self._user = db.query(User.Username).filter(
            User.ID == uid).first().Username
        self._pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == pkgbase_id).first().Name

        query = db.query(User).join(PackageNotification).filter(
            and_(User.CommentNotify == 1,
                 PackageNotification.UserID != uid,
                 PackageNotification.PackageBaseID == pkgbase_id,
                 User.Suspended == 0)
        ).with_entities(
            User.Email,
            User.LangPreference
        ).distinct()
        self._recipients = [(u.Email, u.LangPreference) for u in query]

        pkgcomment = db.query(PackageComment.Comments).filter(
            PackageComment.ID == comment_id).first()
        self._text = pkgcomment.Comments

Lukas Fleischer's avatar
Lukas Fleischer committed
194
        super().__init__()
195
196

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
197
        return self._recipients
198

Lukas Fleischer's avatar
Lukas Fleischer committed
199
    def get_subject(self, lang):
200
201
202
        return aurweb.l10n.translator.translate(
            'AUR Comment for {pkgbase}',
            lang).format(pkgbase=self._pkgbase)
203

Lukas Fleischer's avatar
Lukas Fleischer committed
204
    def get_body(self, lang):
205
206
207
        body = aurweb.l10n.translator.translate(
            '{user} [1] added the following comment to {pkgbase} [2]:',
            lang).format(user=self._user, pkgbase=self._pkgbase)
208
        body += '\n\n' + self._text + '\n\n--\n'
209
210
211
212
213
214
        dnlabel = aurweb.l10n.translator.translate(
            'Disable notifications', lang)
        body += aurweb.l10n.translator.translate(
            'If you no longer wish to receive notifications about this '
            'package, please go to the package page [2] and select '
            '"{label}".', lang).format(label=dnlabel)
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 UpdateNotification(Notification):
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
    def __init__(self, uid, pkgbase_id):

        self._user = db.query(User.Username).filter(
            User.ID == uid).first().Username
        self._pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == pkgbase_id).first().Name

        query = db.query(User).join(PackageNotification).filter(
            and_(User.UpdateNotify == 1,
                 PackageNotification.UserID != uid,
                 PackageNotification.PackageBaseID == pkgbase_id,
                 User.Suspended == 0)
        ).with_entities(
            User.Email,
            User.LangPreference
        ).distinct()
        self._recipients = [(u.Email, u.LangPreference) for u in query]

Lukas Fleischer's avatar
Lukas Fleischer committed
246
        super().__init__()
247
248

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
249
        return self._recipients
250

Lukas Fleischer's avatar
Lukas Fleischer committed
251
    def get_subject(self, lang):
252
253
254
        return aurweb.l10n.translator.translate(
            'AUR Package Update: {pkgbase}',
            lang).format(pkgbase=self._pkgbase)
255

Lukas Fleischer's avatar
Lukas Fleischer committed
256
    def get_body(self, lang):
257
258
259
        body = aurweb.l10n.translator.translate(
            '{user} [1] pushed a new commit to {pkgbase} [2].',
            lang).format(user=self._user, pkgbase=self._pkgbase)
260
        body += '\n\n--\n'
261
262
263
264
265
266
        dnlabel = aurweb.l10n.translator.translate(
            'Disable notifications', lang)
        body += aurweb.l10n.translator.translate(
            'If you no longer wish to receive notifications about this '
            'package, please go to the package page [2] and select '
            '"{label}".', lang).format(label=dnlabel)
267
268
269
270
271
272
273
274
275
276
277
278
279
        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):
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    def __init__(self, uid, pkgbase_id):

        self._user = db.query(User.Username).filter(
            User.ID == uid).first().Username
        self._pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == pkgbase_id).first().Name

        query = db.query(User).join(PackageComaintainer, isouter=True).join(
            PackageBase,
            or_(PackageBase.MaintainerUID == User.ID,
                PackageBase.ID == PackageComaintainer.PackageBaseID)
        ).filter(
            and_(PackageBase.ID == pkgbase_id,
                 User.Suspended == 0)
        ).with_entities(
            User.Email,
            User.LangPreference
        ).distinct()
        self._recipients = [(u.Email, u.LangPreference) for u in query]

        pkgbase = db.query(PackageBase.FlaggerComment).filter(
            PackageBase.ID == pkgbase_id).first()
        self._text = pkgbase.FlaggerComment

Lukas Fleischer's avatar
Lukas Fleischer committed
304
        super().__init__()
305
306

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
307
        return self._recipients
308

Lukas Fleischer's avatar
Lukas Fleischer committed
309
    def get_subject(self, lang):
310
311
312
        return aurweb.l10n.translator.translate(
            'AUR Out-of-date Notification for {pkgbase}',
            lang).format(pkgbase=self._pkgbase)
313

Lukas Fleischer's avatar
Lukas Fleischer committed
314
    def get_body(self, lang):
315
316
317
318
        body = aurweb.l10n.translator.translate(
            'Your package {pkgbase} [1] has been flagged out-of-date by '
            '{user} [2]:', lang).format(pkgbase=self._pkgbase,
                                        user=self._user)
319
320
321
322
323
324
325
326
327
        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):
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
    def __init__(self, uid, pkgbase_id):

        self._user = db.query(User.Username).filter(
            User.ID == uid).first().Username
        self._pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == pkgbase_id).first().Name

        query = db.query(User).join(PackageNotification).filter(
            and_(User.OwnershipNotify == 1,
                 PackageNotification.UserID != uid,
                 PackageNotification.PackageBaseID == pkgbase_id,
                 User.Suspended == 0)
        ).with_entities(
            User.Email,
            User.LangPreference
        ).distinct()
        self._recipients = [(u.Email, u.LangPreference) for u in query]

        pkgbase = db.query(PackageBase.FlaggerComment).filter(
            PackageBase.ID == pkgbase_id).first()
        self._text = pkgbase.FlaggerComment

Lukas Fleischer's avatar
Lukas Fleischer committed
350
        super().__init__()
351
352

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
353
        return self._recipients
354

Lukas Fleischer's avatar
Lukas Fleischer committed
355
    def get_subject(self, lang):
356
357
358
        return aurweb.l10n.translator.translate(
            'AUR Ownership Notification for {pkgbase}',
            lang).format(pkgbase=self._pkgbase)
359
360
361
362
363
364
365

    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
366
    def get_body(self, lang):
367
368
369
        return aurweb.l10n.translator.translate(
            'The package {pkgbase} [1] was adopted by {user} [2].',
            lang).format(pkgbase=self._pkgbase, user=self._user)
370
371
372


class DisownNotification(OwnershipEventNotification):
373
    def get_body(self, lang):
374
375
376
377
        return aurweb.l10n.translator.translate(
            'The package {pkgbase} [1] was disowned by {user} '
            '[2].', lang).format(pkgbase=self._pkgbase,
                                 user=self._user)
378
379
380


class ComaintainershipEventNotification(Notification):
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
    def __init__(self, uid, pkgbase_id):

        self._pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == pkgbase_id).first().Name

        user = db.query(User).filter(
            and_(User.ID == uid,
                 User.Suspended == 0)
        ).with_entities(
            User.Email,
            User.LangPreference
        ).first()

        self._to = user.Email
        self._lang = user.LangPreference

Lukas Fleischer's avatar
Lukas Fleischer committed
397
        super().__init__()
398
399

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

Lukas Fleischer's avatar
Lukas Fleischer committed
402
    def get_subject(self, lang):
403
404
405
        return aurweb.l10n.translator.translate(
            'AUR Co-Maintainer Notification for {pkgbase}',
            lang).format(pkgbase=self._pkgbase)
406
407
408
409
410
411

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


class ComaintainerAddNotification(ComaintainershipEventNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
412
    def get_body(self, lang):
413
414
415
        return aurweb.l10n.translator.translate(
            'You were added to the co-maintainer list of {pkgbase} [1].',
            lang).format(pkgbase=self._pkgbase)
416
417
418


class ComaintainerRemoveNotification(ComaintainershipEventNotification):
Lukas Fleischer's avatar
Lukas Fleischer committed
419
    def get_body(self, lang):
420
421
422
        return aurweb.l10n.translator.translate(
            'You were removed from the co-maintainer list of {pkgbase} '
            '[1].', lang).format(pkgbase=self._pkgbase)
423
424
425


class DeleteNotification(Notification):
426
427
428
429
430
431
432
433
    def __init__(self, uid, old_pkgbase_id, new_pkgbase_id=None):

        self._user = db.query(User.Username).filter(
            User.ID == uid).first().Username
        self._old_pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == old_pkgbase_id).first().Name

        self._new_pkgbase = None
434
        if new_pkgbase_id:
435
436
437
438
439
440
441
442
443
444
445
446
447
            self._new_pkgbase = db.query(PackageBase.Name).filter(
                PackageBase.ID == new_pkgbase_id).first().Name

        query = db.query(User).join(PackageNotification).filter(
            and_(PackageNotification.UserID != uid,
                 PackageNotification.PackageBaseID == old_pkgbase_id,
                 User.Suspended == 0)
        ).with_entities(
            User.Email,
            User.LangPreference
        ).distinct()
        self._recipients = [(u.Email, u.LangPreference) for u in query]

Lukas Fleischer's avatar
Lukas Fleischer committed
448
        super().__init__()
449
450

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
451
        return self._recipients
452

Lukas Fleischer's avatar
Lukas Fleischer committed
453
    def get_subject(self, lang):
454
455
456
        return aurweb.l10n.translator.translate(
            'AUR Package deleted: {pkgbase}',
            lang).format(pkgbase=self._old_pkgbase)
457

Lukas Fleischer's avatar
Lukas Fleischer committed
458
    def get_body(self, lang):
459
        if self._new_pkgbase:
460
461
462
463
            dnlabel = aurweb.l10n.translator.translate(
                'Disable notifications', lang)
            return aurweb.l10n.translator.translate(
                '{user} [1] merged {old} [2] into {new} [3].\n\n'
464
                '--\n'
465
466
467
468
                'If you no longer wish receive notifications about the '
                'new package, please go to [3] and click "{label}".',
                lang).format(user=self._user, old=self._old_pkgbase,
                             new=self._new_pkgbase, label=dnlabel)
469
        else:
470
471
472
473
474
            return aurweb.l10n.translator.translate(
                '{user} [1] deleted {pkgbase} [2].\n\n'
                'You will no longer receive notifications about this '
                'package.', lang).format(user=self._user,
                                         pkgbase=self._old_pkgbase)
475
476
477
478
479
480
481
482
483
484

    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):
485
486
487
488
489
490
491
    def __init__(self, uid, reqid, reqtype, pkgbase_id, merge_into=None):

        self._user = db.query(User.Username).filter(
            User.ID == uid).first().Username
        self._pkgbase = db.query(PackageBase.Name).filter(
            PackageBase.ID == pkgbase_id).first().Name

492
        self._to = aurweb.config.get('options', 'aur_request_ml')
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

        query = db.query(PackageRequest).join(PackageBase).join(
            PackageComaintainer,
            PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID,
            isouter=True
        ).join(
            User,
            or_(User.ID == PackageRequest.UsersID,
                User.ID == PackageBase.MaintainerUID,
                User.ID == PackageComaintainer.UsersID)
        ).filter(
            and_(PackageRequest.ID == reqid,
                 User.Suspended == 0)
        ).with_entities(
            User.Email
        ).distinct()
        self._cc = [u.Email for u in query]

        pkgreq = db.query(PackageRequest.Comments).filter(
            PackageRequest.ID == reqid).first()

        self._text = pkgreq.Comments
515
516
517
518
519
        self._reqid = int(reqid)
        self._reqtype = reqtype
        self._merge_into = merge_into

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

522
523
524
    def get_cc(self):
        return self._cc

Lukas Fleischer's avatar
Lukas Fleischer committed
525
    def get_subject(self, lang):
526
527
528
        return '[PRQ#%d] %s Request for %s' % \
               (self._reqid, self._reqtype.title(), self._pkgbase)

Lukas Fleischer's avatar
Lukas Fleischer committed
529
    def get_body(self, lang):
530
531
532
533
534
        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:
535
536
537
            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)
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
            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)
        return headers


class RequestCloseNotification(Notification):
557
558
559
560
    def __init__(self, uid, reqid, reason):
        user = db.query(User.Username).filter(User.ID == uid).first()
        self._user = user.Username if user else None

561
        self._to = aurweb.config.get('options', 'aur_request_ml')
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591

        query = db.query(PackageRequest).join(PackageBase).join(
            PackageComaintainer,
            PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID,
            isouter=True
        ).join(
            User,
            or_(User.ID == PackageRequest.UsersID,
                User.ID == PackageBase.MaintainerUID,
                User.ID == PackageComaintainer.UsersID)
        ).filter(
            and_(PackageRequest.ID == reqid,
                 User.Suspended == 0)
        ).with_entities(
            User.Email
        ).distinct()
        self._cc = [u.Email for u in query]

        pkgreq = db.query(PackageRequest).join(RequestType).filter(
            PackageRequest.ID == reqid
        ).with_entities(
            PackageRequest.ClosureComment,
            RequestType.Name,
            PackageRequest.PackageBaseName
        ).first()

        self._text = pkgreq.ClosureComment
        self._reqtype = pkgreq.Name
        self._pkgbase = pkgreq.PackageBaseName

592
593
594
595
        self._reqid = int(reqid)
        self._reason = reason

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

598
599
600
    def get_cc(self):
        return self._cc

Lukas Fleischer's avatar
Lukas Fleischer committed
601
    def get_subject(self, lang):
602
603
604
605
        return '[PRQ#%d] %s Request for %s %s' % (self._reqid,
                                                  self._reqtype.title(),
                                                  self._pkgbase,
                                                  self._reason.title())
606

Lukas Fleischer's avatar
Lukas Fleischer committed
607
    def get_body(self, lang):
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
        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)
        return headers


class TUVoteReminderNotification(Notification):
634
    def __init__(self, vote_id):
635
        self._vote_id = int(vote_id)
636
637
638
639
640
641
642
643
644
645
646

        subquery = db.query(TUVote.UserID).filter(TUVote.VoteID == vote_id)
        query = db.query(User).filter(
            and_(User.AccountTypeID.in_((2, 4)),
                 ~User.ID.in_(subquery),
                 User.Suspended == 0)
        ).with_entities(
            User.Email, User.LangPreference
        )
        self._recipients = [(u.Email, u.LangPreference) for u in query]

Lukas Fleischer's avatar
Lukas Fleischer committed
647
        super().__init__()
648
649

    def get_recipients(self):
Lukas Fleischer's avatar
Lukas Fleischer committed
650
        return self._recipients
651

Lukas Fleischer's avatar
Lukas Fleischer committed
652
    def get_subject(self, lang):
653
654
655
        return aurweb.l10n.translator.translate(
            'TU Vote Reminder: Proposal {id}',
            lang).format(id=self._vote_id)
656

Lukas Fleischer's avatar
Lukas Fleischer committed
657
    def get_body(self, lang):
658
659
660
661
        return aurweb.l10n.translator.translate(
            '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)
662
663
664

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


667
def main():
668
    db.get_engine()
669
670
    action = sys.argv[1]
    action_map = {
671
672
673
674
675
676
677
678
679
680
681
682
683
        '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,
684
685
    }

686
687
    with db.begin():
        notification = action_map[action](*sys.argv[2:])
688
    notification.send()
689

690
691
692

if __name__ == '__main__':
    main()