Merged in web-calendar (pull request #48)

Web calendar
This commit is contained in:
Tom Price
2015-07-29 19:01:04 +01:00
7 changed files with 499 additions and 114 deletions

View File

@@ -17,15 +17,58 @@ class CalendarICS(ICalFeed):
timezone = settings.TIME_ZONE timezone = settings.TIME_ZONE
file_name = "rigs.ics" file_name = "rigs.ics"
def get(self, *args, **kwargs): # Cancelled = 'cancelled' = False
timezone.activate(timezone.UTC) # Dry Hire = 'dry-hire' = True
return super(CalendarICS, self).get(*args, **kwargs) # Non Rig = 'non-rig' = True
# Rig = 'rig' = True
# Provisional = 'provisional' = True
# Confirmed/Booked = 'confirmed' = True
def get_object(self, request, *args, **kwargs):
params = {}
def items(self): params['dry-hire'] = request.GET.get('dry-hire','true') == 'true'
params['non-rig'] = request.GET.get('non-rig','true') == 'true'
params['rig'] = request.GET.get('rig','true') == 'true'
params['cancelled'] = request.GET.get('cancelled','false') == 'true'
params['provisional'] = request.GET.get('provisional','true') == 'true'
params['confirmed'] = request.GET.get('confirmed','true') == 'true'
return params
def description(self,params):
desc = "Calendar generated by RIGS system. This includes event types: " + ('Rig, ' if params['rig'] else '') + ('Non-rig, ' if params['non-rig'] else '') + ('Dry Hire ' if params['dry-hire'] else '') + '\n'
desc = desc + "Includes events with status: " + ('Cancelled, ' if params['cancelled'] else '') + ('Provisional, ' if params['provisional'] else '') + ('Confirmed/Booked, ' if params['confirmed'] else '')
return desc
def items(self, params):
#include events from up to 1 year ago #include events from up to 1 year ago
start = datetime.datetime.now() - datetime.timedelta(days=365) start = datetime.datetime.now() - datetime.timedelta(days=365)
filter = Q(start_date__gte=start) & ~Q(status=models.Event.CANCELLED) filter = Q(start_date__gte=start)
typeFilters = Q(pk=None) #Need something that is false for every entry
if params['dry-hire']:
typeFilters = typeFilters | Q(dry_hire=True, is_rig=True)
if params['non-rig']:
typeFilters = typeFilters | Q(is_rig=False)
if params['rig']:
typeFilters = typeFilters | Q(is_rig=True, dry_hire=False)
statusFilters = Q(pk=None) #Need something that is false for every entry
if params['cancelled']:
statusFilters = statusFilters | Q(status=models.Event.CANCELLED)
if params['provisional']:
statusFilters = statusFilters | Q(status=models.Event.PROVISIONAL)
if params['confirmed']:
statusFilters = statusFilters | Q(status=models.Event.CONFIRMED) | Q(status=models.Event.BOOKED)
filter = filter & typeFilters & statusFilters
return models.Event.objects.filter(filter).order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic') return models.Event.objects.filter(filter).order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
@@ -51,38 +94,10 @@ class CalendarICS(ICalFeed):
return title return title
def item_start_datetime(self, item): def item_start_datetime(self, item):
#set start date to the earliest defined time for the event return item.earliest_time
if item.meet_at:
startDateTime = item.meet_at
elif item.access_at:
startDateTime = item.access_at
elif item.has_start_time:
startDateTime = datetime.datetime.combine(item.start_date,item.start_time)
tz = pytz.timezone(settings.TIME_ZONE)
startDateTime = tz.normalize(tz.localize(startDateTime)).astimezone(pytz.timezone(self.timezone))
else:
startDateTime = item.start_date
return startDateTime
def item_end_datetime(self, item): def item_end_datetime(self, item):
# Assume end is same as start return item.latest_time
endDateTime = item.start_date
# If end date defined then use it
if item.end_date:
endDateTime = item.end_date
if item.has_start_time and item.has_end_time: # don't allow an event with specific end but no specific start
endDateTime = datetime.datetime.combine(endDateTime,item.end_time)
tz = pytz.timezone(settings.TIME_ZONE)
endDateTime = tz.normalize(tz.localize(endDateTime)).astimezone(pytz.timezone(self.timezone))
elif item.has_end_time: # if there's a start time specified then an end time should also be specified
endDateTime = datetime.datetime.combine(endDateTime+datetime.timedelta(days=1),datetime.time(00, 00))
#elif item.end_time: # end time but no start time - this is weird - don't think ICS will like it so ignoring
# do nothing
return endDateTime
def item_location(self,item): def item_location(self,item):
return item.venue return item.venue
@@ -91,6 +106,8 @@ class CalendarICS(ICalFeed):
# Create a nice information-rich description # Create a nice information-rich description
# note: only making use of information available to "non-keyholders" # note: only making use of information available to "non-keyholders"
tz = pytz.timezone(self.timezone)
desc = 'Rig ID = '+str(item.pk)+'\n' desc = 'Rig ID = '+str(item.pk)+'\n'
desc += 'Event = ' + item.name + '\n' desc += 'Event = ' + item.name + '\n'
desc += 'Venue = ' + (item.venue.name if item.venue else '---') + '\n' desc += 'Venue = ' + (item.venue.name if item.venue else '---') + '\n'
@@ -102,9 +119,9 @@ class CalendarICS(ICalFeed):
desc += '\n' desc += '\n'
if item.meet_at: if item.meet_at:
desc += 'Crew Meet = ' + (item.meet_at.strftime('%Y-%m-%d %H:%M') if item.meet_at else '---') + '\n' desc += 'Crew Meet = ' + (item.meet_at.astimezone(tz).strftime('%Y-%m-%d %H:%M') if item.meet_at else '---') + '\n'
if item.access_at: if item.access_at:
desc += 'Access At = ' + item.access_at.strftime('%Y-%m-%d %H:%M') + '\n' desc += 'Access At = ' + (item.access_at.astimezone(tz).strftime('%Y-%m-%d %H:%M') if item.access_at else '---') + '\n'
if item.start_date: if item.start_date:
desc += 'Event Start = ' + item.start_date.strftime('%Y-%m-%d') + ((' '+item.start_time.strftime('%H:%M')) if item.has_start_time else '') + '\n' desc += 'Event Start = ' + item.start_date.strftime('%Y-%m-%d') + ((' '+item.start_time.strftime('%H:%M')) if item.has_start_time else '') + '\n'
if item.end_date: if item.end_date:
@@ -113,8 +130,8 @@ class CalendarICS(ICalFeed):
desc += '\n' desc += '\n'
if item.description: if item.description:
desc += 'Event Description:\n'+item.description+'\n\n' desc += 'Event Description:\n'+item.description+'\n\n'
if item.notes: # if item.notes: // Need to add proper keyholder checks before this gets put back
desc += 'Notes:\n'+item.notes+'\n\n' # desc += 'Notes:\n'+item.notes+'\n\n'
base_url = "http://rigs.nottinghamtec.co.uk" base_url = "http://rigs.nottinghamtec.co.uk"
desc += 'URL = '+base_url+str(item.get_absolute_url()) desc += 'URL = '+base_url+str(item.get_absolute_url())

View File

@@ -1,5 +1,5 @@
import hashlib import hashlib
import datetime import datetime, pytz
from django.db import models, connection from django.db import models, connection
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
@@ -239,7 +239,14 @@ class EventManager(models.Manager):
(models.Q(start_date__gte=start.date(), start_date__lte=end.date())) | # Start date in bounds (models.Q(start_date__gte=start.date(), start_date__lte=end.date())) | # Start date in bounds
(models.Q(end_date__gte=start.date(), end_date__lte=end.date())) | # End date in bounds (models.Q(end_date__gte=start.date(), end_date__lte=end.date())) | # End date in bounds
(models.Q(access_at__gte=start, access_at__lte=end)) | # Access at in bounds (models.Q(access_at__gte=start, access_at__lte=end)) | # Access at in bounds
(models.Q(meet_at__gte=start, meet_at__lte=end)) # Meet at in bounds (models.Q(meet_at__gte=start, meet_at__lte=end)) | # Meet at in bounds
(models.Q(start_date__lte=start, end_date__gte=end)) | # Start before, end after
(models.Q(access_at__lte=start, start_date__gte=end)) | # Access before, start after
(models.Q(access_at__lte=start, end_date__gte=end)) | # Access before, end after
(models.Q(meet_at__lte=start, start_date__gte=end)) | # Meet before, start after
(models.Q(meet_at__lte=start, end_date__gte=end)) # Meet before, end after
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic') ).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic')
return events return events
@@ -359,6 +366,59 @@ class Event(models.Model, RevisionMixin):
def has_end_time(self): def has_end_time(self):
return self.end_time is not None return self.end_time is not None
@property
def earliest_time(self):
"""Finds the earliest time defined in the event - this function could return either a tzaware datetime, or a naiive date object"""
#Put all the datetimes in a list
datetime_list = []
if self.access_at:
datetime_list.append(self.access_at)
if self.meet_at:
datetime_list.append(self.meet_at)
# If there is no start time defined, pretend it's midnight
startTimeFaked = False
if self.has_start_time:
startDateTime = datetime.datetime.combine(self.start_date,self.start_time)
else:
startDateTime = datetime.datetime.combine(self.start_date,datetime.time(00,00))
startTimeFaked = True
#timezoneIssues - apply the default timezone to the naiive datetime
tz = pytz.timezone(settings.TIME_ZONE)
startDateTime = tz.localize(startDateTime)
datetime_list.append(startDateTime) # then add it to the list
earliest = min(datetime_list).astimezone(tz) #find the earliest datetime in the list
# if we faked it & it's the earliest, better own up
if startTimeFaked and earliest==startDateTime:
return self.start_date
return earliest
@property
def latest_time(self):
"""Returns the end of the event - this function could return either a tzaware datetime, or a naiive date object"""
tz = pytz.timezone(settings.TIME_ZONE)
endDate = self.end_date
if endDate is None:
endDate = self.start_date
if self.has_end_time:
endDateTime = datetime.datetime.combine(endDate,self.end_time)
tz = pytz.timezone(settings.TIME_ZONE)
endDateTime = tz.localize(endDateTime)
return endDateTime
else:
return endDate
objects = EventManager() objects = EventManager()
def get_absolute_url(self): def get_absolute_url(self):

