diff --git a/.travis.yml b/.travis.yml index b2527c43..4eca0630 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,14 +12,14 @@ install: - export PATH=$PATH:$(pwd) - chmod +x chromedriver - pip install -r requirements.txt - - pip install coveralls codeclimate-test-reporter pep8 + - pip install coveralls codeclimate-test-reporter pycodestyle before_script: - export PATH=$PATH:/usr/lib/chromium-browser/ - python manage.py collectstatic --noinput script: - - pep8 . --exclude=migrations,importer* + - pycodestyle . --exclude=migrations,importer* - python manage.py check - python manage.py makemigrations --check --dry-run - coverage run manage.py test --verbosity=2 diff --git a/PyRIGS/settings.py b/PyRIGS/settings.py index b787bdd1..6d2fbbd6 100644 --- a/PyRIGS/settings.py +++ b/PyRIGS/settings.py @@ -50,7 +50,6 @@ if DEBUG: ADMINS.append(('Testing Superuser', 'superuser@example.com')) # Application definition - INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', @@ -169,6 +168,8 @@ RECAPTCHA_PUBLIC_KEY = os.environ.get('RECAPTCHA_PUBLIC_KEY', "6LeIxAcTAAAAAJcZV RECAPTCHA_PRIVATE_KEY = os.environ.get('RECAPTCHA_PRIVATE_KEY', "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe") # If not set, use development key NOCAPTCHA = True +SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error'] + # Email EMAILER_TEST = False if not DEBUG or EMAILER_TEST: diff --git a/PyRIGS/tests/base.py b/PyRIGS/tests/base.py index ecdacd21..4beb1eeb 100644 --- a/PyRIGS/tests/base.py +++ b/PyRIGS/tests/base.py @@ -11,7 +11,7 @@ def create_browser(): if os.environ.get('CI', False): options.add_argument("--headless") options.add_argument("--no-sandbox") - driver = webdriver.Chrome(chrome_options=options) + driver = webdriver.Chrome(options=options) return driver diff --git a/PyRIGS/urls.py b/PyRIGS/urls.py index cb78130c..9ef4fa53 100644 --- a/PyRIGS/urls.py +++ b/PyRIGS/urls.py @@ -1,3 +1,4 @@ +from django.urls import path from django.conf.urls import include, url from django.contrib import admin from django.contrib.staticfiles.urls import staticfiles_urlpatterns @@ -15,8 +16,8 @@ urlpatterns = [ url('^assets/', include('assets.urls')), url('^user/register/$', RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail), name="registration_register"), - url('^user/', include('django.contrib.auth.urls')), - url('^user/', include('registration.backends.default.urls')), + path('user/', include('django.contrib.auth.urls')), + path('user/', include('registration.backends.default.urls')), url(r'^admin/', admin.site.urls), ] diff --git a/RIGS/admin.py b/RIGS/admin.py index 846f014a..65442968 100644 --- a/RIGS/admin.py +++ b/RIGS/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin from RIGS import models, forms from django.contrib.auth.admin import UserAdmin -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from reversion.admin import VersionAdmin from django.contrib.admin import helpers diff --git a/RIGS/finance.py b/RIGS/finance.py index d536969b..061c81a8 100644 --- a/RIGS/finance.py +++ b/RIGS/finance.py @@ -77,7 +77,7 @@ class InvoicePrint(generic.View): pdfData = buffer.read() - escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name) + escapedEventName = re.sub(r'[^a-zA-Z0-9 \n\.]', '', object.name) response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = "filename=Invoice %05d - N%05d | %s.pdf" % (invoice.pk, invoice.event.pk, escapedEventName) diff --git a/RIGS/migrations/0038_auto_20200306_2000.py b/RIGS/migrations/0038_auto_20200306_2000.py new file mode 100644 index 00000000..f1f893e0 --- /dev/null +++ b/RIGS/migrations/0038_auto_20200306_2000.py @@ -0,0 +1,37 @@ +# Generated by Django 2.0.13 on 2020-03-06 20:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0037_approve_legacy'), + ] + + operations = [ + migrations.AlterModelOptions( + name='event', + options={}, + ), + migrations.AlterModelOptions( + name='invoice', + options={'ordering': ['-invoice_date']}, + ), + migrations.AlterModelOptions( + name='organisation', + options={}, + ), + migrations.AlterModelOptions( + name='person', + options={}, + ), + migrations.AlterModelOptions( + name='profile', + options={'verbose_name': 'user', 'verbose_name_plural': 'users'}, + ), + migrations.AlterModelOptions( + name='venue', + options={}, + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index 0b97ca61..2b22da05 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -8,7 +8,6 @@ from django.contrib.auth.models import AbstractUser from django.conf import settings from django.utils import timezone from django.utils.functional import cached_property -from django.utils.encoding import python_2_unicode_compatible from reversion import revisions as reversion from reversion.models import Version import string @@ -22,7 +21,6 @@ from django.urls import reverse_lazy # Create your models here. -@python_2_unicode_compatible class Profile(AbstractUser): initials = models.CharField(max_length=5, unique=True, null=True, blank=False) phone = models.CharField(max_length=13, null=True, blank=True) @@ -66,11 +64,6 @@ class Profile(AbstractUser): def __str__(self): return self.name - class Meta: - permissions = ( - ('view_profile', 'Can view Profile'), - ) - class RevisionMixin(object): @property @@ -101,7 +94,6 @@ class RevisionMixin(object): @reversion.register -@python_2_unicode_compatible class Person(models.Model, RevisionMixin): name = models.CharField(max_length=50) phone = models.CharField(max_length=15, blank=True, null=True) @@ -137,14 +129,8 @@ class Person(models.Model, RevisionMixin): def get_absolute_url(self): return reverse_lazy('person_detail', kwargs={'pk': self.pk}) - class Meta: - permissions = ( - ('view_person', 'Can view Persons'), - ) - @reversion.register -@python_2_unicode_compatible class Organisation(models.Model, RevisionMixin): name = models.CharField(max_length=50) phone = models.CharField(max_length=15, blank=True, null=True) @@ -181,11 +167,6 @@ class Organisation(models.Model, RevisionMixin): def get_absolute_url(self): return reverse_lazy('organisation_detail', kwargs={'pk': self.pk}) - class Meta: - permissions = ( - ('view_organisation', 'Can view Organisations'), - ) - class VatManager(models.Manager): def current_rate(self): @@ -202,7 +183,6 @@ class VatManager(models.Manager): @reversion.register -@python_2_unicode_compatible class VatRate(models.Model, RevisionMixin): start_at = models.DateField() rate = models.DecimalField(max_digits=6, decimal_places=6) @@ -223,7 +203,6 @@ class VatRate(models.Model, RevisionMixin): @reversion.register -@python_2_unicode_compatible class Venue(models.Model, RevisionMixin): name = models.CharField(max_length=255) phone = models.CharField(max_length=15, blank=True, null=True) @@ -246,11 +225,6 @@ class Venue(models.Model, RevisionMixin): def get_absolute_url(self): return reverse_lazy('venue_detail', kwargs={'pk': self.pk}) - class Meta: - permissions = ( - ('view_venue', 'Can view Venues'), - ) - class EventManager(models.Manager): def current_events(self): @@ -297,7 +271,6 @@ class EventManager(models.Manager): @reversion.register(follow=['items']) -@python_2_unicode_compatible class Event(models.Model, RevisionMixin): # Done to make it much nicer on the database PROVISIONAL = 0 @@ -491,11 +464,6 @@ class Event(models.Model, RevisionMixin): self.full_clean() super(Event, self).save(*args, **kwargs) - class Meta: - permissions = ( - ('view_event', 'Can view Events'), - ) - class EventItem(models.Model): event = models.ForeignKey('Event', related_name='items', blank=True, on_delete=models.CASCADE) @@ -533,7 +501,7 @@ class EventAuthorisation(models.Model, RevisionMixin): uni_id = models.CharField(max_length=10, blank=True, null=True, verbose_name="University ID") account_code = models.CharField(max_length=50, blank=True, null=True) amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="authorisation amount") - sent_by = models.ForeignKey('RIGS.Profile', on_delete=models.CASCADE) + sent_by = models.ForeignKey('Profile', on_delete=models.CASCADE) def get_absolute_url(self): return reverse_lazy('event_detail', kwargs={'pk': self.event.pk}) @@ -543,7 +511,6 @@ class EventAuthorisation(models.Model, RevisionMixin): return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')') -@python_2_unicode_compatible class Invoice(models.Model): event = models.OneToOneField('Event', on_delete=models.CASCADE) invoice_date = models.DateField(auto_now_add=True) @@ -576,13 +543,9 @@ class Invoice(models.Model): return "%i: %s (%.2f)" % (self.pk, self.event, self.balance) class Meta: - permissions = ( - ('view_invoice', 'Can view Invoices'), - ) ordering = ['-invoice_date'] -@python_2_unicode_compatible class Payment(models.Model): CASH = 'C' INTERNAL = 'I' diff --git a/RIGS/rigboard.py b/RIGS/rigboard.py index ae960f4f..6aeff551 100644 --- a/RIGS/rigboard.py +++ b/RIGS/rigboard.py @@ -110,7 +110,7 @@ class EventCreate(generic.CreateView): context['currentVAT'] = models.VatRate.objects.current_rate() form = context['form'] - if re.search('"-\d+"', form['items_json'].value()): + if re.search(r'"-\d+"', form['items_json'].value()): messages.info(self.request, "Your item changes have been saved. Please fix the errors and save the event.") # Get some other objects to include in the form. Used when there are errors but also nice and quick. @@ -206,7 +206,6 @@ class EventPrint(generic.View): } rml = template.render(context) - buffer = rml2pdf.parseString(rml) merger.append(PdfFileReader(buffer)) buffer.close() @@ -219,7 +218,7 @@ class EventPrint(generic.View): response = HttpResponse(content_type='application/pdf') - escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name) + escapedEventName = re.sub(r'[^a-zA-Z0-9 \n\.]', '', object.name) response['Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName) response.write(merged.getvalue()) diff --git a/RIGS/signals.py b/RIGS/signals.py index 5c5e6c66..e1772e07 100644 --- a/RIGS/signals.py +++ b/RIGS/signals.py @@ -73,7 +73,7 @@ def send_eventauthorisation_success_email(instance): external_styles=css).transform() client_email.attach_alternative(html, 'text/html') - escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', instance.event.name) + escapedEventName = re.sub(r'[^a-zA-Z0-9 \n\.]', '', instance.event.name) client_email.attach('N%05d - %s - CONFIRMATION.pdf' % (instance.event.pk, escapedEventName), merged.getvalue(), diff --git a/RIGS/templates/RIGS/event_embed.html b/RIGS/templates/RIGS/event_embed.html index 78816cae..d331ae7e 100644 --- a/RIGS/templates/RIGS/event_embed.html +++ b/RIGS/templates/RIGS/event_embed.html @@ -1,8 +1,7 @@ {% extends 'base_embed.html' %} -{% load static from staticfiles %} +{% load static %} {% block content %} -
@@ -72,7 +71,6 @@

