Merge branch 'master' of f.sfconservancy.org:Conservancy/website
This commit is contained in:
commit
53b95a217f
8 changed files with 49 additions and 5 deletions
|
@ -5,5 +5,7 @@ from .models import Unsubscription
|
||||||
|
|
||||||
@admin.register(Unsubscription)
|
@admin.register(Unsubscription)
|
||||||
class UnsubscriptionAdmin(admin.ModelAdmin):
|
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']
|
search_fields = ['email', 'mailout']
|
||||||
|
|
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -5,6 +5,13 @@ class Unsubscription(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True, blank=True)
|
created = models.DateTimeField(auto_now_add=True, blank=True)
|
||||||
email = models.EmailField()
|
email = models.EmailField()
|
||||||
mailout = models.SlugField()
|
mailout = models.SlugField()
|
||||||
|
actioned = models.DateField(null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['created']
|
ordering = ['created']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.mailout:
|
||||||
|
return f'{self.email} ({self.mailout})'
|
||||||
|
else:
|
||||||
|
return self.email
|
||||||
|
|
|
@ -27,15 +27,27 @@ def unsubscribe(request):
|
||||||
|
|
||||||
Interfaces like Gmail will then provide a user interface to unsubscribe
|
Interfaces like Gmail will then provide a user interface to unsubscribe
|
||||||
which will hit this endpoint.
|
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':
|
if request.method == 'POST':
|
||||||
logger.debug('Unsubscribe GET: %s', request.GET)
|
logger.debug('Unsubscribe GET: %s', request.GET)
|
||||||
logger.debug('Unsubscribe POST: %s', request.POST)
|
logger.debug('Unsubscribe POST: %s', request.POST)
|
||||||
form = UnsubscribeForm(request.GET)
|
form = UnsubscribeForm(request.GET.dict() | request.POST.dict())
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
logger.info('Unsubscribed %s', form.cleaned_data['email'])
|
logger.info('Unsubscribed %s', form.cleaned_data['email'])
|
||||||
return render(request, 'contacts/unsubscribe_success.html')
|
return render(request, 'contacts/unsubscribe_success.html')
|
||||||
else:
|
else:
|
||||||
form = UnsubscribeForm()
|
form = UnsubscribeForm(request.GET.dict() | request.POST.dict())
|
||||||
return render(request, 'contacts/unsubscribe.html', {'form': form})
|
return render(request, 'contacts/unsubscribe.html', {'form': form})
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
a <a href="https://sfconservancy.org/docs/software-freedom-conservancy-v-vizio_2023-12-01_SFC-Motion-Summary-Adjudication.pdf">motion
|
a <a href="https://sfconservancy.org/docs/software-freedom-conservancy-v-vizio_2023-12-01_SFC-Motion-Summary-Adjudication.pdf">motion
|
||||||
for summary adjudication</a>.</p>
|
for summary adjudication</a>.</p>
|
||||||
|
|
||||||
<p>The case's expected trial date is mid-2025.</p>
|
<p>The case's expected trial date is in September 2025.</p>
|
||||||
|
|
||||||
<h3>Portions of Interest from the Docket in the Vizio Case</h3>
|
<h3>Portions of Interest from the Docket in the Vizio Case</h3>
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
payments = SustainerPayment.objects.select_related('order').order_by('paid_time')
|
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 = csv.writer(sys.stdout)
|
||||||
writer.writerow(columns)
|
writer.writerow(columns)
|
||||||
for payment in payments:
|
for payment in payments:
|
||||||
|
@ -22,6 +22,8 @@ class Command(BaseCommand):
|
||||||
order.email,
|
order.email,
|
||||||
payment.amount,
|
payment.amount,
|
||||||
payment.stripe_payment_intent_ref,
|
payment.stripe_payment_intent_ref,
|
||||||
|
order.recurring,
|
||||||
|
order.stripe_subscription_ref,
|
||||||
order.acknowledge_publicly,
|
order.acknowledge_publicly,
|
||||||
repr(order.tshirt_size if order.tshirt_size else ''),
|
repr(order.tshirt_size if order.tshirt_size else ''),
|
||||||
order.add_to_mailing_list,
|
order.add_to_mailing_list,
|
||||||
|
|
|
@ -14,5 +14,7 @@ Postal address:
|
||||||
{% if order.recurring == 'month' and order.tshirt_size %}
|
{% 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 %}
|
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,
|
Kind regards,
|
||||||
Software Freedom Conservancy{% endautoescape %}
|
Software Freedom Conservancy{% endautoescape %}
|
||||||
|
|
|
@ -43,6 +43,7 @@ any of its sponsors.</p>
|
||||||
<li><a rel="nofollow" href="https://code.wildebeest.org/">Mark Wielaard</a></li>
|
<li><a rel="nofollow" href="https://code.wildebeest.org/">Mark Wielaard</a></li>
|
||||||
<li><a rel="nofollow" href="https://www.mozilla.org/foundation/"><img src="{% static 'img/sponsors/mozilla.png' %}" height="101" width="250" alt="Mozilla Foundation" /></a></li>
|
<li><a rel="nofollow" href="https://www.mozilla.org/foundation/"><img src="{% static 'img/sponsors/mozilla.png' %}" height="101" width="250" alt="Mozilla Foundation" /></a></li>
|
||||||
<li><b>David Turner and Danielle Sucher</b></li>
|
<li><b>David Turner and Danielle Sucher</b></li>
|
||||||
|
<li><b>John Gilmore</b></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- This section will be added when we have in-kind contributions -->
|
<!-- This section will be added when we have in-kind contributions -->
|
||||||
|
|
Loading…
Reference in a new issue