mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-09 08:19:41 +00:00
Merge branch 'master' into markdown
# Conflicts: # RIGS/static/css/screen.css # db.sqlite3 # requirements.txt
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# TEC PA & Lighting - PyRIGS #
|
||||
[](https://app.wercker.com/project/bykey/b26100ecccdfb46a9a9056553daac5b7)
|
||||
[](https://app.wercker.com/project/bykey/2dbe0517c3d83859c985ffc5a55a2802)
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@ import simplejson
|
||||
|
||||
from RIGS import models
|
||||
|
||||
#Registration
|
||||
|
||||
# Registration
|
||||
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||
captcha = ReCaptchaField()
|
||||
|
||||
class Meta:
|
||||
model = models.Profile
|
||||
fields = ('username','email','first_name','last_name','initials','phone')
|
||||
fields = ('username', 'email', 'first_name', 'last_name', 'initials', 'phone')
|
||||
|
||||
def clean_initials(self):
|
||||
"""
|
||||
@@ -26,24 +27,22 @@ class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||
raise forms.ValidationError("These initials are already in use. Please supply different initials.")
|
||||
return self.cleaned_data['initials']
|
||||
|
||||
# Login form
|
||||
class LoginForm(AuthenticationForm):
|
||||
captcha = ReCaptchaField(label='Captcha')
|
||||
|
||||
# Login form
|
||||
class PasswordReset(PasswordResetForm):
|
||||
captcha = ReCaptchaField(label='Captcha')
|
||||
|
||||
class ProfileCreationForm(UserCreationForm):
|
||||
|
||||
class ProfileCreationForm(UserCreationForm):
|
||||
class Meta(UserCreationForm.Meta):
|
||||
model = models.Profile
|
||||
|
||||
|
||||
class ProfileChangeForm(UserChangeForm):
|
||||
|
||||
class Meta(UserChangeForm.Meta):
|
||||
model = models.Profile
|
||||
|
||||
|
||||
# Events Shit
|
||||
class EventForm(forms.ModelForm):
|
||||
datetime_input_formats = formats.get_format_lazy("DATETIME_INPUT_FORMATS") + settings.DATETIME_INPUT_FORMATS
|
||||
@@ -96,7 +95,7 @@ class EventForm(forms.ModelForm):
|
||||
|
||||
def _get_or_initialise_item(self, pk, data, event):
|
||||
try:
|
||||
item = models.EventItem.objects.get(pk=pk,event=event)
|
||||
item = models.EventItem.objects.get(pk=pk, event=event)
|
||||
except models.EventItem.DoesNotExist:
|
||||
# This occurs for one of two reasons
|
||||
# 1) The event has been duplicated, so the item PKs belong to another event
|
||||
@@ -134,7 +133,6 @@ class EventForm(forms.ModelForm):
|
||||
for key in items:
|
||||
items[key].save()
|
||||
|
||||
|
||||
return m
|
||||
|
||||
class Meta:
|
||||
@@ -142,4 +140,4 @@ class EventForm(forms.ModelForm):
|
||||
fields = ['is_rig', 'name', 'venue', 'start_time', 'end_date', 'start_date',
|
||||
'end_time', 'meet_at', 'access_at', 'description', 'notes', 'mic',
|
||||
'person', 'organisation', 'dry_hire', 'checked_in_by', 'status',
|
||||
'collector','purchase_order']
|
||||
'collector', 'purchase_order']
|
||||
|
||||
20
RIGS/migrations/0024_auto_20160229_2042.py
Normal file
20
RIGS/migrations/0024_auto_20160229_2042.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('RIGS', '0023_auto_20150529_0048'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='based_on',
|
||||
field=models.ForeignKey(related_name='future_events', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='RIGS.Event', null=True),
|
||||
),
|
||||
]
|
||||
@@ -38,7 +38,10 @@ class Profile(AbstractUser):
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.get_full_name() + ' "' + self.initials + '"'
|
||||
name = self.get_full_name()
|
||||
if self.initials:
|
||||
name += ' "{}"'.format(self.initials)
|
||||
return name
|
||||
|
||||
@property
|
||||
def latest_events(self):
|
||||
@@ -298,7 +301,7 @@ class Event(models.Model, RevisionMixin):
|
||||
status = models.IntegerField(choices=EVENT_STATUS_CHOICES, default=PROVISIONAL)
|
||||
dry_hire = models.BooleanField(default=False)
|
||||
is_rig = models.BooleanField(default=True)
|
||||
based_on = models.ForeignKey('Event', related_name='future_events', blank=True, null=True)
|
||||
based_on = models.ForeignKey('Event', on_delete=models.SET_NULL, related_name='future_events', blank=True, null=True)
|
||||
|
||||
# Timing
|
||||
start_date = models.DateField()
|
||||
|
||||
@@ -37,6 +37,12 @@ class RigboardIndex(generic.TemplateView):
|
||||
class WebCalendar(generic.TemplateView):
|
||||
template_name = 'RIGS/calendar.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(WebCalendar, self).get_context_data(**kwargs)
|
||||
context['view'] = kwargs.get('view','')
|
||||
context['date'] = kwargs.get('date','')
|
||||
return context
|
||||
|
||||
class EventDetail(generic.DetailView):
|
||||
model = models.Event
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ fonts_dir = "fonts"
|
||||
|
||||
# You can select your preferred output style here (can be overridden via the command line):
|
||||
# output_style = :expanded or :nested or :compact or :compressed
|
||||
output_style = :compressed
|
||||
|
||||
# To enable relative paths to assets via compass helper functions. Uncomment:
|
||||
# relative_assets = true
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -39,7 +39,7 @@ var Konami = function (callback) {
|
||||
return false;
|
||||
}
|
||||
}, this);
|
||||
this.iphone.load(link);
|
||||
/*this.iphone.load(link);*/
|
||||
},
|
||||
code: function (link) {
|
||||
window.location = link
|
||||
|
||||
@@ -75,6 +75,16 @@ textarea {
|
||||
}
|
||||
}
|
||||
|
||||
del {
|
||||
background-color: #f2dede;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
ins {
|
||||
background-color: #dff0d8;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.loading-animation {
|
||||
position: relative;
|
||||
margin: 30px auto 0;
|
||||
|
||||
@@ -14,8 +14,28 @@
|
||||
<script src="{% static "js/moment.min.js" %}"></script>
|
||||
<script src="{% static "js/fullcalendar.js" %}"></script>
|
||||
<script>
|
||||
|
||||
function getUrlVars() {
|
||||
var vars = {};
|
||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
|
||||
vars[key] = value;
|
||||
});
|
||||
return vars;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
viewToUrl = {
|
||||
'agendaWeek':'week',
|
||||
'agendaDay':'day',
|
||||
'month':'month'
|
||||
}
|
||||
viewFromUrl = {
|
||||
'week':'agendaWeek',
|
||||
'day':'agendaDay',
|
||||
'month':'month'
|
||||
}
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
editable: false,
|
||||
eventLimit: true, // allow "more" link when too many events
|
||||
@@ -114,8 +134,11 @@
|
||||
$('#day-button').addClass('active');
|
||||
break;
|
||||
}
|
||||
|
||||
history.replaceState(null,null,'{% url 'web_calendar' %}'+viewToUrl[view.name]+'/'+view.intervalStart.format('YYYY-MM-DD')+'/');
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
// set some button listeners
|
||||
@@ -146,6 +169,18 @@
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Go to the initial settings, if they're valid
|
||||
view = viewFromUrl['{{view}}'];
|
||||
$('#calendar').fullCalendar( 'changeView', view);
|
||||
|
||||
day = moment('{{date}}');
|
||||
if(day.isValid()){
|
||||
$('#calendar').fullCalendar( 'gotoDate', day);
|
||||
}else{
|
||||
console.log('Supplied date is invalid - using default')
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
<a href="{% url 'event_detail' pk=object.based_on.pk %}">
|
||||
{% if object.based_on.is_rig %}N{{ object.based_on.pk|stringformat:"05d" }}{% else %}
|
||||
{{ object.based_on.pk }}{% endif %}
|
||||
{{ object.base_on.name }} by {{ object.based_on.mic.name }}
|
||||
{{ object.base_on.name }} {% if object.based_on.mic %}by {{ object.based_on.mic.name }}{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
@@ -234,13 +234,17 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not request.is_ajax %}
|
||||
<div class="col-sm-12 text-right">
|
||||
<div>
|
||||
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
||||
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<keepTogether>
|
||||
<blockTable style="totalTable" colWidths="300,115,80">
|
||||
<tr>
|
||||
<td>{% if not invoice %}VAT Registration Number: 116252989{% endif %}</td>
|
||||
<td>{% if not invoice %}VAT Registration Number: 170734807{% endif %}</td>
|
||||
<td>Total (ex. VAT)</td>
|
||||
<td>£ {{ object.sum_total|floatformat:2 }}</td>
|
||||
</tr>
|
||||
@@ -225,7 +225,7 @@
|
||||
|
||||
<para>
|
||||
{% if invoice %}
|
||||
VAT Registration Number: 116252989
|
||||
VAT Registration Number: 170734807
|
||||
{% else %}
|
||||
<b>This contract is not an invoice.</b>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,40 +1,21 @@
|
||||
{% for change in version.field_changes %}
|
||||
|
||||
<button title="Changes to {{ change.field.verbose_name }}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='
|
||||
|
||||
{% if change.new %}
|
||||
<div class="alert alert-success {% if change.long %}overflow-ellipsis{% endif %}">
|
||||
{% if change.linebreaks %}
|
||||
{{change.new|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.new}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if change.old %}
|
||||
<div class="alert alert-danger {% if change.long %}overflow-ellipsis{% endif %}">
|
||||
{% if change.linebreaks %}
|
||||
{{change.old|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.old}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
'>{{ change.field.verbose_name }}</button>
|
||||
<button title="Changes to {{ change.field.verbose_name }}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}
|
||||
{% include "RIGS/version_changes_change.html" %}
|
||||
{% endspaceless %}'>{{ change.field.verbose_name }}</button>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% for itemChange in version.item_changes %}
|
||||
<button title="Changes to item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='
|
||||
<button title="Changes to item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}
|
||||
<ul class="list-group">
|
||||
{% for change in itemChange.changes %}
|
||||
<h4>{{ change.field.verbose_name }}</h4>
|
||||
|
||||
{% if change.new %}<div class="alert alert-success">{{change.new|linebreaksbr}}</div>{% endif %}
|
||||
{% if change.old %}<div class="alert alert-danger">{{change.old|linebreaksbr}}</div>{% endif %}
|
||||
|
||||
<li class="list-group-item">
|
||||
<h4 class="list-group-item-heading">{{ change.field.verbose_name }}</h4>
|
||||
{% include "RIGS/version_changes_change.html" %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'</button>
|
||||
{% endspaceless %}'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'</button>
|
||||
{% endfor %}
|
||||
34
RIGS/templates/RIGS/version_changes_change.html
Normal file
34
RIGS/templates/RIGS/version_changes_change.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{# pass in variable "change" to this template #}
|
||||
{% if change.linebreaks and change.new and change.old %}
|
||||
{% for diff in change.diff %}
|
||||
{% if diff.type == "insert" %}
|
||||
<ins>{{ diff.text|linebreaksbr }}</ins>
|
||||
{% elif diff.type == "delete" %}
|
||||
<del>{{diff.text|linebreaksbr}}</del>
|
||||
{% else %}
|
||||
<span>{{diff.text|linebreaksbr}}</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% if change.old %}
|
||||
<del {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
||||
{% if change.linebreaks %}
|
||||
{{change.old|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.old}}
|
||||
{% endif %}
|
||||
</del>
|
||||
{% endif %}
|
||||
{% if change.new and change.old %}
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% if change.new %}
|
||||
<ins {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
||||
{% if change.linebreaks %}
|
||||
{{change.new|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.new}}
|
||||
{% endif %}
|
||||
</ins>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -4,7 +4,7 @@ from django.test.client import Client
|
||||
from django.core import mail
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.common.exceptions import StaleElementReferenceException
|
||||
from selenium.common.exceptions import StaleElementReferenceException, WebDriverException
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from RIGS import models
|
||||
import re
|
||||
@@ -159,6 +159,7 @@ class EventTest(LiveServerTestCase):
|
||||
|
||||
self.browser = webdriver.Firefox()
|
||||
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
||||
self.browser.maximize_window()
|
||||
os.environ['RECAPTCHA_TESTING'] = 'True'
|
||||
|
||||
def tearDown(self):
|
||||
@@ -177,8 +178,6 @@ class EventTest(LiveServerTestCase):
|
||||
|
||||
username.send_keys("EventTest")
|
||||
password.send_keys("EventTestPassword")
|
||||
self.browser.execute_script(
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
submit.click()
|
||||
|
||||
self.assertEqual(self.live_server_url + n, self.browser.current_url)
|
||||
@@ -197,233 +196,245 @@ class EventTest(LiveServerTestCase):
|
||||
self.browser.get(self.live_server_url + '/rigboard/')
|
||||
|
||||
def testRigCreate(self):
|
||||
# Requests address
|
||||
self.browser.get(self.live_server_url + '/event/create/')
|
||||
# Gets redirected to login and back
|
||||
self.authenticate('/event/create/')
|
||||
|
||||
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
# Check has slided up correctly - second save button hidden
|
||||
save = self.browser.find_element_by_xpath(
|
||||
'(//button[@type="submit"])[3]')
|
||||
self.assertFalse(save.is_displayed())
|
||||
|
||||
# Click Rig button
|
||||
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
||||
|
||||
# Slider expands and save button visible
|
||||
self.assertTrue(save.is_displayed())
|
||||
form = self.browser.find_element_by_tag_name('form')
|
||||
|
||||
# Create new person
|
||||
add_person_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "add")]')
|
||||
add_person_button.click()
|
||||
|
||||
# See modal has opened
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
# Fill person form out and submit
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 1")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
# See new person selected
|
||||
person1 = models.Person.objects.get(name="Test Person 1")
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Change mind and add another
|
||||
add_person_button.click()
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 2")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
person2 = models.Person.objects.get(name="Test Person 2")
|
||||
self.assertEqual(person2.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# Have to do this explcitly to force the wait for it to update
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person2.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Was right the first time, change it back
|
||||
person_select = form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]')
|
||||
person_select.send_keys(person1.name)
|
||||
person_dropped = form.find_element_by_xpath(
|
||||
'//ul[contains(@class, "inner selectpicker")]//span[contains(text(), "%s")]' % person1.name)
|
||||
person_dropped.click()
|
||||
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Edit Person 1 to have a better name
|
||||
form.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Edit Person", modal.find_element_by_tag_name('h3').text)
|
||||
name = modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]')
|
||||
self.assertEqual(person1.name, name.get_attribute('value'))
|
||||
name.clear()
|
||||
name.send_keys('Rig ' + person1.name)
|
||||
name.send_keys(Keys.ENTER)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
self.assertFalse(modal.is_displayed())
|
||||
person1 = models.Person.objects.get(pk=person1.pk)
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
|
||||
# Create organisation
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_organisation" and contains(@href, "add")]')
|
||||
add_button.click()
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Organisation", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Organisation.objects.get(name="Test Organisation")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_organisation"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_organisation"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Create veneue
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_venue" and contains(@href, "add")]')
|
||||
add_button.click()
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Venue", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Venue.objects.get(name="Test Venue")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_venue"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_venue"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set start date/time
|
||||
form.find_element_by_id('id_start_date').send_keys('3015-05-25')
|
||||
form.find_element_by_id('id_start_time').send_keys('06:59')
|
||||
|
||||
# Set end date/time
|
||||
form.find_element_by_id('id_end_date').send_keys('4000-06-27')
|
||||
form.find_element_by_id('id_end_time').send_keys('07:00')
|
||||
|
||||
# Add item
|
||||
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||
wait.until(animation_is_finished())
|
||||
modal = self.browser.find_element_by_id("itemModal")
|
||||
modal.find_element_by_id("item_name").send_keys("Test Item 1")
|
||||
modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
|
||||
e = modal.find_element_by_id("item_quantity")
|
||||
e.click()
|
||||
e.send_keys(Keys.UP)
|
||||
e.send_keys(Keys.UP)
|
||||
e = modal.find_element_by_id("item_cost")
|
||||
e.send_keys("23.95")
|
||||
e.send_keys(Keys.ENTER) # enter submit
|
||||
|
||||
# Confirm item has been saved to json field
|
||||
objectitems = self.browser.execute_script("return objectitems;")
|
||||
self.assertEqual(1, len(objectitems))
|
||||
testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID
|
||||
self.assertEqual("Test Item 1", testitem['name'])
|
||||
self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields
|
||||
|
||||
# See new item appear in table
|
||||
row = self.browser.find_element_by_id('item--1') # ID number is known, see above
|
||||
self.assertIn("Test Item 1", row.find_element_by_xpath('//span[@class="name"]').text)
|
||||
self.assertIn("This is an item description", row.find_element_by_xpath('//div[@class="item-description"]').text)
|
||||
self.assertEqual(u'£ 23.95', row.find_element_by_xpath('//tr[@id="item--1"]/td[2]').text)
|
||||
self.assertEqual("2", row.find_element_by_xpath('//td[@class="quantity"]').text)
|
||||
self.assertEqual(u'£ 47.90', row.find_element_by_xpath('//tr[@id="item--1"]/td[4]').text)
|
||||
|
||||
# Check totals
|
||||
self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').text)
|
||||
self.assertIn("(TBC)", self.browser.find_element_by_id('vat-rate').text)
|
||||
self.assertEqual("9.58", self.browser.find_element_by_id('vat').text)
|
||||
self.assertEqual("57.48", self.browser.find_element_by_id('total').text)
|
||||
|
||||
# Attempt to save - missing title
|
||||
save.click()
|
||||
|
||||
# See error
|
||||
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||
self.assertTrue(error.is_displayed())
|
||||
# Should only have one error message
|
||||
self.assertEqual("Name", error.find_element_by_xpath('//dt[1]').text)
|
||||
self.assertEqual("This field is required.", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||
# don't need error so close it
|
||||
error.find_element_by_xpath('//div[contains(@class, "alert-danger")]//button[@class="close"]').click()
|
||||
try:
|
||||
self.assertFalse(error.is_displayed())
|
||||
except StaleElementReferenceException:
|
||||
# Requests address
|
||||
self.browser.get(self.live_server_url + '/event/create/')
|
||||
# Gets redirected to login and back
|
||||
self.authenticate('/event/create/')
|
||||
|
||||
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
# Check has slided up correctly - second save button hidden
|
||||
save = self.browser.find_element_by_xpath(
|
||||
'(//button[@type="submit"])[3]')
|
||||
self.assertFalse(save.is_displayed())
|
||||
|
||||
# Click Rig button
|
||||
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
||||
|
||||
# Slider expands and save button visible
|
||||
self.assertTrue(save.is_displayed())
|
||||
form = self.browser.find_element_by_tag_name('form')
|
||||
|
||||
# Create new person
|
||||
wait.until(animation_is_finished())
|
||||
add_person_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "add")]')
|
||||
add_person_button.click()
|
||||
|
||||
# See modal has opened
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
# Fill person form out and submit
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 1")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
# See new person selected
|
||||
person1 = models.Person.objects.get(name="Test Person 1")
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Change mind and add another
|
||||
wait.until(animation_is_finished())
|
||||
add_person_button.click()
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 2")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
person2 = models.Person.objects.get(name="Test Person 2")
|
||||
self.assertEqual(person2.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# Have to do this explcitly to force the wait for it to update
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person2.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Was right the first time, change it back
|
||||
person_select = form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]')
|
||||
person_select.send_keys(person1.name)
|
||||
person_dropped = form.find_element_by_xpath(
|
||||
'//ul[contains(@class, "inner selectpicker")]//span[contains(text(), "%s")]' % person1.name)
|
||||
person_dropped.click()
|
||||
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Edit Person 1 to have a better name
|
||||
form.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Edit Person", modal.find_element_by_tag_name('h3').text)
|
||||
name = modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]')
|
||||
self.assertEqual(person1.name, name.get_attribute('value'))
|
||||
name.clear()
|
||||
name.send_keys('Rig ' + person1.name)
|
||||
name.send_keys(Keys.ENTER)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
self.assertFalse(modal.is_displayed())
|
||||
person1 = models.Person.objects.get(pk=person1.pk)
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
|
||||
# Create organisation
|
||||
wait.until(animation_is_finished())
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_organisation" and contains(@href, "add")]')
|
||||
add_button.click()
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Organisation", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Organisation.objects.get(name="Test Organisation")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_organisation"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_organisation"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Create venue
|
||||
wait.until(animation_is_finished())
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_venue" and contains(@href, "add")]')
|
||||
wait.until(animation_is_finished())
|
||||
add_button.click()
|
||||
wait.until(animation_is_finished())
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Venue", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Venue.objects.get(name="Test Venue")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_venue"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_venue"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set start date/time
|
||||
form.find_element_by_id('id_start_date').send_keys('3015-05-25')
|
||||
form.find_element_by_id('id_start_time').send_keys('06:59')
|
||||
|
||||
# Set end date/time
|
||||
form.find_element_by_id('id_end_date').send_keys('4000-06-27')
|
||||
form.find_element_by_id('id_end_time').send_keys('07:00')
|
||||
|
||||
# Add item
|
||||
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||
wait.until(animation_is_finished())
|
||||
modal = self.browser.find_element_by_id("itemModal")
|
||||
modal.find_element_by_id("item_name").send_keys("Test Item 1")
|
||||
modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
|
||||
e = modal.find_element_by_id("item_quantity")
|
||||
e.click()
|
||||
e.send_keys(Keys.UP)
|
||||
e.send_keys(Keys.UP)
|
||||
e = modal.find_element_by_id("item_cost")
|
||||
e.send_keys("23.95")
|
||||
e.send_keys(Keys.ENTER) # enter submit
|
||||
|
||||
# Confirm item has been saved to json field
|
||||
objectitems = self.browser.execute_script("return objectitems;")
|
||||
self.assertEqual(1, len(objectitems))
|
||||
testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID
|
||||
self.assertEqual("Test Item 1", testitem['name'])
|
||||
self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields
|
||||
|
||||
# See new item appear in table
|
||||
row = self.browser.find_element_by_id('item--1') # ID number is known, see above
|
||||
self.assertIn("Test Item 1", row.find_element_by_xpath('//span[@class="name"]').text)
|
||||
self.assertIn("This is an item description", row.find_element_by_xpath('//div[@class="item-description"]').text)
|
||||
self.assertEqual(u'£ 23.95', row.find_element_by_xpath('//tr[@id="item--1"]/td[2]').text)
|
||||
self.assertEqual("2", row.find_element_by_xpath('//td[@class="quantity"]').text)
|
||||
self.assertEqual(u'£ 47.90', row.find_element_by_xpath('//tr[@id="item--1"]/td[4]').text)
|
||||
|
||||
# Check totals
|
||||
self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').text)
|
||||
self.assertIn("(TBC)", self.browser.find_element_by_id('vat-rate').text)
|
||||
self.assertEqual("9.58", self.browser.find_element_by_id('vat').text)
|
||||
self.assertEqual("57.48", self.browser.find_element_by_id('total').text)
|
||||
|
||||
# Attempt to save - missing title
|
||||
save.click()
|
||||
|
||||
# See error
|
||||
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||
self.assertTrue(error.is_displayed())
|
||||
# Should only have one error message
|
||||
self.assertEqual("Name", error.find_element_by_xpath('//dt[1]').text)
|
||||
self.assertEqual("This field is required.", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||
# don't need error so close it
|
||||
error.find_element_by_xpath('//div[contains(@class, "alert-danger")]//button[@class="close"]').click()
|
||||
try:
|
||||
self.assertFalse(error.is_displayed())
|
||||
except StaleElementReferenceException:
|
||||
pass
|
||||
except:
|
||||
self.assertFail("Element does not appear to have been deleted")
|
||||
|
||||
# Check at least some data is preserved. Some = all will be there
|
||||
option = self.browser.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set title
|
||||
e = self.browser.find_element_by_id('id_name')
|
||||
e.send_keys('Test Event Name')
|
||||
e.send_keys(Keys.ENTER)
|
||||
|
||||
# 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)
|
||||
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
|
||||
pass
|
||||
except:
|
||||
self.assertFail("Element does not appear to have been deleted")
|
||||
|
||||
# Check at least some data is preserved. Some = all will be there
|
||||
option = self.browser.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set title
|
||||
e = self.browser.find_element_by_id('id_name')
|
||||
e.send_keys('Test Event Name')
|
||||
e.send_keys(Keys.ENTER)
|
||||
|
||||
# See redirected to success page
|
||||
event = models.Event.objects.get(name='Test Event Name')
|
||||
self.assertIn("N0000%d | Test Event Name"%event.pk, self.browser.find_element_by_xpath('//h1').text)
|
||||
|
||||
def testEventDuplicate(self):
|
||||
testEvent = models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end")
|
||||
@@ -610,8 +621,9 @@ class EventTest(LiveServerTestCase):
|
||||
save.click()
|
||||
|
||||
# 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, self.browser.find_element_by_xpath('//h1').text)
|
||||
self.assertIn("N0000%d | Test Event Name"%event.pk, successTitle)
|
||||
|
||||
def testRigNonRig(self):
|
||||
self.browser.get(self.live_server_url + '/event/create/')
|
||||
@@ -752,8 +764,6 @@ class IcalTest(LiveServerTestCase):
|
||||
|
||||
username.send_keys("EventTest")
|
||||
password.send_keys("EventTestPassword")
|
||||
self.browser.execute_script(
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
submit.click()
|
||||
|
||||
self.assertEqual(self.live_server_url + n, self.browser.current_url)
|
||||
|
||||
@@ -1,233 +1,329 @@
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from RIGS import models
|
||||
from datetime import date, timedelta
|
||||
from datetime import date, timedelta, datetime, time
|
||||
from decimal import *
|
||||
|
||||
|
||||
class ProfileTestCase(TestCase):
|
||||
def test_str(self):
|
||||
profile = models.Profile(first_name='Test', last_name='Case')
|
||||
self.assertEqual(str(profile), 'Test Case')
|
||||
profile.initials = 'TC'
|
||||
self.assertEqual(str(profile), 'Test Case "TC"')
|
||||
|
||||
|
||||
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')
|
||||
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')
|
||||
|
||||
def test_find_correct(self):
|
||||
r = models.VatRate.objects.find_rate('2015-03-01')
|
||||
self.assertEqual(r.comment, 'test1')
|
||||
r = models.VatRate.objects.find_rate('2016-03-01')
|
||||
self.assertEqual(r.comment, 'test2')
|
||||
def test_find_correct(self):
|
||||
r = models.VatRate.objects.find_rate('2015-03-01')
|
||||
self.assertEqual(r.comment, 'test1')
|
||||
r = models.VatRate.objects.find_rate('2016-03-01')
|
||||
self.assertEqual(r.comment, 'test2')
|
||||
|
||||
def test_percent_correct(self):
|
||||
r = models.VatRate.objects.get(rate=0.20)
|
||||
self.assertEqual(r.as_percent, 20)
|
||||
|
||||
def test_percent_correct(self):
|
||||
r = models.VatRate.objects.get(rate=0.20)
|
||||
self.assertEqual(r.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)
|
||||
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)
|
||||
|
||||
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")
|
||||
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")
|
||||
|
||||
# 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")
|
||||
# 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")
|
||||
|
||||
# 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
|
||||
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")
|
||||
|
||||
# 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
|
||||
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")
|
||||
|
||||
# 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
|
||||
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")
|
||||
|
||||
def test_count(self):
|
||||
# Santiy check we have the expected events created
|
||||
self.assertEqual(models.Event.objects.count(), 18, "Incorrect number of events, check setup")
|
||||
def test_count(self):
|
||||
# Santiy check we have the expected events created
|
||||
self.assertEqual(models.Event.objects.count(), 18, "Incorrect number of events, check setup")
|
||||
|
||||
def test_rig_count(self):
|
||||
# by my count this is 7
|
||||
self.assertEqual(models.Event.objects.rig_count(), 8)
|
||||
def test_rig_count(self):
|
||||
# by my count this is 7
|
||||
self.assertEqual(models.Event.objects.rig_count(), 8)
|
||||
|
||||
def test_current_events(self):
|
||||
current_events = models.Event.objects.current_events()
|
||||
self.assertEqual(len(current_events), len(self.current_events))
|
||||
for eid in self.current_events:
|
||||
self.assertIn(models.Event.objects.get(name="TE E%d"%eid), current_events)
|
||||
def test_current_events(self):
|
||||
current_events = models.Event.objects.current_events()
|
||||
self.assertEqual(len(current_events), len(self.current_events))
|
||||
for eid in self.current_events:
|
||||
self.assertIn(models.Event.objects.get(name="TE E%d" % eid), current_events)
|
||||
|
||||
for eid in self.not_current_events:
|
||||
self.assertNotIn(models.Event.objects.get(name="TE E%d"%eid), current_events)
|
||||
for eid in self.not_current_events:
|
||||
self.assertNotIn(models.Event.objects.get(name="TE E%d" % eid), current_events)
|
||||
|
||||
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
|
||||
event.save()
|
||||
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
|
||||
event.save()
|
||||
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], v1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], v2.latest_events)
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], v1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], v2.latest_events)
|
||||
|
||||
def test_related_vatrate(self):
|
||||
self.assertEqual(self.vatrate, models.Event.objects.all()[0].vat_rate)
|
||||
def test_related_vatrate(self):
|
||||
self.assertEqual(self.vatrate, models.Event.objects.all()[0].vat_rate)
|
||||
|
||||
def test_related_person(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
def test_related_person(self):
|
||||
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
|
||||
event.save()
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p2
|
||||
event.save()
|
||||
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], p1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], p2.latest_events)
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], p1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], p2.latest_events)
|
||||
|
||||
def test_related_organisation(self):
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
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
|
||||
event.save()
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], o1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], o2.latest_events)
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], o1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], o2.latest_events)
|
||||
|
||||
def test_organisation_person_join(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
def test_organisation_person_join(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
|
||||
events = models.Event.objects.all()
|
||||
# p1 in o1 + o2, p2 in o1
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p1
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
for event in events[5:7]:
|
||||
event.person = p2
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
events = models.Event.objects.all()
|
||||
# p1 in o1 + o2, p2 in o1
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p1
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
for event in events[5:7]:
|
||||
event.person = p2
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
|
||||
events = models.Event.objects.all()
|
||||
events = models.Event.objects.all()
|
||||
|
||||
# Check person's organisations
|
||||
self.assertIn((o1,2), p1.organisations)
|
||||
self.assertIn((o2,1), p1.organisations)
|
||||
self.assertIn((o1,2), p2.organisations)
|
||||
self.assertEqual(len(p2.organisations), 1)
|
||||
# Check person's organisations
|
||||
self.assertIn((o1, 2), p1.organisations)
|
||||
self.assertIn((o2, 1), p1.organisations)
|
||||
self.assertIn((o1, 2), p2.organisations)
|
||||
self.assertEqual(len(p2.organisations), 1)
|
||||
|
||||
# Check organisation's persons
|
||||
self.assertIn((p1,2), o1.persons)
|
||||
self.assertIn((p2,2), o1.persons)
|
||||
self.assertIn((p1,1), o2.persons)
|
||||
self.assertEqual(len(o2.persons),1)
|
||||
# Check organisation's persons
|
||||
self.assertIn((p1, 2), o1.persons)
|
||||
self.assertIn((p2, 2), o1.persons)
|
||||
self.assertIn((p1, 1), o2.persons)
|
||||
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]
|
||||
self.assertEqual(event.status, models.Event.CANCELLED)
|
||||
self.assertTrue(event.cancelled)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
def test_cancelled_property(self):
|
||||
event = models.Event.objects.all()[0]
|
||||
event.status = models.Event.CANCELLED
|
||||
event.save()
|
||||
event = models.Event.objects.all()[0]
|
||||
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]
|
||||
self.assertEqual(event.status, models.Event.CONFIRMED)
|
||||
self.assertTrue(event.confirmed)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
|
||||
def test_earliest_time(self):
|
||||
event = models.Event(name="TE ET", start_date=date(2016, 01, 01))
|
||||
|
||||
# Just a start date
|
||||
self.assertEqual(event.earliest_time, date(2016, 01, 01))
|
||||
|
||||
# With start time
|
||||
event.start_time = time(9, 00)
|
||||
self.assertEqual(event.earliest_time, self.create_datetime(2016, 1, 1, 9, 00))
|
||||
|
||||
# With access time
|
||||
event.access_at = self.create_datetime(2015, 12, 03, 9, 57)
|
||||
self.assertEqual(event.earliest_time, event.access_at)
|
||||
|
||||
# With meet time
|
||||
event.meet_at = self.create_datetime(2015, 12, 03, 9, 55)
|
||||
self.assertEqual(event.earliest_time, event.meet_at)
|
||||
|
||||
# Check order isn't important
|
||||
event.start_date = date(2015, 12, 03)
|
||||
self.assertEqual(event.earliest_time, self.create_datetime(2015, 12, 03, 9, 00))
|
||||
|
||||
def test_latest_time(self):
|
||||
event = models.Event(name="TE LT", start_date=date(2016, 01, 01))
|
||||
|
||||
# Just start date
|
||||
self.assertEqual(event.latest_time, event.start_date)
|
||||
|
||||
# Just end date
|
||||
event.end_date = date(2016, 1, 2)
|
||||
self.assertEqual(event.latest_time, event.end_date)
|
||||
|
||||
# With end time
|
||||
event.end_time = time(23, 00)
|
||||
self.assertEqual(event.latest_time, self.create_datetime(2016, 1, 2, 23, 00))
|
||||
|
||||
def test_in_bounds(self):
|
||||
manager = models.Event.objects
|
||||
events = [
|
||||
manager.create(name="TE IB0", start_date='2016-01-02'), # yes no
|
||||
manager.create(name="TE IB1", start_date='2015-12-31', end_date='2016-01-04'),
|
||||
|
||||
# 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'),
|
||||
|
||||
# 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))
|
||||
self.assertIn(events[0], in_bounds)
|
||||
self.assertIn(events[1], in_bounds)
|
||||
self.assertIn(events[2], in_bounds)
|
||||
self.assertIn(events[3], in_bounds)
|
||||
self.assertIn(events[4], in_bounds)
|
||||
self.assertIn(events[5], in_bounds)
|
||||
|
||||
self.assertNotIn(events[6], in_bounds)
|
||||
|
||||
def create_datetime(self, year, month, day, hour, min):
|
||||
tz = pytz.timezone(settings.TIME_ZONE)
|
||||
return tz.localize(datetime(year, month, day, hour, min))
|
||||
|
||||
def test_confirmed_property(self):
|
||||
event = models.Event.objects.all()[0]
|
||||
event.status = models.Event.CONFIRMED
|
||||
event.save()
|
||||
event = models.Event.objects.all()[0]
|
||||
self.assertEqual(event.status, models.Event.CONFIRMED)
|
||||
self.assertTrue(event.confirmed)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
|
||||
class EventItemTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.e1 = models.Event.objects.create(name="TI E1", start_date=date.today())
|
||||
self.e2 = models.Event.objects.create(name="TI E2", start_date=date.today())
|
||||
def setUp(self):
|
||||
self.e1 = models.Event.objects.create(name="TI E1", start_date=date.today())
|
||||
self.e2 = models.Event.objects.create(name="TI E2", start_date=date.today())
|
||||
|
||||
def test_item_cost(self):
|
||||
item = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
self.assertEqual(item.total_cost, 1.00)
|
||||
def test_item_cost(self):
|
||||
item = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
self.assertEqual(item.total_cost, 1.00)
|
||||
|
||||
item.cost = 2.50
|
||||
self.assertEqual(item.total_cost, 2.50)
|
||||
item.cost = 2.50
|
||||
self.assertEqual(item.total_cost, 2.50)
|
||||
|
||||
item.quantity = 4
|
||||
self.assertEqual(item.total_cost, 10.00)
|
||||
item.quantity = 4
|
||||
self.assertEqual(item.total_cost, 10.00)
|
||||
|
||||
# need to tidy up
|
||||
item.delete()
|
||||
# need to tidy up
|
||||
item.delete()
|
||||
|
||||
def test_item_order(self):
|
||||
i1 = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
i2 = models.EventItem.objects.create(event=self.e1, name="TI I2", quantity=1, cost=1.00, order=2)
|
||||
def test_item_order(self):
|
||||
i1 = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
i2 = models.EventItem.objects.create(event=self.e1, name="TI I2", quantity=1, cost=1.00, order=2)
|
||||
|
||||
items = self.e1.items.all()
|
||||
self.assertListEqual([i1, i2], list(items))
|
||||
|
||||
items = self.e1.items.all()
|
||||
self.assertListEqual([i1, i2], list(items))
|
||||
|
||||
class EventPricingTestCase(TestCase):
|
||||
def setUp(self):
|
||||
models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01')
|
||||
models.VatRate.objects.create(rate=0.10, comment="TP V2", start_at=date.today()-timedelta(days=1))
|
||||
self.e1 = models.Event.objects.create(name="TP E1", start_date=date.today()-timedelta(days=2))
|
||||
self.e2 = models.Event.objects.create(name="TP E2", start_date=date.today())
|
||||
def setUp(self):
|
||||
models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01')
|
||||
models.VatRate.objects.create(rate=0.10, comment="TP V2", start_at=date.today() - timedelta(days=1))
|
||||
self.e1 = models.Event.objects.create(name="TP E1", start_date=date.today() - timedelta(days=2))
|
||||
self.e2 = models.Event.objects.create(name="TP E2", start_date=date.today())
|
||||
|
||||
# Create some items E1, total 70.40
|
||||
# Create some items E2, total 381.20
|
||||
self.i1 = models.EventItem.objects.create(event=self.e1, name="TP I1", quantity=1, cost=50.00, order=1)
|
||||
self.i2 = models.EventItem.objects.create(event=self.e1, name="TP I2", quantity=2, cost=3.20, order=2)
|
||||
self.i3 = models.EventItem.objects.create(event=self.e1, name="TP I3", quantity=7, cost=2.00, order=3)
|
||||
self.i4 = models.EventItem.objects.create(event=self.e2, name="TP I4", quantity=2, cost=190.60, order=1)
|
||||
# Create some items E1, total 70.40
|
||||
# Create some items E2, total 381.20
|
||||
self.i1 = models.EventItem.objects.create(event=self.e1, name="TP I1", quantity=1, cost=50.00, order=1)
|
||||
self.i2 = models.EventItem.objects.create(event=self.e1, name="TP I2", quantity=2, cost=3.20, order=2)
|
||||
self.i3 = models.EventItem.objects.create(event=self.e1, name="TP I3", quantity=7, cost=2.00, order=3)
|
||||
self.i4 = models.EventItem.objects.create(event=self.e2, name="TP I4", quantity=2, cost=190.60, order=1)
|
||||
|
||||
# Decimal type is needed here as that is what is returned from the model.
|
||||
# Using anything else results in a failure due to floating point arritmetic
|
||||
def test_sum_totals(self):
|
||||
self.assertEqual(self.e1.sum_total, Decimal('70.40'))
|
||||
self.assertEqual(self.e2.sum_total, Decimal('381.20'))
|
||||
# Decimal type is needed here as that is what is returned from the model.
|
||||
# Using anything else results in a failure due to floating point arritmetic
|
||||
def test_sum_totals(self):
|
||||
self.assertEqual(self.e1.sum_total, Decimal('70.40'))
|
||||
self.assertEqual(self.e2.sum_total, Decimal('381.20'))
|
||||
|
||||
def test_vat_rate(self):
|
||||
self.assertEqual(self.e1.vat_rate.rate, Decimal('0.20'))
|
||||
self.assertEqual(self.e2.vat_rate.rate, Decimal('0.10'))
|
||||
def test_vat_rate(self):
|
||||
self.assertEqual(self.e1.vat_rate.rate, Decimal('0.20'))
|
||||
self.assertEqual(self.e2.vat_rate.rate, Decimal('0.10'))
|
||||
|
||||
def test_vat_ammount(self):
|
||||
self.assertEqual(self.e1.vat, Decimal('14.08'))
|
||||
self.assertEqual(self.e2.vat, Decimal('38.12'))
|
||||
def test_vat_ammount(self):
|
||||
self.assertEqual(self.e1.vat, Decimal('14.08'))
|
||||
self.assertEqual(self.e2.vat, Decimal('38.12'))
|
||||
|
||||
def test_grand_total(self):
|
||||
self.assertEqual(self.e1.total, Decimal('84.48'))
|
||||
self.assertEqual(self.e2.total, Decimal('419.32'))
|
||||
def test_grand_total(self):
|
||||
self.assertEqual(self.e1.total, Decimal('84.48'))
|
||||
self.assertEqual(self.e2.total, Decimal('419.32'))
|
||||
|
||||
@@ -69,6 +69,8 @@ urlpatterns = patterns('',
|
||||
# Rigboard
|
||||
url(r'^rigboard/$', login_required(rigboard.RigboardIndex.as_view()), name='rigboard'),
|
||||
url(r'^rigboard/calendar/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/(?P<date>(\d{4}-\d{2}-\d{2}))/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||
url(r'^rigboard/archive/$', RedirectView.as_view(permanent=True,pattern_name='event_archive')),
|
||||
url(r'^rigboard/activity/$',
|
||||
permission_required_with_403('RIGS.view_event')(versioning.ActivityTable.as_view()),
|
||||
|
||||
@@ -17,6 +17,7 @@ from reversion.models import Version
|
||||
from django.contrib.contenttypes.models import ContentType # Used to lookup the content_type
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.db.models import ForeignKey, IntegerField, EmailField, TextField
|
||||
from diff_match_patch import diff_match_patch
|
||||
|
||||
from RIGS import models, forms
|
||||
import datetime
|
||||
@@ -64,6 +65,25 @@ def model_compare(oldObj, newObj, excluded_keys=[]):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def diff(self):
|
||||
oldText = unicode(self.display_value(self._old)) or ""
|
||||
newText = unicode(self.display_value(self._new)) or ""
|
||||
dmp = diff_match_patch()
|
||||
diffs = dmp.diff_main(oldText, newText)
|
||||
dmp.diff_cleanupSemantic(diffs)
|
||||
|
||||
outputDiffs = []
|
||||
|
||||
for (op, data) in diffs:
|
||||
if op == dmp.DIFF_INSERT:
|
||||
outputDiffs.append({'type':'insert', 'text':data})
|
||||
elif op == dmp.DIFF_DELETE:
|
||||
outputDiffs.append({'type':'delete', 'text':data})
|
||||
elif op == dmp.DIFF_EQUAL:
|
||||
outputDiffs.append({'type':'equal', 'text':data})
|
||||
return outputDiffs
|
||||
|
||||
changes = []
|
||||
|
||||
for thisField in theFields:
|
||||
|
||||
@@ -33,7 +33,7 @@ def login(request, **kwargs):
|
||||
else:
|
||||
from django.contrib.auth.views import login
|
||||
|
||||
return login(request, authentication_form=forms.LoginForm)
|
||||
return login(request)
|
||||
|
||||
"""
|
||||
Called from a modal window (e.g. when an item is submitted to an event/invoice).
|
||||
|
||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
@@ -1,4 +1,5 @@
|
||||
beautifulsoup4==4.4.1
|
||||
diff-match-patch==20121119
|
||||
dj-database-url==0.3.0
|
||||
dj-static==0.0.6
|
||||
Django==1.8.2
|
||||
@@ -21,7 +22,7 @@ python-dateutil==2.4.2
|
||||
pytz==2015.4
|
||||
raven==5.8.1
|
||||
reportlab==3.1.44
|
||||
selenium==2.46.0
|
||||
selenium==2.53.1
|
||||
simplejson==3.7.2
|
||||
six==1.9.0
|
||||
sqlparse==0.1.15
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
|
||||
<link rel="icon" type="image/png" href="{% static "imgs/pyrigs-avatar.png" %}">
|
||||
<link rel="apple-touch-icon" href="{% static "imgs/pyrigs-avatar.png" %}">
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,700,300,400' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,700,300,400' rel='stylesheet'
|
||||
type='text/css'>
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{% static "css/screen.css" %}">
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
|
||||
<script src="//code.jquery.com/jquery-latest.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-1.8.3.min.js"
|
||||
integrity="sha256-YcbK69I5IXQftf/mYD8WY0/KmEDCv1asggHpJk1trM8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.ravenjs.com/1.3.0/jquery,native/raven.min.js"></script>
|
||||
<script>Raven.config('{% sentry_public_dsn %}').install()</script>
|
||||
{% block preload_js %}
|
||||
@@ -46,32 +48,40 @@
|
||||
<div class="navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
{% if user.is_authenticated %}
|
||||
<li><a href="/">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Rigboard<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'rigboard' %}"><span class="glyphicon glyphicon-list"></span> Rigboard</a></li>
|
||||
<li><a href="{% url 'event_archive' %}"><span class="glyphicon glyphicon-book"></span> Archive</a></li>
|
||||
<li><a href="{% url 'web_calendar' %}"><span class="glyphicon glyphicon-calendar"></span> Calendar</a></li>
|
||||
{% if perms.RIGS.view_event %}
|
||||
<li><a href="{% url 'activity_table' %}"><span class="glyphicon glyphicon-random"></span> Recent Changes</a></li>
|
||||
{% endif %}
|
||||
{% if perms.RIGS.add_event %}
|
||||
<li><a href="{% url 'event_create' %}"><span class="glyphicon glyphicon-plus"></span> New Event</a></li>
|
||||
{% endif %}
|
||||
<li><a href="/">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Rigboard<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'rigboard' %}"><span class="glyphicon glyphicon-list"></span>
|
||||
Rigboard</a></li>
|
||||
<li><a href="{% url 'event_archive' %}"><span class="glyphicon glyphicon-book"></span>
|
||||
Archive</a></li>
|
||||
<li><a href="{% url 'web_calendar' %}"><span class="glyphicon glyphicon-calendar"></span>
|
||||
Calendar</a></li>
|
||||
{% if perms.RIGS.view_event %}
|
||||
<li><a href="{% url 'activity_table' %}"><span
|
||||
class="glyphicon glyphicon-random"></span> Recent Changes</a></li>
|
||||
{% endif %}
|
||||
{% if perms.RIGS.add_event %}
|
||||
<li><a href="{% url 'event_create' %}"><span class="glyphicon glyphicon-plus"></span>
|
||||
New Event</a></li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if perms.RIGS.view_invoice %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Invoices<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'invoice_list' %}"><span class="glyphicon glyphicon-gbp"></span> Active</a></li>
|
||||
<li><a href="{% url 'invoice_list' %}"><span class="glyphicon glyphicon-gbp"></span> Active</a>
|
||||
</li>
|
||||
{% if perms.RIGS.add_invoice %}
|
||||
<li><a href="{% url 'invoice_waiting' %}"><span class="glyphicon glyphicon-briefcase"></span> Waiting</a></li>
|
||||
<li><a href="{% url 'invoice_waiting' %}"><span
|
||||
class="glyphicon glyphicon-briefcase"></span> Waiting</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'invoice_archive' %}"><span class="glyphicon glyphicon-book"></span> Archive</a></li>
|
||||
<li><a href="{% url 'invoice_archive' %}"><span class="glyphicon glyphicon-book"></span>
|
||||
Archive</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
@@ -144,10 +154,6 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="col-sm-12 text-center">
|
||||
Reminder: Please consider carefully before booking rigs at this moment
|
||||
</div>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
@@ -182,7 +188,7 @@
|
||||
jQuery(document).on('click', '.modal-href', function (e) {
|
||||
$link = jQuery(this);
|
||||
// Anti modal inception
|
||||
if($link.parents('#modal').length == 0) {
|
||||
if ($link.parents('#modal').length == 0) {
|
||||
e.preventDefault();
|
||||
modaltarget = $link.data('target');
|
||||
modalobject = "";
|
||||
@@ -194,11 +200,11 @@
|
||||
|
||||
|
||||
var easter_egg = new Konami();
|
||||
easter_egg.code = function() {
|
||||
easter_egg.code = function () {
|
||||
var s = document.createElement('script');
|
||||
s.type='text/javascript';
|
||||
s.type = 'text/javascript';
|
||||
document.body.appendChild(s);
|
||||
s.src='{% static "js/asteroids.min.js"%}';
|
||||
s.src = '{% static "js/asteroids.min.js"%}';
|
||||
ga('send', 'event', 'easter_egg', 'activated');
|
||||
}
|
||||
easter_egg.load();
|
||||
|
||||
@@ -6,18 +6,12 @@
|
||||
<form action="{% url 'login' %}" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="id_username">{{ form.username.label }}</label>
|
||||
{% render_field form.username class+="form-control" placeholder=form.username.label %}
|
||||
{% render_field form.username class+="form-control" placeholder=form.username.label autofocus="" %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.password.id_for_label }}">{{ form.password.label }}</label>
|
||||
{% render_field form.password class+="form-control" placeholder=form.password.label %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.captcha.id_for_label }}">{{ form.captcha.label }}</label>
|
||||
<div class="text-center">
|
||||
{{ form.captcha }}
|
||||
</div>
|
||||
</div>
|
||||
<a href="{% url 'registration_register' %}" class="btn">Register</a>
|
||||
<a href="{% url 'password_reset' %}" class="btn">Forgotten Password</a>
|
||||
<input type="submit" value="Login" class="btn btn-primary"/>
|
||||
|
||||
Reference in New Issue
Block a user