View File

@@ -17,7 +17,6 @@
$(document).ready(function() { $(document).ready(function() {
$('#calendar').fullCalendar({ $('#calendar').fullCalendar({
//defaultDate: '2015-02-12',
editable: false, editable: false,
eventLimit: true, // allow "more" link when too many events eventLimit: true, // allow "more" link when too many events
firstDay: 1, firstDay: 1,
@@ -37,75 +36,156 @@
// options apply to basicDay and agendaDay views // options apply to basicDay and agendaDay views
} }
}, },
buttonText:{ header:false,
today: 'Today',
month: 'Month',
week: 'Week',
day: 'Day'
},
header:{
left: 'title',
center: '',
right: 'today prev,next month,agendaWeek,agendaDay'
},
events: function(start_moment, end_moment, timezone, callback) { events: function(start_moment, end_moment, timezone, callback) {
$.ajax({ $.ajax({
url: '/api/event', url: '/api/event',
dataType: 'json', dataType: 'json',
data: { data: {
start: moment(start_moment).format("YYYY-MM-DD[T]HH:mm:ss[Z]"), start: moment(start_moment).format("YYYY-MM-DD[T]HH:mm:ss"),
end: moment(end_moment).format("YYYY-MM-DD[T]HH:mm:ss[Z]") end: moment(end_moment).format("YYYY-MM-DD[T]HH:mm:ss")
}, },
success: function(doc) { success: function(doc) {
var events = []; var events = [];
var colours = colours = {'Provisional': '#f0ad4e',
'Confirmed': '#5cb85c' ,
'Booked': '#5cb85c' ,
'Cancelled': 'grey' ,
'non-rig': '#5bc0de'
};
$(doc).each(function() { $(doc).each(function() {
thisEvent = [];
colours = {'Provisional': 'orange',
'Confirmed': 'green' ,
'Booked': 'green' ,
'Cancelled': 'grey'
};
thisEvent['start'] = $(this).attr('start_date');
if ($(this).attr('start_time')) {
thisEvent['start'] += 'T' + $(this).attr('start_time');
}
if ($(this).attr('end_date')) {
thisEvent['end'] = $(this).attr('end_date');
if ($(this).attr('end_time')) {
thisEvent['end'] += 'T' + $(this).attr('end_time');
}
}
thisEvent['className'] = 'modal-href';
thisEvent['title'] = $(this).attr('title');
thisEvent['color'] = colours[$(this).attr('status')];
thisEvent['url'] = $(this).attr('url'); thisEvent = {
'start': $(this).attr('earliest'),
'end': $(this).attr('latest'),
'className': 'modal-href',
'title': $(this).attr('title'),
'url': $(this).attr('url')
}
if($(this).attr('is_rig')==true || $(this).attr('status') == "Cancelled"){
thisEvent['color'] = colours[$(this).attr('status')];
}else{
thisEvent['color'] = colours['non-rig'];
}
events.push(thisEvent); events.push(thisEvent);
}); });
callback(events); callback(events);
} }
}); });
},
viewRender: function(view, element){
// Set the title of the view
$('#calendar-header').text(view.title);
// Enable/Disable "Today" button as required
if(moment().isBetween(view.intervalStart, view.intervalEnd)){
//Today is within the current view
$('#today-button').prop('disabled', true);
}else{
$('#today-button').prop('disabled', false);
}
// Set active view select button
switch(view.name){
case 'month':
$('#month-button').addClass('active');
$('#week-button').removeClass('active');
$('#day-button').removeClass('active');
break;
case 'agendaWeek':
$('#month-button').removeClass('active');
$('#week-button').addClass('active');
$('#day-button').removeClass('active');
break;
case 'agendaDay':
$('#month-button').removeClass('active');
$('#week-button').removeClass('active');
$('#day-button').addClass('active');
break;
}
} }
}); });
// set some button listeners
$('#next-button').click(function(){ $('#calendar').fullCalendar('next') });
$('#prev-button').click(function(){ $('#calendar').fullCalendar('prev') });
$('#today-button').click(function(){ $('#calendar').fullCalendar('today') });
$('#month-button').click(function(){ $('#calendar').fullCalendar('changeView','month') });
$('#week-button').click(function(){ $('#calendar').fullCalendar('changeView','agendaWeek') });
$('#day-button').click(function(){ $('#calendar').fullCalendar('changeView','agendaDay') });
$('#go-to-date-input').change(function(){
if( moment($('#go-to-date-input').val()).isValid() ){
$('#go-to-date-button').prop('disabled', false);
}else{
$('#go-to-date-button').prop('disabled', true);
}
});
$('#go-to-date-button').click(function(){
day = moment($('#go-to-date-input').val()) ;
if(day.isValid()){
$('#calendar').fullCalendar( 'gotoDate', day);
}else{
alert('Invalid Date');
}
});
}); });
</script> </script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div style="col-sm-12">
<div id='calendar'> <div class="col-sm-12">
<div class="pull-left">
<span id="calendar-header" class="h2"></span>
</div>
<div class="form-inline pull-right btn-page">
<div class="input-group">
<input type="date" class="form-control" id="go-to-date-input" placeholder="Go to date...">
<span class="input-group-btn">
<button class="btn btn-default" id="go-to-date-button" type="button" disabled>Go!</button>
</span>
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary" id="today-button">Today</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default" id="prev-button"><span class="glyphicon glyphicon-chevron-left"></span></button>
<button type="button" class="btn btn-default" id="next-button"><span class="glyphicon glyphicon-chevron-right"></span></button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default" id="month-button">Month</button>
<button type="button" class="btn btn-default" id="week-button">Week</button>
<button type="button" class="btn btn-default" id="day-button">Day</button>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="row">
<div class="col-sm-12">
<div id='calendar'>
</div>
</div>
{% endblock %} {% endblock %}

