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.
This commit is contained in:
Ben Sturmfels 2024-04-09 22:50:06 +10:00
parent ef3dd503d8
commit 789d0c8c84
Signed by: bsturmfels
GPG key ID: 023C05E2C9C068F0
10 changed files with 86 additions and 33 deletions

View file

@ -1,10 +1,8 @@
from django.contrib import admin from django.contrib import admin
from .models import ContactEntry from .models import Unsubscription
@admin.register(ContactEntry)
class ContactEntryAdmin(admin.ModelAdmin):
list_display = ('email', 'subscribe_conservancy')
@admin.register(Unsubscription)
class UnsubscriptionAdmin(admin.ModelAdmin):
list_display = ['created', 'email']

View file

@ -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'],
},
),
]

View file

@ -1,14 +1,9 @@
from django.db import models from django.db import models
class ContactEntry(models.Model): class Unsubscription(models.Model):
"""Conservancy contact system created = models.DateTimeField(auto_now_add=True, blank=True)
email = models.EmailField()
Hopefully this will be deprecated soon"""
email = models.EmailField() # should make it unique, but we really cannot
subscribe_conservancy = models.BooleanField(default=False)
class Meta: class Meta:
ordering = ('email',) ordering = ['created']

View file

@ -0,0 +1,10 @@
{% extends "base_conservancy.html" %}
{% block outercontent %}
<div class="mw8 center ph2 ph3 mb4">
<h1>Unsubscribe</h1>
<form action="." method="post">
{{ form.as_p }}
<p><button type="submit" class="ph3 pv2">Submit</button></p>
</form>
</div>
{% endblock %}

View file

@ -0,0 +1,6 @@
{% extends "base_conservancy.html" %}
{% block outercontent %}
<div class="mw8 center ph2 ph3 mb4">
<h1>Unsubscribe successful</h1>
</div>
{% endblock %}

View file

@ -1,7 +1,7 @@
from django.urls import path from django.urls import path
from .views import subscribe from .views import unsubscribe
urlpatterns = [ urlpatterns = [
path('', subscribe), path('unsubscribe/', unsubscribe),
] ]

View file

@ -1,25 +1,31 @@
import logging
from django.forms import ModelForm from django.forms import ModelForm
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render from django.shortcuts import render
from .models import ContactEntry from .models import Unsubscription
logger = logging.getLogger(__name__)
def subscribe(request): class UnsubscribeForm(ModelForm):
"""Mailing list subscription form
"""
class ContactEntryForm(ModelForm):
class Meta: class Meta:
model = ContactEntry 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': 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(): if form.is_valid():
form.save() 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: else:
form = ContactEntryForm() form = UnsubscribeForm()
return render(request, 'contacts/unsubscribe.html', {'form': form})
return render(request, 'contacts/subscribe.html', {'form': form})

View file

@ -59,6 +59,11 @@ LOGGING = {
'handlers': ['console'], 'handlers': ['console'],
'propagate': False, 'propagate': False,
}, },
'conservancy.contacts': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
}
}, },
'root': { 'root': {
'handlers': ['console'], 'handlers': ['console'],

View file

@ -30,6 +30,7 @@ urlpatterns = [
path('assignment/', include('conservancy.assignment.urls')), path('assignment/', include('conservancy.assignment.urls')),
path('blog/', include('conservancy.blog.urls')), path('blog/', include('conservancy.blog.urls')),
path('casts/the-corresponding-source/', include('conservancy.podjango.urls')), path('casts/the-corresponding-source/', include('conservancy.podjango.urls')),
path('contacts/', include('conservancy.contacts.urls')),
path('contractpatch/', include('conservancy.contractpatch.urls')), path('contractpatch/', include('conservancy.contractpatch.urls')),
path('feeds/', feeds.view), path('feeds/', feeds.view),
path('feeds/blog/', feeds.BlogFeed()), path('feeds/blog/', feeds.BlogFeed()),