From: Jeremy Kerr Date: Mon, 19 Sep 2011 01:42:44 +0000 (+0800) Subject: Merge branch 'notifications' X-Git-Url: http://git.ozlabs.org/?a=commitdiff_plain;h=75d8cf966034e673afe0077ba393d8b2eb3e9b93;hp=-c;p=patchwork Merge branch 'notifications' --- 75d8cf966034e673afe0077ba393d8b2eb3e9b93 diff --combined apps/patchwork/utils.py index 5a8e4c0,5cb45e8..e7619c3 --- a/apps/patchwork/utils.py +++ b/apps/patchwork/utils.py @@@ -18,8 -18,17 +18,17 @@@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - from patchwork.models import Bundle, Project, BundlePatch + import itertools + import datetime from django.shortcuts import get_object_or_404 + from django.template.loader import render_to_string + from django.contrib.sites.models import Site + from django.conf import settings + from django.core.mail import EmailMessage + from django.db.models import Max + from patchwork.forms import MultiplePatchForm + from patchwork.models import Bundle, Project, BundlePatch, UserProfile, \ + PatchChangeNotification, EmailOptout def get_patch_ids(d, prefix = 'patch_id'): ids = [] @@@ -49,12 -58,12 +58,12 @@@ class Order(object) def __init__(self, str = None, editable = False): self.reversed = False self.editable = editable + (self.order, self.reversed) = self.default_order if self.editable: return if str is None or str == '': - (self.order, self.reversed) = self.default_order return reversed = False @@@ -63,6 -72,7 +72,6 @@@ reversed = True if str not in self.order_map.keys(): - (self.order, self.reversed) = self.default_order return self.order = str @@@ -136,3 -146,60 +145,60 @@@ def set_bundle(user, project, action, d bundle.save() return [] + + def send_notifications(): + date_limit = datetime.datetime.now() - \ + datetime.timedelta(minutes = + settings.NOTIFICATION_DELAY_MINUTES) + + # This gets funky: we want to filter out any notifications that should + # be grouped with other notifications that aren't ready to go out yet. To + # do that, we join back onto PatchChangeNotification (PCN -> Patch -> + # Person -> Patch -> max(PCN.last_modified)), filtering out any maxima + # that are with the date_limit. + qs = PatchChangeNotification.objects \ + .annotate(m = Max('patch__submitter__patch__patchchangenotification' + '__last_modified')) \ + .filter(m__lt = date_limit) + + groups = itertools.groupby(qs.order_by('patch__submitter'), + lambda n: n.patch.submitter) + + errors = [] + + for (recipient, notifications) in groups: + notifications = list(notifications) + + def delete_notifications(): + PatchChangeNotification.objects.filter( + pk__in = notifications).delete() + + if EmailOptout.is_optout(recipient.email): + delete_notifications() + continue + + context = { + 'site': Site.objects.get_current(), + 'person': recipient, + 'notifications': notifications, + } + 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 ex: + errors.append((recipient, ex)) + continue + + delete_notifications() + + return errors diff --combined apps/settings.py index 24d3762,4432f3f..7523099 --- a/apps/settings.py +++ b/apps/settings.py @@@ -10,12 -10,12 +10,12 @@@ ADMINS = MANAGERS = ADMINS -DATABASE_ENGINE = 'postgresql_psycopg2' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. -DATABASE_NAME = 'patchwork' # Or path to database file if using sqlite3. -DATABASE_USER = '' # Not used with sqlite3. -DATABASE_PASSWORD = '' # Not used with sqlite3. -DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. -DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'patchwork', + }, +} # Local time zone for this installation. Choices can be found here: # http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE @@@ -64,7 -64,7 +64,7 @@@ MIDDLEWARE_CLASSES = ROOT_URLCONF = 'apps.urls' - LOGIN_URL = '/accounts/login' + LOGIN_URL = '/user/login/' LOGIN_REDIRECT_URL = '/user/' # If you change the ROOT_DIR setting in your local_settings.py, you'll need to @@@ -96,13 -96,15 +96,15 @@@ INSTALLED_APPS = 'django.contrib.sites', 'django.contrib.admin', 'patchwork', - 'registration', ) DEFAULT_PATCHES_PER_PAGE = 100 DEFAULT_FROM_EMAIL = 'Patchwork ' - ACCOUNT_ACTIVATION_DAYS = 7 + CONFIRMATION_VALIDITY_DAYS = 7 + + NOTIFICATION_DELAY_MINUTES = 10 + NOTIFICATION_FROM_EMAIL = DEFAULT_FROM_EMAIL # Set to True to enable the Patchwork XML-RPC interface ENABLE_XMLRPC = False diff --combined docs/INSTALL index ee87e4d,050fc9f..c63d6f7 --- a/docs/INSTALL +++ b/docs/INSTALL @@@ -3,13 -3,13 +3,13 @@@ Deploying Patchwor Patchwork uses the django framework - there is some background on deploying django applications here: - http://www.djangobook.com/en/1.0/chapter20/ + http://www.djangobook.com/en/2.0/chapter12/ You'll need the following (applications used for patchwork development are in brackets): * A python interpreter - * django + * django >= 1.2 * A webserver (apache) * mod_python or flup * A database server (postgresql) @@@ -73,7 -73,7 +73,7 @@@ lib/packages is for stuff we'll download, lib/python is to add to our python path. We'll symlink python modules into lib/python. - At the time of release, patchwork depends on django version 1.0 or + At the time of release, patchwork depends on django version 1.2 or later. Your distro probably provides this. If not, do a: cd lib/packages @@@ -81,17 -81,6 +81,6 @@@ cd ../python ln -s ../packages/django/django ./django - We also use the django-registration infrastructure from - http://bitbucket.org/ubernostrum/django-registration/. Your distro - may provide the django-registration python module (in Ubuntu/Debian it's - called 'python-django-registration'). If not, download the module - and symlink it to lib/python/ : - - cd lib/packages/ - hg clone http://bitbucket.org/ubernostrum/django-registration/ - cd ../python - ln -s ../packages/django-registration/registration ./registration - We also use some Javascript libraries: cd lib/packages @@@ -115,6 -104,8 +104,8 @@@ ADMINS TIME_ZONE LANGUAGE_CODE + DEFAULT_FROM_EMAIL + NOTIFICATION_FROM_EMAIL You can generate the SECRET_KEY with the following python code: