Merge branch 'master' into feature/online-auth

# Conflicts:
#	RIGS/rigboard.py
#	RIGS/test_functional.py
#	RIGS/urls.py
#	requirements.txt
This commit is contained in:
David Taylor
2017-05-12 20:53:00 +01:00
23 changed files with 382 additions and 227 deletions

View File

@@ -2,7 +2,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 _
import reversion
from reversion.admin import VersionAdmin
from django.contrib.admin import helpers
from django.template.response import TemplateResponse
@@ -12,10 +12,12 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Count
from django.forms import ModelForm
from reversion import revisions as reversion
# Register your models here.
admin.site.register(models.VatRate, reversion.VersionAdmin)
admin.site.register(models.Event, reversion.VersionAdmin)
admin.site.register(models.EventItem, reversion.VersionAdmin)
admin.site.register(models.VatRate, VersionAdmin)
admin.site.register(models.Event, VersionAdmin)
admin.site.register(models.EventItem, VersionAdmin)
admin.site.register(models.Invoice)
admin.site.register(models.Payment)
@@ -41,7 +43,7 @@ class ProfileAdmin(UserAdmin):
add_form = forms.ProfileCreationForm
class AssociateAdmin(reversion.VersionAdmin):
class AssociateAdmin(VersionAdmin):
list_display = ('id', 'name', 'number_of_events')
search_fields = ['id', 'name']
list_display_links = ['id', 'name']
@@ -93,8 +95,7 @@ class AssociateAdmin(reversion.VersionAdmin):
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
'forms': forms
}
return TemplateResponse(request, 'RIGS/admin_associate_merge.html', context,
current_app=self.admin_site.name)
return TemplateResponse(request, 'RIGS/admin_associate_merge.html', context)
@admin.register(models.Person)

View File

@@ -15,6 +15,9 @@ from z3c.rml import rml2pdf
from RIGS import models
from django import forms
forms.DateField.widget = forms.DateInput(attrs={'type': 'date'})
class InvoiceIndex(generic.ListView):
model = models.Invoice
@@ -55,8 +58,8 @@ class InvoicePrint(generic.View):
invoice = get_object_or_404(models.Invoice, pk=pk)
object = invoice.event
template = get_template('RIGS/event_print.xml')
copies = ('TEC', 'Client')
context = RequestContext(request, {
context = {
'object': object,
'fonts': {
'opensans': {
@@ -66,7 +69,7 @@ class InvoicePrint(generic.View):
},
'invoice': invoice,
'current_user': request.user,
})
}
rml = template.render(context)
buffer = StringIO.StringIO()
@@ -78,7 +81,7 @@ class InvoicePrint(generic.View):
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, escapedEventName)
response['Content-Disposition'] = "filename=Invoice %05d - N%05d | %s.pdf" % (invoice.pk, invoice.event.pk, escapedEventName)
response.write(pdfData)
return response

View File

@@ -10,6 +10,10 @@ import simplejson
from RIGS import models
# Override the django form defaults to use the HTML date/time/datetime UI elements
forms.DateField.widget = forms.DateInput(attrs={'type': 'date'})
forms.TimeField.widget = forms.DateInput(attrs={'type': 'time'})
forms.DateTimeField.widget = forms.DateInput(attrs={'type': 'datetime-local'})
# Registration
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
@@ -45,7 +49,7 @@ class ProfileChangeForm(UserChangeForm):
# Events Shit
class EventForm(forms.ModelForm):
datetime_input_formats = formats.get_format_lazy("DATETIME_INPUT_FORMATS") + settings.DATETIME_INPUT_FORMATS
datetime_input_formats = formats.get_format_lazy("DATETIME_INPUT_FORMATS") + list(settings.DATETIME_INPUT_FORMATS)
meet_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
access_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)

View File

@@ -1,7 +1,7 @@
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import Group, Permission
from django.db import transaction
import reversion
from reversion import revisions as reversion
import datetime
import random

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-31 12:02
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('RIGS', '0024_auto_20160229_2042'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='username',
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')], verbose_name='username'),
),
migrations.AlterField(
model_name='vatrate',
name='start_at',
field=models.DateField(),
),
]

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.1 on 2017-05-10 17:46
from __future__ import unicode_literals
import django.contrib.auth.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('RIGS', '0025_auto_20160331_1302'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='username',
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.ASCIIUsernameValidator()], verbose_name='username'),
),
]

