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

1
.gitignore vendored
View File

@@ -53,6 +53,7 @@ coverage.xml
# Django stuff: # Django stuff:
*.log *.log
db.sqlite3
# Sphinx documentation # Sphinx documentation
docs/_build/ docs/_build/

View File

@@ -1,5 +1,5 @@
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.shortcuts import render_to_response from django.shortcuts import render
from django.template import RequestContext from django.template import RequestContext
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@@ -26,15 +26,15 @@ def user_passes_test_with_403(test_func, login_url=None, oembed_view=None):
return view_func(request, *args, **kwargs) return view_func(request, *args, **kwargs)
elif not request.user.is_authenticated(): elif not request.user.is_authenticated():
if oembed_view is not None: if oembed_view is not None:
extra_context = {} context = {}
extra_context['oembed_url'] = "{0}://{1}{2}".format(request.scheme, request.META['HTTP_HOST'], reverse(oembed_view, kwargs=kwargs)) context['oembed_url'] = "{0}://{1}{2}".format(request.scheme, request.META['HTTP_HOST'], reverse(oembed_view, kwargs=kwargs))
extra_context['login_url'] = "{0}?{1}={2}".format(login_url, REDIRECT_FIELD_NAME, request.get_full_path()) context['login_url'] = "{0}?{1}={2}".format(login_url, REDIRECT_FIELD_NAME, request.get_full_path())
resp = render_to_response('login_redirect.html', extra_context, context_instance=RequestContext(request)) resp = render(request, 'login_redirect.html', context=context)
return resp return resp
else: else:
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, request.get_full_path())) return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, request.get_full_path()))
else: else:
resp = render_to_response('403.html', context_instance=RequestContext(request)) resp = render(request, '403.html')
resp.status_code = 403 resp.status_code = 403
return resp return resp
_checklogin.__doc__ = view_func.__doc__ _checklogin.__doc__ = view_func.__doc__
@@ -62,7 +62,7 @@ def api_key_required(function):
userid = kwargs.get('api_pk') userid = kwargs.get('api_pk')
key = kwargs.get('api_key') key = kwargs.get('api_key')
error_resp = render_to_response('403.html', context_instance=RequestContext(request)) error_resp = render(request, '403.html')
error_resp.status_code = 403 error_resp.status_code = 403
if key is None: if key is None:

View File