View File

@@ -2,6 +2,33 @@
{% block title %}RIGS Profile {{object.pk}}{% endblock %} {% block title %}RIGS Profile {{object.pk}}{% endblock %}
{% block js %}
<script>
$(document).ready(function() {
$('#urlParamForm').change(function(){
url = "?";
$('#urlParamForm *').filter(':input').each(function(index, value){
defaultVal = $(value).data('default');
param = $(value).val();
val = $(value).prop('checked');
if(val != defaultVal){
url = url+param+"="+val+"&";
}
});
ics_url = $('#cal-url').data('url') + url.substring(0, url.length - 1);
$('#cal-url').text(ics_url);
gcal_url = $('#gcal-link').data('url') + encodeURIComponent(url.substring(0, url.length - 1));
$('#gcal-link').attr('href',gcal_url);
});
$('#urlParamForm').change(); //Do the initial setting
});
</script>
{% endblock %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-md-10 col-md-offset-1"> <div class="col-md-10 col-md-offset-1">
@@ -68,16 +95,42 @@
{% endif %} {% endif %}
</dd> </dd>
<dt>Calendar Options</dt>
<dd>
<div class="well well-sm text-center">
<form class="form-inline" id="urlParamForm">
<div class="form-group">
<label class="checkbox-inline">
<input type="checkbox" value="rig" data-default="true" checked> Rigs
</label>
<label class="checkbox-inline">
<input type="checkbox" value="non-rig" data-default="true" checked> Non-Rigs
</label>
<label class="checkbox-inline">
<input type="checkbox" value="dry-hire" data-default="true" checked> Dry-Hires
</label>
<label class="checkbox-inline">
<input type="checkbox" value="cancelled" data-default="false" > Cancelled
</label>
<label class="checkbox-inline">
<input type="checkbox" value="provisional" data-default="true" checked> Provisional
</label>
<label class="checkbox-inline">
<input type="checkbox" value="confirmed" data-default="true" checked> Confirmed/Booked
</label>
</div>
</form>
</div>
</dd>
<dt>Calendar URL</dt> <dt>Calendar URL</dt>
<dd> <dd>
{% if user.api_key %} {% if user.api_key %}
<pre>http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}</pre> <pre id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></pre>
<small><a href="http://www.google.com/calendar/render?cid=http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}">Click here</a> to add to google calendar.<br/> <small><a id="gcal-link" data-url="http://www.google.com/calendar/render?cid=http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}" href="">Click here</a> to add to google calendar.<br/>
To sync from google calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small> To sync from google calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
{% else %} {% else %}
<pre>No API Key Generated</pre> <pre>No API Key Generated</pre>
{% endif %} {% endif %}
</dd> </dd>
</dl> </dl>
{% endif %} {% endif %}

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.test import LiveServerTestCase from django.test import LiveServerTestCase
from django.test.client import Client
from django.core import mail from django.core import mail
from selenium import webdriver from selenium import webdriver
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
@@ -8,6 +9,7 @@ from selenium.webdriver.support.ui import WebDriverWait
from RIGS import models from RIGS import models
import re import re
import os import os
from datetime import date, timedelta
from django.db import transaction from django.db import transaction
import reversion import reversion
import json import json
@@ -576,6 +578,195 @@ class EventTest(LiveServerTestCase):
organisationPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Contact Details")]/..') organisationPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Contact Details")]/..')
class IcalTest(LiveServerTestCase):
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(
username="EventTest", first_name="Event", last_name="Test", initials="ETU", is_superuser=True)
self.profile.set_password("EventTestPassword")
self.profile.save()
# produce 7 normal events - 5 current - 1 last week - 1 two years ago - 2 provisional - 2 confirmed - 3 booked
models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end")
models.Event.objects.create(name="TE E2", status=models.Event.PROVISIONAL, start_date=date.today(), description="start today no end")
models.Event.objects.create(name="TE E3", status=models.Event.CONFIRMED, start_date=date.today(), end_date=date.today(), description="start today with end today")
models.Event.objects.create(name="TE E4", status=models.Event.CONFIRMED, start_date=date.today()-timedelta(weeks=104), description="start past 2 years no end")
models.Event.objects.create(name="TE E5", status=models.Event.BOOKED, start_date=date.today()-timedelta(days=7), end_date=date.today()-timedelta(days=1), description="start past 1 week with end past")
models.Event.objects.create(name="TE E6", status=models.Event.BOOKED, 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", status=models.Event.BOOKED, 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")
# 5 dry hire - 3 current - 1 cancelled
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")
self.browser = webdriver.Firefox()
os.environ['RECAPTCHA_TESTING'] = 'True'
def tearDown(self):
self.browser.quit()
os.environ['RECAPTCHA_TESTING'] = 'False'
def authenticate(self, n=None):
self.assertIn(
self.live_server_url + '/user/login/', self.browser.current_url)
if n:
self.assertIn('?next=%s' % n, self.browser.current_url)
username = self.browser.find_element_by_id('id_username')
password = self.browser.find_element_by_id('id_password')
submit = self.browser.find_element_by_css_selector(
'input[type=submit]')
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)
def testApiKeyGeneration(self):
# Requests address
self.browser.get(self.live_server_url + '/user/')
# Gets redirected to login
self.authenticate('/user/')
# Completes and comes back to /user/
# Checks that no api key is displayed
self.assertEqual("No API Key Generated", self.browser.find_element_by_xpath("//div[@id='content']/div/div/div[3]/dl[2]/dd").text)
self.assertEqual("No API Key Generated", self.browser.find_element_by_css_selector("pre").text)
# Now creates an API key, and check a URL is displayed one
self.browser.find_element_by_link_text("Generate API Key").click()
self.assertIn("rigs.ics", self.browser.find_element_by_id("cal-url").text)
self.assertNotIn("?", self.browser.find_element_by_id("cal-url").text)
# Lets change everything so it's not the default value
self.browser.find_element_by_xpath("//input[@value='rig']").click()
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
self.browser.find_element_by_xpath("//input[@value='dry-hire']").click()
self.browser.find_element_by_xpath("//input[@value='cancelled']").click()
self.browser.find_element_by_xpath("//input[@value='provisional']").click()
self.browser.find_element_by_xpath("//input[@value='confirmed']").click()
# and then check the url is correct
self.assertIn("rigs.ics?rig=false&non-rig=false&dry-hire=false&cancelled=true&provisional=false&confirmed=false", self.browser.find_element_by_id("cal-url").text)
# Awesome - all seems to work
def testICSFiles(self):
# Requests address
self.browser.get(self.live_server_url + '/user/')
# Gets redirected to login
self.authenticate('/user/')
# Now creates an API key, and check a URL is displayed one
self.browser.find_element_by_link_text("Generate API Key").click()
c = Client()
# Default settings - should have all non-cancelled events
# Get the ical file (can't do this in selanium because reasons)
icalUrl = self.browser.find_element_by_id("cal-url").text
response = c.get(icalUrl)
self.assertEqual(200, response.status_code)
#Check has entire file
self.assertIn("BEGIN:VCALENDAR", response.content)
self.assertIn("END:VCALENDAR", response.content)
expectedIn= [1,2,3,5,6,7,10,11,12,13,15,16,17]
for test in range(1,18):
if test in expectedIn:
self.assertIn("TE E"+str(test)+" ", response.content)
else:
self.assertNotIn("TE E"+str(test)+" ", response.content)
# Only dry hires
self.browser.find_element_by_xpath("//input[@value='rig']").click()
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
icalUrl = self.browser.find_element_by_id("cal-url").text
response = c.get(icalUrl)
self.assertEqual(200, response.status_code)
expectedIn= [10,11,12,13]
for test in range(1,18):
if test in expectedIn:
self.assertIn("TE E"+str(test)+" ", response.content)
else:
self.assertNotIn("TE E"+str(test)+" ", response.content)
# Only provisional rigs
self.browser.find_element_by_xpath("//input[@value='rig']").click()
self.browser.find_element_by_xpath("//input[@value='dry-hire']").click()
self.browser.find_element_by_xpath("//input[@value='confirmed']").click()
icalUrl = self.browser.find_element_by_id("cal-url").text
response = c.get(icalUrl)
self.assertEqual(200, response.status_code)
expectedIn= [1,2]
for test in range(1,18):
if test in expectedIn:
self.assertIn("TE E"+str(test)+" ", response.content)
else:
self.assertNotIn("TE E"+str(test)+" ", response.content)
# Only cancelled non-rigs
self.browser.find_element_by_xpath("//input[@value='rig']").click()
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
self.browser.find_element_by_xpath("//input[@value='provisional']").click()
self.browser.find_element_by_xpath("//input[@value='cancelled']").click()
icalUrl = self.browser.find_element_by_id("cal-url").text
response = c.get(icalUrl)
self.assertEqual(200, response.status_code)
expectedIn= [18]
for test in range(1,18):
if test in expectedIn:
self.assertIn("TE E"+str(test)+" ", response.content)
else:
self.assertNotIn("TE E"+str(test)+" ", response.content)
# Nothing selected
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
self.browser.find_element_by_xpath("//input[@value='cancelled']").click()
icalUrl = self.browser.find_element_by_id("cal-url").text
response = c.get(icalUrl)
self.assertEqual(200, response.status_code)
expectedIn= []
for test in range(1,18):
if test in expectedIn:
self.assertIn("TE E"+str(test)+" ", response.content)
else:
self.assertNotIn("TE E"+str(test)+" ", response.content)
# Wow - that was a lot of tests
class animation_is_finished(object): class animation_is_finished(object):
""" Checks if animation is done """ """ Checks if animation is done """

