summaryrefslogtreecommitdiff
path: root/patchwork/notifications.py
diff options
context:
space:
mode:
authorStephen Finucane <stephenfinucane@hotmail.com>2016-08-22 15:06:48 +0100
committerStephen Finucane <stephenfinucane@hotmail.com>2016-09-07 21:17:41 +0100
commitff4a10f47d9839056c67f50d07044e2ce05386a0 (patch)
tree4006b5c5a7bd74eb18e9e1484e142c244370ddbb /patchwork/notifications.py
parent804ff045e0893249bc80d0bd96de3e963faf7a46 (diff)
downloadpatchwork-ff4a10f47d9839056c67f50d07044e2ce05386a0.tar
patchwork-ff4a10f47d9839056c67f50d07044e2ce05386a0.tar.gz
utils: Rename to 'notifications'
Every function in this file is related to notifications. Rename the file and functions therein to something more meaningful. Signed-off-by: Stephen Finucane <stephenfinucane@hotmail.com>
Diffstat (limited to 'patchwork/notifications.py')
-rw-r--r--patchwork/notifications.py116
1 files changed, 116 insertions, 0 deletions
diff --git a/patchwork/notifications.py b/patchwork/notifications.py
new file mode 100644
index 0000000..5420401
--- /dev/null
+++ b/patchwork/notifications.py
@@ -0,0 +1,116 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import datetime
+import itertools
+
+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, Q, F
+
+from patchwork.compat import render_to_string
+from patchwork.models import EmailConfirmation
+from patchwork.models import EmailOptout
+from patchwork.models import PatchChangeNotification
+
+
+def send_notifications():
+ date_limit = datetime.datetime.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/patch-change-notification-subject.text',
+ context).strip()
+ content = render_to_string('patchwork/patch-change-notification.mail',
+ context)
+
+ message = EmailMessage(subject=subject, body=content,
+ from_email=settings.NOTIFICATION_FROM_EMAIL,
+ to=[recipient.email],
+ headers={'Precedence': 'bulk'})
+
+ try:
+ message.send()
+ except Exception 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=datetime.datetime.now() - EmailConfirmation.validity) |
+ Q(active=False))
+ EmailConfirmation.objects.filter(q).delete()
+
+ # remove inactive users with no pending confirmation
+ pending_confs = EmailConfirmation.objects.values('user')
+ users = User.objects.filter(is_active=False,
+ last_login=F('date_joined')).exclude(
+ id__in=pending_confs)
+
+ # delete users
+ users.delete()