diff --git a/conservancy/contacts/admin.py b/conservancy/contacts/admin.py
index 94048d4b..f6c68b1c 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 00000000..e10b2fab
--- /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 00000000..e69de29b
diff --git a/conservancy/contacts/models.py b/conservancy/contacts/models.py
index 14ac7484..58e89a75 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 00000000..86de5a67
--- /dev/null
+++ b/conservancy/contacts/templates/contacts/unsubscribe.html
@@ -0,0 +1,10 @@
+{% extends "base_conservancy.html" %}
+{% block outercontent %}
+
+{% endblock %}
diff --git a/conservancy/contacts/templates/contacts/unsubscribe_success.html b/conservancy/contacts/templates/contacts/unsubscribe_success.html
new file mode 100644
index 00000000..e4938995
--- /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 661e6891..74f1c84d 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 95ccfc09..65ea3445 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
+
+logger = logging.getLogger(__name__)
+
+class UnsubscribeForm(ModelForm):
+ class Meta:
+ model = Unsubscription
+ fields = ['email']
-def subscribe(request):
- """Mailing list subscription form
- """
-
- class ContactEntryForm(ModelForm):
- class Meta:
- model = ContactEntry
-
- 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 1d5c3132..6ca284d6 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 a23c6baa..dc2fe862 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()),