- {% if object.meet_at %}

Crew meet: @@ -97,10 +95,7 @@ {{ object.description|linebreaksbr }}

{% endif %} -
- - {% endblock %} diff --git a/RIGS/templates/RIGS/event_print_page.xml b/RIGS/templates/RIGS/event_print_page.xml index 4b1ddfdf..09507167 100644 --- a/RIGS/templates/RIGS/event_print_page.xml +++ b/RIGS/templates/RIGS/event_print_page.xml @@ -1,7 +1,6 @@ +{% load filters %} - - @@ -13,7 +12,7 @@ - {{ object.description|default_if_none:""|linebreaksbr }} + {{ object.description|default_if_none:""|linebreaksxml }} @@ -75,9 +74,9 @@ {% if invoice %} {% if object.organisation.address %} - {{ object.organisation.address|default_if_none:""|linebreaksbr }} + {{ object.organisation.address|default_if_none:""|linebreaksxml }} {% elif object.person.address %} - {{ object.person.address|default_if_none:""|linebreaksbr }} + {{ object.person.address|default_if_none:""|linebreaksxml }} {% endif %} {% endif %} @@ -109,12 +108,12 @@

{{ object.venue.name }}

{% if not invoice %} - {{ object.venue.address|default_if_none:""|linebreaksbr }} + {{ object.venue.address|default_if_none:""|linebreaksxml }} {% endif %} - +