@@ -10,26 +10,31 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY') if os.environ.get('SECRET_KEY') else 'gxhy(a#5mhp289_=6xx$7jh=eh$ymxg^ymc+di*0c*geiu3p_e' SECRET_KEY = os.environ.get('SECRET_KEY') if os.environ.get(
'SECRET_KEY') else 'gxhy(a#5mhp289_=6xx$7jh=eh$ymxg^ymc+di*0c*geiu3p_e'
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(int(os.environ.get('DEBUG'))) if os.environ.get('DEBUG') else True DEBUG = bool(int(os.environ.get('DEBUG'))) if os.environ.get('DEBUG') else True
STAGING = bool(int(os.environ.get('STAGING'))) if os.environ.get('STAGING') else False
TEMPLATE_DEBUG = True STAGING = bool(int(os.environ.get('STAGING'))) if os.environ.get('STAGING') else False
ALLOWED_HOSTS = ['pyrigs.nottinghamtec.co.uk', 'rigs.nottinghamtec.co.uk', 'pyrigs.herokuapp.com'] ALLOWED_HOSTS = ['pyrigs.nottinghamtec.co.uk', 'rigs.nottinghamtec.co.uk', 'pyrigs.herokuapp.com']
if STAGING: if STAGING:
ALLOWED_HOSTS.append('.herokuapp.com') ALLOWED_HOSTS.append('.herokuapp.com')
if DEBUG:
ALLOWED_HOSTS.append('localhost')
ALLOWED_HOSTS.append('example.com')
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
if not DEBUG: if not DEBUG:
SECURE_SSL_REDIRECT = True # Redirect all http requests to https SECURE_SSL_REDIRECT = True # Redirect all http requests to https
@@ -40,7 +45,6 @@ ADMINS = (
('Tom Price', 'tomtom5152@gmail.com') ('Tom Price', 'tomtom5152@gmail.com')
) )
# Application definition # Application definition
INSTALLED_APPS = ( INSTALLED_APPS = (
@@ -63,6 +67,7 @@ INSTALLED_APPS = (
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware', 'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
'reversion.middleware.RevisionMiddleware', 'reversion.middleware.RevisionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
@@ -77,7 +82,6 @@ ROOT_URLCONF = 'PyRIGS.urls'
WSGI_APPLICATION = 'PyRIGS.wsgi.application' WSGI_APPLICATION = 'PyRIGS.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = { DATABASES = {
@@ -89,6 +93,7 @@ DATABASES = {
if not DEBUG: if not DEBUG:
import dj_database_url import dj_database_url
DATABASES['default'] = dj_database_url.config() DATABASES['default'] = dj_database_url.config()
# Logging # Logging
@@ -152,8 +157,8 @@ RAVEN_CONFIG = {
AUTH_USER_MODEL = 'RIGS.Profile' AUTH_USER_MODEL = 'RIGS.Profile'
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/user/login' LOGIN_URL = '/user/login/'
LOGOUT_URL = '/user/logout' LOGOUT_URL = '/user/logout/'
ACCOUNT_ACTIVATION_DAYS = 7 ACCOUNT_ACTIVATION_DAYS = 7
@@ -167,7 +172,7 @@ EMAILER_TEST = False
if not DEBUG or EMAILER_TEST: if not DEBUG or EMAILER_TEST:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = os.environ.get('EMAIL_HOST') EMAIL_HOST = os.environ.get('EMAIL_HOST')
EMAIL_PORT = int(os.environ.get('EMAIL_PORT')) EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 25))
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER') EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD') EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_USE_TLS = bool(int(os.environ.get('EMAIL_USE_TLS', 0))) EMAIL_USE_TLS = bool(int(os.environ.get('EMAIL_USE_TLS', 0)))
@@ -193,18 +198,6 @@ USE_TZ = True
DATETIME_INPUT_FORMATS = ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S') DATETIME_INPUT_FORMATS = ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S')
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.core.context_processors.tz",
"django.core.context_processors.request",
"django.contrib.messages.context_processors.messages",
)
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/ # https://docs.djangoproject.com/en/1.7/howto/static-files/
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
@@ -214,9 +207,28 @@ STATIC_DIRS = (
os.path.join(BASE_DIR, 'static/') os.path.join(BASE_DIR, 'static/')
) )
TEMPLATE_DIRS = ( TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'templates'),
) ],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
"django.contrib.auth.context_processors.auth",
"django.template.context_processors.debug",
"django.template.context_processors.i18n",
"django.template.context_processors.media",
"django.template.context_processors.static",
"django.template.context_processors.tz",
"django.template.context_processors.request",
"django.contrib.messages.context_processors.messages",
],
'debug': DEBUG
},
},
]
USE_GRAVATAR = True USE_GRAVATAR = True

View File