View File

@@ -6,9 +6,10 @@ from django.views import generic
from django.db.models import Q from django.db.models import Q
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.core import serializers from django.core import serializers
from django.conf import settings
import simplejson import simplejson
from django.contrib import messages from django.contrib import messages
import datetime import datetime, pytz
import operator import operator
from registration.views import RegistrationView from registration.views import RegistrationView
@@ -298,39 +299,22 @@ class SecureAPIRequest(generic.View):
if model == "event" and start and end: if model == "event" and start and end:
# Probably a calendar request # Probably a calendar request
start_datetime = datetime.datetime.strptime( start, "%Y-%m-%dT%H:%M:%SZ" ) start_datetime = datetime.datetime.strptime( start, "%Y-%m-%dT%H:%M:%S" )
end_datetime = datetime.datetime.strptime( end, "%Y-%m-%dT%H:%M:%SZ" ) end_datetime = datetime.datetime.strptime( end, "%Y-%m-%dT%H:%M:%S" )
objects = self.models[model].objects.events_in_bounds(start_datetime,end_datetime) objects = self.models[model].objects.events_in_bounds(start_datetime,end_datetime)
results = [] results = []
for item in objects: for item in objects:
data = { data = {
'pk': item.pk, 'pk': item.pk,
'title': item.name 'title': item.name,
'is_rig': item.is_rig,
'status': str(item.get_status_display()),
'earliest': item.earliest_time.isoformat(),
'latest': item.latest_time.isoformat(),
'url': str(item.get_absolute_url())
} }
data['is_rig'] = item.is_rig
data['status'] = str(item.get_status_display())
if item.start_date:
data['start_date'] = item.start_date.strftime('%Y-%m-%d')
if item.has_start_time:
data['start_time'] = item.start_time.strftime('%H:%M:%SZ')
if item.end_date:
data['end_date'] = item.end_date.strftime('%Y-%m-%d')
if item.has_end_time:
data['end_time'] = item.end_time.strftime('%H:%M:%SZ')
if item.meet_at:
data['meet_at'] = item.meet_at.strftime('%Y-%m-%dT%H:%M:%SZ')
if item.access_at:
data['access_at'] = item.access_at.strftime('%Y-%m-%dT%H:%M:%SZ')
data['url'] = str(reverse_lazy('event_detail',kwargs={'pk':item.pk}))
results.append(data) results.append(data)
json = simplejson.dumps(results) json = simplejson.dumps(results)

View File

@@ -18,7 +18,7 @@ PyPDF2==1.24
python-dateutil==2.4.2 python-dateutil==2.4.2
pytz==2015.4 pytz==2015.4
reportlab==3.1.44 reportlab==3.1.44
selenium==2.45.0 selenium==2.46.0
simplejson==3.7.2 simplejson==3.7.2
six==1.9.0 six==1.9.0
sqlparse==0.1.15 sqlparse==0.1.15