Timings

@@ -185,7 +184,7 @@ {% if item.description %} - {{ item.description|linebreaksbr }} + {{ item.description|linebreaksxml }} {% endif %} diff --git a/RIGS/templates/RIGS/invoice_detail.html b/RIGS/templates/RIGS/invoice_detail.html index 2e0211da..72c87a49 100644 --- a/RIGS/templates/RIGS/invoice_detail.html +++ b/RIGS/templates/RIGS/invoice_detail.html @@ -111,7 +111,7 @@ {% endif %} -
Authorsation request sent by
+
Authorisation request sent by
{{ object.authorisation.sent_by }}
diff --git a/RIGS/templates/RIGS/item_modal.html b/RIGS/templates/RIGS/item_modal.html index f34062ac..e9802230 100644 --- a/RIGS/templates/RIGS/item_modal.html +++ b/RIGS/templates/RIGS/item_modal.html @@ -33,7 +33,6 @@
-
diff --git a/RIGS/templates/RIGS/item_table.html b/RIGS/templates/RIGS/item_table.html index 9f055aa9..34f1697f 100644 --- a/RIGS/templates/RIGS/item_table.html +++ b/RIGS/templates/RIGS/item_table.html @@ -13,7 +13,7 @@ {% if edit %} diff --git a/RIGS/templates/RIGS/password_reset_disable.html b/RIGS/templates/RIGS/password_reset_disable.html deleted file mode 100644 index eec6e791..00000000 --- a/RIGS/templates/RIGS/password_reset_disable.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends 'base_rigs.html' %} - -{% block title %}Password Reset Disabled{% endblock %} - -{% block content %} -

