diff --git a/client/src/leaderboardtemplate.jade b/client/src/leaderboardtemplate.jade index 0c89a9d2..84859e0f 100644 --- a/client/src/leaderboardtemplate.jade +++ b/client/src/leaderboardtemplate.jade @@ -32,9 +32,6 @@ mixin check(condition) tr.leaderboard-row td a(href=item.absolute_url)= item.name - if item.pledge - a(href=item.pledge.url) - i.pledged.fa.fa-handshake-o(title=`${item.name} have pledged to secure their site.`) td.desktop-only +check(item.valid_https) td.desktop-only diff --git a/client/src/styles/_home.scss b/client/src/styles/_home.scss index 587fb22d..464e6197 100644 --- a/client/src/styles/_home.scss +++ b/client/src/styles/_home.scss @@ -17,7 +17,7 @@ .stat-block { display: inline-block; - width: 33%; + width: 49%; vertical-align: top; } diff --git a/client/src/styles/_leaderboard.scss b/client/src/styles/_leaderboard.scss index 0fafc6a7..fdd5de4f 100644 --- a/client/src/styles/_leaderboard.scss +++ b/client/src/styles/_leaderboard.scss @@ -72,9 +72,6 @@ margin: 0; } - i.pledged { - margin-left: 10px; - } } @media (max-width: $mediaMedium) { diff --git a/client/src/styles/_pledge.scss b/client/src/styles/_pledge.scss deleted file mode 100644 index 3cd7aeb5..00000000 --- a/client/src/styles/_pledge.scss +++ /dev/null @@ -1,19 +0,0 @@ -.template-site-pledge { - label { - width: 140px; - display: inline-block; - text-align: right; - margin-right: $spacingUnit; - } - - input[type="url"], input[type="email"] { - display: inline-block; - max-width: 75%; - text-align: left; - padding: 20px 30px; - } - - input[type="submit"] { - cursor: pointer; - } -} diff --git a/client/src/styles/_site-page.scss b/client/src/styles/_site-page.scss index 47692bfd..2e2dd215 100644 --- a/client/src/styles/_site-page.scss +++ b/client/src/styles/_site-page.scss @@ -81,19 +81,4 @@ padding: $spacingUnit; } - .pledge { - background-color: #9eff8e; - border: 1px solid gray; - margin: 0 auto; - margin-top: $spacingUnit * 2; - padding: $spacingUnit / 2; - text-align: center; - width: 650px; - - i { - display: inline-block; - margin-right: $spacingUnit / 2; - } - - } } diff --git a/client/src/styles/main.scss b/client/src/styles/main.scss index aa89c0a1..14a33b53 100644 --- a/client/src/styles/main.scss +++ b/client/src/styles/main.scss @@ -22,5 +22,4 @@ @import 'blog-index'; @import 'site-index'; @import 'site-page'; -@import 'pledge'; @import 'forms'; diff --git a/home/models.py b/home/models.py index 3d9c3c8e..e156db71 100644 --- a/home/models.py +++ b/home/models.py @@ -88,8 +88,6 @@ def get_context(self, request): context['percent_offering_https'] = 0 context['percent_defaulting_to_https'] = 0 - context['num_pledged'] = len([site for site in sites if site.pledge]) - # Serialize sites with the results of their latest scans for the teaser context['sites_json'] = json.dumps([site.to_dict() for site in sites]) diff --git a/home/templates/home/home_page.html b/home/templates/home/home_page.html index 1b46e650..ca9ad56c 100644 --- a/home/templates/home/home_page.html +++ b/home/templates/home/home_page.html @@ -17,10 +17,6 @@
{{ page.sub_title }}
{{ percent_defaulting_to_https }}%
default to HTTPS
-
-
{{ num_pledged }}
-
site{{ num_pledged|pluralize }} committed to change
-
diff --git a/pledges/__init__.py b/pledges/__init__.py deleted file mode 100644 index caf94098..00000000 --- a/pledges/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'pledges.apps.PledgesConfig' diff --git a/pledges/admin.py b/pledges/admin.py deleted file mode 100644 index 222da2c8..00000000 --- a/pledges/admin.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.contrib import admin - -from .models import Pledge - -admin.site.register(Pledge) diff --git a/pledges/apps.py b/pledges/apps.py deleted file mode 100644 index 5fa04a77..00000000 --- a/pledges/apps.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.apps import AppConfig - - -class PledgesConfig(AppConfig): - name = 'pledges' - - def ready(self): - from . import signals # noqa: F401 diff --git a/pledges/forms.py b/pledges/forms.py deleted file mode 100644 index 35dc711f..00000000 --- a/pledges/forms.py +++ /dev/null @@ -1,40 +0,0 @@ -import re -from urllib.parse import urlparse -from urllib.request import urlopen, HTTPError - -from django.forms import ModelForm, ValidationError - -from .models import Pledge - - -class PledgeForm(ModelForm): - class Meta: - model = Pledge - fields = ['site', 'url', 'contact_email'] - - def clean(self): - # To discourage spam and make moderation easier, we require: - - # 1. The URL should match the domain of the site - site = self.cleaned_data['site'] - domain_re = r'([\w\.]+\.)?{}'.format(site.domain.replace('.', r'\.')) - parsed_url = urlparse(self.cleaned_data['url']) - if not re.match(domain_re, parsed_url.netloc): - raise ValidationError( - 'URL domain must match or be a subdomain of the site domain.' - ) - - # 2. The contact email address should match the domain of the site - email_re = '.+@{}'.format(site.domain.replace('.', r'\.')) - if not re.match(email_re, self.cleaned_data['contact_email']): - raise ValidationError( - 'Contact email address must match the site domain.' - ) - - # 3. The URL of the statement of intent should point to a live page - try: - urlopen(self.cleaned_data['url']) - except HTTPError: - raise ValidationError( - 'URL must be accessible.' - ) diff --git a/pledges/migrations/0001_initial.py b/pledges/migrations/0001_initial.py deleted file mode 100644 index 56da3dad..00000000 --- a/pledges/migrations/0001_initial.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.3 on 2016-11-11 09:16 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion -import pledges.models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('sites', '0016_auto_20161103_2350'), - ] - - operations = [ - migrations.CreateModel( - name='Pledge', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('url', models.URLField()), - ('contact_email', models.EmailField(max_length=254)), - ('confirmed', models.BooleanField(default=False, editable=False)), - ('confirmation_nonce', models.CharField(default=pledges.models.generate_confirmation_nonce, editable=False, max_length=255)), - ('review_status', models.CharField(choices=[('N', 'Needs Review'), ('A', 'Approved'), ('R', 'Rejected')], default='N', max_length=1)), - ('timestamp', models.DateTimeField(auto_now_add=True)), - ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pledges', to='sites.Site')), - ], - ), - ] diff --git a/pledges/migrations/0002_auto_20161112_0448.py b/pledges/migrations/0002_auto_20161112_0448.py deleted file mode 100644 index d025eec1..00000000 --- a/pledges/migrations/0002_auto_20161112_0448.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.3 on 2016-11-12 04:48 -from __future__ import unicode_literals - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('pledges', '0001_initial'), - ] - - operations = [ - migrations.RenameField( - model_name='pledge', - old_name='timestamp', - new_name='submitted', - ), - ] diff --git a/pledges/migrations/__init__.py b/pledges/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pledges/models.py b/pledges/models.py deleted file mode 100644 index 943c93db..00000000 --- a/pledges/models.py +++ /dev/null @@ -1,52 +0,0 @@ -from base64 import b16encode -from os import urandom - -from django.db import models - - -# Create your models here. -def generate_confirmation_nonce(): - # Use Base-16 to avoid potential URL encoding issues - return b16encode(urandom(32)) - - -class Pledge(models.Model): - site = models.ForeignKey( - 'sites.Site', - on_delete=models.CASCADE, - related_name='pledges' - ) - url = models.URLField() - contact_email = models.EmailField() - - confirmed = models.BooleanField(default=False, editable=False) - confirmation_nonce = models.CharField( - max_length=255, - default=generate_confirmation_nonce, - editable=False - ) - - STATUS_NEEDS_REVIEW = 'N' - STATUS_APPROVED = 'A' - STATUS_REJECTED = 'R' - STATUS_CHOICES = ( - (STATUS_NEEDS_REVIEW, 'Needs Review'), - (STATUS_APPROVED, 'Approved'), - (STATUS_REJECTED, 'Rejected'), - ) - review_status = models.CharField( - max_length=1, - choices=STATUS_CHOICES, - default=STATUS_NEEDS_REVIEW - ) - - submitted = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return "Pledge: {}".format(self.site.name) - - def to_dict(self): - return { - 'submitted': self.submitted.isoformat(), - 'url': self.url, - } diff --git a/pledges/signals.py b/pledges/signals.py deleted file mode 100644 index 23b34fd5..00000000 --- a/pledges/signals.py +++ /dev/null @@ -1,18 +0,0 @@ -# Signals are meant to be used as a last resort. We want to send an email when -# a pledge is approved, but since this happens through wagtailmodeladmin and -# not one of the views in the pledges app, we cannot just call -# send_review_confirmation_email from the view. Therefore, this seems like a -# reasonable use case for signals. - -from django.db.models.signals import post_save -from django.dispatch import receiver - -from .models import Pledge -from .views import send_review_confirmation_email - - -@receiver(post_save, sender=Pledge) -def maybe_send_review_confirmation_email(sender, **kwargs): - pledge = kwargs.get('instance') - if pledge.review_status == Pledge.STATUS_APPROVED: - send_review_confirmation_email(pledge) diff --git a/pledges/templates/pledges/confirm.html b/pledges/templates/pledges/confirm.html deleted file mode 100644 index bf96ca7b..00000000 --- a/pledges/templates/pledges/confirm.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Confirm your pledge{% endblock %} - -{% block body_class %}template-confirm-pledge{% endblock %} - -{% block content %} -
-
-

Confirm your pledge

-
You're almost done!
-
-
- -
-
-

Confirm your pledge to secure {{ pledge.site.name }}:

-
- {% csrf_token %} - - -
-
-
-{% endblock %} diff --git a/pledges/templates/pledges/confirmed.html b/pledges/templates/pledges/confirmed.html deleted file mode 100644 index 67128662..00000000 --- a/pledges/templates/pledges/confirmed.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Pledge confirmed{% endblock %} - -{% block body_class %}template-confirm-pledge{% endblock %} - -{% block content %} -
-
-

Pledge confirmed

-
You're done!
-
-
- -
-
-

Your pledge to secure {{ pledge.site.name }} has been confirmed!

-

We'll review your pledge soon. Once it is approved, you will receive a confirmation email and a notice will be added to your site's score page.

-
-
-{% endblock %} diff --git a/pledges/templates/pledges/emails/admin_notification.txt b/pledges/templates/pledges/emails/admin_notification.txt deleted file mode 100644 index 4fdf7099..00000000 --- a/pledges/templates/pledges/emails/admin_notification.txt +++ /dev/null @@ -1,3 +0,0 @@ -A pledge for {{ site.name }} has been confirmed and is ready for review: - -{{ moderation_link }} diff --git a/pledges/templates/pledges/emails/confirmation.txt b/pledges/templates/pledges/emails/confirmation.txt deleted file mode 100644 index c430bbba..00000000 --- a/pledges/templates/pledges/emails/confirmation.txt +++ /dev/null @@ -1,14 +0,0 @@ -Thanks for submitting a pledge to secure your site on Secure the News! - -To finish the process, confirm your submission by opening the following link in -your browser and clicking "Confirm": - -{{ confirmation_link }} - -Once you have confirmed your submission, it will become available for us to -review. You will receive an email notification once your pledge submission is -either approved or rejected. - -If you did not intend to submit a pledge to Secure the News, you don't have to -do anything - we won't act unless the submission is confirmed. If you have any -questions or concerns, please reach out to us at: contact@securethe.news. diff --git a/pledges/templates/pledges/emails/reviewed.txt b/pledges/templates/pledges/emails/reviewed.txt deleted file mode 100644 index 9f136e0b..00000000 --- a/pledges/templates/pledges/emails/reviewed.txt +++ /dev/null @@ -1,5 +0,0 @@ -Your pledge to secure your site has been {{ pledge.get_review_status_display|lower }}! - -{% if pledge.review_status == pledge.STATUS_APPROVED %}The score page for your site has been updated to reflect your pledge.{% endif %} - -If you have any questions or concerns, please reach out to us at: contact@securethe.news. diff --git a/pledges/templates/pledges/pledge.html b/pledges/templates/pledges/pledge.html deleted file mode 100644 index 884d3b8e..00000000 --- a/pledges/templates/pledges/pledge.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Pledge to Secure your Site{% endblock %} - -{% block body_class %}template-site-pledge{% endblock %} - -{% block content %} -
-
-

Pledge to Secure Your Site

-
Publicly share your intention to protect your readers by securing your site
-
-
- -
-
-

Planning to secure your site? We recognize that deploying HTTPS is a - serious undertaking that can take a lot of time and attention. If you - pledge to secure your site, we'll indicate your commitment to doing so - on your site's score page so your users will know you're working on - it.

-

If you're involved with one of the news organizations listed on Secure - the News, you can use the form below to pledge to securing your site. In - order to do so, you will need to:

-

-

    -
  1. Publish a page on your website indicating your intent to secure your site.
  2. -
  3. Fill out the form below, providing a link to your statement of intent and a contact email address so we can be in touch if we have any questions.
  4. -
-

-

Once you've submitted the form, Freedom of the Press Foundation staff - will review your submission. If it meets our criteria, we will approve it, - which will update your site's score page to reflect your intention to - secure your site.

-
- {% csrf_token %} - {{ form.as_p }} - -
-
-
-{% endblock %} diff --git a/pledges/templates/pledges/thanks.html b/pledges/templates/pledges/thanks.html deleted file mode 100644 index bafeb902..00000000 --- a/pledges/templates/pledges/thanks.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Pledge to Secure your Site{% endblock %} - -{% block body_class %}template-site-pledge{% endblock %} - -{% block content %} -
-
-

Pledge to Secure Your Site

-
Publicly share your intention to protect your readers by securing your site
-
-
- -
-
-

Thanks for pledging to secure your site!

-

We've sent an email to the contact email address you provided with instructions to confirm your submission. Once you've confirmed your submission, it will be available for us to review.

-
-
-{% endblock %} diff --git a/pledges/tests.py b/pledges/tests.py deleted file mode 100644 index e55d6890..00000000 --- a/pledges/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase # noqa: F401 - -# Create your tests here. diff --git a/pledges/urls.py b/pledges/urls.py deleted file mode 100644 index 624616cd..00000000 --- a/pledges/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf.urls import url - -from . import views - -app_name = 'pledges' -urlpatterns = [ - url(r'^$', views.pledge, name='pledge'), - url(r'^thanks$', views.thanks, name='thanks'), - url(r'^(?P[0-9]+)/confirm$', views.confirm, name='confirm'), - url(r'^(?P[0-9]+)/confirmed$', views.confirmed, name='confirmed'), -] diff --git a/pledges/views.py b/pledges/views.py deleted file mode 100644 index a0fba869..00000000 --- a/pledges/views.py +++ /dev/null @@ -1,127 +0,0 @@ -from urllib.parse import urlencode - -from django.conf import settings -from django.core.mail import mail_admins, send_mail -from django.core.exceptions import SuspiciousOperation -from django.urls import reverse -from django.http import HttpResponseRedirect, HttpResponseBadRequest -from django.shortcuts import get_object_or_404, render -from django.template.loader import render_to_string -from django.utils.crypto import constant_time_compare - -from .forms import PledgeForm -from .models import Pledge -from .wagtail_hooks import PledgeAdmin - - -def pledge(request): - if request.method == 'POST': - form = PledgeForm(request.POST) - if form.is_valid(): - new_pledge = form.save() - send_confirmation_email(request, new_pledge) - return HttpResponseRedirect(reverse('pledges:thanks')) - else: - form = PledgeForm() - - return render(request, 'pledges/pledge.html', {'form': form}) - - -def thanks(request): - return render(request, 'pledges/thanks.html') - - -def confirm(request, pk): - pledge = get_object_or_404(Pledge, pk=pk) - - # If the pledge has already been confirmed, redirect to confirmation page. - if pledge.confirmed: - return HttpResponseRedirect(reverse('pledges:confirmed', kwargs={ - 'pk': pledge.pk - })) - - if request.method == 'POST': - nonce = request.POST.get('nonce') - if not constant_time_compare(pledge.confirmation_nonce, nonce): - raise SuspiciousOperation( - "Received pledge with invalid nonce (pk={}, nonce={})".format( - pledge.pk, nonce)) - - pledge.confirmed = True - pledge.save() - send_admin_notification_email(request, pledge) - - return HttpResponseRedirect(reverse('pledges:confirmed', kwargs={ - 'pk': pledge.pk - })) - - nonce = request.GET.get('nonce') - if not nonce: - return HttpResponseBadRequest() - - return render(request, 'pledges/confirm.html', { - 'pledge': pledge, - 'nonce': nonce, - }) - - -def confirmed(request, pk): - pledge = get_object_or_404(Pledge, pk=pk) - return render(request, 'pledges/confirmed.html', {'pledge': pledge}) - - -def send_confirmation_email(request, pledge): - assert not pledge.confirmed, "{} is already confirmed" - - subject = "Confirm your pledge to secure your site" - - confirmation_link = request.build_absolute_uri("{}?{}".format( - reverse('pledges:confirm', kwargs={'pk': pledge.pk}), - urlencode({'nonce': pledge.confirmation_nonce}) - )) - - message = render_to_string('pledges/emails/confirmation.txt', { - 'confirmation_link': confirmation_link - }) - - send_mail( - subject=subject, - message=message, - from_email=settings.DEFAULT_FROM_EMAIL, - recipient_list=[pledge.contact_email, ] - ) - - -def send_admin_notification_email(request, pledge): - """Notify the admins that a submitted pledge has been - confirmed and is ready for review.""" - subject = 'Pledge Ready for Review: {}'.format(pledge.site.name) - - # Get the wagtailmodeladmin PledgeAdmin so we can derive the edit - # url for the newly submitted pledge. - pledge_admin = PledgeAdmin() - - body = render_to_string('pledges/emails/admin_notification.txt', { - 'site': pledge.site, - 'moderation_link': request.build_absolute_uri( - pledge_admin.url_helper.get_action_url('edit', pledge.pk) - ), - }) - - mail_admins(subject, body) - - -def send_review_confirmation_email(pledge): - subject = 'Secure the News Pledge Review: {}'.format( - pledge.get_review_status_display()) - - message = render_to_string( - 'pledges/emails/reviewed.txt', - {'pledge': pledge}) - - send_mail( - subject=subject, - message=message, - from_email=settings.DEFAULT_FROM_EMAIL, - recipient_list=[pledge.contact_email, ] - ) diff --git a/pledges/wagtail_hooks.py b/pledges/wagtail_hooks.py deleted file mode 100644 index 50cd98f5..00000000 --- a/pledges/wagtail_hooks.py +++ /dev/null @@ -1,23 +0,0 @@ -from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register - -from .models import Pledge - - -class PledgeAdmin(ModelAdmin): - model = Pledge - menu_label = 'Pledges' - menu_icon = 'form' - add_to_settings_menu = False - - list_display = ('site', 'submitted', 'review_status') - list_filter = ('review_status',) - - search_fields = ('url', 'contact_email') - - def get_queryset(self, request): - """Only display confirmed pledges.""" - qs = super(PledgeAdmin, self).get_queryset(request) - return qs.filter(confirmed=True) - - -modeladmin_register(PledgeAdmin) diff --git a/securethenews/settings/base.py b/securethenews/settings/base.py index 508883ad..3fa75546 100644 --- a/securethenews/settings/base.py +++ b/securethenews/settings/base.py @@ -30,7 +30,6 @@ 'search', 'sites', - 'pledges', 'blog', 'wagtail.contrib.forms', diff --git a/securethenews/urls.py b/securethenews/urls.py index 4201af29..2cce3f5b 100644 --- a/securethenews/urls.py +++ b/securethenews/urls.py @@ -28,7 +28,6 @@ path('search/', search_views.search, name='search'), path('sites/', include('sites.urls')), - path('pledge/', include('pledges.urls')), path('news/', include('blog.urls')), path('api/', include('api.urls')), diff --git a/sites/models.py b/sites/models.py index c145265a..0c11b11b 100644 --- a/sites/models.py +++ b/sites/models.py @@ -13,8 +13,6 @@ from wagtailautocomplete.edit_handlers import AutocompletePanel -from pledges.models import Pledge - class ScannedSitesManager(models.Manager): def get_queryset(self): @@ -73,15 +71,6 @@ def save(self, *args, **kwargs): self.full_clean() super(Site, self).save(*args, **kwargs) - @property - def pledge(self): - """Return the latest approved pledge, or None""" - return self.pledges.filter( - review_status=Pledge.STATUS_APPROVED - ).order_by( - '-submitted' - ).first() - def to_dict(self): """Generate a JSON-serializable dict of this object's attributes, including the results of the most recent scan.""" @@ -90,7 +79,6 @@ def to_dict(self): name=self.name, domain=self.domain, absolute_url=self.get_absolute_url(), - pledge=self.pledge.to_dict() if self.pledge else None, **self.scans.latest().to_dict() ) diff --git a/sites/templates/sites/site.html b/sites/templates/sites/site.html index 7b8d8b7b..ecb4ca2a 100644 --- a/sites/templates/sites/site.html +++ b/sites/templates/sites/site.html @@ -35,13 +35,6 @@
Security Rating: {% grade scan %}
- {% if site.pledge %} -
- - {{ site.name }} pledged to secure their site on {{ site.pledge.submitted|date:"F j, Y"}}. -
- {% endif %} -
diff --git a/sites/test_models.py b/sites/test_models.py index 570af7a8..13764f36 100644 --- a/sites/test_models.py +++ b/sites/test_models.py @@ -51,11 +51,6 @@ def test_unicode_aware_slugs_can_be_modified(self): site.save() self.assertIn('í', site.slug) - def test_site_without_pledge(self): - """Site.pledge should return None if there are no approved - pledges for the Site.""" - self.assertIsNone(self.site.pledge) - class TestScan(TestCase):