Parcourir la source

Command to send reminders on close data expiration

Send reminders to authors, meant to be called by cron-like.

ref #27
Jocelyn Delalande il y a 7 ans
Parent
commit
2a62e6450f

+ 17 - 0
README.md

@@ -78,6 +78,23 @@ Notification sender address:
 
     DEFAULT_FROM_EMAIL='notifier@example.tld'
 
+
+### Data expiration
+
+The data gets deleted after one year, if the contributing user does not give
+its explicit consent to keep it one more year.
+
+Reminders are sent to the contribution author when expiration date gets
+close. By default we send two notifications :
+
+    DATA_EXPIRATION_REMINDERS = [
+        30,  # 1 month before
+        7,   # 1 week before
+    ]
+
+You can tweak it to your will or decide to send no reminder (with value `[]`).
+
+
 Migrate from bottle version (optional)
 ======================================
 

+ 0 - 0
wifiwithme/apps/contribmap/management/__init__.py


+ 0 - 0
wifiwithme/apps/contribmap/management/commands/__init__.py


+ 69 - 0
wifiwithme/apps/contribmap/management/commands/send_expiration_reminders.py

@@ -0,0 +1,69 @@
+""" Send reminders for contribution that are about to expire
+
+It offers a way for contributors to opt-in keeping the data one year more (or
+deleting it right now).
+
+Reminders are sent when the script is called exactly `n` days before the
+expiration date.
+
+This `n` can be configured via `DATA_EXPIRATION_REMINDERS` setting.
+"""
+
+from django.conf import settings
+from django.core.mail import send_mail
+from django.core.management.base import BaseCommand, CommandError
+from django.template.loader import get_template
+
+
+from ...models import Contrib
+
+
+class Command(BaseCommand):
+    help = __doc__
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            '--dry-run', default=False, action='store_true',
+            help="Do not actually send emails, just pretend to")
+
+    def handle(self, dry_run, *args, **options):
+        if dry_run:
+            self.stderr.write('DRY RUN MODE: we do not actually send emails.')
+
+        for ndays in settings.DATA_EXPIRATION_REMINDERS:
+            expirating_contribs = Contrib.objects.expires_in_days(ndays)
+            for contrib in expirating_contribs:
+                if not contrib.email:
+                    self._warn_no_email(contrib, ndays)
+                else:
+                    if not dry_run:
+                        self.send_expiration_reminder(contrib, ndays)
+                    self._log_sent_email(contrib, ndays)
+
+    def _warn_no_email(self, contrib, ndays):
+        self.stderr.write(
+            'WARNING : the contribution {} is about to expire in {} days but'
+            + 'do not define a contact email.'.format(
+                contrib, ndays))
+
+    def _log_sent_email(self, contrib, ndays):
+        self.stderr.write(
+            "Sent reminder email to for {} expiration in {} days".format(
+                contrib, ndays))
+
+    def send_expiration_reminder(self, contrib, ndays):
+        subject = get_template(
+            'contribmap/mails/expiration_reminder.subject')
+        body = get_template(
+            'contribmap/mails/expiration_reminder.txt')
+
+        context = {
+            'contrib': contrib,
+            'ndays': ndays,
+        }
+        send_mail(
+            subject.render(context),
+            body.render(context),
+            settings.DEFAULT_FROM_EMAIL,
+            [contrib.email],
+        )

+ 1 - 0
wifiwithme/apps/contribmap/templates/contribmap/mails/expiration_reminder.subject

@@ -0,0 +1 @@
+[wifi-with-me] Votre demande #{{ contrib.id }} expire dans {{ ndays }} jours

+ 15 - 0
wifiwithme/apps/contribmap/templates/contribmap/mails/expiration_reminder.txt

@@ -0,0 +1,15 @@
+Chèr·e {{ contrib.name }},
+
+Vous aviez déposé le {{ contrib.date }} une demande
+
+Votre demande a bien été enregistrée. Elle est en ligne publiquement à l'adresse : <{{ permalink }}>.
+
+Si tout ou partie des informations n'apparaissent pas, c'est que vous avez choisi qu'elles ne soient pas publiques.
+
+Vous pouvez gérer ou supprimer ta demande grace à ce lien privé à conserver :
+
+<{{ management_link }}>
+
+Bien à toi,
+
+Les bénévoles de {{ isp.NAME }}

+ 2 - 2
wifiwithme/apps/contribmap/templates/contribmap/mails/new_contrib_author_notice.txt

@@ -4,10 +4,10 @@ Votre demande a bien été enregistrée. Elle est en ligne publiquement à l'adr
 
 Si tout ou partie des informations n'apparaissent pas, c'est que vous avez choisi qu'elles ne soient pas publiques.
 
-Vous pouvez gérer ou supprimer ta demande grace à ce lien privé à conserver :
+Vous pouvez gérer ou supprimer votre demande grace à ce lien privé à conserver :
 
 <{{ management_link }}>
 
-Bien à toi,
+Bien à vous,
 
 Les bénévoles de {{ isp.NAME }}

+ 34 - 0
wifiwithme/apps/contribmap/tests.py

@@ -3,6 +3,7 @@ import json
 import warnings
 
 from django.core import mail
+from django.core.management import call_command
 from django.core.signing import BadSignature
 from django.contrib.auth.models import User
 from django.test import TestCase, Client, override_settings
@@ -398,3 +399,36 @@ class ContribTokenManagerTests(TestCase):
         self.assertEqual(
             manager.get_instance_if_allowed(token, contrib.pk),
             contrib)
+
+
+class TestManagementCommands(TestCase):
+    def setUp(self):
+        contrib = Contrib.objects.create(
+            name='John',
+            email='foo@example.com',
+            contrib_type=Contrib.CONTRIB_CONNECT,
+            latitude=0.5,
+            longitude=0.5,
+        )
+        contrib.expiration_date = datetime.datetime(
+            2010, 10, 10, tzinfo=pytz.utc)
+        contrib.save()
+
+    @override_settings(DATA_EXPIRATION_REMINDERS=[10])
+    def test_send_expiration_reminders(self):
+        # 11 days before (should not send)
+        with freeze_time('29-09-2010', tz_offset=0):
+            call_command('send_expiration_reminders')
+            self.assertEqual(len(mail.outbox), 0)
+
+        # 9 days before (should not send)
+        with freeze_time('01-10-2010', tz_offset=0):
+            call_command('send_expiration_reminders')
+            self.assertEqual(len(mail.outbox), 0)
+
+        # 10 days before (should send)
+        with freeze_time('30-09-2010', tz_offset=0):
+            call_command('send_expiration_reminders', '--dry-run')
+            self.assertEqual(len(mail.outbox), 0)
+            call_command('send_expiration_reminders')
+            self.assertEqual(len(mail.outbox), 1)

+ 8 - 0
wifiwithme/settings/base.py

@@ -137,3 +137,11 @@ STATICFILES_DIRS = [
 NOTIFICATION_EMAILS = []
 
 SITE_URL = 'http://example.com/wifi'
+
+
+# Data expiration warning
+
+DATA_EXPIRATION_REMINDERS = [
+    30,  # 1 month before
+    7,   # 1 week before
+]