Password reset is disabled

-

We are very sorry for the inconvenience, but due to a security vulnerability, password reset is currently disabled until the vulnerability can be patched.

-

If you are locked out of your account, please contact an administrator and we can manually perform a reset

-{% endblock %} \ No newline at end of file diff --git a/RIGS/templatetags/filters.py b/RIGS/templatetags/filters.py index a90ecd64..60b7117d 100644 --- a/RIGS/templatetags/filters.py +++ b/RIGS/templatetags/filters.py @@ -2,10 +2,24 @@ from django import template from django import forms from django.forms.forms import NON_FIELD_ERRORS from django.forms.utils import ErrorDict +from django.utils.text import normalize_newlines +from django.template.defaultfilters import stringfilter +from django.utils.safestring import SafeData, mark_safe +from django.utils.html import escape register = template.Library() +@register.filter(is_safe=True, needs_autoescape=True) +@stringfilter +def linebreaksxml(value, autoescape=True): + autoescape = autoescape and not isinstance(value, SafeData) + value = normalize_newlines(value) + if autoescape: + value = escape(value) + return mark_safe(value.replace('\n', '
')) + + @register.filter def multiply(value, arg): return value * arg diff --git a/RIGS/test_functional.py b/RIGS/test_functional.py index df4863c1..c40e9592 100644 --- a/RIGS/test_functional.py +++ b/RIGS/test_functional.py @@ -94,7 +94,8 @@ class UserRegistrationTest(LiveServerTestCase): # Read what the error is alert = self.browser.find_element_by_css_selector( 'div.alert-danger').text - self.assertIn("password fields didn't match", alert) + # TODO Use regex matching to handle smart/unsmart quotes... + self.assertIn("password fields didn", alert) # Passwords should be empty self.assertEqual(password1.get_attribute('value'), '') @@ -121,7 +122,7 @@ class UserRegistrationTest(LiveServerTestCase): email = mail.outbox[0] self.assertIn('John Smith "JS" activation required', email.subject) urls = re.findall( - 'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email.body) + r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email.body) self.assertEqual(len(urls), 1) mail.outbox = [] # empty this for later @@ -504,8 +505,10 @@ class EventTest(LiveServerTestCase): # Add item form.find_element_by_xpath('//button[contains(@class, "item-add")]').click() - wait.until(animation_is_finished()) modal = self.browser.find_element_by_id("itemModal") + wait.until(animation_is_finished()) + # See modal has opened + self.assertTrue(modal.is_displayed()) modal.find_element_by_id("item_name").send_keys("Test Item 3") modal.find_element_by_id("item_description").send_keys( "This is an item description\nthat for reasons unknown spans two lines") diff --git a/RIGS/test_models.py b/RIGS/test_models.py index d35cbbe2..1f97e9cd 100644 --- a/RIGS/test_models.py +++ b/RIGS/test_models.py @@ -424,7 +424,7 @@ class RIGSVersionTestCase(TestCase): def test_find_parent_version(self): # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') self.assertEqual(currentVersion._object_version.object.notes, "A new note on the event") # Check the prev version is loaded correctly @@ -436,7 +436,7 @@ class RIGSVersionTestCase(TestCase): def test_changes_since(self): # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') changes = currentVersion.changes self.assertEqual(len(changes.field_changes), 1) @@ -453,7 +453,7 @@ class RIGSVersionTestCase(TestCase): self.event.save() # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') diff = currentVersion.changes # There are two changes @@ -475,7 +475,7 @@ class RIGSVersionTestCase(TestCase): self.person.save() # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.person).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.person).latest('revision__date_created') diff = currentVersion.changes # Should be declared as long @@ -488,7 +488,7 @@ class RIGSVersionTestCase(TestCase): self.event.save() # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') # Check the diff is correct self.assertEqual(currentVersion.changes.field_changes[0].diff, @@ -504,12 +504,12 @@ class RIGSVersionTestCase(TestCase): self.event.status = models.Event.CONFIRMED self.event.save() - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') self.assertEqual(currentVersion.changes.field_changes[0].old, 'Provisional') self.assertEqual(currentVersion.changes.field_changes[0].new, 'Confirmed') def test_creation_behaviour(self): - firstVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created').parent + firstVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created').parent diff = firstVersion.changes # Mainly to check for exceptions: @@ -522,7 +522,7 @@ class RIGSVersionTestCase(TestCase): self.event.save() # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') diffs = currentVersion.changes.item_changes @@ -541,7 +541,7 @@ class RIGSVersionTestCase(TestCase): item1.save() self.event.save() - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') diffs = currentVersion.changes.item_changes @@ -563,7 +563,7 @@ class RIGSVersionTestCase(TestCase): self.event.save() # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest(field_name='revision__date_created') + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') diffs = currentVersion.changes.item_changes diff --git a/RIGS/test_unit.py b/RIGS/test_unit.py index fb89cfb7..5d5d79cb 100644 --- a/RIGS/test_unit.py +++ b/RIGS/test_unit.py @@ -226,7 +226,7 @@ class TestPrintPaperwork(TestCase): cls.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1') cls.events = { - 1: models.Event.objects.create(name="TE E1", start_date=date.today()), + 1: models.Event.objects.create(name="TE E1", start_date=date.today(), description="This is an event description\nthat for a very specific reason spans two lines."), } cls.invoices = { diff --git a/RIGS/urls.py b/RIGS/urls.py index 006270c9..98a5c9e7 100644 --- a/RIGS/urls.py +++ b/RIGS/urls.py @@ -1,7 +1,9 @@ +from django.urls import path from django.conf.urls import url -from django.contrib.auth.views import password_reset +from django.contrib.auth.views import PasswordResetView from django.contrib.auth.decorators import login_required +from django.contrib.auth.views import LoginView from RIGS import models, views, rigboard, finance, ical, versioning, forms from django.views.generic import RedirectView from django.views.decorators.clickjacking import xframe_options_exempt @@ -16,10 +18,8 @@ urlpatterns = [ url('^$', login_required(views.Index.as_view()), name='index'), url(r'^closemodal/$', views.CloseModal.as_view(), name='closemodal'), - url('^user/login/$', views.login, name='login'), - url('^user/login/embed/$', xframe_options_exempt(views.login_embed), name='login_embed'), - - url(r'^user/password_reset/$', views.PasswordResetDisabled.as_view()), + path('user/login/', LoginView.as_view(authentication_form=forms.CheckApprovedForm), name='login'), + path('user/login/embed/', xframe_options_exempt(views.LoginEmbed.as_view()), name='login_embed'), url(r'^search_help/$', views.SearchHelp.as_view(), name='search_help'), diff --git a/RIGS/versioning.py b/RIGS/versioning.py index 9dff4a3e..cd99d353 100644 --- a/RIGS/versioning.py +++ b/RIGS/versioning.py @@ -25,7 +25,7 @@ class FieldComparison(object): self._new = new def display_value(self, value): - if isinstance(self.field, IntegerField) and len(self.field.choices) > 0: + if isinstance(self.field, IntegerField) and self.field.choices is not None and len(self.field.choices) > 0: return [x[1] for x in self.field.choices if x[0] == value][0] if self.field.name == "risk_assessment_edit_url": return "completed" if value else "" @@ -184,8 +184,7 @@ class RIGSVersion(Version): versions = RIGSVersion.objects.get_for_object_reference(self.content_type.model_class(), thisId).select_related("revision", "revision__user").all() try: - previousVersion = versions.filter(revision_id__lt=self.revision_id).latest( - field_name='revision__date_created') + previousVersion = versions.filter(revision_id__lt=self.revision_id).latest('revision__date_created') except ObjectDoesNotExist: return False diff --git a/RIGS/views.py b/RIGS/views.py index db2c6a2d..ca8bc66e 100644 --- a/RIGS/views.py +++ b/RIGS/views.py @@ -3,6 +3,7 @@ from django.http.response import HttpResponseRedirect from django.http import HttpResponse from django.urls import reverse_lazy, reverse, NoReverseMatch from django.views import generic +from django.contrib.auth.views import LoginView from django.db.models import Q from django.shortcuts import get_object_or_404 from django.core import serializers @@ -34,16 +35,6 @@ class Index(generic.TemplateView): return context -def login(request, **kwargs): - if request.user.is_authenticated: - next = request.GET.get('next', '/') - return HttpResponseRedirect(next) - else: - from django.contrib.auth.views import login - - return login(request, authentication_form=forms.CheckApprovedForm) - - class SearchHelp(generic.TemplateView): template_name = 'RIGS/search_help.html' @@ -52,14 +43,11 @@ class SearchHelp(generic.TemplateView): # Then we can check for it and show a nice error # Don't worry, django.contrib.auth.views.login will # check for it before logging the user in -@csrf_exempt -def login_embed(request, **kwargs): - if request.user.is_authenticated: - next = request.GET.get('next', '/') - return HttpResponseRedirect(next) - else: - from django.contrib.auth.views import login +class LoginEmbed(LoginView): + template_name = 'registration/login_embed.html' + @csrf_exempt + def dispatch(self, request, *args, **kwargs): if request.method == "POST": csrf_cookie = request.COOKIES.get('csrftoken', None) @@ -67,7 +55,7 @@ def login_embed(request, **kwargs): messages.warning(request, 'Cookies do not seem to be enabled. Try logging in using a new tab.') request.method = 'GET' # Render the page without trying to login - return login(request, template_name="registration/login_embed.html", authentication_form=forms.EmbeddedAuthenticationForm) + return super().dispatch(request, *args, **kwargs) """ @@ -423,7 +411,3 @@ class ResetApiKey(generic.RedirectView): self.request.user.save() return reverse_lazy('profile_detail') - - -class PasswordResetDisabled(generic.TemplateView): - template_name = "RIGS/password_reset_disable.html" diff --git a/assets/migrations/0006_auto_20180728_1451_squashed_0021_auto_20190105_1156.py b/assets/migrations/0006_auto_20180728_1451_squashed_0021_auto_20190105_1156.py index f15341e1..dcf7980e 100644 --- a/assets/migrations/0006_auto_20180728_1451_squashed_0021_auto_20190105_1156.py +++ b/assets/migrations/0006_auto_20180728_1451_squashed_0021_auto_20190105_1156.py @@ -57,7 +57,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='asset', name='parent', - field=models.ForeignKey(blank=True, null=True, on_delete=None, related_name='asset_parent', to='assets.Asset'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='asset_parent', to='assets.Asset'), ), migrations.RemoveField( model_name='asset', @@ -85,7 +85,7 @@ class Migration(migrations.Migration): ('circuits', models.IntegerField(blank=True, null=True)), ('cores', models.IntegerField(blank=True, null=True)), ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.AssetCategory')), - ('parent', models.ForeignKey(blank=True, null=True, on_delete=None, related_name='asset_parent', to='assets.Cable')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='asset_parent', to='assets.Cable')), ], options={ 'abstract': False, diff --git a/assets/migrations/0010_auto_20200207_1737.py b/assets/migrations/0010_auto_20200207_1737.py deleted file mode 100644 index 6ffeb824..00000000 --- a/assets/migrations/0010_auto_20200207_1737.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.0.13 on 2020-02-07 17:37 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0009_auto_20200103_2215'), - ] - - operations = [ - migrations.AlterModelOptions( - name='supplier', - options={'ordering': ['name'], 'permissions': (('view_supplier', 'Can view a supplier'),)}, - ), - ] diff --git a/assets/migrations/0010_auto_20200219_1444.py b/assets/migrations/0010_auto_20200219_1444.py new file mode 100644 index 00000000..fe5744f4 --- /dev/null +++ b/assets/migrations/0010_auto_20200219_1444.py @@ -0,0 +1,21 @@ +# Generated by Django 3.0.3 on 2020-02-19 14:44 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0009_auto_20200103_2215'), + ] + + operations = [ + migrations.AlterModelOptions( + name='asset', + options={'ordering': ['asset_id_prefix', 'asset_id_number'], 'permissions': [('asset_finance', 'Can see financial data for assets')]}, + ), + migrations.AlterModelOptions( + name='supplier', + options={'ordering': ['name']}, + ), + ] diff --git a/assets/models.py b/assets/models.py index bda0a30f..300e51e5 100644 --- a/assets/models.py +++ b/assets/models.py @@ -41,13 +41,10 @@ class AssetStatus(models.Model): @reversion.register class Supplier(models.Model, RevisionMixin): - name = models.CharField(max_length=80) - class Meta: ordering = ['name'] - permissions = ( - ('view_supplier', 'Can view a supplier'), - ) + + name = models.CharField(max_length=80) def get_absolute_url(self): return reverse('supplier_list') @@ -70,10 +67,9 @@ class Connector(models.Model): class Asset(models.Model, RevisionMixin): class Meta: ordering = ['asset_id_prefix', 'asset_id_number'] - permissions = ( - ('asset_finance', 'Can see financial data for assets'), - ('view_asset', 'Can view an asset') - ) + permissions = [ + ('asset_finance', 'Can see financial data for assets') + ] parent = models.ForeignKey(to='self', related_name='asset_parent', blank=True, null=True, on_delete=models.SET_NULL) diff --git a/assets/templates/asset_embed.html b/assets/templates/asset_embed.html index c4a40187..2d98a541 100644 --- a/assets/templates/asset_embed.html +++ b/assets/templates/asset_embed.html @@ -1,8 +1,7 @@ {% extends 'base_embed.html' %} -{% load static from staticfiles %} +{% load static %} {% block content %} -
- - {% endblock %} diff --git a/assets/tests/test_assets.py b/assets/tests/test_assets.py index ba134d71..24e575c4 100644 --- a/assets/tests/test_assets.py +++ b/assets/tests/test_assets.py @@ -253,7 +253,7 @@ class TestSupplierCreateAndEdit(AutoLoginTest): def test_supplier_edit(self): self.page = pages.SupplierEdit(self.driver, self.live_server_url, supplier_id=self.supplier.pk).open() - self.assertEquals("Fullmetal Heavy Industry", self.page.name) + self.assertEqual("Fullmetal Heavy Industry", self.page.name) new_name = "Cyberdyne Systems" self.page.name = new_name self.page.submit() diff --git a/requirements.txt b/requirements.txt index 48634106..e737650a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,41 +1,24 @@ -beautifulsoup4==4.6.0 -contextlib2==0.5.5 -diff-match-patch==20121119 +diff-match-patch==20181111 dj-database-url==0.5.0 dj-static==0.0.6 -Django==2.0.13 -django-filter==2.0.0 -django-widget-tweaks==1.4.3 -django-debug-toolbar==1.9.1 -django-ical==1.4 -django-recaptcha==1.4.0 -django-registration-redux==2.4 -django-reversion==2.0.13 -django-toolbelt==0.0.1 -premailer==3.2.0 -git+git://github.com/jazzband/django-widget-tweaks.git@1.4.2 -gunicorn==19.8.1 -icalendar==4.0.1 -lxml==4.2.1 -Markdown==2.6.11 -Pillow==6.2.0 -psycopg2==2.7.4 -Pygments==2.2.0 +Django==3.0.3 +django-debug-toolbar==2.2 +django-ical==1.7.0 +django-recaptcha==2.0.6 +django-registration-redux==2.7 +django-reversion==3.0.7 +django-widget-tweaks==1.4.5 +gunicorn==20.0.4 +icalendar==4.0.4 +lxml==4.5.0 +premailer==3.6.1 +psycopg2==2.8.4 PyPDF2==1.26.0 -python-dateutil==2.7.3 -pytz==2018.4 -raven==6.8.0 -reportlab==3.4.0 -selenium==3.12.0 -simplejson==3.15.0 -six==1.11.0 -sqlparse==0.2.4 -static3==0.7.0 -svg2rlg==0.3 -yolk==0.4.3 -whitenoise==4.1.2 -z3c.rml==3.5.0 -zope.event==4.3.0 -zope.interface==4.5.0 -zope.schema==4.5.0 -pypom==2.2.0 \ No newline at end of file +PyPOM==2.2.0 +pytz==2019.3 +raven==6.10.0 +requests==2.23.0 +selenium==3.141.0 +simplejson==3.17.0 +whitenoise==5.0.1 +z3c.rml==3.9.1 diff --git a/templates/400.html b/templates/400.html index dda8d561..85b6b95a 100644 --- a/templates/400.html +++ b/templates/400.html @@ -1,5 +1,5 @@ {% extends 'base_rigs.html' %} -{% load staticfiles %} +{% load static %} {% block title %}Bad Request{% endblock %} {% block content %} diff --git a/templates/401.html b/templates/401.html index 7fc7dfe0..9b1d45bc 100644 --- a/templates/401.html +++ b/templates/401.html @@ -1,5 +1,5 @@ {% extends 'base_rigs.html' %} -{% load staticfiles %} +{% load static %} {% block title %}Unauthorized{% endblock %} {% block content %} diff --git a/templates/403.html b/templates/403.html index 7fdb8f24..734e3116 100644 --- a/templates/403.html +++ b/templates/403.html @@ -1,5 +1,5 @@ {% extends 'base_rigs.html' %} -{% load staticfiles %} +{% load static %} {% block title %}Forbidden{% endblock %} {% block content %} diff --git a/templates/404.html b/templates/404.html index 5a4ef0bf..d1f933d8 100644 --- a/templates/404.html +++ b/templates/404.html @@ -1,5 +1,5 @@ {% extends 'base_rigs.html' %} -{% load staticfiles %} +{% load static %} {% block title %}Page Not Found{% endblock %} {% block content %} diff --git a/templates/500.html b/templates/500.html index 26fd115d..39802962 100644 --- a/templates/500.html +++ b/templates/500.html @@ -1,5 +1,5 @@ {% extends 'base_rigs.html' %} -{% load staticfiles %} +{% load static %} {% block title %}Server error{% endblock %} {% block content %} diff --git a/templates/base.html b/templates/base.html index a902a7ab..39cf5e58 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,7 +1,6 @@ -{% load static from staticfiles %} +{% load static %} {% load raven %} - - - @@ -47,12 +44,9 @@ +
@@ -32,7 +29,7 @@ +
- - - diff --git a/templates/base_embed.html b/templates/base_embed.html index 6a7a8741..c4fb417b 100644 --- a/templates/base_embed.html +++ b/templates/base_embed.html @@ -1,4 +1,4 @@ -{% load static from staticfiles %} +{% load static %} {% load raven %} diff --git a/templates/login_redirect.html b/templates/login_redirect.html index 6b69cdfd..29bb8ef7 100644 --- a/templates/login_redirect.html +++ b/templates/login_redirect.html @@ -1,5 +1,5 @@ {% extends 'base_rigs.html' %} -{% load staticfiles %} +{% load static %} {% block title %}Login Required{% endblock %} {% block js %} diff --git a/templates/registration/loginform.html b/templates/registration/loginform.html index 328ad18b..20fde945 100644 --- a/templates/registration/loginform.html +++ b/templates/registration/loginform.html @@ -1,8 +1,6 @@ - {% load widget_tweaks %} {% include 'form_errors.html' %}
-
{% csrf_token %}