View File

@@ -1,19 +1,22 @@
import datetime
import hashlib
import pytz
import random
import datetime, pytz
from django.db import models
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
import string
import random
from collections import Counter
from decimal import Decimal
import reversion
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse_lazy
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
# Create your models here.
@@ -175,7 +178,7 @@ class Organisation(models.Model, RevisionMixin):
class VatManager(models.Manager):
def current_rate(self):
return self.find_rate(datetime.datetime.now())
return self.find_rate(timezone.now())
def find_rate(self, date):
# return self.filter(startAt__lte=date).latest()
@@ -190,7 +193,7 @@ class VatManager(models.Manager):
@reversion.register
@python_2_unicode_compatible
class VatRate(models.Model, RevisionMixin):
start_at = models.DateTimeField()
start_at = models.DateField()
rate = models.DecimalField(max_digits=6, decimal_places=6)
comment = models.CharField(max_length=255)
@@ -241,18 +244,12 @@ class Venue(models.Model, RevisionMixin):
class EventManager(models.Manager):
def current_events(self):
events = self.filter(
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False) & ~models.Q(
status=Event.CANCELLED)) | # Starts after with no end
(models.Q(end_date__gte=datetime.date.today(), dry_hire=False) & ~models.Q(
status=Event.CANCELLED)) | # Ends after
(models.Q(dry_hire=True, start_date__gte=datetime.date.today()) & ~models.Q(
status=Event.CANCELLED)) | # Active dry hire
(models.Q(dry_hire=True, checked_in_by__isnull=True) & (
models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) | # Active dry hire GT
models.Q(status=Event.CANCELLED, start_date__gte=datetime.date.today()) # Canceled but not started
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person',
'organisation',
'venue', 'mic')
(models.Q(start_date__gte=timezone.now().date(), end_date__isnull=True, dry_hire=False) & ~models.Q(status=Event.CANCELLED)) | # Starts after with no end
(models.Q(end_date__gte=timezone.now().date(), dry_hire=False) & ~models.Q(status=Event.CANCELLED)) | # Ends after
(models.Q(dry_hire=True, start_date__gte=timezone.now().date()) & ~models.Q(status=Event.CANCELLED)) | # Active dry hire
(models.Q(dry_hire=True, checked_in_by__isnull=True) & (models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) | # Active dry hire GT
models.Q(status=Event.CANCELLED, start_date__gte=timezone.now().date()) # Canceled but not started
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic')
return events
def events_in_bounds(self, start, end):
@@ -275,12 +272,12 @@ class EventManager(models.Manager):
def rig_count(self):
event_count = self.filter(
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False,
(models.Q(start_date__gte=timezone.now().date(), end_date__isnull=True, dry_hire=False,
is_rig=True) & ~models.Q(
status=Event.CANCELLED)) | # Starts after with no end
(models.Q(end_date__gte=datetime.date.today(), dry_hire=False, is_rig=True) & ~models.Q(
(models.Q(end_date__gte=timezone.now().date(), dry_hire=False, is_rig=True) & ~models.Q(
status=Event.CANCELLED)) | # Ends after
(models.Q(dry_hire=True, start_date__gte=datetime.date.today(), is_rig=True) & ~models.Q(
(models.Q(dry_hire=True, start_date__gte=timezone.now().date(), is_rig=True) & ~models.Q(
status=Event.CANCELLED)) | # Active dry hire
(models.Q(dry_hire=True, checked_in_by__isnull=True, is_rig=True) & (
models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) # Active dry hire GT

View File

@@ -151,7 +151,7 @@ class EventPrint(generic.View):
merger = PdfFileMerger()
context = RequestContext(request, {
context = {
'object': object,
'fonts': {
'opensans': {
@@ -161,7 +161,7 @@ class EventPrint(generic.View):
},
'quote': True,
'current_user': request.user,
})
}
rml = template.render(context)

View File

@@ -289,10 +289,10 @@
<div class="col-sm-8">
<div class="row">
<div class="col-sm-12 col-md-7" data-toggle="tooltip" title="Start date for event, required">
{% render_field form.start_date type="date" class+="form-control" %}
{% render_field form.start_date class+="form-control" %}
</div>
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="Start time of event, can be left blank">
{% render_field form.start_time type="time" class+="form-control" %}
{% render_field form.start_time class+="form-control" %}
</div>
</div>
</div>
@@ -304,10 +304,10 @@
<div class="col-sm-8">
<div class="row">
<div class="col-sm-12 col-md-7" data-toggle="tooltip" title="End date of event, leave blank if unknown or same as start date">
{% render_field form.end_date type="date" class+="form-control" %}
{% render_field form.end_date class+="form-control" %}
</div>
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="End time of event, leave blank if unknown">
{% render_field form.end_time type="time" class+="form-control" %}
{% render_field form.end_time class+="form-control" %}
</div>
</div>
@@ -329,7 +329,7 @@
class="col-sm-4 control-label">{{ form.access_at.label }}</label>
<div class="col-sm-8">
{% render_field form.access_at type="datetime-local" class+="form-control" %}
{% render_field form.access_at class+="form-control" %}
</div>
</div>
<div class="form-group" data-toggle="tooltip" title="The date/time at which crew should meet for this event">
@@ -337,7 +337,7 @@
class="col-sm-4 control-label">{{ form.meet_at.label }}</label>
<div class="col-sm-8">
{% render_field form.meet_at type="datetime-local" class+="form-control" %}
{% render_field form.meet_at class+="form-control" %}
</div>
</div>
<div class="form-group">

View File

@@ -16,7 +16,7 @@
for="{{ form.date.id_for_label }}">{{ form.date.label }}</label>
<div class="col-sm-10">
{% render_field form.date type="date" class+="form-control" %}
{% render_field form.date class+="form-control" %}
</div>
</div>

View File

@@ -18,6 +18,14 @@ from selenium.webdriver.support.ui import WebDriverWait
from RIGS import models
import re
import os
from datetime import date, timedelta
from django.db import transaction
from reversion import revisions as reversion
import json
class UserRegistrationTest(LiveServerTestCase):
def setUp(self):
@@ -434,7 +442,8 @@ class EventTest(LiveServerTestCase):
# See redirected to success page
successTitle = self.browser.find_element_by_xpath('//h1').text
event = models.Event.objects.get(name='Test Event Name')
self.assertIn("N0000%d | Test Event Name" % event.pk, successTitle)
self.assertIn("N%05d | Test Event Name"%event.pk, successTitle)
except WebDriverException:
# This is a dirty workaround for wercker being a bit funny and not running it correctly.
# Waiting for wercker to get back to me about this
@@ -496,9 +505,9 @@ class EventTest(LiveServerTestCase):
# Attempt to save
save.click()
self.assertNotIn("N0000%d" % testEvent.pk, self.browser.find_element_by_xpath('//h1').text)
self.assertNotIn("Event data duplicated but not yet saved",
self.browser.find_element_by_id('content').text) # Check info message not visible
self.assertNotIn("N%05d"%testEvent.pk, self.browser.find_element_by_xpath('//h1').text)
self.assertNotIn("Event data duplicated but not yet saved", self.browser.find_element_by_id('content').text) # Check info message not visible
# Check the new items are visible
table = self.browser.find_element_by_id('item-table') # ID number is known, see above
@@ -507,15 +516,22 @@ class EventTest(LiveServerTestCase):
self.assertIn("Test Item 3", table.text)
infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
self.assertIn("N0000%d" % testEvent.pk,
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk)) # Go back to the old event
# Check that based-on hasn't crept into the old event
self.assertIn("N%05d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
# Check the PO hasn't carried through
self.assertNotIn("TESTPO", infoPanel.find_element_by_xpath('//dt[text()="PO"]/following-sibling::dd[1]').text)
self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk)) #Go back to the old event
#Check that based-on hasn't crept into the old event
infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
self.assertNotIn("N0000%d" % testEvent.pk,
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
self.assertNotIn("N%05d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
# Check the PO remains on the old event
self.assertIn("TESTPO", infoPanel.find_element_by_xpath('//dt[text()="PO"]/following-sibling::dd[1]').text)
# Check the items are as they were
table = self.browser.find_element_by_id('item-table') # ID number is known, see above
@@ -630,8 +646,9 @@ class EventTest(LiveServerTestCase):
# See redirected to success page
successTitle = self.browser.find_element_by_xpath('//h1').text
event = models.Event.objects.get(name='Test Event Name')
self.assertIn("N0000%d | Test Event Name" % event.pk, successTitle)
self.assertIn("N%05d | Test Event Name"%event.pk, successTitle)
def testRigNonRig(self):
self.browser.get(self.live_server_url + '/event/create/')
# Gets redirected to login and back

View File

@@ -17,71 +17,82 @@ class ProfileTestCase(TestCase):
class VatRateTestCase(TestCase):
def setUp(self):
models.VatRate.objects.create(start_at='2014-03-01', rate=0.20, comment='test1')
models.VatRate.objects.create(start_at='2016-03-01', rate=0.15, comment='test2')
@classmethod
def setUpTestData(cls):
cls.rates = {
0: models.VatRate.objects.create(start_at='2014-03-01', rate=0.20, comment='test1'),
1: models.VatRate.objects.create(start_at='2016-03-01', rate=0.15, comment='test2'),
}
def test_find_correct(self):
r = models.VatRate.objects.find_rate('2015-03-01')
self.assertEqual(r.comment, 'test1')
self.assertEqual(r, self.rates[0])
r = models.VatRate.objects.find_rate('2016-03-01')
self.assertEqual(r.comment, 'test2')
self.assertEqual(r, self.rates[1])
def test_percent_correct(self):
r = models.VatRate.objects.get(rate=0.20)
self.assertEqual(r.as_percent, 20)
self.assertEqual(self.rates[0].as_percent, 20)
class EventTestCase(TestCase):
def setUp(self):
self.all_events = set(range(1, 18))
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
self.not_current_events = set(self.all_events) - set(self.current_events)
@classmethod
def setUpTestData(cls):
cls.all_events = set(range(1, 18))
cls.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
cls.not_current_events = set(cls.all_events) - set(cls.current_events)
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
self.profile = models.Profile.objects.create(username="testuser1", email="1@test.com")
cls.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
cls.profile = models.Profile.objects.create(username="testuser1", email="1@test.com")
# produce 7 normal events - 5 current
models.Event.objects.create(name="TE E1", start_date=date.today() + timedelta(days=6),
description="start future no end")
models.Event.objects.create(name="TE E2", start_date=date.today(), description="start today no end")
models.Event.objects.create(name="TE E3", start_date=date.today(), end_date=date.today(),
description="start today with end today")
models.Event.objects.create(name="TE E4", start_date='2014-03-20', description="start past no end")
models.Event.objects.create(name="TE E5", start_date='2014-03-20', end_date='2014-03-21',
description="start past with end past")
models.Event.objects.create(name="TE E6", start_date=date.today() - timedelta(days=2),
end_date=date.today() + timedelta(days=2), description="start past, end future")
models.Event.objects.create(name="TE E7", start_date=date.today() + timedelta(days=2),
end_date=date.today() + timedelta(days=2), description="start + end in future")
cls.events = {
# produce 7 normal events - 5 current
1: models.Event.objects.create(name="TE E1", start_date=date.today() + timedelta(days=6),
description="start future no end"),
2: models.Event.objects.create(name="TE E2", start_date=date.today(), description="start today no end"),
3: models.Event.objects.create(name="TE E3", start_date=date.today(), end_date=date.today(),
description="start today with end today"),
4: models.Event.objects.create(name="TE E4", start_date='2014-03-20', description="start past no end"),
5: models.Event.objects.create(name="TE E5", start_date='2014-03-20', end_date='2014-03-21',
description="start past with end past"),
6: models.Event.objects.create(name="TE E6", start_date=date.today() - timedelta(days=2),
end_date=date.today() + timedelta(days=2),
description="start past, end future"),
7: models.Event.objects.create(name="TE E7", start_date=date.today() + timedelta(days=2),
end_date=date.today() + timedelta(days=2),
description="start + end in future"),
# 2 cancelled - 1 current
models.Event.objects.create(name="TE E8", start_date=date.today() + timedelta(days=2),
end_date=date.today() + timedelta(days=2), status=models.Event.CANCELLED,
description="cancelled in future")
models.Event.objects.create(name="TE E9", start_date=date.today() - timedelta(days=1),
end_date=date.today() + timedelta(days=2), status=models.Event.CANCELLED,
description="cancelled and started")
# 2 cancelled - 1 current
8: models.Event.objects.create(name="TE E8", start_date=date.today() + timedelta(days=2),
end_date=date.today() + timedelta(days=2), status=models.Event.CANCELLED,
description="cancelled in future"),
9: models.Event.objects.create(name="TE E9", start_date=date.today() - timedelta(days=1),
end_date=date.today() + timedelta(days=2), status=models.Event.CANCELLED,
description="cancelled and started"),
# 5 dry hire - 3 current
models.Event.objects.create(name="TE E10", start_date=date.today(), dry_hire=True, description="dryhire today")
models.Event.objects.create(name="TE E11", start_date=date.today(), dry_hire=True, checked_in_by=self.profile,
description="dryhire today, checked in")
models.Event.objects.create(name="TE E12", start_date=date.today() - timedelta(days=1), dry_hire=True,
status=models.Event.BOOKED, description="dryhire past")
models.Event.objects.create(name="TE E13", start_date=date.today() - timedelta(days=2), dry_hire=True,
checked_in_by=self.profile, description="dryhire past checked in")
models.Event.objects.create(name="TE E14", start_date=date.today(), dry_hire=True,
status=models.Event.CANCELLED, description="dryhire today cancelled")
# 5 dry hire - 3 current
10: models.Event.objects.create(name="TE E10", start_date=date.today(), dry_hire=True,
description="dryhire today"),
11: models.Event.objects.create(name="TE E11", start_date=date.today(), dry_hire=True,
checked_in_by=cls.profile,
description="dryhire today, checked in"),
12: models.Event.objects.create(name="TE E12", start_date=date.today() - timedelta(days=1), dry_hire=True,
status=models.Event.BOOKED, description="dryhire past"),
13: models.Event.objects.create(name="TE E13", start_date=date.today() - timedelta(days=2), dry_hire=True,
checked_in_by=cls.profile, description="dryhire past checked in"),
14: models.Event.objects.create(name="TE E14", start_date=date.today(), dry_hire=True,
status=models.Event.CANCELLED, description="dryhire today cancelled"),
# 4 non rig - 3 current
models.Event.objects.create(name="TE E15", start_date=date.today(), is_rig=False, description="non rig today")
models.Event.objects.create(name="TE E16", start_date=date.today() + timedelta(days=1), is_rig=False,
description="non rig tomorrow")
models.Event.objects.create(name="TE E17", start_date=date.today() - timedelta(days=1), is_rig=False,
description="non rig yesterday")
models.Event.objects.create(name="TE E18", start_date=date.today(), is_rig=False, status=models.Event.CANCELLED,
description="non rig today cancelled")
# 4 non rig - 3 current
15: models.Event.objects.create(name="TE E15", start_date=date.today(), is_rig=False,
description="non rig today"),
16: models.Event.objects.create(name="TE E16", start_date=date.today() + timedelta(days=1), is_rig=False,
description="non rig tomorrow"),
17: models.Event.objects.create(name="TE E17", start_date=date.today() - timedelta(days=1), is_rig=False,
description="non rig yesterday"),
18: models.Event.objects.create(name="TE E18", start_date=date.today(), is_rig=False,
status=models.Event.CANCELLED,
description="non rig today cancelled"),
}
def test_count(self):
# Santiy check we have the expected events created
@@ -103,17 +114,23 @@ class EventTestCase(TestCase):
def test_related_venue(self):
v1 = models.Venue.objects.create(name="TE V1")
v2 = models.Venue.objects.create(name="TE V2")
events = models.Event.objects.all()
for event in events[:2]:
event.venue = v1
event.save()
for event in events[3:4]:
event.venue = v2
e1 = []
e2 = []
for (key, event) in self.events.iteritems():
if event.pk % 2:
event.venue = v1
e1.append(event)
else:
event.venue = v2
e2.append(event)
event.save()
events = models.Event.objects.all()
self.assertItemsEqual(events[:2], v1.latest_events)
self.assertItemsEqual(events[3:4], v2.latest_events)
self.assertItemsEqual(e1, v1.latest_events)
self.assertItemsEqual(e2, v2.latest_events)
for (key, event) in self.events.iteritems():
event.venue = None
def test_related_vatrate(self):
self.assertEqual(self.vatrate, models.Event.objects.all()[0].vat_rate)
@@ -122,33 +139,43 @@ class EventTestCase(TestCase):
p1 = models.Person.objects.create(name="TE P1")
p2 = models.Person.objects.create(name="TE P2")
events = models.Event.objects.all()
for event in events[:2]:
event.person = p1
event.save()
for event in events[3:4]:
event.person = p2
e1 = []
e2 = []
for (key, event) in self.events.iteritems():
if event.pk % 2:
event.person = p1
e1.append(event)
else:
event.person = p2
e2.append(event)
event.save()
events = models.Event.objects.all()
self.assertItemsEqual(events[:2], p1.latest_events)
self.assertItemsEqual(events[3:4], p2.latest_events)
self.assertItemsEqual(e1, p1.latest_events)
self.assertItemsEqual(e2, p2.latest_events)
for (key, event) in self.events.iteritems():
event.person = None
def test_related_organisation(self):
o1 = models.Organisation.objects.create(name="TE O1")
o2 = models.Organisation.objects.create(name="TE O2")
events = models.Event.objects.all()
for event in events[:2]:
event.organisation = o1
event.save()
for event in events[3:4]:
event.organisation = o2
e1 = []
e2 = []
for (key, event) in self.events.iteritems():
if event.pk % 2:
event.organisation = o1
e1.append(event)
else:
event.organisation = o2
e2.append(event)
event.save()
events = models.Event.objects.all()
self.assertItemsEqual(events[:2], o1.latest_events)
self.assertItemsEqual(events[3:4], o2.latest_events)
self.assertItemsEqual(e1, o1.latest_events)
self.assertItemsEqual(e2, o2.latest_events)
for (key, event) in self.events.iteritems():
event.organisation = None
def test_organisation_person_join(self):
p1 = models.Person.objects.create(name="TE P1")
@@ -186,20 +213,20 @@ class EventTestCase(TestCase):
self.assertEqual(len(o2.persons), 1)
def test_cancelled_property(self):
event = models.Event.objects.all()[0]
event.status = models.Event.CANCELLED
event.save()
event = models.Event.objects.all()[0]
edit = self.events[1]
edit.status = models.Event.CANCELLED
edit.save()
event = models.Event.objects.get(pk=edit.pk)
self.assertEqual(event.status, models.Event.CANCELLED)
self.assertTrue(event.cancelled)
event.status = models.Event.PROVISIONAL
event.save()
def test_confirmed_property(self):
event = models.Event.objects.all()[0]
event.status = models.Event.CONFIRMED
event.save()
event = models.Event.objects.all()[0]
edit = self.events[1]
edit.status = models.Event.CONFIRMED
edit.save()
event = models.Event.objects.get(pk=edit.pk)
self.assertEqual(event.status, models.Event.CONFIRMED)
self.assertTrue(event.confirmed)
event.status = models.Event.PROVISIONAL
@@ -250,14 +277,14 @@ class EventTestCase(TestCase):
# basic checks
manager.create(name='TE IB2', start_date='2016-01-02', end_date='2016-01-04'),
manager.create(name='TE IB3', start_date='2015-12-31', end_date='2016-01-03'),
manager.create(name='TE IB4', start_date='2016-01-04', access_at='2016-01-03'),
manager.create(name='TE IB5', start_date='2016-01-04', meet_at='2016-01-02'),
manager.create(name='TE IB4', start_date='2016-01-04', access_at=self.create_datetime(2016, 01, 03, 00, 00)),
manager.create(name='TE IB5', start_date='2016-01-04', meet_at=self.create_datetime(2016, 01, 02, 00, 00)),
# negative check
manager.create(name='TE IB6', start_date='2015-12-31', end_date='2016-01-01'),
]
in_bounds = manager.events_in_bounds(datetime(2016, 1, 2), datetime(2016, 1, 3))
in_bounds = manager.events_in_bounds(self.create_datetime(2016, 1, 2, 0, 0), self.create_datetime(2016, 1, 3, 0, 0))
self.assertIn(events[0], in_bounds)
self.assertIn(events[1], in_bounds)
self.assertIn(events[2], in_bounds)

View File

@@ -164,6 +164,8 @@ class TestInvoiceDelete(TestCase):
def setUpTestData(cls):
cls.profile = models.Profile.objects.create(username="testuser1", email="1@test.com", is_superuser=True, is_active=True, is_staff=True)
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()),
2: models.Event.objects.create(name="TE E2", start_date=date.today())
@@ -214,6 +216,39 @@ class TestInvoiceDelete(TestCase):
self.assertTrue(models.Invoice.objects.get(pk=self.invoices[1].pk))
class TestPrintPaperwork(TestCase):
@classmethod
def setUpTestData(cls):
cls.profile = models.Profile.objects.create(username="testuser1", email="1@test.com", is_superuser=True, is_active=True, is_staff=True)
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()),
}
cls.invoices = {
1: models.Invoice.objects.create(event=cls.events[1]),
}
def setUp(self):
self.profile.set_password('testuser')
self.profile.save()
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
def test_print_paperwork_success(self):
request_url = reverse('event_print', kwargs={'pk': self.events[1].pk})
response = self.client.get(request_url, follow=True)
self.assertEqual(response.status_code, 200)
def test_print_invoice_success(self):
request_url = reverse('invoice_print', kwargs={'pk': self.invoices[1].pk})
response = self.client.get(request_url, follow=True)
self.assertEqual(response.status_code, 200)
class TestEmbeddedViews(TestCase):
@classmethod
def setUpTestData(cls):

View File

@@ -1,4 +1,6 @@
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.contrib.auth.views import password_reset
from django.contrib.auth.decorators import login_required
from RIGS import models, views, rigboard, finance, ical, versioning, forms
from django.views.generic import RedirectView
@@ -7,17 +9,17 @@ from django.views.decorators.clickjacking import xframe_options_exempt
from PyRIGS.decorators import permission_required_with_403
from PyRIGS.decorators import api_key_required
urlpatterns = patterns('',
urlpatterns = [
# Examples:
# url(r'^$', 'PyRIGS.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url('^$', login_required(views.Index.as_view()), name='index'),
url(r'^closemodal/$', views.CloseModal.as_view(), name='closemodal'),
url('^user/login/$', 'RIGS.views.login', name='login'),
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/$', 'django.contrib.auth.views.password_reset',
{'password_reset_form': forms.PasswordReset}),
url(r'^user/password_reset/$', password_reset, {'password_reset_form': forms.PasswordReset}),
# People
url(r'^people/$', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
@@ -188,4 +190,4 @@ urlpatterns = patterns('',
RedirectView.as_view(permanent=True, pattern_name='event_detail')),
url(r'^bookings/$', RedirectView.as_view(permanent=True, pattern_name='rigboard')),
url(r'^bookings/past/$', RedirectView.as_view(permanent=True, pattern_name='event_archive')),
)
]

View File

@@ -158,7 +158,7 @@ def get_previous_version(version):
thisId = version.object_id
thisVersionId = version.pk
versions = reversion.get_for_object_reference(version.content_type.model_class(), thisId)
versions = reversion.revisions.get_for_object_reference(version.content_type.model_class(), thisId)
try:
previousVersions = versions.filter(revision_id__lt=version.revision_id).latest(
@@ -199,7 +199,7 @@ def get_changes_for_version(newVersion, oldVersion=None):
class VersionHistory(generic.ListView):
model = reversion.revisions.Version
model = Version
template_name = "RIGS/version_history.html"
paginate_by = 25
@@ -207,7 +207,7 @@ class VersionHistory(generic.ListView):
thisModel = self.kwargs['model']
# thisObject = get_object_or_404(thisModel, pk=self.kwargs['pk'])
versions = reversion.get_for_object_reference(thisModel, self.kwargs['pk'])
versions = reversion.revisions.get_for_object_reference(thisModel, self.kwargs['pk'])
return versions
@@ -236,7 +236,7 @@ class VersionHistory(generic.ListView):
class ActivityTable(generic.ListView):
model = reversion.revisions.Version
model = Version
template_name = "RIGS/activity_table.html"
paginate_by = 25
@@ -260,7 +260,7 @@ class ActivityTable(generic.ListView):
class ActivityFeed(generic.ListView):
model = reversion.revisions.Version
model = Version
template_name = "RIGS/activity_feed_data.html"
paginate_by = 25

View File

@@ -30,7 +30,7 @@ class Index(generic.TemplateView):
def login(request, **kwargs):
if request.user.is_authenticated():
next = request.REQUEST.get('next', '/')
next = request.GET.get('next', '/')
return HttpResponseRedirect(next)
else:
from django.contrib.auth.views import login
@@ -44,9 +44,8 @@ def login(request, **kwargs):
# check for it before logging the user in
@csrf_exempt
def login_embed(request, **kwargs):
print("Running LOGIN")
if request.user.is_authenticated():
next = request.REQUEST.get('next', '/')
next = request.GET.get('next', '/')
return HttpResponseRedirect(next)
else:
from django.contrib.auth.views import login