diff --git a/autocomplete/widgets.py b/autocomplete/widgets.py index e144516..ac01ec5 100644 --- a/autocomplete/widgets.py +++ b/autocomplete/widgets.py @@ -9,8 +9,8 @@ from django.http import HttpResponse, HttpResponseRedirect from django.contrib.admin.widgets import RelatedFieldWidgetWrapper -from django.utils.translation import ugettext as _ -from django.utils.encoding import force_text +from django.utils.translation import gettext as _ +from django.utils.encoding import force_str from django.utils.html import escape from django.utils.datastructures import MultiValueDict @@ -259,7 +259,7 @@ def response_add(self, request, obj, post_url_continue='../%s/'): opts = obj._meta pk_value = obj._get_pk_val() - msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} + msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_str(opts.verbose_name), 'obj': force_str(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if '_continue' in request.POST: @@ -274,7 +274,7 @@ def response_add(self, request, obj, post_url_continue='../%s/'): return HttpResponse('' % (escape(pk_value), escape(obj))) elif '_addanother' in request.POST: - self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_text(opts.verbose_name))) + self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_str(opts.verbose_name))) return HttpResponseRedirect(request.path) else: self.message_user(request, msg) diff --git a/countries/models.py b/countries/models.py index ce4849c..6099ea8 100644 --- a/countries/models.py +++ b/countries/models.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class Country(models.Model): diff --git a/lp/urls.py b/lp/urls.py index 9316380..bf10448 100644 --- a/lp/urls.py +++ b/lp/urls.py @@ -1,10 +1,10 @@ -from django.conf.urls import url +from django.urls import path from lp import views urlpatterns = [ - url(r'^edition/$', views.edition), - url(r'^sample/$', views.sample), - url(r'^meta.json$', views.meta_json), - url(r'^icon.png$', views.icon), + path('edition/', views.edition), + path('sample/', views.sample), + path('meta.json', views.meta_json), + path('icon.png', views.icon), ] diff --git a/merged/tests.py b/merged/tests.py index d19b884..45c29f4 100644 --- a/merged/tests.py +++ b/merged/tests.py @@ -6,31 +6,31 @@ class MergeTest(TestCase): def test_doing_a_merge(self): - make_production( + hamlet1 = make_production( 'Hamlet', 'A tragedy', ['Shakespeare Productions'], [{'name': 'Theatre', 'start': '2013-01-01', 'end': '2013-01-14'}] ) - make_production( + hamlet2 = make_production( 'Hamlet', 'A tragedy', ['Shakespeare Productions'], [{'name': 'Stirchley Theatre', 'start': '2013-01-01', 'end': '2013-01-14'}] ) - resp = self.client.get('/play/1/hamlet/production/1') + resp = self.client.get(hamlet1.get_absolute_url()) self.assertContains(resp, 'Hamlet') - resp = self.client.get('/play/1/hamlet/production/2') + resp = self.client.get(hamlet2.get_absolute_url()) self.assertContains(resp, 'Hamlet') - resp = self.client.get('/play/1/hamlet/production/2/merge') + resp = self.client.get(hamlet2.get_absolute_url() + '/merge') self.assertContains(resp, 'Thanks for helping improve the accuracy of the site.') - resp = self.client.get('/play/1/hamlet/production/2') + resp = self.client.get(hamlet2.get_absolute_url()) self.assertNotContains(resp, 'This is a duplicate') - resp = self.client.get('/play/1/hamlet/production/1') + resp = self.client.get(hamlet1.get_absolute_url()) self.assertContains(resp, 'This is a duplicate of Shakespeare Productions production of Hamlet') - resp = self.client.post('/play/1/hamlet/production/1/merge', {'dupe': True}) + resp = self.client.post(hamlet1.get_absolute_url() + '/merge', {'dupe': True}) self.assertContains(resp, 'Thanks again for helping') self.assertEqual(len(mail.outbox), 1) - resp = self.client.post('/play/1/hamlet/production/1/merge', {'stop': True}, follow=True) - self.assertRedirects(resp, '/play/1/hamlet/production/1') + resp = self.client.post(hamlet1.get_absolute_url() + '/merge', {'stop': True}, follow=True) + self.assertRedirects(resp, hamlet1.get_absolute_url()) diff --git a/productions/models.py b/productions/models.py index 8febf82..9754efa 100644 --- a/productions/models.py +++ b/productions/models.py @@ -314,7 +314,7 @@ class Part(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE) role = models.CharField( u'R\u00f4le', max_length=200, blank=True, help_text=u'e.g. \u201cRomeo\u201d or \u201cDirector\u201d') - cast = models.NullBooleanField( + cast = models.BooleanField( null=True, blank=True, verbose_name='Cast/Crew', help_text=u'Crew includes all non-cast, from director to musicians to producers') credited_as = models.CharField( diff --git a/profiles/models.py b/profiles/models.py index 7a69c2c..b8ae4e2 100644 --- a/profiles/models.py +++ b/profiles/models.py @@ -2,7 +2,7 @@ from django.conf import settings from django.contrib.auth.models import AbstractUser from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class User(AbstractUser): diff --git a/profiles/views.py b/profiles/views.py index 5fd93a9..770d05c 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -1,16 +1,10 @@ from django.http import HttpResponseRedirect, Http404 from django.contrib.auth.tokens import PasswordResetTokenGenerator -from django.contrib.sites.shortcuts import get_current_site from django.contrib.auth.decorators import login_required from django.shortcuts import get_object_or_404 -from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login -from django.conf import settings -from django.shortcuts import render, resolve_url -from django.template.response import TemplateResponse -from django.utils.http import is_safe_url -from django.views.decorators.cache import never_cache -from django.views.decorators.csrf import csrf_protect -from django.views.decorators.debug import sensitive_post_parameters +from django.contrib.auth import login as auth_login +from django.contrib.auth.views import LoginView as DjangoLoginView +from django.shortcuts import render from django.db.models import Q, Min from django.db.models.expressions import RawSQL @@ -79,46 +73,8 @@ def register(request): return render(request, 'registration/register.html', {'form': form}) -@sensitive_post_parameters() -@csrf_protect -@never_cache -def login(request, template_name='registration/login.html', - redirect_field_name=REDIRECT_FIELD_NAME, - authentication_form=AuthenticationForm, - extra_context=None): - """ - Displays the login form and handles the login action. - """ - redirect_to = request.POST.get(redirect_field_name, - request.GET.get(redirect_field_name, '')) - - if request.method == "POST": - form = authentication_form(request, data=request.POST) - if form.is_valid(): - - # Ensure the user-originating redirection url is safe. - if not is_safe_url(url=redirect_to, allowed_hosts=request.get_host()): - redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) - - # Okay, security check complete. Log the user in. - auth_login(request, form.get_user()) - - return HttpResponseRedirect(redirect_to) - else: - form = authentication_form(request) - - current_site = get_current_site(request) - - context = { - 'form': form, - redirect_field_name: redirect_to, - 'site': current_site, - 'site_name': current_site.name, - } - if extra_context is not None: - context.update(extra_context) - - return TemplateResponse(request, template_name, context) +class LoginView(DjangoLoginView): + form_class = AuthenticationForm # def registration_complete(request): diff --git a/requirements-base.txt b/requirements-base.txt index 2720940..ed2af8a 100644 --- a/requirements-base.txt +++ b/requirements-base.txt @@ -1,8 +1,10 @@ mysqlclient==2.0.2 Pillow==10.1.0 +# Upgrade to 8.0.0 when DJ3 django-cleanup==6.0.0 django-contrib-comments==2.2.0 -django-nose==1.4.7 -django-reversion==3.0.7 +# Upgrade to 5.0.8 when DJ3 +django-reversion==4.0.2 +# Upgrade to 12.10.0 when running on DJ3 sorl-thumbnail==12.8.0 python-dateutil==2.8.2 diff --git a/templates/admin/edit_part_inline.html b/templates/admin/edit_part_inline.html index 8b88bf4..ff60ee3 100644 --- a/templates/admin/edit_part_inline.html +++ b/templates/admin/edit_part_inline.html @@ -29,9 +29,9 @@

{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

{% for field in inline_admin_formset.fields %} {% if not field.is_hidden %} - {% ifnotequal field.label 'LookupPerson' %} + {% if field.label != 'LookupPerson' %} {{ field.label|capfirst }} - {% endifnotequal %} + {% endif %} {% endif %} {% endfor %} {% if inline_admin_formset.formset.can_delete %}{% trans "Delete?" %}{% endif %} @@ -63,17 +63,17 @@

{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

{% for fieldset in inline_admin_form %} {% for line in fieldset %} {% for field in line %} - {% ifnotequal field.field.name 'lookup_person' %} + {% if field.field.name != 'lookup_person' %} {{ field.field.errors.as_ul }} - {% ifequal field.field.name 'person' %} + {% if field.field.name == 'person' %} {% else %} {{ field.field }} - {% endifequal %} + {% endif %} - {% endifnotequal %} + {% endif %} {% endfor %} {% endfor %} {% endfor %} diff --git a/templates/base.html b/templates/base.html index a66ac85..0162c19 100644 --- a/templates/base.html +++ b/templates/base.html @@ -146,7 +146,7 @@ Your profile | Sign out {% else %} -Sign in +Sign in {% endif %}

{% endblock %} @@ -160,9 +160,9 @@

{% endif %} -{% ifequal request.META.HTTP_HOST "staging.theatricalia.com" %} +{% if request.META.HTTP_HOST == "staging.theatricalia.com" %} {% else %} -{% endifequal %} +{% endif %} diff --git a/templates/home.html b/templates/home.html index eec9336..3b881d9 100644 --- a/templates/home.html +++ b/templates/home.html @@ -49,20 +49,20 @@

For example…

by {{ production.get_companies_display }}{% endif %}, {% endthumbnail %} -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.date_summary|prettify }}, at {{ production.places.all.0.get_name_display|prettify }}.

{% else %} - {% ifequal production.places.count 0 %} + {% if production.places.count == 0 %} at an unknown location. {% else %} at {% for place in production.place_set.all %} {% if forloop.last and not forloop.first %} and {% endif %} {{ place.place.get_name_display|prettify }} - ({{ place.date_summary|prettify }}){% ifequal forloop.revcounter0 0 %}{% else %}{% ifequal forloop.revcounter0 1 %}{% ifnotequal forloop.counter0 0 %},{% endifnotequal %}{% else %},{% endifequal %}{% endifequal %}{% endfor %}. - {% endifequal %} -{% endifequal %} + ({{ place.date_summary|prettify }}){% if forloop.revcounter0 == 0 %}{% elif forloop.revcounter0 == 1 %}{% if forloop.counter0 != 0 %},{% endif %}{% else %},{% endif %}{% endfor %}. + {% endif %} +{% endif %}

More →

@@ -106,14 +106,13 @@

Most recent…

  • …addition: {% if latest_production %} {{ latest_production.play.get_title_display|prettify }}, -{% ifequal latest_production.places.count 1 %} +{% if latest_production.places.count == 1 %} at {{ latest_production.places.all.0|prettify }}, {{ latest_production.date_summary|prettify }}. {% if latest_production.place_set.all.0.press_date and latest_production.place_set.all.0.start_date %} Press night was {{ latest_production.place_set.all.0.press_date|date:"jS F Y"|prettify }}. {% endif %} -{% else %} -{% ifequal latest_production.places.count 0 %} +{% elif latest_production.places.count == 0 %} at an unknown location. {% else %} {% firstof latest_production.place_set_ordered|length as places %} @@ -121,16 +120,13 @@

    Most recent…

    {% for place in latest_production.place_set_ordered|slice:":5" %} {% if forloop.last and not forloop.first and places|add:0 <= 5 %} and {% endif %} {{ place.place|prettify }} - ({{ place.date_summary|prettify }}){% ifequal forloop.revcounter0 0 %}{% else %}{% ifequal forloop.revcounter0 1 %}{% ifnotequal forloop.counter0 0 %},{% endifnotequal %}{% else %},{% endifequal %}{% endifequal %}{% endfor %}{% if places|add:0 > 5 %} and other locations{% endif %}. -{% endifequal %} -{% endifequal %} -{% ifnotequal latest_production.last_modifier latest_production.creator %} + ({{ place.date_summary|prettify }}){% if forloop.revcounter0 == 0 %}{% elif forloop.revcounter0 == 1 %}{% if forloop.counter0 != 0 %},{% endif %}{% else %},{% endif %}{% endfor %}{% if places|add:0 > 5 %} and other locations{% endif %}. +{% endif %} +{% if latest_production.last_modifier != latest_production.creator %} Added by {{ latest_production.creator.name }}, last modified by {{ latest_production.last_modifier.name }}. -{% else %} -{% if latest_production.creator.name %} +{% elif latest_production.creator.name %} Added by {{ latest_production.creator.name }}. {% endif %} -{% endifnotequal %} {% else %} Nothing in the system yet! {% endif %} diff --git a/templates/merged/buttons.html b/templates/merged/buttons.html index f819783..7075d0c 100644 --- a/templates/merged/buttons.html +++ b/templates/merged/buttons.html @@ -1,8 +1,8 @@ -{% ifnotequal object.id duplicate.id %} +{% if object.id != duplicate.id %}
    {% csrf_token %}


    -{% endifnotequal %} +{% endif %} diff --git a/templates/pagination.html b/templates/pagination.html index cc20ecf..9706a5f 100644 --- a/templates/pagination.html +++ b/templates/pagination.html @@ -1,15 +1,15 @@ {% load humanize %} {% if page_obj.has_other_pages %}

    - {% if page_obj.has_previous %} - {% ifequal page_obj.previous_page_number 1 %} + {% if page_obj.has_previous %} + {% if page_obj.previous_page_number == 1 %} ← Previous {% else %} ← Previous - {% endifequal %} - {% else %} - ← Previous - {% endif %} + {% endif %} + {% else %} + ← Previous + {% endif %} · {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ paginator.count|intcomma }} diff --git a/templates/people/person.html b/templates/people/person.html index 5cf5062..e8d61bf 100644 --- a/templates/people/person.html +++ b/templates/people/person.html @@ -48,11 +48,11 @@

    Current & Upcoming productions

    {{ production.part__role__concatenate }}, {% endif %} {% if production.get_companies_display %}, {{ production.get_companies_display }}{% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} @@ -70,11 +70,11 @@

    Past productions

    {{ production.part__role__concatenate }}, {% endif %} {% if production.get_companies_display %}, {{ production.get_companies_display }}{% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} diff --git a/templates/people/person_list.html b/templates/people/person_list.html index 2f68c5f..61f991b 100644 --- a/templates/people/person_list.html +++ b/templates/people/person_list.html @@ -9,22 +9,22 @@

    People – {{ letter }}

    diff --git a/templates/people/production_list.html b/templates/people/production_list.html index 41ab4f3..b06e1ee 100644 --- a/templates/people/production_list.html +++ b/templates/people/production_list.html @@ -24,11 +24,11 @@

    {{ type }}

    {{ production.part__role__concatenate }}, {% endif %} {% if production.get_companies_display %}, {{ production.get_companies_display }}{% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} diff --git a/templates/place.html b/templates/place.html index 3d0e615..f92e94d 100644 --- a/templates/place.html +++ b/templates/place.html @@ -86,8 +86,8 @@

    Past productions

    {% if place.type or place.size %}
  • - {% if place.type %}{% ifequal place.type "multiple" %}An adaptable theatre{% else %}A {{ place.type }} theatre{% endifequal %}{% endif %}{% if place.size and place.type %}, - s{% else %}{% if place.size %}S{% endif %}{% endif %}{%if place.size %}eats {{ place.size }}{% endif %}. + {% if place.type %}{% if place.type == "multiple" %}An adaptable theatre{% else %}A {{ place.type }} theatre{% endif %}{% endif %}{% if place.size and place.type %}, + s{% elif place.size %}S{% endif %}{%if place.size %}eats {{ place.size }}{% endif %}. {% endif %} {% if place.opening_date %}
  • Opened {{ place.opening_date|prettify }}{% endif %} {% if place.closing_date %}
  • Closed {{ place.closing_date|prettify }}{% endif %} diff --git a/templates/places/place_edit.html b/templates/places/place_edit.html index d6c3fd0..7705a9f 100644 --- a/templates/places/place_edit.html +++ b/templates/places/place_edit.html @@ -19,13 +19,9 @@

    Editing {{ place.get_name_display|prettify }}

    {% for field in form %} - {% if not field.is_hidden %} - {% ifnotequal field.label 'Latitude' %} - {% ifnotequal field.label 'Longitude' %} + {% if not field.is_hidden and field.label != 'Latitude' and field.label != 'Longitude' %}

    {{ field.label_tag }} {{ field }}

    {% if field.help_text %}

    {{ field.help_text }}

    {% endif %} - {% endifnotequal %} - {% endifnotequal %} {% endif %} {% endfor %} diff --git a/templates/places/place_list.html b/templates/places/place_list.html index 53fb69c..43020b3 100644 --- a/templates/places/place_list.html +++ b/templates/places/place_list.html @@ -7,23 +7,23 @@ diff --git a/templates/plays/play_edit.html b/templates/plays/play_edit.html index b06d878..5eedce3 100644 --- a/templates/plays/play_edit.html +++ b/templates/plays/play_edit.html @@ -27,14 +27,14 @@

    Editing {{ play|prettify }}

    {{ form.person.label_tag }} {{ form.person }} {% for field in form %} -{% ifnotequal field.label 'Author' %} +{% if field.label != 'Author' %} {% if field.is_hidden %} {{ field }} {% else %} {{ field.errors }} {{ field.label_tag }} {{ field }} {% endif %} -{% endifnotequal %} +{% endif %} {% endfor %}
    {% endfor %} diff --git a/templates/plays/play_list.html b/templates/plays/play_list.html index 7d5a34f..edd72ac 100644 --- a/templates/plays/play_list.html +++ b/templates/plays/play_list.html @@ -7,22 +7,22 @@

    Plays – {{ letter }}

    diff --git a/templates/production.html b/templates/production.html index 19638c8..45a7438 100644 --- a/templates/production.html +++ b/templates/production.html @@ -25,13 +25,13 @@ {% endthumbnail %} {% endwith %} -{% else %}{% if flickr.photos.photo %} +{% elif flickr.photos.photo %} {% with flickr.photos.photo|random as photo %}
    {{ photo.title }}
    {% endwith %} -{% endif %}{% endif %} +{% endif %} {% if production.book_tickets and not production.finished %}
    @@ -83,7 +83,7 @@

    Cast

    {% for part in cast %} {{ part.role_or_unknown|prettify }} -{% if part.credited_as %}
      ({% ifnotequal part.credited_as "uncredited" %}credited as {% endifnotequal %}{{ part.credited_as|prettify }}){% endif %} +{% if part.credited_as %}
      ({% if part.credited_as != "uncredited" %}credited as {% endif %}{{ part.credited_as|prettify }}){% endif %} {% if part.start_date or part.end_date %}
      ({{ part.date_summary|prettify }}){% endif %} {% endfor %} @@ -135,7 +135,7 @@

    Cast

  • Source: {{ production.source|safe }}
  • {% endif %} -{% ifnotequal production.last_modifier production.creator %} +{% if production.last_modifier != production.creator %} {% if production.creator.name %}
  • Added by {{ production.creator.name }}, last modified by {{ production.last_modifier.name }}.
  • {% else %} @@ -149,7 +149,7 @@

    Cast

  • Last modified by {{ production.last_modifier.name }}.
  • {% endif %} {% endif %} -{% endifnotequal %} +{% endif %} diff --git a/templates/productions/company.html b/templates/productions/company.html index 1d9433c..25dcd60 100644 --- a/templates/productions/company.html +++ b/templates/productions/company.html @@ -22,11 +22,11 @@

    Current & Upcoming productions

    @@ -40,11 +40,11 @@

    Past productions

    diff --git a/templates/productions/company_production_list.html b/templates/productions/company_production_list.html index f41c0a5..a62ea87 100644 --- a/templates/productions/company_production_list.html +++ b/templates/productions/company_production_list.html @@ -15,11 +15,11 @@

    {{ type }}

    diff --git a/templates/productions/edit-part.html b/templates/productions/edit-part.html index f45de63..73a6a8f 100644 --- a/templates/productions/edit-part.html +++ b/templates/productions/edit-part.html @@ -22,7 +22,7 @@

    Editing production

    {{ form.person.label_tag }} {{ form.person }}

    {% for field in form %} -{% ifnotequal field.label 'Person' %} +{% if field.label != 'Person' %} {% if field.is_hidden %} {{ field }} {% else %} @@ -31,7 +31,7 @@

    Editing production

    {% if field.help_text %}({{ field.help_text }}){% endif %}

    {% endif %} -{% endifnotequal %} +{% endif %} {% endfor %}

    diff --git a/templates/productions/edit-parts.html b/templates/productions/edit-parts.html index 6bf13a0..80a5e04 100644 --- a/templates/productions/edit-parts.html +++ b/templates/productions/edit-parts.html @@ -37,7 +37,7 @@

    Add new Part

    {{ form.person.label_tag }} {{ form.person }}

    {% for field in form %} -{% ifnotequal field.label 'Person' %} +{% if field.label != 'Person' %} {% if field.is_hidden %} {{ field }} {% else %} @@ -46,7 +46,7 @@

    Add new Part

    {% if field.help_text %}({{ field.help_text }}){% endif %}

    {% endif %} -{% endifnotequal %} +{% endif %} {% endfor %}

    diff --git a/templates/productions/sidebar_bit.html b/templates/productions/sidebar_bit.html index 8886135..943055b 100644 --- a/templates/productions/sidebar_bit.html +++ b/templates/productions/sidebar_bit.html @@ -1,20 +1,17 @@ {% load prettify %} -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.date_summary|prettify }}, at .

    {% if production.place_set.all.0.press_date and production.place_set.all.0.start_date %}

    Press night was {{ production.place_set.all.0.press_date|date:"jS F Y"|prettify }}.

    {% endif %} -{% else %} -{% ifequal production.places.count 0 %} +{% elif production.places.count == 0 %} at an unknown location. {% else %} at {% for place in places %} {% if forloop.last and not forloop.first %} and {% endif %} - ({{ place.date_summary|prettify }}){% ifequal forloop.revcounter0 0 %}{% else %}{% ifequal forloop.revcounter0 1 %}{% ifnotequal forloop.counter0 0 %},{% endifnotequal %}{% else %},{% endifequal %}{% endifequal %}{% endfor %}. -{% endifequal %} -{% endifequal %} - + ({{ place.date_summary|prettify }}){% if forloop.revcounter0 == 0 %}{% elif forloop.revcounter0 == 1 %}{% if forloop.counter0 != 0 %},{% endif %}{% else %},{% endif %}{% endfor %}. +{% endif %} diff --git a/templates/profile.html b/templates/profile.html index a359363..1209f10 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% load prettify %} -{% block title %}{{ view.name|prettify|striptags }}’{% ifnotequal view.name|last 's' %}s{% endifnotequal %} profile{% endblock %} +{% block title %}{{ view.name|prettify|striptags }}’{% if view.name|last != 's' %}s{% endif %} profile{% endblock %} {% block extra_head %} @@ -9,7 +9,7 @@ {% block content %} -

    {{ view.name|prettify }}’{% ifnotequal view.name|last 's' %}s{% endifnotequal %} profile

    +

    {{ view.name|prettify }}’{% if view.name|last != 's' %}s{% endif %} profile

    {% include 'includes/messages.html' %} @@ -41,22 +41,22 @@

    Seen, or going to see

    Last five observations

    diff --git a/templates/search-around-productions.html b/templates/search-around-productions.html index 43cdd4e..112456d 100644 --- a/templates/search-around-productions.html +++ b/templates/search-around-productions.html @@ -19,11 +19,11 @@

    {{ type }}

    {% for production in page_obj.object_list %}
  • {{ production.play.get_title_display|prettify }}{% if production.get_companies_display %}, {{ production.get_companies_display }}{% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} diff --git a/templates/search-around.html b/templates/search-around.html index 192f787..cb798f1 100644 --- a/templates/search-around.html +++ b/templates/search-around.html @@ -22,11 +22,11 @@

    Current & Upcoming productions

    {% for production in future.object_list %}
  • {{ production.play.get_title_display|prettify }}{% if production.get_companies_display %}, {{ production.get_companies_display }}{% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} @@ -41,11 +41,11 @@

    Past productions

    {% for production in past.object_list %}
  • {{ production.play.get_title_display|prettify }}{% if production.get_companies_display %}, {{ production.get_companies_display }}{% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} diff --git a/templates/search-parts.html b/templates/search-parts.html index 284666e..44f1639 100644 --- a/templates/search-parts.html +++ b/templates/search-parts.html @@ -17,11 +17,11 @@

    Parts

    {{ part.role|prettify }}, played by {{ part.person|prettify }}, in {{ part.production.play.get_title_display|prettify }}{% if part.production.get_companies_display %}, {{ part.production.get_companies_display }}{% endif %} {{ part.production.date_summary|prettify }}, -{% ifequal part.production.places.count 1 %} +{% if part.production.places.count == 1 %} {{ part.production.place_summary|prettify }}. {% else %} {{ part.production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} diff --git a/templates/search.html b/templates/search.html index 259d9f3..f9d7e7d 100644 --- a/templates/search.html +++ b/templates/search.html @@ -5,12 +5,12 @@ {% block content %} -

    Search{% if search %} for {% ifequal sounds_people 2 %}similar to {% endifequal %} +

    Search{% if search %} for {% if sounds_people == 2 %}similar to {% endif %} “{{ search }}”{% endif %}

    @@ -117,10 +117,9 @@

    Production companies

    {% endif %}
    -{% ifequal error 'Length' %} +{% if error == 'Length' %}

    The minimum search length is three characters, as anything else returns too many results.

    -{% else %} -{% if plays or places or people or parts.object_list or companies %} +{% elif plays or places or people or parts.object_list or companies %} {% else %}

    I’m afraid we couldn’t find any results. If you’re searching for someone, try just their first or last name.

    @@ -129,7 +128,6 @@

    Production companies

    add a production to the site, involving the play, person, or place you searched for, so that future users of the site can benefit. They thank you in advance! {% endif %} -{% endifequal %} {% endblock %} diff --git a/templates/search/productions.html b/templates/search/productions.html index d53b2b4..98ba023 100644 --- a/templates/search/productions.html +++ b/templates/search/productions.html @@ -18,11 +18,11 @@

    Matching productions

    {{ production.searched_people|prettify_list }} {% endif %} {{ production.date_summary|prettify }}, -{% ifequal production.places.count 1 %} +{% if production.places.count == 1 %} {{ production.place_summary|prettify }}. {% else %} {{ production.place_summary|prettify }}. -{% endifequal %} +{% endif %} {% endfor %} diff --git a/theatricalia/settings/base.py b/theatricalia/settings/base.py index 1b0f314..0bcc51f 100644 --- a/theatricalia/settings/base.py +++ b/theatricalia/settings/base.py @@ -61,8 +61,7 @@ } } -SOUTH_TESTS_MIGRATE = False -TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' ALLOWED_HOSTS = ['theatricalia.com', 'theatricalia.com.', 'localhost', 'staging.theatricalia.com'] @@ -98,7 +97,7 @@ 'django.contrib.staticfiles.finders.AppDirectoriesFinder', # 'django.contrib.staticfiles.finders.DefaultStorageFinder', ) -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.CachedStaticFilesStorage' +STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' if 'test' in sys.argv: STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' @@ -141,7 +140,7 @@ if DEBUG: MIDDLEWARE.insert(5, 'debug_toolbar.middleware.DebugToolbarMiddleware') -if 'staging' not in OUR_ROOT: +if not DEBUG: SECURE_HSTS_SECONDS = 31536000 CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True @@ -163,7 +162,6 @@ 'sorl.thumbnail', 'reversion', 'countries', - 'django_nose', 'common', 'places', 'plays', diff --git a/theatricalia/urls.py b/theatricalia/urls.py index fd36cd9..5c511ba 100644 --- a/theatricalia/urls.py +++ b/theatricalia/urls.py @@ -1,7 +1,7 @@ from django.conf import settings -from django.conf.urls import include, url from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from django.urls import include, path, re_path, register_converter from . import views @@ -21,6 +21,26 @@ from feeds import PersonFeed, PlayFeed, PlaceFeed, NearbyFeed, UserSeenFeed, NewsFeed + +class StringConverter: + def to_python(self, value): + return value + + def to_url(self, value): + return value + + +class Base32Converter(StringConverter): + regex = '[0-9a-zA-Z]+' + + +class LetterConverter(StringConverter): + regex = '[a-z0*]' + + +register_converter(Base32Converter, 'b32') +register_converter(LetterConverter, 'letter') + urlpatterns = [ # Example: # (r'^theatricalia/', include('theatricalia.foo.urls')), @@ -29,125 +49,125 @@ # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), - url(r'^admin/', admin.site.urls), - - url(r'^tickets/boxoffice$', profiles.register, name='register'), - url(r'^tickets/(?P[0-9A-Za-z]+)-(?P.+)$', profiles.register_confirm, name='register-confirm'), - url(r'^tickets$', profiles.login, name='login'), - url(r'^tickets/exchange$', auth_views.PasswordChangeView.as_view(), name='password_change'), - url(r'^tickets/exchanged$', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'), - url(r'^tickets/lost$', auth_views.PasswordResetView.as_view(), name='password_reset'), - url(r'^tickets/lost/done$', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'), - url(r'^tickets/lost/(?P[0-9A-Za-z_\-]+)/(?P.+)$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), - url(r'^tickets/lost/found$', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'), - url(r'^tickets/returns$', auth_views.LogoutView.as_view(), name='logout'), - - url('^$', views.home, name='home'), - - url('^about$', views.static_about, name='about'), - url('^assistance$', views.static_help, name='help'), - url('^criticism$', views.static_contact, name='criticism'), - url('^colophon$', views.static_colophon, name='colophon'), - url('^moo$', views.static_moocards, name='moo'), - - url('^play/(?P.*?)/(?P.*)/feed$', PlayFeed()), - url('^person/(?P.*?)/(?P.*)/feed$', PersonFeed()), - url('^place/(?P.*?)/(?P.*)/feed$', PlaceFeed()), - url('^around/(?P.*)/feed$', NearbyFeed()), - url('^profile/(?P.*)/feed/seen$', UserSeenFeed()), - - url('^play/.*?/(?Pproduction/.*/merge)$', merged.merge), - url('^(?P(play|person|place|company)/.*)/merge$', merged.merge), - - url('^d/(?P.+)$', productions.production_short_url), - url('^production/(?P.+)$', productions.production_short_url), - url('^c/(?P.+)$', productions.production_company_short_url), - url('^p/(?P.+)$', plays.play_short_url), - url('^t/(?P.+)$', places.place_short_url), - url('^a/(?P.+)$', people.person_short_url), - - url('^api/(?Pproduction|play|place|company|person)/(?P[^/]+)/flickr$', common.api_flickr), - - url('^plays$', plays.PlayList.as_view(), name='plays_all'), - url('^plays/(?P[a-z0*])$', plays.PlayList.as_view(), name='plays'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)/seen/(?Padd|remove)$', productions.production_seen, name='production-seen'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)/edit$', productions.production_edit, name='production-edit'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)/edit/cast$', productions.production_edit_cast, name='production-edit-cast'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)/edit/(?P[0-9]+)$', productions.part_edit, name='part-edit'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)/corrected$', productions.production_corrected, name='production-corrected'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+).(?Pjson)$', productions.production, name='production-json'), - url('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)$', productions.production, name='production'), - url('^play/(?P.*?)/(?P.*)/future$', plays.play_productions, {'type': 'future'}, name='play-productions-future'), - url('^play/(?P.*?)/(?P.*)/past$', plays.play_productions, {'type': 'past'}, name='play-productions-past'), - url('^play/(?P.*?)/(?P.*)/edit$', plays.play_edit, name='play-edit'), - url('^play/(?P.*?)/(?P.*)/add$', productions.add_from_play, name='play-production-add'), - url('^play/(?P.*?)/(?P.*)$', plays.play, name='play'), - url('^play/(?P.+)$', plays.play_short_url), + path('admin/', admin.site.urls), + + path('tickets/boxoffice', profiles.register, name='register'), + path('tickets/-', profiles.register_confirm, name='register-confirm'), + path('tickets', profiles.LoginView.as_view(), name='login'), + path('tickets/exchange', auth_views.PasswordChangeView.as_view(), name='password_change'), + path('tickets/exchanged', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'), + path('tickets/lost', auth_views.PasswordResetView.as_view(), name='password_reset'), + path('tickets/lost/done', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'), + path('tickets/lost//', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), + path('tickets/lost/found', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'), + path('tickets/returns', auth_views.LogoutView.as_view(), name='logout'), + + path('', views.home, name='home'), + + path('about', views.static_about, name='about'), + path('assistance', views.static_help, name='help'), + path('criticism', views.static_contact, name='criticism'), + path('colophon', views.static_colophon, name='colophon'), + path('moo', views.static_moocards, name='moo'), + + path('play///feed', PlayFeed()), + path('person///feed', PersonFeed()), + path('place///feed', PlaceFeed()), + path('around//feed', NearbyFeed()), + path('profile//feed/seen', UserSeenFeed()), + + re_path('^play/.*?/(?Pproduction/.*/merge)$', merged.merge), + re_path('^(?P(play|person|place|company)/.*)/merge$', merged.merge), + + path('d/', productions.production_short_url), + path('production/', productions.production_short_url), + path('c/', productions.production_company_short_url), + path('p/', plays.play_short_url), + path('t/', places.place_short_url), + path('a/', people.person_short_url), + + re_path('^api/(?Pproduction|play|place|company|person)/(?P[^/]+)/flickr$', common.api_flickr), + + path('plays', plays.PlayList.as_view(), name='plays_all'), + path('plays/', plays.PlayList.as_view(), name='plays'), + re_path('^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)/seen/(?Padd|remove)$', productions.production_seen, name='production-seen'), + path('play///production//edit', productions.production_edit, name='production-edit'), + path('play///production//edit/cast', productions.production_edit_cast, name='production-edit-cast'), + path('play///production//edit/', productions.part_edit, name='part-edit'), + path('play///production//corrected', productions.production_corrected, name='production-corrected'), + re_path(r'^play/(?P.*?)/(?P.*?)/production/(?P[0-9a-z]+)\.(?Pjson)$', productions.production, name='production-json'), + path('play///production/', productions.production, name='production'), + path('play///future', plays.play_productions, {'type': 'future'}, name='play-productions-future'), + path('play///past', plays.play_productions, {'type': 'past'}, name='play-productions-past'), + path('play///edit', plays.play_edit, name='play-edit'), + path('play///add', productions.add_from_play, name='play-production-add'), + path('play//', plays.play, name='play'), + path('play/', plays.play_short_url), # url('^play/(?P.*?)/part/(?P.*)$', productions.by_part), - url('^people$', people.PersonList.as_view(), name='people_all'), - url('^people/(?P[a-z0*])$', people.PersonList.as_view(), name='people'), - url('^person/(?P.*?)/(?P.*)/future$', people.person_productions, {'type': 'future'}, name='person-productions-future'), - url('^person/(?P.*?)/(?P.*)/past$', people.person_productions, {'type': 'past'}, name='person-productions-past'), - url('^person/(?P.*?)/(?P.*)/edit$', people.person_edit, name='person-edit'), - url(r'^person/(?P.*?)/(?P.*)\.js$', people.person_js, name='person-json'), - url('^person/(?P.*?)/(?P.*)$', people.person, name='person'), - url('^person/(?P.+)$', people.person_short_url), - - url('^places$', places.PlaceList.as_view(), name='places_all'), - url('^places/(?P[a-z0*])$', places.PlaceList.as_view(), name='places'), - url('^place/(?P[^/]+)/(?P.*)/future$', places.place_productions, {'type': 'future'}, name='place-productions-future'), - url('^place/(?P[^/]+)/(?P.*)/past$', places.place_productions, {'type': 'past'}, name='place-productions-past'), - url('^place/(?P[^/]+)/(?P.*)/edit$', places.place_edit, name='place-edit'), - url('^place/(?P[^/]+)/(?P.*)/add$', productions.add_from_place, name='place-production-add'), - url('^place/(?P[^/]+)/(?P.*)/productions$', places.productions, name='place-productions'), - url('^place/(?P[^/]+)/(?P.*)/people$', places.people, name='place-people'), - url('^place/(?P[^/]+)/(?P[^/]*)$', places.place, name='place'), - url('^place/(?P[^/]+)$', places.place_short_url), - - url('^company/(?P[^/]+)/(?P.*)/future$', productions.company_productions, {'type': 'future'}, name='company-productions-future'), - url('^company/(?P[^/]+)/(?P.*)/past$', productions.company_productions, {'type': 'past'}, name='company-productions-past'), - url('^company/(?P[^/]+)/(?P.*)/edit$', productions.company_edit, name='company-edit'), - url('^company/(?P[^/]+)/(?P.*)/add$', productions.add_from_company, name='company-production-add'), - url('^company/(?P[^/]+)/(?P[^/]*)$', productions.company, name='company'), - url('^company/(?P[^/]+)$', productions.production_company_short_url), - - url('^observations/post/', productions.post_comment_wrapper), - url(r'^observations/remove/(?P\d+)', productions.hide_comment, name='hide-comment'), - url('^observations/', include('django_comments.urls')), - url('^photograph/take/', photos.take_photo, name='take-photo'), - url('^photograph/taken/', photos.photo_taken, name='photo-taken'), - url('^photograph/view/(?P[0-9a-z]+)$', photos.view, name='photo-view'), - - url('^search/around/(?P.+)/future$', search.search_around, {'type': 'future'}, name='search-around-future'), - url('^search/around/(?P.+)/past$', search.search_around, {'type': 'past'}, name='search-around-past'), - url('^search/around/(?P.+)$', search.search_around, name='search-around'), - url('^search/parts/(?P.+)$', search.search_parts, name='search-parts'), - url('^search$', search.search, name='search'), - - url('^ajax/autocomplete$', search.search_autocomplete, name='search-autocomplete'), - - url('^add$', productions.production_add, name='production-add'), - - url('^profile/edit$', profiles.profile_edit, name='profile-edit'), - url('^profile/(?P.*)$', profiles.profile, name='profile'), - url('^profile$', profiles.profile_user, name='profile-user'), - - url('^(?Ppublicity)/feed$', NewsFeed()), - url('^publicity$', news.NewsIndex.as_view(), name='news-index'), - url(r'^publicity/(?P\d{4})$', news.NewsYear.as_view(), name='news-year'), - url(r'^publicity/(?P\d{4})/(?P\w+)$', news.NewsMonth.as_view(), name='news-month'), - url(r'^publicity/(?P\d{4})/(?P\w+)/(?P[-\w]+)$', - news.NewsArticle.as_view(), name='news-entry'), - - url('^random$', views.random_production, name='random'), + path('people', people.PersonList.as_view(), name='people_all'), + path('people/', people.PersonList.as_view(), name='people'), + re_path('^person/(?P.*?)/(?P.*)/future$', people.person_productions, {'type': 'future'}, name='person-productions-future'), + re_path('^person/(?P.*?)/(?P.*)/past$', people.person_productions, {'type': 'past'}, name='person-productions-past'), + re_path('^person/(?P.*?)/(?P.*)/edit$', people.person_edit, name='person-edit'), + re_path(r'^person/(?P.*?)/(?P.*)\.js$', people.person_js, name='person-json'), + re_path('^person/(?P.*?)/(?P.*)$', people.person, name='person'), + re_path('^person/(?P.+)$', people.person_short_url), + + path('places', places.PlaceList.as_view(), name='places_all'), + path('places/', places.PlaceList.as_view(), name='places'), + re_path('^place/(?P[^/]+)/(?P.*)/future$', places.place_productions, {'type': 'future'}, name='place-productions-future'), + re_path('^place/(?P[^/]+)/(?P.*)/past$', places.place_productions, {'type': 'past'}, name='place-productions-past'), + re_path('^place/(?P[^/]+)/(?P.*)/edit$', places.place_edit, name='place-edit'), + re_path('^place/(?P[^/]+)/(?P.*)/add$', productions.add_from_place, name='place-production-add'), + re_path('^place/(?P[^/]+)/(?P.*)/productions$', places.productions, name='place-productions'), + path('place///people', places.people, name='place-people'), + path('place//', places.place, name='place'), + path('place/', places.place_short_url), + + re_path('^company/(?P[^/]+)/(?P.*)/future$', productions.company_productions, {'type': 'future'}, name='company-productions-future'), + re_path('^company/(?P[^/]+)/(?P.*)/past$', productions.company_productions, {'type': 'past'}, name='company-productions-past'), + re_path('^company/(?P[^/]+)/(?P.*)/edit$', productions.company_edit, name='company-edit'), + re_path('^company/(?P[^/]+)/(?P.*)/add$', productions.add_from_company, name='company-production-add'), + re_path('^company/(?P[^/]+)/(?P[^/]*)$', productions.company, name='company'), + re_path('^company/(?P[^/]+)$', productions.production_company_short_url), + + path('observations/post/', productions.post_comment_wrapper), + re_path(r'^observations/remove/(?P\d+)', productions.hide_comment, name='hide-comment'), + path('observations/', include('django_comments.urls')), + path('photograph/take/', photos.take_photo, name='take-photo'), + path('photograph/taken/', photos.photo_taken, name='photo-taken'), + re_path('^photograph/view/(?P[0-9a-z]+)$', photos.view, name='photo-view'), + + re_path('^search/around/(?P.+)/future$', search.search_around, {'type': 'future'}, name='search-around-future'), + re_path('^search/around/(?P.+)/past$', search.search_around, {'type': 'past'}, name='search-around-past'), + re_path('^search/around/(?P.+)$', search.search_around, name='search-around'), + re_path('^search/parts/(?P.+)$', search.search_parts, name='search-parts'), + path('search', search.search, name='search'), + + path('ajax/autocomplete', search.search_autocomplete, name='search-autocomplete'), + + path('add', productions.production_add, name='production-add'), + + path('profile/edit', profiles.profile_edit, name='profile-edit'), + path('profile/', profiles.profile, name='profile'), + path('profile', profiles.profile_user, name='profile-user'), + + path('publicity/feed', NewsFeed()), + path('publicity', news.NewsIndex.as_view(), name='news-index'), + path('publicity/', news.NewsYear.as_view(), name='news-year'), + path('publicity//', news.NewsMonth.as_view(), name='news-month'), + path('publicity///', + news.NewsArticle.as_view(), name='news-entry'), + + path('random', views.random_production, name='random'), # url('forums/forum/', include('forums.django-forum.forum.urls')), # url('forums/simple/', include('forums.django-simpleforum.forum.urls')), # url('forums/bb/', include('forums.djangobb.djangobb.urls')), # url('forums/counterpoint/', include('forums.counterpoint.counterpoint.urls')), - url('^lp/day/', include('lp.urls')), + path('lp/day/', include('lp.urls')), ] urlpatterns += staticfiles_urlpatterns() @@ -156,5 +176,5 @@ if settings.DEBUG: import debug_toolbar urlpatterns += [ - url(r'^__debug__/', include(debug_toolbar.urls)), + path('__debug__/', include(debug_toolbar.urls)), ] diff --git a/tox.ini b/tox.ini index 5b3e79c..dcfe560 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,8 @@ skipsdist = True envlist = flake8, django-v{2,3,4} [testenv] -basepython = python3 -commands = python -W all -W ignore::PendingDeprecationWarning -m coverage run manage.py test +basepython = python3.9 +commands = python -W all -W ignore::PendingDeprecationWarning -m coverage run manage.py test --keepdb deps = coverage -r{toxinidir}/requirements-base.txt @@ -20,7 +20,7 @@ deps = flake8 [flake8] max-line-length=119 -exclude=.tox,migrations,sounds,import,bootstrap.py +exclude=.tox,migrations,sounds,import,bootstrap.py,venv extend-ignore=E402,E722,E501 [gh-actions:env]