From 789d0c8c843afef49218724fc68ef2fa30fae15d 2024-04-09 12:53:24 From: Ben Sturmfels Date: 2024-04-09 12:53:24 Subject: [PATCH] contacts: Remove ContactEntry and add Unsubscription This change removes the unused `ContactEntry` model and the `subscribe` view and replaces it with an `Unsubscription` model and an `unsubscribe` view. It works similarly, but is intended to be used with the `list-unsubscribe` and `list-unsubscribe-post` headers. --- diff --git a/conservancy/contacts/admin.py b/conservancy/contacts/admin.py index 94048d4bdeea0bd9b66d2afd18e14ff455a726b4..f6c68b1cd1631a2c2a5dcf9e60c4aa8af0143690 100644 --- a/conservancy/contacts/admin.py +++ b/conservancy/contacts/admin.py @@ -1,10 +1,8 @@ from django.contrib import admin -from .models import ContactEntry - - -@admin.register(ContactEntry) -class ContactEntryAdmin(admin.ModelAdmin): - list_display = ('email', 'subscribe_conservancy') +from .models import Unsubscription +@admin.register(Unsubscription) +class UnsubscriptionAdmin(admin.ModelAdmin): + list_display = ['created', 'email'] diff --git a/conservancy/contacts/migrations/0001_initial.py b/conservancy/contacts/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..e10b2fabcaf6db905cc477b786bd0279efbe5714 --- /dev/null +++ b/conservancy/contacts/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.11 on 2024-04-09 08:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name='Unsubscription', + fields=[ + ( + 'id', + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name='ID', + ), + ), + ('created', models.DateTimeField(auto_now_add=True)), + ('email', models.EmailField(max_length=254)), + ], + options={ + 'ordering': ['created'], + }, + ), + ] diff --git a/conservancy/contacts/migrations/__init__.py b/conservancy/contacts/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/conservancy/contacts/models.py b/conservancy/contacts/models.py index 14ac74848d12e310d4ab824e8337b1c65810fccd..58e89a75abb655072e7b663fb004f8eb8d3a6587 100644 --- a/conservancy/contacts/models.py +++ b/conservancy/contacts/models.py @@ -1,14 +1,9 @@ from django.db import models -class ContactEntry(models.Model): - """Conservancy contact system - - Hopefully this will be deprecated soon""" - - email = models.EmailField() # should make it unique, but we really cannot - subscribe_conservancy = models.BooleanField(default=False) +class Unsubscription(models.Model): + created = models.DateTimeField(auto_now_add=True, blank=True) + email = models.EmailField() class Meta: - ordering = ('email',) - + ordering = ['created'] diff --git a/conservancy/contacts/templates/contacts/unsubscribe.html b/conservancy/contacts/templates/contacts/unsubscribe.html new file mode 100644 index 0000000000000000000000000000000000000000..86de5a67543d2b6ce3148446cbb03caf5b4e3cbe --- /dev/null +++ b/conservancy/contacts/templates/contacts/unsubscribe.html @@ -0,0 +1,10 @@ +{% extends "base_conservancy.html" %} +{% block outercontent %} +
+

Unsubscribe

+
+ {{ form.as_p }} +

+
+
+{% endblock %} diff --git a/conservancy/contacts/templates/contacts/unsubscribe_success.html b/conservancy/contacts/templates/contacts/unsubscribe_success.html new file mode 100644 index 0000000000000000000000000000000000000000..e4938995a0590b31f559cc128342bbc5ffb6e402 --- /dev/null +++ b/conservancy/contacts/templates/contacts/unsubscribe_success.html @@ -0,0 +1,6 @@ +{% extends "base_conservancy.html" %} +{% block outercontent %} +
+

Unsubscribe successful

+
+{% endblock %} diff --git a/conservancy/contacts/urls.py b/conservancy/contacts/urls.py index 661e68911f8d37eaf233eebb0b5de3bde303ac1c..74f1c84d6557d92674783ad92c8db8de0e0b4b02 100644 --- a/conservancy/contacts/urls.py +++ b/conservancy/contacts/urls.py @@ -1,7 +1,7 @@ from django.urls import path -from .views import subscribe +from .views import unsubscribe urlpatterns = [ - path('', subscribe), + path('unsubscribe/', unsubscribe), ] diff --git a/conservancy/contacts/views.py b/conservancy/contacts/views.py index 95ccfc09340d49cbf7a6e7cd3ffc76a2bdfbc93b..65ea3445d0b0e0d2c9ad8126a6fb202413643d4c 100644 --- a/conservancy/contacts/views.py +++ b/conservancy/contacts/views.py @@ -1,25 +1,31 @@ +import logging + from django.forms import ModelForm +from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render -from .models import ContactEntry - +from .models import Unsubscription -def subscribe(request): - """Mailing list subscription form - """ +logger = logging.getLogger(__name__) - class ContactEntryForm(ModelForm): - class Meta: - model = ContactEntry +class UnsubscribeForm(ModelForm): + class Meta: + model = Unsubscription + fields = ['email'] - ContactEntryForm.base_fields['subscribe_conservancy'].label = 'Receive Software Freedom Conservancy updates' +# Exempt from CSRF protection so that it can be triggered by Gmail's on-click +# unsubscribe. +@csrf_exempt +def unsubscribe(request): if request.method == 'POST': - form = ContactEntryForm(request.POST) + logger.debug('Unsubscribe GET: %s', request.GET) + logger.debug('Unsubscribe POST: %s', request.POST) + form = UnsubscribeForm(request.POST) if form.is_valid(): form.save() - return render(request, 'contacts/subscribe_success.html', {'form': form.cleaned_data}) + logger.info('Unsubscribed %s', form.cleaned_data['email']) + return render(request, 'contacts/unsubscribe_success.html') else: - form = ContactEntryForm() - - return render(request, 'contacts/subscribe.html', {'form': form}) + form = UnsubscribeForm() + return render(request, 'contacts/unsubscribe.html', {'form': form}) diff --git a/conservancy/settings/base.py b/conservancy/settings/base.py index 1d5c3132691ef081ab3b7b5d4b778041e0a08515..6ca284d6148f2d2797b3161e692603dc1b97531a 100644 --- a/conservancy/settings/base.py +++ b/conservancy/settings/base.py @@ -59,6 +59,11 @@ LOGGING = { 'handlers': ['console'], 'propagate': False, }, + 'conservancy.contacts': { + 'handlers': ['console'], + 'level': 'DEBUG', + 'propagate': False, + } }, 'root': { 'handlers': ['console'], diff --git a/conservancy/urls.py b/conservancy/urls.py index a23c6baa2cb5a7603e2b0b3c73097a6b0f531024..dc2fe8624e881af5d5f35f9241ebc5984fb875da 100644 --- a/conservancy/urls.py +++ b/conservancy/urls.py @@ -30,6 +30,7 @@ urlpatterns = [ path('assignment/', include('conservancy.assignment.urls')), path('blog/', include('conservancy.blog.urls')), path('casts/the-corresponding-source/', include('conservancy.podjango.urls')), + path('contacts/', include('conservancy.contacts.urls')), path('contractpatch/', include('conservancy.contractpatch.urls')), path('feeds/', feeds.view), path('feeds/blog/', feeds.BlogFeed()),