@@ -1,4 +1,4 @@
from django.conf.urls import patterns, 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
from django.conf import settings from django.conf import settings
@@ -6,7 +6,7 @@ from registration.backends.default.views import RegistrationView
import RIGS import RIGS
from RIGS import regbackend from RIGS import regbackend
urlpatterns = patterns('', urlpatterns = [
# Examples: # Examples:
# url(r'^$', 'PyRIGS.views.home', name='home'), # url(r'^$', 'PyRIGS.views.home', name='home'),
# url(r'^blog/', include('blog.urls')), # url(r'^blog/', include('blog.urls')),
@@ -18,7 +18,12 @@ urlpatterns = patterns('',
url('^user/', include('registration.backends.default.urls')), url('^user/', include('registration.backends.default.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
) ]
if settings.DEBUG: if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns() urlpatterns += staticfiles_urlpatterns()
import debug_toolbar
urlpatterns = [
url(r'^__debug__/', include(debug_toolbar.urls)),
] + urlpatterns

View File

@@ -1,6 +1,8 @@
# TEC PA & Lighting - PyRIGS # # TEC PA & Lighting - PyRIGS #
[![Build Status](https://travis-ci.org/nottinghamtec/PyRIGS.svg?branch=develop)](https://travis-ci.org/nottinghamtec/PyRIGS) [![Build Status](https://travis-ci.org/nottinghamtec/PyRIGS.svg?branch=develop)](https://travis-ci.org/nottinghamtec/PyRIGS)
[![Coverage Status](https://coveralls.io/repos/github/nottinghamtec/PyRIGS/badge.svg?branch=develop)](https://coveralls.io/github/nottinghamtec/PyRIGS?branch=develop) [![Coverage Status](https://coveralls.io/repos/github/nottinghamtec/PyRIGS/badge.svg?branch=develop)](https://coveralls.io/github/nottinghamtec/PyRIGS?branch=develop)
[![Dependency Status](https://gemnasium.com/badges/github.com/nottinghamtec/PyRIGS.svg)](https://gemnasium.com/github.com/nottinghamtec/PyRIGS)
Welcome to TEC PA & Lightings PyRIGS program. This is a reimplementation of the existing Rig Information Gathering System (RIGS) that was developed using Ruby on Rails. Welcome to TEC PA & Lightings PyRIGS program. This is a reimplementation of the existing Rig Information Gathering System (RIGS) that was developed using Ruby on Rails.

View File

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

View File

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

View File

@@ -10,6 +10,10 @@ import simplejson
from RIGS import models 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 # Registration
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail): class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
@@ -45,7 +49,7 @@ class ProfileChangeForm(UserChangeForm):
# Events Shit # Events Shit
class EventForm(forms.ModelForm): 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) meet_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
access_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.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import Group, Permission from django.contrib.auth.models import Group, Permission
from django.db import transaction from django.db import transaction
import reversion from reversion import revisions as reversion
import datetime import datetime
import random 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 datetime
import hashlib import hashlib
import pytz import datetime, pytz
import random
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 string
import random
from collections import Counter from collections import Counter
from decimal import Decimal 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.exceptions import ValidationError
from django.core.urlresolvers import reverse_lazy 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. # Create your models here.
@@ -175,7 +178,7 @@ class Organisation(models.Model, RevisionMixin):
class VatManager(models.Manager): class VatManager(models.Manager):
def current_rate(self): def current_rate(self):
return self.find_rate(datetime.datetime.now()) return self.find_rate(timezone.now())
def find_rate(self, date): def find_rate(self, date):
# return self.filter(startAt__lte=date).latest() # return self.filter(startAt__lte=date).latest()
@@ -190,7 +193,7 @@ class VatManager(models.Manager):
@reversion.register @reversion.register
@python_2_unicode_compatible @python_2_unicode_compatible
class VatRate(models.Model, RevisionMixin): class VatRate(models.Model, RevisionMixin):
start_at = models.DateTimeField() start_at = models.DateField()
rate = models.DecimalField(max_digits=6, decimal_places=6) rate = models.DecimalField(max_digits=6, decimal_places=6)
comment = models.CharField(max_length=255) comment = models.CharField(max_length=255)
@@ -241,18 +244,12 @@ class Venue(models.Model, RevisionMixin):
class EventManager(models.Manager): class EventManager(models.Manager):
def current_events(self): def current_events(self):
events = self.filter( events = self.filter(
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False) & ~models.Q( (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
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(end_date__gte=datetime.date.today(), dry_hire=False) & ~models.Q( (models.Q(dry_hire=True, start_date__gte=timezone.now().date()) & ~models.Q(status=Event.CANCELLED)) | # Active dry hire
status=Event.CANCELLED)) | # Ends after (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(dry_hire=True, start_date__gte=datetime.date.today()) & ~models.Q( models.Q(status=Event.CANCELLED, start_date__gte=timezone.now().date()) # Canceled but not started
status=Event.CANCELLED)) | # Active dry hire ).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic')
(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')
return events return events
def events_in_bounds(self, start, end): def events_in_bounds(self, start, end):
@@ -275,12 +272,12 @@ class EventManager(models.Manager):
def rig_count(self): def rig_count(self):
event_count = self.filter( 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( is_rig=True) & ~models.Q(
status=Event.CANCELLED)) | # Starts after with no end 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 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 status=Event.CANCELLED)) | # Active dry hire
(models.Q(dry_hire=True, checked_in_by__isnull=True, is_rig=True) & ( (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 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() merger = PdfFileMerger()
context = RequestContext(request, { context = {
'object': object, 'object': object,
'fonts': { 'fonts': {
'opensans': { 'opensans': {
@@ -161,7 +161,7 @@ class EventPrint(generic.View):
}, },
'quote': True, 'quote': True,
'current_user': request.user, 'current_user': request.user,
}) }
rml = template.render(context) rml = template.render(context)

View File

@@ -289,10 +289,10 @@
<div class="col-sm-8"> <div class="col-sm-8">
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-7" data-toggle="tooltip" title="Start date for event, required"> <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>
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="Start time of event, can be left blank"> <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> </div>
</div> </div>
@@ -304,10 +304,10 @@
<div class="col-sm-8"> <div class="col-sm-8">
<div class="row"> <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"> <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>
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="End time of event, leave blank if unknown"> <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>
</div> </div>
@@ -329,7 +329,7 @@
class="col-sm-4 control-label">{{ form.access_at.label }}</label> class="col-sm-4 control-label">{{ form.access_at.label }}</label>
<div class="col-sm-8"> <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> </div>
<div class="form-group" data-toggle="tooltip" title="The date/time at which crew should meet for this event"> <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> class="col-sm-4 control-label">{{ form.meet_at.label }}</label>
<div class="col-sm-8"> <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> </div>
<div class="form-group"> <div class="form-group">

View File

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

View File

@@ -18,6 +18,14 @@ from selenium.webdriver.support.ui import WebDriverWait
from RIGS import models 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): class UserRegistrationTest(LiveServerTestCase):
def setUp(self): def setUp(self):
@@ -434,7 +442,8 @@ class EventTest(LiveServerTestCase):
# See redirected to success page # See redirected to success page
successTitle = self.browser.find_element_by_xpath('//h1').text successTitle = self.browser.find_element_by_xpath('//h1').text
event = models.Event.objects.get(name='Test Event Name') 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: except WebDriverException:
# This is a dirty workaround for wercker being a bit funny and not running it correctly. # 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 # Waiting for wercker to get back to me about this
@@ -496,9 +505,9 @@ class EventTest(LiveServerTestCase):
# Attempt to save # Attempt to save
save.click() 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.assertNotIn("N%05d"%testEvent.pk, self.browser.find_element_by_xpath('//h1').text)
self.browser.find_element_by_id('content').text) # Check info message not visible 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 # Check the new items are visible
table = self.browser.find_element_by_id('item-table') # ID number is known, see above 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) self.assertIn("Test Item 3", table.text)
infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..') 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.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 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 #Check that based-on hasn't crept into the old event
infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..') 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 # Check the items are as they were
table = self.browser.find_element_by_id('item-table') # ID number is known, see above table = self.browser.find_element_by_id('item-table') # ID number is known, see above
@@ -630,7 +646,8 @@ class EventTest(LiveServerTestCase):
# See redirected to success page # See redirected to success page
successTitle = self.browser.find_element_by_xpath('//h1').text successTitle = self.browser.find_element_by_xpath('//h1').text
event = models.Event.objects.get(name='Test Event Name') 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): def testRigNonRig(self):
self.browser.get(self.live_server_url + '/event/create/') self.browser.get(self.live_server_url + '/event/create/')

View File

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

View File

@@ -164,6 +164,8 @@ class TestInvoiceDelete(TestCase):
def setUpTestData(cls): 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.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 = { 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()),
2: models.Event.objects.create(name="TE E2", 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)) 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): class TestEmbeddedViews(TestCase):
@classmethod @classmethod
def setUpTestData(cls): 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 django.contrib.auth.decorators import login_required
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
@@ -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 permission_required_with_403
from PyRIGS.decorators import api_key_required from PyRIGS.decorators import api_key_required
urlpatterns = patterns('', urlpatterns = [
# Examples: # Examples:
# url(r'^$', 'PyRIGS.views.home', name='home'), # url(r'^$', 'PyRIGS.views.home', name='home'),
# url(r'^blog/', include('blog.urls')), # url(r'^blog/', include('blog.urls')),
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/$', '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('^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 # People
url(r'^people/$', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()), 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')), RedirectView.as_view(permanent=True, pattern_name='event_detail')),
url(r'^bookings/$', RedirectView.as_view(permanent=True, pattern_name='rigboard')), url(r'^bookings/$', RedirectView.as_view(permanent=True, pattern_name='rigboard')),
url(r'^bookings/past/$', RedirectView.as_view(permanent=True, pattern_name='event_archive')), 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 thisId = version.object_id
thisVersionId = version.pk 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: try:
previousVersions = versions.filter(revision_id__lt=version.revision_id).latest( 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): class VersionHistory(generic.ListView):
model = reversion.revisions.Version model = Version
template_name = "RIGS/version_history.html" template_name = "RIGS/version_history.html"
paginate_by = 25 paginate_by = 25
@@ -207,7 +207,7 @@ class VersionHistory(generic.ListView):
thisModel = self.kwargs['model'] thisModel = self.kwargs['model']
# thisObject = get_object_or_404(thisModel, pk=self.kwargs['pk']) # 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 return versions
@@ -236,7 +236,7 @@ class VersionHistory(generic.ListView):
class ActivityTable(generic.ListView): class ActivityTable(generic.ListView):
model = reversion.revisions.Version model = Version
template_name = "RIGS/activity_table.html" template_name = "RIGS/activity_table.html"
paginate_by = 25 paginate_by = 25
@@ -260,7 +260,7 @@ class ActivityTable(generic.ListView):
class ActivityFeed(generic.ListView): class ActivityFeed(generic.ListView):
model = reversion.revisions.Version model = Version
template_name = "RIGS/activity_feed_data.html" template_name = "RIGS/activity_feed_data.html"
paginate_by = 25 paginate_by = 25

View File

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

Binary file not shown.

View File

@@ -1,34 +1,37 @@
beautifulsoup4==4.6.0
contextlib2==0.5.5
diff-match-patch==20121119 diff-match-patch==20121119
dj-database-url==0.3.0 dj-database-url==0.4.2
dj-static==0.0.6 dj-static==0.0.6
Django==1.8.2 Django==1.11.1
django-debug-toolbar==1.3.0 django-debug-toolbar==1.8
django-ical==1.3 django-ical==1.4
django-recaptcha==1.0.4 django-recaptcha==1.3.0
django-registration-redux==1.2 django-registration-redux==1.6
django-reversion==1.8.7 django-reversion==1.10.2
django-toolbelt==0.0.1 django-toolbelt==0.0.1
django-widget-tweaks==1.3
gunicorn==19.3.0
icalendar==3.9.0
lxml==3.4.4
Pillow==2.8.1
premailer==3.0.1 premailer==3.0.1
psycopg2==2.6 django-widget-tweaks==1.4.1
Pygments==2.0.2 gunicorn==19.7.1
PyPDF2==1.24 icalendar==3.11.4
python-dateutil==2.4.2 lxml==3.7.3
pytz==2015.4 Markdown==2.6.8
raven==5.8.1 Pillow==4.1.1
reportlab==3.1.44 psycopg2==2.7.1
selenium==2.53.6 Pygments==2.2.0
simplejson==3.7.2 PyPDF2==1.26.0
six==1.9.0 python-dateutil==2.6.0
sqlparse==0.1.15 pytz==2017.2
static3==0.6.1 raven==6.0.0
reportlab==3.4.0
selenium==2.53.1
simplejson==3.10.0
six==1.10.0
sqlparse==0.2.3
static3==0.7.0
svg2rlg==0.3 svg2rlg==0.3
yolk==0.4.3 yolk==0.4.3
z3c.rml==2.8.1 z3c.rml==3.2.0
zope.event==4.0.3 zope.event==4.2.0
zope.interface==4.1.2 zope.interface==4.4.0
zope.schema==4.4.2 zope.schema==4.4.2