From 71d31efcdb70122f705d8136239771747ca3b07d Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Wed, 29 Jan 2020 10:48:35 +0100 Subject: [PATCH 1/1] Opt-out --- src/messaging/locale/pl/LC_MESSAGES/django.mo | Bin 3131 -> 3136 bytes src/messaging/locale/pl/LC_MESSAGES/django.po | 4 +- .../migrations/0004_auto_20200129_1035.py | 74 ++++++++++++++++++ src/messaging/models.py | 31 +++++++- .../templates/messaging/contact_form.html | 11 +++ .../templates/messaging/email_body.html | 6 ++ src/messaging/urls.py | 1 + src/messaging/views.py | 9 +++ 8 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 src/messaging/migrations/0004_auto_20200129_1035.py create mode 100644 src/messaging/templates/messaging/contact_form.html create mode 100644 src/messaging/templates/messaging/email_body.html diff --git a/src/messaging/locale/pl/LC_MESSAGES/django.mo b/src/messaging/locale/pl/LC_MESSAGES/django.mo index 6ee4e30f4582449e0f7fd050478232c9927fa3f4..f57284f74b10ee3b06a6d0eb6cdcf73ab033705a 100644 GIT binary patch delta 270 zcmdljaX@0j7RGu@1_lN(E(Qh;ARPdt*?@E;luiKBqCkE+koE)8wLqF3NS}eySAet< zkbehA>jUZkKw1Gv>vJwq-K{K-HXWd0l=%@3p(b2Eg28JmFu0ziSo zQ2Gjx76kI20%@R`4Bw$N6Awh37f6G|<)O3|kY)k$O@TBkkha>~$&}5)XtDV#n>Djs nqC$CP@zJKlyhMeP)Z&u-a-cwFVoH8){?XY-+BbW0ePRRvgv0Gxp7RGuL1_lN(E(Qh;AngsL*?@Eil#T|{qCkEUkoE)86+oIDNFRsN=Yg~m zkbfOW>jUXuKw1GvYjHC$=mKePAT0u zD19DC3j+BMfHcrdhEGuXFI1d^2O=&7rB#763s9W_kY)warkgvNvRN1nH-BZbW|pi} hD6cF&+LV}AsZf$yT#{d2sgSCho0yri*^lcJBLF5bB*6dx diff --git a/src/messaging/locale/pl/LC_MESSAGES/django.po b/src/messaging/locale/pl/LC_MESSAGES/django.po index d66ee7495..45da1b5e1 100644 --- a/src/messaging/locale/pl/LC_MESSAGES/django.po +++ b/src/messaging/locale/pl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-29 10:10+0100\n" -"PO-Revision-Date: 2020-01-29 10:11+0100\n" +"PO-Revision-Date: 2020-01-29 10:18+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: pl\n" @@ -31,7 +31,7 @@ msgstr "Ograniczenia wysyłki" #: admin.py:41 #, python-format msgid "Test e-mail has been sent to %(email)s." -msgstr "Na adres %(email)s zostały wysłany testowy e-mail." +msgstr "Na adres %(email)s została wysłana testowa wiadomość." #: admin.py:43 msgid "You have no email set. Test e-mail not sent." diff --git a/src/messaging/migrations/0004_auto_20200129_1035.py b/src/messaging/migrations/0004_auto_20200129_1035.py new file mode 100644 index 000000000..edaaf0586 --- /dev/null +++ b/src/messaging/migrations/0004_auto_20200129_1035.py @@ -0,0 +1,74 @@ +# Generated by Django 2.2.9 on 2020-01-29 09:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('messaging', '0003_auto_20200128_2230'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='key', + field=models.CharField(blank=True, default='', max_length=64), + preserve_default=False, + ), + migrations.AlterField( + model_name='contact', + name='level', + field=models.PositiveSmallIntegerField(choices=[(20, 'Would-be donor'), (30, 'One-time donor'), (40, 'Recurring donor'), (10, 'Cold'), (50, 'Opt out')]), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_1', + field=models.BooleanField(default=True, verbose_name='Monday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_2', + field=models.BooleanField(default=True, verbose_name='Tuesday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_3', + field=models.BooleanField(default=True, verbose_name='Wednesday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_4', + field=models.BooleanField(default=True, verbose_name='Thursday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_5', + field=models.BooleanField(default=True, verbose_name='Friday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_6', + field=models.BooleanField(default=True, verbose_name='Saturday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='dow_7', + field=models.BooleanField(default=True, verbose_name='Sunday'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='max_days_since', + field=models.SmallIntegerField(blank=True, null=True, verbose_name='max days since'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='min_days_since', + field=models.SmallIntegerField(blank=True, null=True, verbose_name='min days since'), + ), + migrations.AlterField( + model_name='emailtemplate', + name='state', + field=models.CharField(choices=[('cold', 'cold group'), ('club-payment-unfinished', 'club would-be donors'), ('club-single', 'club one-time donors'), ('club-membership-expiring', 'club one-time donors with donation expiring'), ('club-recurring', 'club recurring donors'), ('club-recurring-payment-problem', 'club recurring donors with donation expired')], help_text='?', max_length=128, verbose_name='state'), + ), + ] diff --git a/src/messaging/models.py b/src/messaging/models.py index 6f158e9a5..24cf623f1 100644 --- a/src/messaging/models.py +++ b/src/messaging/models.py @@ -3,8 +3,10 @@ from django.conf import settings from django.core.mail import send_mail from django.db import models from django.template import Template, Context +from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from sentry_sdk import capture_exception +from catalogue.utils import get_random_hash from .recipient import Recipient from .states import states @@ -54,8 +56,24 @@ class EmailTemplate(models.Model): raise ValueError('Unknown state', s.state) def send(self, recipient, verbose=False, dry_run=False, test=False): - subject = Template(self.subject).render(Context(recipient.context)) - body = Template(self.body).render(Context(recipient.context)) + ctx = Context(recipient.context) + + if test: + contact = Contact(email=recipient.email, key='test') + else: + # TODO: actually, we should just use Contacts instead of recipients. + contact = Contact.objects.get(email=recipient.email) + + ctx['contact'] = contact + + subject = Template(self.subject).render(ctx) + + if test: + subject = "[test] " + subject + + body_template = '{% extends "messaging/email_body.html" %}{% block body %}' + self.body + '{% endblock %}' + + body = Template(body_template).render(ctx) if verbose: print(recipient.email, subject) if not dry_run: @@ -113,6 +131,15 @@ class Contact(models.Model): ]) since = models.DateTimeField() expires_at = models.DateTimeField(null=True, blank=True) + key = models.CharField(max_length=64, blank=True) + + def save(self, *args, **kwargs): + if not self.key: + self.key = get_random_hash(self.email) + super().save(*args, **kwargs) + + def get_optout_url(self): + return reverse('messaging_optout', args=[self.key]) @classmethod def update(cls, email, level, since, expires_at=None): diff --git a/src/messaging/templates/messaging/contact_form.html b/src/messaging/templates/messaging/contact_form.html new file mode 100644 index 000000000..bbe9f37d4 --- /dev/null +++ b/src/messaging/templates/messaging/contact_form.html @@ -0,0 +1,11 @@ +{% extends "base/base.html" %} + +{% block body %} + +

Czy na pewno chcesz zrezygnować z otrzymywania e-maili na adres {{ object.email }}?

+ +
+ +
+ +{% endblock %} diff --git a/src/messaging/templates/messaging/email_body.html b/src/messaging/templates/messaging/email_body.html new file mode 100644 index 000000000..b6f9202dc --- /dev/null +++ b/src/messaging/templates/messaging/email_body.html @@ -0,0 +1,6 @@ +{% load i18n %}{% block body %} +{% endblock %} + +-- +{% trans "Visit this address if you don't want to be contacted in the future:" %} +https://wolnelektury.pl{{ contact.get_optout_url }} diff --git a/src/messaging/urls.py b/src/messaging/urls.py index 8f1fc1f85..499000896 100644 --- a/src/messaging/urls.py +++ b/src/messaging/urls.py @@ -4,4 +4,5 @@ from . import views urlpatterns = [ path('states//info.json', views.state_info), + path('opt-out//', views.OptOutView.as_view(), name='messaging_optout'), ] diff --git a/src/messaging/views.py b/src/messaging/views.py index 31debe180..f3881bb61 100644 --- a/src/messaging/views.py +++ b/src/messaging/views.py @@ -3,6 +3,8 @@ from django.http import JsonResponse from django.urls import reverse from django.shortcuts import render from django.utils.translation import ugettext as _ +from django.views.generic import UpdateView +from . import models from .states import states @@ -28,3 +30,10 @@ def state_info(request, slug): "help": help_text, }) + +class OptOutView(UpdateView): + model = models.Contact + slug_url_kwarg = 'key' + slug_field = 'key' + fields = ['level'] + -- 2.20.1