mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-16 19:49:41 +00:00
Compare commits
22 Commits
c12dae6676
...
python_dep
| Author | SHA1 | Date | |
|---|---|---|---|
|
e1b84f5182
|
|||
|
7773bf96c8
|
|||
|
739913a2c9
|
|||
| 5c5ccd244d | |||
|
b7dcb2ccc5
|
|||
|
16b10333d5
|
|||
|
cf7934974e
|
|||
|
3cf13299eb
|
|||
|
6a65d14e5e
|
|||
|
b497ec11a0
|
|||
|
79ec9214f9
|
|||
|
2be88c8927
|
|||
|
e315c458de
|
|||
|
1559f9098d
|
|||
|
1dacbc1444
|
|||
|
8c981cc366
|
|||
|
a8261e0e7e
|
|||
|
|
e8c44a6346 | ||
|
|
1ba765a884 | ||
|
|
b9e6747918 | ||
|
c3934e09bd
|
|||
|
|
fc938c897c |
@@ -12,14 +12,14 @@ install:
|
|||||||
- export PATH=$PATH:$(pwd)
|
- export PATH=$PATH:$(pwd)
|
||||||
- chmod +x chromedriver
|
- chmod +x chromedriver
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements.txt
|
||||||
- pip install coveralls codeclimate-test-reporter pep8
|
- pip install coveralls codeclimate-test-reporter pycodestyle
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- export PATH=$PATH:/usr/lib/chromium-browser/
|
- export PATH=$PATH:/usr/lib/chromium-browser/
|
||||||
- python manage.py collectstatic --noinput
|
- python manage.py collectstatic --noinput
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- pep8 . --exclude=migrations,importer*
|
- pycodestyle . --exclude=migrations,importer*
|
||||||
- python manage.py check
|
- python manage.py check
|
||||||
- python manage.py makemigrations --check --dry-run
|
- python manage.py makemigrations --check --dry-run
|
||||||
- coverage run manage.py test --verbosity=2
|
- coverage run manage.py test --verbosity=2
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ if DEBUG:
|
|||||||
ADMINS.append(('Testing Superuser', 'superuser@example.com'))
|
ADMINS.append(('Testing Superuser', 'superuser@example.com'))
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'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
|
RECAPTCHA_PRIVATE_KEY = os.environ.get('RECAPTCHA_PRIVATE_KEY', "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe") # If not set, use development key
|
||||||
NOCAPTCHA = True
|
NOCAPTCHA = True
|
||||||
|
|
||||||
|
SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']
|
||||||
|
|
||||||
# Email
|
# Email
|
||||||
EMAILER_TEST = False
|
EMAILER_TEST = False
|
||||||
if not DEBUG or EMAILER_TEST:
|
if not DEBUG or EMAILER_TEST:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ def create_browser():
|
|||||||
if os.environ.get('CI', False):
|
if os.environ.get('CI', False):
|
||||||
options.add_argument("--headless")
|
options.add_argument("--headless")
|
||||||
options.add_argument("--no-sandbox")
|
options.add_argument("--no-sandbox")
|
||||||
driver = webdriver.Chrome(chrome_options=options)
|
driver = webdriver.Chrome(options=options)
|
||||||
return driver
|
return driver
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from django.urls import path
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
@@ -15,8 +16,8 @@ urlpatterns = [
|
|||||||
url('^assets/', include('assets.urls')),
|
url('^assets/', include('assets.urls')),
|
||||||
url('^user/register/$', RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
url('^user/register/$', RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
||||||
name="registration_register"),
|
name="registration_register"),
|
||||||
url('^user/', include('django.contrib.auth.urls')),
|
path('user/', include('django.contrib.auth.urls')),
|
||||||
url('^user/', include('registration.backends.default.urls')),
|
path('user/', include('registration.backends.default.urls')),
|
||||||
|
|
||||||
url(r'^admin/', admin.site.urls),
|
url(r'^admin/', admin.site.urls),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from RIGS import models, forms
|
from RIGS import models, forms
|
||||||
from django.contrib.auth.admin import UserAdmin
|
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 reversion.admin import VersionAdmin
|
||||||
|
|
||||||
from django.contrib.admin import helpers
|
from django.contrib.admin import helpers
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class InvoicePrint(generic.View):
|
|||||||
|
|
||||||
pdfData = buffer.read()
|
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 = HttpResponse(content_type='application/pdf')
|
||||||
response['Content-Disposition'] = "filename=Invoice %05d - N%05d | %s.pdf" % (invoice.pk, invoice.event.pk, escapedEventName)
|
response['Content-Disposition'] = "filename=Invoice %05d - N%05d | %s.pdf" % (invoice.pk, invoice.event.pk, escapedEventName)
|
||||||
|
|||||||
37
RIGS/migrations/0038_auto_20200306_2000.py
Normal file
37
RIGS/migrations/0038_auto_20200306_2000.py
Normal file
@@ -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={},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -8,7 +8,6 @@ from django.contrib.auth.models import AbstractUser
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
from reversion.models import Version
|
from reversion.models import Version
|
||||||
import string
|
import string
|
||||||
@@ -22,7 +21,6 @@ from django.urls import reverse_lazy
|
|||||||
|
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Profile(AbstractUser):
|
class Profile(AbstractUser):
|
||||||
initials = models.CharField(max_length=5, unique=True, null=True, blank=False)
|
initials = models.CharField(max_length=5, unique=True, null=True, blank=False)
|
||||||
phone = models.CharField(max_length=13, null=True, blank=True)
|
phone = models.CharField(max_length=13, null=True, blank=True)
|
||||||
@@ -66,11 +64,6 @@ class Profile(AbstractUser):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
('view_profile', 'Can view Profile'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class RevisionMixin(object):
|
class RevisionMixin(object):
|
||||||
@property
|
@property
|
||||||
@@ -101,7 +94,6 @@ class RevisionMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Person(models.Model, RevisionMixin):
|
class Person(models.Model, RevisionMixin):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
phone = models.CharField(max_length=15, blank=True, null=True)
|
phone = models.CharField(max_length=15, blank=True, null=True)
|
||||||
@@ -137,14 +129,8 @@ class Person(models.Model, RevisionMixin):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('person_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('person_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
('view_person', 'Can view Persons'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Organisation(models.Model, RevisionMixin):
|
class Organisation(models.Model, RevisionMixin):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
phone = models.CharField(max_length=15, blank=True, null=True)
|
phone = models.CharField(max_length=15, blank=True, null=True)
|
||||||
@@ -181,11 +167,6 @@ class Organisation(models.Model, RevisionMixin):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('organisation_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('organisation_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
('view_organisation', 'Can view Organisations'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class VatManager(models.Manager):
|
class VatManager(models.Manager):
|
||||||
def current_rate(self):
|
def current_rate(self):
|
||||||
@@ -202,7 +183,6 @@ class VatManager(models.Manager):
|
|||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@python_2_unicode_compatible
|
|
||||||
class VatRate(models.Model, RevisionMixin):
|
class VatRate(models.Model, RevisionMixin):
|
||||||
start_at = models.DateField()
|
start_at = models.DateField()
|
||||||
rate = models.DecimalField(max_digits=6, decimal_places=6)
|
rate = models.DecimalField(max_digits=6, decimal_places=6)
|
||||||
@@ -223,7 +203,6 @@ class VatRate(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Venue(models.Model, RevisionMixin):
|
class Venue(models.Model, RevisionMixin):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
phone = models.CharField(max_length=15, blank=True, null=True)
|
phone = models.CharField(max_length=15, blank=True, null=True)
|
||||||
@@ -246,11 +225,6 @@ class Venue(models.Model, RevisionMixin):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('venue_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('venue_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
('view_venue', 'Can view Venues'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class EventManager(models.Manager):
|
class EventManager(models.Manager):
|
||||||
def current_events(self):
|
def current_events(self):
|
||||||
@@ -297,7 +271,6 @@ class EventManager(models.Manager):
|
|||||||
|
|
||||||
|
|
||||||
@reversion.register(follow=['items'])
|
@reversion.register(follow=['items'])
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Event(models.Model, RevisionMixin):
|
class Event(models.Model, RevisionMixin):
|
||||||
# Done to make it much nicer on the database
|
# Done to make it much nicer on the database
|
||||||
PROVISIONAL = 0
|
PROVISIONAL = 0
|
||||||
@@ -491,11 +464,6 @@ class Event(models.Model, RevisionMixin):
|
|||||||
self.full_clean()
|
self.full_clean()
|
||||||
super(Event, self).save(*args, **kwargs)
|
super(Event, self).save(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
('view_event', 'Can view Events'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class EventItem(models.Model):
|
class EventItem(models.Model):
|
||||||
event = models.ForeignKey('Event', related_name='items', blank=True, on_delete=models.CASCADE)
|
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")
|
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)
|
account_code = models.CharField(max_length=50, blank=True, null=True)
|
||||||
amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="authorisation amount")
|
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):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('event_detail', kwargs={'pk': self.event.pk})
|
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 + ')')
|
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Invoice(models.Model):
|
class Invoice(models.Model):
|
||||||
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
||||||
invoice_date = models.DateField(auto_now_add=True)
|
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)
|
return "%i: %s (%.2f)" % (self.pk, self.event, self.balance)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = (
|
|
||||||
('view_invoice', 'Can view Invoices'),
|
|
||||||
)
|
|
||||||
ordering = ['-invoice_date']
|
ordering = ['-invoice_date']
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Payment(models.Model):
|
class Payment(models.Model):
|
||||||
CASH = 'C'
|
CASH = 'C'
|
||||||
INTERNAL = 'I'
|
INTERNAL = 'I'
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class EventCreate(generic.CreateView):
|
|||||||
context['currentVAT'] = models.VatRate.objects.current_rate()
|
context['currentVAT'] = models.VatRate.objects.current_rate()
|
||||||
|
|
||||||
form = context['form']
|
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.")
|
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.
|
# 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)
|
rml = template.render(context)
|
||||||
|
|
||||||
buffer = rml2pdf.parseString(rml)
|
buffer = rml2pdf.parseString(rml)
|
||||||
merger.append(PdfFileReader(buffer))
|
merger.append(PdfFileReader(buffer))
|
||||||
buffer.close()
|
buffer.close()
|
||||||
@@ -219,7 +218,7 @@ class EventPrint(generic.View):
|
|||||||
|
|
||||||
response = HttpResponse(content_type='application/pdf')
|
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['Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName)
|
||||||
response.write(merged.getvalue())
|
response.write(merged.getvalue())
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ def send_eventauthorisation_success_email(instance):
|
|||||||
external_styles=css).transform()
|
external_styles=css).transform()
|
||||||
client_email.attach_alternative(html, 'text/html')
|
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),
|
client_email.attach('N%05d - %s - CONFIRMATION.pdf' % (instance.event.pk, escapedEventName),
|
||||||
merged.getvalue(),
|
merged.getvalue(),
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
{% extends 'base_embed.html' %}
|
{% extends 'base_embed.html' %}
|
||||||
{% load static from staticfiles %}
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
@@ -72,7 +71,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
|
|
||||||
{% if object.meet_at %}
|
{% if object.meet_at %}
|
||||||
<p>
|
<p>
|
||||||
<strong>Crew meet:</strong>
|
<strong>Crew meet:</strong>
|
||||||
@@ -97,10 +95,7 @@
|
|||||||
{{ object.description|linebreaksbr }}
|
{{ object.description|linebreaksbr }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
{% load filters %}
|
||||||
<setNextFrame name="main"/>
|
<setNextFrame name="main"/>
|
||||||
<nextFrame/>
|
<nextFrame/>
|
||||||
|
|
||||||
|
|
||||||
<blockTable style="headLayout" colWidths="330,165">
|
<blockTable style="headLayout" colWidths="330,165">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
@@ -13,7 +12,7 @@
|
|||||||
|
|
||||||
<keepInFrame>
|
<keepInFrame>
|
||||||
<para style="style.event_description">
|
<para style="style.event_description">
|
||||||
{{ object.description|default_if_none:""|linebreaksbr }}
|
{{ object.description|default_if_none:""|linebreaksxml }}
|
||||||
</para>
|
</para>
|
||||||
</keepInFrame>
|
</keepInFrame>
|
||||||
</td>
|
</td>
|
||||||
@@ -75,9 +74,9 @@
|
|||||||
{% if invoice %}
|
{% if invoice %}
|
||||||
<keepInFrame>
|
<keepInFrame>
|
||||||
{% if object.organisation.address %}
|
{% if object.organisation.address %}
|
||||||
<para style="specific_description">{{ object.organisation.address|default_if_none:""|linebreaksbr }}</para>
|
<para style="specific_description">{{ object.organisation.address|default_if_none:""|linebreaksxml }}</para>
|
||||||
{% elif object.person.address %}
|
{% elif object.person.address %}
|
||||||
<para style="specific_description">{{ object.person.address|default_if_none:""|linebreaksbr }}</para>
|
<para style="specific_description">{{ object.person.address|default_if_none:""|linebreaksxml }}</para>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</keepInFrame>
|
</keepInFrame>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -109,7 +108,7 @@
|
|||||||
<h3>{{ object.venue.name }}</h3>
|
<h3>{{ object.venue.name }}</h3>
|
||||||
{% if not invoice %}
|
{% if not invoice %}
|
||||||
<keepInFrame>
|
<keepInFrame>
|
||||||
<para style="specific_description">{{ object.venue.address|default_if_none:""|linebreaksbr }}</para>
|
<para style="specific_description">{{ object.venue.address|default_if_none:""|linebreaksxml }}</para>
|
||||||
</keepInFrame>
|
</keepInFrame>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
@@ -185,7 +184,7 @@
|
|||||||
{% if item.description %}
|
{% if item.description %}
|
||||||
</para>
|
</para>
|
||||||
<para style="item_description">
|
<para style="item_description">
|
||||||
<em>{{ item.description|linebreaksbr }}</em>
|
<em>{{ item.description|linebreaksxml }}</em>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Authorsation request sent by</dt>
|
<dt>Authorisation request sent by</dt>
|
||||||
<dd>{{ object.authorisation.sent_by }}</dd>
|
<dd>{{ object.authorisation.sent_by }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="modal fade" id="itemModal" role="dialog" aria-labelledby="itemModal" aria-hidded="true">
|
<div class="modal fade" id="itemModal" role="dialog" aria-labelledby="itemModal" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@@ -33,7 +33,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="item_quantity" class="col-sm-4 control-label">Quantity</label>
|
<label for="item_quantity" class="col-sm-4 control-label">Quantity</label>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button type="button" class="btn btn-default btn-xs item-add"
|
<button type="button" class="btn btn-default btn-xs item-add"
|
||||||
data-url="{#% url eventitem_add object.pk %#}" data-toggle="modal"
|
data-toggle="modal"
|
||||||
data-target="#itemModal">
|
data-target="#itemModal">
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
|
||||||
|
|
||||||
{% block title %}Password Reset Disabled{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<h1>Password reset is disabled</h1>
|
|
||||||
<p> We are very sorry for the inconvenience, but due to a security vulnerability, password reset is currently disabled until the vulnerability can be patched.</p>
|
|
||||||
<p> If you are locked out of your account, please contact an administrator and we can manually perform a reset</p>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -2,10 +2,24 @@ from django import template
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.forms.forms import NON_FIELD_ERRORS
|
from django.forms.forms import NON_FIELD_ERRORS
|
||||||
from django.forms.utils import ErrorDict
|
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 = 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', '<br />'))
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def multiply(value, arg):
|
def multiply(value, arg):
|
||||||
return value * arg
|
return value * arg
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
# Read what the error is
|
# Read what the error is
|
||||||
alert = self.browser.find_element_by_css_selector(
|
alert = self.browser.find_element_by_css_selector(
|
||||||
'div.alert-danger').text
|
'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
|
# Passwords should be empty
|
||||||
self.assertEqual(password1.get_attribute('value'), '')
|
self.assertEqual(password1.get_attribute('value'), '')
|
||||||
@@ -121,7 +122,7 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
self.assertIn('John Smith "JS" activation required', email.subject)
|
self.assertIn('John Smith "JS" activation required', email.subject)
|
||||||
urls = re.findall(
|
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)
|
self.assertEqual(len(urls), 1)
|
||||||
|
|
||||||
mail.outbox = [] # empty this for later
|
mail.outbox = [] # empty this for later
|
||||||
@@ -504,8 +505,10 @@ class EventTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Add item
|
# Add item
|
||||||
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||||
wait.until(animation_is_finished())
|
|
||||||
modal = self.browser.find_element_by_id("itemModal")
|
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_name").send_keys("Test Item 3")
|
||||||
modal.find_element_by_id("item_description").send_keys(
|
modal.find_element_by_id("item_description").send_keys(
|
||||||
"This is an item description\nthat for reasons unknown spans two lines")
|
"This is an item description\nthat for reasons unknown spans two lines")
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
|
|
||||||
def test_find_parent_version(self):
|
def test_find_parent_version(self):
|
||||||
# Find the most recent version
|
# 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")
|
self.assertEqual(currentVersion._object_version.object.notes, "A new note on the event")
|
||||||
|
|
||||||
# Check the prev version is loaded correctly
|
# Check the prev version is loaded correctly
|
||||||
@@ -436,7 +436,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
|
|
||||||
def test_changes_since(self):
|
def test_changes_since(self):
|
||||||
# Find the most recent version
|
# 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
|
changes = currentVersion.changes
|
||||||
self.assertEqual(len(changes.field_changes), 1)
|
self.assertEqual(len(changes.field_changes), 1)
|
||||||
@@ -453,7 +453,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
self.event.save()
|
self.event.save()
|
||||||
|
|
||||||
# Find the most recent version
|
# 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
|
diff = currentVersion.changes
|
||||||
|
|
||||||
# There are two changes
|
# There are two changes
|
||||||
@@ -475,7 +475,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
self.person.save()
|
self.person.save()
|
||||||
|
|
||||||
# Find the most recent version
|
# 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
|
diff = currentVersion.changes
|
||||||
|
|
||||||
# Should be declared as long
|
# Should be declared as long
|
||||||
@@ -488,7 +488,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
self.event.save()
|
self.event.save()
|
||||||
|
|
||||||
# Find the most recent version
|
# 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
|
# Check the diff is correct
|
||||||
self.assertEqual(currentVersion.changes.field_changes[0].diff,
|
self.assertEqual(currentVersion.changes.field_changes[0].diff,
|
||||||
@@ -504,12 +504,12 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
self.event.status = models.Event.CONFIRMED
|
self.event.status = models.Event.CONFIRMED
|
||||||
self.event.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')
|
||||||
self.assertEqual(currentVersion.changes.field_changes[0].old, 'Provisional')
|
self.assertEqual(currentVersion.changes.field_changes[0].old, 'Provisional')
|
||||||
self.assertEqual(currentVersion.changes.field_changes[0].new, 'Confirmed')
|
self.assertEqual(currentVersion.changes.field_changes[0].new, 'Confirmed')
|
||||||
|
|
||||||
def test_creation_behaviour(self):
|
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
|
diff = firstVersion.changes
|
||||||
|
|
||||||
# Mainly to check for exceptions:
|
# Mainly to check for exceptions:
|
||||||
@@ -522,7 +522,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
self.event.save()
|
self.event.save()
|
||||||
|
|
||||||
# Find the most recent version
|
# 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
|
diffs = currentVersion.changes.item_changes
|
||||||
|
|
||||||
@@ -541,7 +541,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
item1.save()
|
item1.save()
|
||||||
self.event.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
|
diffs = currentVersion.changes.item_changes
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@ class RIGSVersionTestCase(TestCase):
|
|||||||
self.event.save()
|
self.event.save()
|
||||||
|
|
||||||
# Find the most recent version
|
# 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
|
diffs = currentVersion.changes.item_changes
|
||||||
|
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ class TestPrintPaperwork(TestCase):
|
|||||||
cls.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
cls.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
||||||
|
|
||||||
cls.events = {
|
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 = {
|
cls.invoices = {
|
||||||
|
|||||||
10
RIGS/urls.py
10
RIGS/urls.py
@@ -1,7 +1,9 @@
|
|||||||
|
from django.urls import path
|
||||||
from django.conf.urls import url
|
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.decorators import login_required
|
||||||
|
from django.contrib.auth.views import LoginView
|
||||||
from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||||
@@ -16,10 +18,8 @@ urlpatterns = [
|
|||||||
url('^$', login_required(views.Index.as_view()), name='index'),
|
url('^$', login_required(views.Index.as_view()), name='index'),
|
||||||
url(r'^closemodal/$', views.CloseModal.as_view(), name='closemodal'),
|
url(r'^closemodal/$', views.CloseModal.as_view(), name='closemodal'),
|
||||||
|
|
||||||
url('^user/login/$', views.login, name='login'),
|
path('user/login/', LoginView.as_view(authentication_form=forms.CheckApprovedForm), name='login'),
|
||||||
url('^user/login/embed/$', xframe_options_exempt(views.login_embed), name='login_embed'),
|
path('user/login/embed/', xframe_options_exempt(views.LoginEmbed.as_view()), name='login_embed'),
|
||||||
|
|
||||||
url(r'^user/password_reset/$', views.PasswordResetDisabled.as_view()),
|
|
||||||
|
|
||||||
url(r'^search_help/$', views.SearchHelp.as_view(), name='search_help'),
|
url(r'^search_help/$', views.SearchHelp.as_view(), name='search_help'),
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
versions = RIGSVersion.objects.get_for_object_reference(self.content_type.model_class(), thisId).select_related("revision", "revision__user").all()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
previousVersion = versions.filter(revision_id__lt=self.revision_id).latest(
|
previousVersion = versions.filter(revision_id__lt=self.revision_id).latest('revision__date_created')
|
||||||
field_name='revision__date_created')
|
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from django.http.response import HttpResponseRedirect
|
|||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.urls import reverse_lazy, reverse, NoReverseMatch
|
from django.urls import reverse_lazy, reverse, NoReverseMatch
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
from django.contrib.auth.views import LoginView
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
@@ -34,16 +35,6 @@ class Index(generic.TemplateView):
|
|||||||
return context
|
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):
|
class SearchHelp(generic.TemplateView):
|
||||||
template_name = 'RIGS/search_help.html'
|
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
|
# Then we can check for it and show a nice error
|
||||||
# Don't worry, django.contrib.auth.views.login will
|
# Don't worry, django.contrib.auth.views.login will
|
||||||
# check for it before logging the user in
|
# check for it before logging the user in
|
||||||
@csrf_exempt
|
class LoginEmbed(LoginView):
|
||||||
def login_embed(request, **kwargs):
|
template_name = 'registration/login_embed.html'
|
||||||
if request.user.is_authenticated:
|
|
||||||
next = request.GET.get('next', '/')
|
|
||||||
return HttpResponseRedirect(next)
|
|
||||||
else:
|
|
||||||
from django.contrib.auth.views import login
|
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
csrf_cookie = request.COOKIES.get('csrftoken', None)
|
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.')
|
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
|
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()
|
self.request.user.save()
|
||||||
|
|
||||||
return reverse_lazy('profile_detail')
|
return reverse_lazy('profile_detail')
|
||||||
|
|
||||||
|
|
||||||
class PasswordResetDisabled(generic.TemplateView):
|
|
||||||
template_name = "RIGS/password_reset_disable.html"
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='asset',
|
model_name='asset',
|
||||||
name='parent',
|
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(
|
migrations.RemoveField(
|
||||||
model_name='asset',
|
model_name='asset',
|
||||||
@@ -85,7 +85,7 @@ class Migration(migrations.Migration):
|
|||||||
('circuits', models.IntegerField(blank=True, null=True)),
|
('circuits', models.IntegerField(blank=True, null=True)),
|
||||||
('cores', 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')),
|
('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={
|
options={
|
||||||
'abstract': False,
|
'abstract': False,
|
||||||
|
|||||||
@@ -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'),)},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
21
assets/migrations/0010_auto_20200219_1444.py
Normal file
21
assets/migrations/0010_auto_20200219_1444.py
Normal file
@@ -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']},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -41,13 +41,10 @@ class AssetStatus(models.Model):
|
|||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class Supplier(models.Model, RevisionMixin):
|
class Supplier(models.Model, RevisionMixin):
|
||||||
name = models.CharField(max_length=80)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
permissions = (
|
|
||||||
('view_supplier', 'Can view a supplier'),
|
name = models.CharField(max_length=80)
|
||||||
)
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('supplier_list')
|
return reverse('supplier_list')
|
||||||
@@ -70,10 +67,9 @@ class Connector(models.Model):
|
|||||||
class Asset(models.Model, RevisionMixin):
|
class Asset(models.Model, RevisionMixin):
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['asset_id_prefix', 'asset_id_number']
|
ordering = ['asset_id_prefix', 'asset_id_number']
|
||||||
permissions = (
|
permissions = [
|
||||||
('asset_finance', 'Can see financial data for assets'),
|
('asset_finance', 'Can see financial data for assets')
|
||||||
('view_asset', 'Can view an asset')
|
]
|
||||||
)
|
|
||||||
|
|
||||||
parent = models.ForeignKey(to='self', related_name='asset_parent',
|
parent = models.ForeignKey(to='self', related_name='asset_parent',
|
||||||
blank=True, null=True, on_delete=models.SET_NULL)
|
blank=True, null=True, on_delete=models.SET_NULL)
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
{% extends 'base_embed.html' %}
|
{% extends 'base_embed.html' %}
|
||||||
{% load static from staticfiles %}
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<a href="/assets">
|
<a href="/assets">
|
||||||
@@ -35,6 +34,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ class TestSupplierCreateAndEdit(AutoLoginTest):
|
|||||||
def test_supplier_edit(self):
|
def test_supplier_edit(self):
|
||||||
self.page = pages.SupplierEdit(self.driver, self.live_server_url, supplier_id=self.supplier.pk).open()
|
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"
|
new_name = "Cyberdyne Systems"
|
||||||
self.page.name = new_name
|
self.page.name = new_name
|
||||||
self.page.submit()
|
self.page.submit()
|
||||||
|
|||||||
@@ -1,41 +1,24 @@
|
|||||||
beautifulsoup4==4.6.0
|
diff-match-patch==20181111
|
||||||
contextlib2==0.5.5
|
|
||||||
diff-match-patch==20121119
|
|
||||||
dj-database-url==0.5.0
|
dj-database-url==0.5.0
|
||||||
dj-static==0.0.6
|
dj-static==0.0.6
|
||||||
Django==2.0.13
|
Django==3.0.3
|
||||||
django-filter==2.0.0
|
django-debug-toolbar==2.2
|
||||||
django-widget-tweaks==1.4.3
|
django-ical==1.7.0
|
||||||
django-debug-toolbar==1.9.1
|
django-recaptcha==2.0.6
|
||||||
django-ical==1.4
|
django-registration-redux==2.7
|
||||||
django-recaptcha==1.4.0
|
django-reversion==3.0.7
|
||||||
django-registration-redux==2.4
|
django-widget-tweaks==1.4.5
|
||||||
django-reversion==2.0.13
|
gunicorn==20.0.4
|
||||||
django-toolbelt==0.0.1
|
icalendar==4.0.4
|
||||||
premailer==3.2.0
|
lxml==4.5.0
|
||||||
git+git://github.com/jazzband/django-widget-tweaks.git@1.4.2
|
premailer==3.6.1
|
||||||
gunicorn==19.8.1
|
psycopg2==2.8.4
|
||||||
icalendar==4.0.1
|
|
||||||
lxml==4.2.1
|
|
||||||
Markdown==2.6.11
|
|
||||||
Pillow==6.2.0
|
|
||||||
psycopg2==2.7.4
|
|
||||||
Pygments==2.2.0
|
|
||||||
PyPDF2==1.26.0
|
PyPDF2==1.26.0
|
||||||
python-dateutil==2.7.3
|
PyPOM==2.2.0
|
||||||
pytz==2018.4
|
pytz==2019.3
|
||||||
raven==6.8.0
|
raven==6.10.0
|
||||||
reportlab==3.4.0
|
requests==2.23.0
|
||||||
selenium==3.12.0
|
selenium==3.141.0
|
||||||
simplejson==3.15.0
|
simplejson==3.17.0
|
||||||
six==1.11.0
|
whitenoise==5.0.1
|
||||||
sqlparse==0.2.4
|
z3c.rml==3.9.1
|
||||||
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
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% block title %}Bad Request{% endblock %}
|
{% block title %}Bad Request{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% block title %}Unauthorized{% endblock %}
|
{% block title %}Unauthorized{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% block title %}Forbidden{% endblock %}
|
{% block title %}Forbidden{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% block title %}Page Not Found{% endblock %}
|
{% block title %}Page Not Found{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% block title %}Server error{% endblock %}
|
{% block title %}Server error{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{% load static from staticfiles %}
|
{% load static %}
|
||||||
{% load raven %}
|
{% load raven %}
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html
|
<html
|
||||||
dir="{% if LANGUAGE_BIDI %}rtl{% else %}ltr{% endif %}"
|
dir="{% if LANGUAGE_BIDI %}rtl{% else %}ltr{% endif %}"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{% load static from staticfiles %}
|
{% load static %}
|
||||||
{% load raven %}
|
{% load raven %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
{% load static from staticfiles %}
|
{% load static %}
|
||||||
{% load raven %}
|
{% load raven %}
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<table class="main-table">
|
<table class="main-table">
|
||||||
<tr class="client-header">
|
<tr class="client-header">
|
||||||
<td align="center">
|
<td align="center">
|
||||||
@@ -51,8 +48,5 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{% load static from staticfiles %}
|
{% load static %}
|
||||||
{% load raven %}
|
{% load raven %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% block title %}Login Required{% endblock %}
|
{% block title %}Login Required{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
|
|
||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
{% include 'form_errors.html' %}
|
{% include 'form_errors.html' %}
|
||||||
<div class="col-sm-6 col-sm-offset-3 col-lg-4 col-lg-offset-4">
|
<div class="col-sm-6 col-sm-offset-3 col-lg-4 col-lg-offset-4">
|
||||||
|
|
||||||
<form action="{% url 'login' %}" method="post" role="form" target="_self">{% csrf_token %}
|
<form action="{% url 'login' %}" method="post" role="form" target="_self">{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="id_username">{{ form.username.label }}</label>
|
<label for="id_username">{{ form.username.label }}</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user