-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathnotifications.py
More file actions
113 lines (89 loc) · 3.39 KB
/
notifications.py
File metadata and controls
113 lines (89 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# Patchwork - automated patch tracking system
# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
import datetime
import itertools
import smtplib
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.mail import EmailMessage
from django.db.models import Count
from django.db.models import Q
from django.template.loader import render_to_string
from django.utils import timezone as tz_utils
from patchwork.models import EmailConfirmation
from patchwork.models import EmailOptout
from patchwork.models import PatchChangeNotification
def send_notifications():
date_limit = tz_utils.now() - datetime.timedelta(
minutes=settings.NOTIFICATION_DELAY_MINUTES
)
# We delay sending notifications to a user if they have other
# notifications that are still in the "pending" state. To do this,
# we compare the total number of patch change notifications queued
# for each user against the number of "ready" notifications.
qs = PatchChangeNotification.objects.all()
qs2 = (
PatchChangeNotification.objects.filter(last_modified__lt=date_limit)
.values('patch__submitter')
.annotate(count=Count('patch__submitter'))
)
qs2 = {elem['patch__submitter']: elem['count'] for elem in qs2}
groups = itertools.groupby(
qs.order_by('patch__submitter'), lambda n: n.patch.submitter
)
errors = []
for recipient, notifications in groups:
notifications = list(notifications)
if recipient.id not in qs2 or qs2[recipient.id] < len(notifications):
continue
projects = set([n.patch.project.linkname for n in notifications])
def delete_notifications():
pks = [n.pk for n in notifications]
PatchChangeNotification.objects.filter(pk__in=pks).delete()
if EmailOptout.is_optout(recipient.email):
delete_notifications()
continue
context = {
'site': Site.objects.get_current(),
'notifications': notifications,
'projects': projects,
}
subject = render_to_string(
'patchwork/mails/patch-change-notification-subject.txt', context
).strip()
content = render_to_string(
'patchwork/mails/patch-change-notification.txt', context
)
message = EmailMessage(
subject=subject,
body=content,
from_email=settings.NOTIFICATION_FROM_EMAIL,
to=[recipient.email],
headers={'Precedence': 'bulk'},
)
try:
message.send()
except smtplib.SMTPException as ex:
errors.append((recipient, ex))
continue
delete_notifications()
return errors
def expire_notifications():
"""Expire any pending confirmations.
Users whose registration confirmation has expired are removed.
"""
# expire any invalid confirmations
q = Q(date__lt=tz_utils.now() - EmailConfirmation.validity) | Q(
active=False
)
EmailConfirmation.objects.filter(q).delete()
# remove inactive users with no pending confirmation
pending_confs = EmailConfirmation.objects.filter(
user__isnull=False
).values('user')
users = User.objects.filter(is_active=False).exclude(id__in=pending_confs)
# delete users
users.delete()