From: Radek Czajka Date: Wed, 29 Jan 2020 09:48:35 +0000 (+0100) Subject: Opt-out X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/71d31efcdb70122f705d8136239771747ca3b07d?ds=inline Opt-out --- diff --git a/src/messaging/locale/pl/LC_MESSAGES/django.mo b/src/messaging/locale/pl/LC_MESSAGES/django.mo index 6ee4e30f4..f57284f74 100644 Binary files a/src/messaging/locale/pl/LC_MESSAGES/django.mo and b/src/messaging/locale/pl/LC_MESSAGES/django.mo differ 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'] +