From a4689db62bbf73a7474d52837628e47be56822c6 Mon Sep 17 00:00:00 2001
From: Denver Gingerich
Date: Thu, 5 Dec 2024 15:32:00 -0800
Subject: [PATCH 1/6] Update Vizio trial date
---
conservancy/content/copyleft-compliance/vizio.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/conservancy/content/copyleft-compliance/vizio.html b/conservancy/content/copyleft-compliance/vizio.html
index c83fcc35..4589b150 100644
--- a/conservancy/content/copyleft-compliance/vizio.html
+++ b/conservancy/content/copyleft-compliance/vizio.html
@@ -18,7 +18,7 @@
a motion
for summary adjudication.
-The case's expected trial date is mid-2025.
+The case's expected trial date is in September 2025.
Portions of Interest from the Docket in the Vizio Case
From c377b329e21cdf1bb58b2b494ffa7ec9f101fe2c Mon Sep 17 00:00:00 2001
From: Paul Visscher
Date: Fri, 6 Dec 2024 14:13:46 -0500
Subject: [PATCH 2/6] add john gilmore to sponsor list
---
conservancy/templates/supporters/sponsors.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/conservancy/templates/supporters/sponsors.html b/conservancy/templates/supporters/sponsors.html
index 83f7a311..dc1e2bfe 100644
--- a/conservancy/templates/supporters/sponsors.html
+++ b/conservancy/templates/supporters/sponsors.html
@@ -43,6 +43,7 @@ any of its sponsors.
Mark Wielaard
David Turner and Danielle Sucher
+John Gilmore
From de861fe14dc1b764812a907ef4b4c2bbd03670f2 Mon Sep 17 00:00:00 2001
From: Ben Sturmfels
Date: Wed, 11 Dec 2024 10:37:02 +1100
Subject: [PATCH 3/6] contacts: Update unsubscribe to work through browser GET
interface
Also add field to mark unsubscribes as actioned.
---
conservancy/contacts/admin.py | 1 +
.../migrations/0003_unsubscription_actioned.py | 18 ++++++++++++++++++
conservancy/contacts/models.py | 7 +++++++
conservancy/contacts/views.py | 16 ++++++++++++++--
4 files changed, 40 insertions(+), 2 deletions(-)
create mode 100644 conservancy/contacts/migrations/0003_unsubscription_actioned.py
diff --git a/conservancy/contacts/admin.py b/conservancy/contacts/admin.py
index 9a61da2b..e5faaba2 100644
--- a/conservancy/contacts/admin.py
+++ b/conservancy/contacts/admin.py
@@ -6,4 +6,5 @@ from .models import Unsubscription
@admin.register(Unsubscription)
class UnsubscriptionAdmin(admin.ModelAdmin):
list_display = ['created', 'email', 'mailout']
+ list_filter = ['mailout', 'actioned']
search_fields = ['email', 'mailout']
diff --git a/conservancy/contacts/migrations/0003_unsubscription_actioned.py b/conservancy/contacts/migrations/0003_unsubscription_actioned.py
new file mode 100644
index 00000000..5ca7b62b
--- /dev/null
+++ b/conservancy/contacts/migrations/0003_unsubscription_actioned.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.2 on 2024-12-10 18:34
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contacts', '0002_unsubscription_mailout'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='unsubscription',
+ name='actioned',
+ field=models.DateField(blank=True, null=True),
+ ),
+ ]
diff --git a/conservancy/contacts/models.py b/conservancy/contacts/models.py
index 729b1c5c..dc78c668 100644
--- a/conservancy/contacts/models.py
+++ b/conservancy/contacts/models.py
@@ -5,6 +5,13 @@ class Unsubscription(models.Model):
created = models.DateTimeField(auto_now_add=True, blank=True)
email = models.EmailField()
mailout = models.SlugField()
+ actioned = models.DateField(null=True, blank=True)
class Meta:
ordering = ['created']
+
+ def __str__(self):
+ if self.mailout:
+ return f'{self.email} ({self.mailout})'
+ else:
+ return self.email
diff --git a/conservancy/contacts/views.py b/conservancy/contacts/views.py
index ed528120..78b05b90 100644
--- a/conservancy/contacts/views.py
+++ b/conservancy/contacts/views.py
@@ -27,15 +27,27 @@ def unsubscribe(request):
Interfaces like Gmail will then provide a user interface to unsubscribe
which will hit this endpoint.
+
+ Our understanding is that Gmail will submit the form with and HTTP POST request, but
+ with GET-style URL parameters. Hence this feature has been built to work both with
+ GET and POST-style data as well as GET and POST methods, just in case. Test it like
+ this:
+
+ curl -X POST -d 'email=foo@bar.com&mailout=jan2024-new' https://sfconservancy.org/contacts/unsubscribe/
+ curl -X POST 'https://sfconservancy.org/contacts/unsubscribe/?email=foo@bar.com&mailout=jan2024-new'
+
+ Or visit in a browser:
+
+ https://sfconservancy.org/contacts/unsubscribe/?email=foo@bar.com&mailout=jan2024-new
"""
if request.method == 'POST':
logger.debug('Unsubscribe GET: %s', request.GET)
logger.debug('Unsubscribe POST: %s', request.POST)
- form = UnsubscribeForm(request.GET)
+ form = UnsubscribeForm(request.GET.dict() | request.POST.dict())
if form.is_valid():
form.save()
logger.info('Unsubscribed %s', form.cleaned_data['email'])
return render(request, 'contacts/unsubscribe_success.html')
else:
- form = UnsubscribeForm()
+ form = UnsubscribeForm(request.GET.dict() | request.POST.dict())
return render(request, 'contacts/unsubscribe.html', {'form': form})
From 45fd0c4f5efb019398d1f03d4b630045446b9f77 Mon Sep 17 00:00:00 2001
From: Ben Sturmfels
Date: Tue, 17 Dec 2024 12:12:14 +1100
Subject: [PATCH 4/6] supporters: Mention tax receipt in supporter email
---
.../supporters/templates/supporters/mail/sustainer_thanks.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/conservancy/supporters/templates/supporters/mail/sustainer_thanks.txt b/conservancy/supporters/templates/supporters/mail/sustainer_thanks.txt
index 8cb73ffc..fcbd8e3b 100644
--- a/conservancy/supporters/templates/supporters/mail/sustainer_thanks.txt
+++ b/conservancy/supporters/templates/supporters/mail/sustainer_thanks.txt
@@ -14,5 +14,7 @@ Postal address:
{% if order.recurring == 'month' and order.tshirt_size %}
Please note that you may not receive the T-shirt until you've paid at least $60.{% endif %}
+An official donation receipt suitable for tax purposes should arrive via email within 2 weeks.
+
Kind regards,
Software Freedom Conservancy{% endautoescape %}
From 882d578e46a194fa93896284a4e8287bfd105662 Mon Sep 17 00:00:00 2001
From: Ben Sturmfels
Date: Wed, 18 Dec 2024 10:05:34 +1100
Subject: [PATCH 5/6] contacts: Allow unsubscribes to be actioned from list
view
---
conservancy/contacts/admin.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/conservancy/contacts/admin.py b/conservancy/contacts/admin.py
index e5faaba2..0865e933 100644
--- a/conservancy/contacts/admin.py
+++ b/conservancy/contacts/admin.py
@@ -5,6 +5,7 @@ from .models import Unsubscription
@admin.register(Unsubscription)
class UnsubscriptionAdmin(admin.ModelAdmin):
- list_display = ['created', 'email', 'mailout']
+ list_display = ['created', 'email', 'mailout', 'actioned']
+ list_editable = ['actioned']
list_filter = ['mailout', 'actioned']
search_fields = ['email', 'mailout']
From c80f8b41ac9a29393109b274481b8e1e77cceb25 Mon Sep 17 00:00:00 2001
From: Ben Sturmfels
Date: Wed, 18 Dec 2024 10:20:49 +1100
Subject: [PATCH 6/6] supporters: Add recurring details to Stripe export
---
conservancy/supporters/management/commands/export_stripe.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/conservancy/supporters/management/commands/export_stripe.py b/conservancy/supporters/management/commands/export_stripe.py
index e6c0f606..86b1e9bc 100644
--- a/conservancy/supporters/management/commands/export_stripe.py
+++ b/conservancy/supporters/management/commands/export_stripe.py
@@ -10,7 +10,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
payments = SustainerPayment.objects.select_related('order').order_by('paid_time')
- columns = ['order_time', 'payment_time', 'name', 'email', 'amount', 'transaction_id', 'public_ack', 'shirt_size', 'join_list', 'street', 'city', 'state', 'zip_code', 'country']
+ columns = ['order_time', 'payment_time', 'name', 'email', 'amount', 'transaction_id', 'recurring', 'subscription_id', 'public_ack', 'shirt_size', 'join_list', 'street', 'city', 'state', 'zip_code', 'country']
writer = csv.writer(sys.stdout)
writer.writerow(columns)
for payment in payments:
@@ -22,6 +22,8 @@ class Command(BaseCommand):
order.email,
payment.amount,
payment.stripe_payment_intent_ref,
+ order.recurring,
+ order.stripe_subscription_ref,
order.acknowledge_publicly,
repr(order.tshirt_size if order.tshirt_size else ''),
order.add_to_mailing_list,