general: add support for Python 3 (#23678)
This commit is contained in:
parent
427a4e25d9
commit
f4203d05f3
|
@ -14,6 +14,8 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
from chrono.agendas.models import Desk, ICSError
|
||||
|
@ -28,4 +30,4 @@ class Command(BaseCommand):
|
|||
try:
|
||||
desk.create_timeperiod_exceptions_from_remote_ics(desk.timeperiod_exceptions_remote_url)
|
||||
except ICSError as e:
|
||||
print >> sys.stderr, u'unable to create timeperiod exceptions for "%s": %s' % (desk, e)
|
||||
print(u'unable to create timeperiod exceptions for "%s": %s' % (desk, e), file=sys.stderr)
|
||||
|
|
|
@ -27,7 +27,7 @@ from django.core.urlresolvers import reverse
|
|||
from django.db import models, transaction
|
||||
from django.db.models import Q
|
||||
from django.utils.dates import WEEKDAYS
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
from django.utils.formats import date_format, get_format
|
||||
from django.utils.text import slugify
|
||||
from django.utils.timezone import localtime, now, make_aware, make_naive, is_aware
|
||||
|
@ -157,6 +157,7 @@ class Agenda(models.Model):
|
|||
WEEKDAYS_LIST = sorted(WEEKDAYS.items(), key=lambda x: x[0])
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class TimeSlot(object):
|
||||
def __init__(self, start_datetime, meeting_type, desk):
|
||||
self.start_datetime = start_datetime
|
||||
|
@ -165,10 +166,11 @@ class TimeSlot(object):
|
|||
self.id = '%s:%s' % (self.meeting_type.id, start_datetime.strftime('%Y-%m-%d-%H%M'))
|
||||
self.desk = desk
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return date_format(self.start_datetime, format='DATETIME_FORMAT')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class TimePeriod(models.Model):
|
||||
weekday = models.IntegerField(_('Week day'), choices=WEEKDAYS_LIST)
|
||||
start_time = models.TimeField(_('Start'))
|
||||
|
@ -178,7 +180,7 @@ class TimePeriod(models.Model):
|
|||
class Meta:
|
||||
ordering = ['weekday', 'start_time']
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return u'%s / %s → %s' % (
|
||||
force_text(WEEKDAYS[self.weekday]),
|
||||
date_format(self.start_time, 'TIME_FORMAT'),
|
||||
|
@ -265,6 +267,7 @@ class MeetingType(models.Model):
|
|||
}
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Event(models.Model):
|
||||
agenda = models.ForeignKey(Agenda)
|
||||
start_datetime = models.DateTimeField(_('Date/time'))
|
||||
|
@ -280,7 +283,7 @@ class Event(models.Model):
|
|||
class Meta:
|
||||
ordering = ['agenda', 'start_datetime', 'label']
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
if self.label:
|
||||
return self.label
|
||||
return date_format(localtime(self.start_datetime), format='DATETIME_FORMAT')
|
||||
|
@ -374,6 +377,7 @@ class Booking(models.Model):
|
|||
self.save()
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Desk(models.Model):
|
||||
agenda = models.ForeignKey(Agenda)
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
|
@ -382,7 +386,7 @@ class Desk(models.Model):
|
|||
_('URL to fetch time period exceptions from'),
|
||||
blank=True, max_length=500)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
class Meta:
|
||||
|
@ -468,9 +472,7 @@ class Desk(models.Model):
|
|||
with transaction.atomic():
|
||||
update_datetime = now()
|
||||
for vevent in parsed.contents.get('vevent', []):
|
||||
summary = vevent.contents['summary'][0].value
|
||||
if not isinstance(summary, unicode):
|
||||
summary = unicode(summary, 'utf-8')
|
||||
summary = force_text(vevent.contents['summary'][0].value)
|
||||
try:
|
||||
start_dt = vevent.dtstart.value
|
||||
if not isinstance(start_dt, datetime.datetime):
|
||||
|
@ -562,6 +564,7 @@ class Desk(models.Model):
|
|||
return openslots.search(aware_date, aware_next_date)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class TimePeriodException(models.Model):
|
||||
desk = models.ForeignKey(Desk)
|
||||
external_id = models.CharField(_('External ID'), max_length=256, blank=True)
|
||||
|
@ -574,7 +577,7 @@ class TimePeriodException(models.Model):
|
|||
class Meta:
|
||||
ordering = ['start_datetime']
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
if is_midnight(self.start_datetime) and is_midnight(self.end_datetime):
|
||||
# if both dates are at midnight don't include the time part
|
||||
if self.end_datetime == self.start_datetime + datetime.timedelta(days=1):
|
||||
|
|
|
@ -22,7 +22,9 @@ import operator
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import six
|
||||
from django.utils.dateparse import parse_date
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.timezone import now, make_aware, localtime
|
||||
|
||||
from rest_framework import permissions, serializers, status
|
||||
|
@ -68,7 +70,7 @@ def get_all_slots(agenda, meeting_type):
|
|||
|
||||
# remove excluded slot
|
||||
excluded_slot_by_desk = get_exceptions_by_desk(agenda)
|
||||
for desk, excluded_interval in excluded_slot_by_desk.iteritems():
|
||||
for desk, excluded_interval in excluded_slot_by_desk.items():
|
||||
for interval in excluded_interval:
|
||||
begin, end = interval
|
||||
open_slots_by_desk[desk].remove_overlap(localtime(begin), localtime(end))
|
||||
|
@ -176,7 +178,7 @@ class Datetimes(APIView):
|
|||
datetime.datetime.combine(parse_date(request.GET['date_end']), datetime.time(0, 0))))
|
||||
|
||||
response = {'data': [{'id': x.id,
|
||||
'text': unicode(x),
|
||||
'text': force_text(x),
|
||||
'datetime': localtime(x.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'disabled': bool(x.full),
|
||||
'api': {
|
||||
|
@ -240,7 +242,7 @@ class MeetingDatetimes(APIView):
|
|||
|
||||
response = {'data': [{'id': x.id,
|
||||
'datetime': localtime(x.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'text': unicode(x),
|
||||
'text': force_text(x),
|
||||
'disabled': bool(x.full),
|
||||
'api': {
|
||||
'fillslot_url': fillslot_url.replace(fake_event_pk, str(x.id)),
|
||||
|
@ -339,7 +341,7 @@ class Fillslot(APIView):
|
|||
except ValueError:
|
||||
return Response({
|
||||
'err': 1,
|
||||
'reason': 'invalid value for count (%r)' % request.GET['count'],
|
||||
'reason': 'invalid value for count (%s)' % request.GET['count'],
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
available_desk = None
|
||||
|
|
|
@ -90,7 +90,7 @@ class Intervals(object):
|
|||
'Add an interval object'
|
||||
a = self.__insert_point(interval.begin, interval)
|
||||
b = self.__insert_point(interval.end, interval)
|
||||
for i in xrange(a + 1, b):
|
||||
for i in range(a + 1, b):
|
||||
self.container[i].append(interval)
|
||||
|
||||
def __iter_interval(self, begin, end, modify=False):
|
||||
|
@ -181,5 +181,5 @@ class Intervals(object):
|
|||
# check some invariants
|
||||
assert self.points[a] == interval.begin
|
||||
assert self.points[b] == interval.end
|
||||
for i in xrange(a, b + 1):
|
||||
for i in range(a, b + 1):
|
||||
self.container[i].remove(interval)
|
||||
|
|
|
@ -14,12 +14,16 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import csv
|
||||
import datetime
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.models import Group
|
||||
from django.forms import ValidationError
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -143,9 +147,11 @@ class ImportEventsForm(forms.Form):
|
|||
|
||||
def clean_events_csv_file(self):
|
||||
content = self.cleaned_data['events_csv_file'].read()
|
||||
if '\0' in content:
|
||||
if b'\0' in content:
|
||||
raise ValidationError(_('Invalid file format.'))
|
||||
|
||||
if six.PY3:
|
||||
content = content.decode('utf-8')
|
||||
try:
|
||||
dialect = csv.Sniffer().sniff(content)
|
||||
except csv.Error:
|
||||
|
@ -181,7 +187,7 @@ class ImportEventsForm(forms.Form):
|
|||
except ValueError:
|
||||
raise ValidationError(_('Invalid file format. (number of places in waiting list, line %d)') % (i+1))
|
||||
if len(csvline) >= 5:
|
||||
event.label = ' '.join(csvline[4:])
|
||||
event.label = ' '.join([force_text(x) for x in csvline[4:]])
|
||||
events.append(event)
|
||||
self.events = events
|
||||
|
||||
|
|
|
@ -234,8 +234,8 @@ class AgendaDayView(DayArchiveView):
|
|||
info['opening_hours'] = opening_hours = []
|
||||
for opening_hour in desk.get_opening_hours(current_date.date()):
|
||||
opening_hours.append({
|
||||
'css_top': 100 * (opening_hour.begin - start_date).seconds / 3600,
|
||||
'css_height': 100 * (opening_hour.end - opening_hour.begin).seconds / 3600,
|
||||
'css_top': 100 * (opening_hour.begin - start_date).seconds // 3600,
|
||||
'css_height': 100 * (opening_hour.end - opening_hour.begin).seconds // 3600,
|
||||
})
|
||||
infos.append(info)
|
||||
info['bookings'] = bookings = [] # bookings for this desk
|
||||
|
@ -565,13 +565,14 @@ class DeskImportTimePeriodExceptionsView(ManagedAgendaSubobjectMixin, UpdateView
|
|||
exceptions = None
|
||||
try:
|
||||
if form.cleaned_data['ics_file']:
|
||||
exceptions = form.instance.create_timeperiod_exceptions_from_ics(form.cleaned_data['ics_file'])
|
||||
ics_file_content = force_text(form.cleaned_data['ics_file'].read())
|
||||
exceptions = form.instance.create_timeperiod_exceptions_from_ics(ics_file_content)
|
||||
elif form.cleaned_data['ics_url']:
|
||||
exceptions = form.instance.create_timeperiod_exceptions_from_remote_ics(form.cleaned_data['ics_url'])
|
||||
else:
|
||||
form.instance.remove_timeperiod_exceptions_from_remote_ics()
|
||||
except ICSError as e:
|
||||
form.add_error(None, unicode(e))
|
||||
form.add_error(None, force_text(e))
|
||||
return self.form_invalid(form)
|
||||
form.instance.timeperiod_exceptions_remote_url = form.cleaned_data['ics_url']
|
||||
form.instance.save()
|
||||
|
|
|
@ -167,4 +167,4 @@ REQUESTS_PROXIES = None
|
|||
local_settings_file = os.environ.get('CHRONO_SETTINGS_FILE',
|
||||
os.path.join(os.path.dirname(__file__), 'local_settings.py'))
|
||||
if os.path.exists(local_settings_file):
|
||||
execfile(local_settings_file)
|
||||
exec(open(local_settings_file).read())
|
||||
|
|
|
@ -14,13 +14,12 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import urllib
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import resolve_url
|
||||
from django.utils.six.moves.urllib.parse import quote
|
||||
|
||||
if 'mellon' in settings.INSTALLED_APPS:
|
||||
from mellon.utils import get_idps
|
||||
|
@ -33,7 +32,7 @@ def login(request, *args, **kwargs):
|
|||
if not 'next' in request.GET:
|
||||
return HttpResponseRedirect(resolve_url('mellon_login'))
|
||||
return HttpResponseRedirect(resolve_url('mellon_login') + '?next='
|
||||
+ urllib.quote(request.GET.get('next')))
|
||||
+ quote(request.GET.get('next')))
|
||||
return auth_views.login(request, *args, **kwargs)
|
||||
|
||||
def logout(request, next_page=None):
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Get venv site-packages path
|
||||
DSTDIR=`python3 -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'`
|
||||
|
||||
# Get not venv site-packages path
|
||||
# Remove first path (assuming that is the venv path)
|
||||
NONPATH=`echo $PATH | sed 's/^[^:]*://'`
|
||||
SRCDIR=`PATH=$NONPATH python3 -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'`
|
||||
|
||||
# Clean up
|
||||
rm -f $DSTDIR/lasso.*
|
||||
rm -f $DSTDIR/_lasso.*
|
||||
|
||||
# Link
|
||||
ln -sv /usr/lib/python3/dist-packages/lasso.py $DSTDIR/
|
||||
ln -sv /usr/lib/python3/dist-packages/_lasso.cpython-36m-x86_64-linux-gnu.so $DSTDIR/
|
||||
|
||||
exit 0
|
2
setup.py
2
setup.py
|
@ -36,7 +36,7 @@ def get_version():
|
|||
p = subprocess.Popen(['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE)
|
||||
result = p.communicate()[0]
|
||||
if p.returncode == 0:
|
||||
version = result.split()[0][1:]
|
||||
version = str(result.split()[0][1:])
|
||||
version = version.replace('-', '.')
|
||||
return version
|
||||
return '0'
|
||||
|
|
|
@ -266,8 +266,8 @@ def test_timeexception_creation_from_ics_with_dates():
|
|||
exceptions_count = desk.create_timeperiod_exceptions_from_ics(ics_sample)
|
||||
assert exceptions_count == 2
|
||||
for exception in TimePeriodException.objects.filter(desk=desk):
|
||||
assert localtime(exception.start_datetime) == make_aware(datetime.datetime(2018, 01, 01, 00, 00))
|
||||
assert localtime(exception.end_datetime) == make_aware(datetime.datetime(2018, 01, 01, 00, 00))
|
||||
assert localtime(exception.start_datetime) == make_aware(datetime.datetime(2018, 1, 1, 0, 0))
|
||||
assert localtime(exception.end_datetime) == make_aware(datetime.datetime(2018, 1, 1, 0, 0))
|
||||
|
||||
def test_timeexception_create_from_invalid_ics():
|
||||
agenda = Agenda(label=u'Test 6 agenda')
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import datetime
|
||||
import pytest
|
||||
import sys
|
||||
import urlparse
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import connection
|
||||
from django.test import override_settings
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
from django.utils.six.moves.urllib import parse as urlparse
|
||||
from django.utils.timezone import now, make_aware, localtime
|
||||
|
||||
from chrono.agendas.models import (Agenda, Event, Booking,
|
||||
|
@ -686,7 +686,7 @@ def test_multiple_booking_api(app, some_data, user):
|
|||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/?count=NaN' % (agenda.slug, event.id), status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['reason'] == "invalid value for count (u'NaN')"
|
||||
assert resp.json['reason'] == "invalid value for count (NaN)"
|
||||
|
||||
resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
|
||||
Booking.objects.get(id=resp.json['booking_id'])
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from cStringIO import StringIO
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
|
@ -8,6 +9,8 @@ import tempfile
|
|||
|
||||
import pytest
|
||||
from django.core.management import call_command
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.utils.six import StringIO
|
||||
from django.utils.timezone import make_aware
|
||||
|
||||
from chrono.agendas.models import (Agenda, Event, MeetingType, TimePeriod,
|
||||
|
@ -53,7 +56,7 @@ def test_import_export(app, some_data, meetings_agenda):
|
|||
assert Agenda.objects.count() == 0
|
||||
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
f.write(output)
|
||||
f.write(force_bytes(output))
|
||||
f.flush()
|
||||
call_command('import_site', f.name)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.utils.timezone import make_aware, now, localtime
|
||||
import datetime
|
||||
|
@ -98,8 +100,8 @@ def test_home_redirect(app):
|
|||
def test_access(app, admin_user):
|
||||
app = login(app)
|
||||
resp = app.get('/manage/', status=200)
|
||||
assert '<h2>Agendas</h2>' in resp.body
|
||||
assert "This site doesn't have any agenda yet." in resp.body
|
||||
assert '<h2>Agendas</h2>' in resp.text
|
||||
assert "This site doesn't have any agenda yet." in resp.text
|
||||
|
||||
def test_logout(app, admin_user):
|
||||
app = login(app)
|
||||
|
@ -112,7 +114,7 @@ def test_menu_json(app, admin_user):
|
|||
assert resp.json[0]['url'] == 'http://testserver/manage/'
|
||||
assert resp.json[0]['label'] == 'Agendas'
|
||||
resp2 = app.get('/manage/menu.json?callback=Q', status=200)
|
||||
assert resp2.body == 'Q(%s);' % resp.body
|
||||
assert resp2.text == 'Q(%s);' % resp.text
|
||||
|
||||
def test_view_agendas_as_manager(app, manager_user):
|
||||
agenda = Agenda(label=u'Foo Bar')
|
||||
|
@ -124,9 +126,9 @@ def test_view_agendas_as_manager(app, manager_user):
|
|||
|
||||
app = login(app, username='manager', password='manager')
|
||||
resp = app.get('/manage/', status=200)
|
||||
assert 'Foo Bar' in resp.body
|
||||
assert 'Bar Foo' not in resp.body
|
||||
assert 'New' not in resp.body
|
||||
assert 'Foo Bar' in resp.text
|
||||
assert 'Bar Foo' not in resp.text
|
||||
assert 'New' not in resp.text
|
||||
|
||||
# check user doesn't have access
|
||||
app.get('/manage/agendas/%s/' % agenda2.id, status=403)
|
||||
|
@ -134,8 +136,8 @@ def test_view_agendas_as_manager(app, manager_user):
|
|||
# check view gives access to the settings page for "events" agenda
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
# but there's no links to actions
|
||||
assert not '>New Event<' in resp.body
|
||||
assert not '>Options<' in resp.body
|
||||
assert not '>New Event<' in resp.text
|
||||
assert not '>Options<' in resp.text
|
||||
app.get('/manage/agendas/%s/add-event' % agenda.id, status=403)
|
||||
app.get('/manage/agendas/%s/edit' % agenda.id, status=403)
|
||||
|
||||
|
@ -157,8 +159,8 @@ def test_add_agenda(app, admin_user):
|
|||
agenda = Agenda.objects.get(label='Foo bar')
|
||||
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
||||
resp = resp.follow()
|
||||
assert 'Foo bar' in resp.body
|
||||
assert '<h2>Settings' in resp.body
|
||||
assert 'Foo bar' in resp.text
|
||||
assert '<h2>Settings' in resp.text
|
||||
|
||||
def test_add_agenda_as_manager(app, manager_user):
|
||||
# open /manage/ access to manager_user, and check agenda creation is not
|
||||
|
@ -182,8 +184,8 @@ def test_options_agenda(app, admin_user):
|
|||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
||||
resp = resp.follow()
|
||||
assert 'Foo baz' in resp.body
|
||||
assert '<h2>Settings' in resp.body
|
||||
assert 'Foo baz' in resp.text
|
||||
assert '<h2>Settings' in resp.text
|
||||
|
||||
def test_options_agenda_as_manager(app, manager_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -192,11 +194,12 @@ def test_options_agenda_as_manager(app, manager_user):
|
|||
app = login(app, username='manager', password='manager')
|
||||
resp = app.get('/manage/', status=200)
|
||||
resp = resp.click('Foo bar')
|
||||
assert not 'Settings' in resp.body
|
||||
assert not 'Settings' in resp.text
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200) # ok for "events" agendas
|
||||
resp = app.get('/manage/agendas/%s/edit' % agenda.id, status=403)
|
||||
agenda.kind = 'meetings'
|
||||
agenda.save()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=403)
|
||||
resp = app.get('/manage/agendas/%s/edit' % agenda.id, status=403)
|
||||
|
||||
|
@ -214,8 +217,8 @@ def test_options_agenda_as_manager(app, manager_user):
|
|||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
||||
resp = resp.follow()
|
||||
assert 'Foo baz' in resp.body
|
||||
assert '<h2>Settings' in resp.body
|
||||
assert 'Foo baz' in resp.text
|
||||
assert '<h2>Settings' in resp.text
|
||||
|
||||
def test_delete_agenda(app, admin_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -227,7 +230,7 @@ def test_delete_agenda(app, admin_user):
|
|||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/')
|
||||
resp = resp.follow()
|
||||
assert not 'Foo bar' in resp.body
|
||||
assert not 'Foo bar' in resp.text
|
||||
|
||||
def test_delete_busy_agenda(app, admin_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -240,21 +243,21 @@ def test_delete_busy_agenda(app, admin_user):
|
|||
resp = app.get('/manage/', status=200)
|
||||
resp = resp.click('Foo bar').follow()
|
||||
resp = resp.click('Delete')
|
||||
assert 'Are you sure you want to delete this?' in resp.body
|
||||
assert 'Are you sure you want to delete this?' in resp.text
|
||||
|
||||
booking = Booking(event=event)
|
||||
booking.save()
|
||||
resp = app.get('/manage/', status=200)
|
||||
resp = resp.click('Foo bar').follow()
|
||||
resp = resp.click('Delete')
|
||||
assert 'This cannot be removed' in resp.body
|
||||
assert 'This cannot be removed' in resp.text
|
||||
|
||||
booking.cancellation_datetime = now()
|
||||
booking.save()
|
||||
resp = app.get('/manage/', status=200)
|
||||
resp = resp.click('Foo bar').follow()
|
||||
resp = resp.click('Delete')
|
||||
assert 'Are you sure you want to delete this?' in resp.body
|
||||
assert 'Are you sure you want to delete this?' in resp.text
|
||||
|
||||
# suddenly the booking is no longer cancelled, but the admin clicks on the
|
||||
# delete button.
|
||||
|
@ -269,8 +272,8 @@ def test_delete_agenda_as_manager(app, manager_user):
|
|||
app = login(app, username='manager', password='manager')
|
||||
resp = app.get('/manage/', status=200)
|
||||
resp = resp.click('Foo bar').follow()
|
||||
assert 'Options' in resp.body
|
||||
assert 'Delete' not in resp.body
|
||||
assert 'Options' in resp.text
|
||||
assert 'Delete' not in resp.text
|
||||
resp = app.get('/manage/agendas/%s/delete' % agenda.id, status=403)
|
||||
|
||||
def test_add_event(app, admin_user):
|
||||
|
@ -279,7 +282,7 @@ def test_add_event(app, admin_user):
|
|||
agenda.save()
|
||||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
assert "This agenda doesn't have any event yet." in resp.body
|
||||
assert "This agenda doesn't have any event yet." in resp.text
|
||||
year = now().year + 1
|
||||
resp = resp.click('New Event')
|
||||
resp.form['start_datetime'] = '%s-02-15 17:00' % year
|
||||
|
@ -287,10 +290,10 @@ def test_add_event(app, admin_user):
|
|||
resp = resp.form.submit()
|
||||
resp = resp.follow()
|
||||
event = Event.objects.get(places=10)
|
||||
assert not "This agenda doesn't have any event yet." in resp.body
|
||||
assert '/manage/events/%s/' % event.id in resp.body
|
||||
assert ('Feb. 15, %s, 5 p.m.' % year) in resp.body
|
||||
assert '10 places' in resp.body
|
||||
assert not "This agenda doesn't have any event yet." in resp.text
|
||||
assert '/manage/events/%s/' % event.id in resp.text
|
||||
assert ('Feb. 15, %s, 5 p.m.' % year) in resp.text
|
||||
assert '10 places' in resp.text
|
||||
|
||||
resp_datetimes = app.get('/api/agenda/%s/datetimes/' % agenda.id)
|
||||
assert resp_datetimes.json['data'][0]['text'] == 'Feb. 15, %s, 5 p.m.' % year
|
||||
|
@ -312,17 +315,17 @@ def test_add_event_as_manager(app, manager_user):
|
|||
agenda.save()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/' % agenda.id).follow()
|
||||
assert '<h2>Settings' in resp.body
|
||||
assert '<h2>Settings' in resp.text
|
||||
resp = resp.click('New Event')
|
||||
resp.form['start_datetime'] = '2016-02-15 17:00'
|
||||
resp.form['places'] = 10
|
||||
resp = resp.form.submit()
|
||||
resp = resp.follow()
|
||||
event = Event.objects.get(places=10)
|
||||
assert not "This agenda doesn't have any event yet." in resp.body
|
||||
assert '/manage/events/%s/' % event.id in resp.body
|
||||
assert 'Feb. 15, 2016, 5 p.m.' in resp.body
|
||||
assert '10 places' in resp.body
|
||||
assert not "This agenda doesn't have any event yet." in resp.text
|
||||
assert '/manage/events/%s/' % event.id in resp.text
|
||||
assert 'Feb. 15, 2016, 5 p.m.' in resp.text
|
||||
assert '10 places' in resp.text
|
||||
|
||||
def test_edit_event(app, admin_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -339,9 +342,9 @@ def test_edit_event(app, admin_user):
|
|||
resp.form['places'] = 20
|
||||
resp = resp.form.submit()
|
||||
resp = resp.follow()
|
||||
assert '/manage/events/%s/' % event.id in resp.body
|
||||
assert 'Feb. 16, 2016, 5 p.m.' in resp.body
|
||||
assert '20 places' in resp.body
|
||||
assert '/manage/events/%s/' % event.id in resp.text
|
||||
assert 'Feb. 16, 2016, 5 p.m.' in resp.text
|
||||
assert '20 places' in resp.text
|
||||
|
||||
def test_edit_missing_event(app, admin_user):
|
||||
app = login(app)
|
||||
|
@ -366,9 +369,9 @@ def test_edit_event_as_manager(app, manager_user):
|
|||
resp.form['places'] = 20
|
||||
resp = resp.form.submit()
|
||||
resp = resp.follow()
|
||||
assert '/manage/events/%s/' % event.id in resp.body
|
||||
assert 'Feb. 16, 2016, 5 p.m.' in resp.body
|
||||
assert '20 places' in resp.body
|
||||
assert '/manage/events/%s/' % event.id in resp.text
|
||||
assert 'Feb. 16, 2016, 5 p.m.' in resp.text
|
||||
assert '20 places' in resp.text
|
||||
|
||||
def test_booked_places(app, admin_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -380,8 +383,8 @@ def test_booked_places(app, admin_user):
|
|||
Booking(event=event).save()
|
||||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
assert '10 places' in resp.body
|
||||
assert '2 booked places' in resp.body
|
||||
assert '10 places' in resp.text
|
||||
assert '2 booked places' in resp.text
|
||||
|
||||
def test_event_classes(app, admin_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -394,20 +397,20 @@ def test_event_classes(app, admin_user):
|
|||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
assert not 'full' in resp.body
|
||||
assert not 'overbooking' in resp.body
|
||||
assert not 'full' in resp.text
|
||||
assert not 'overbooking' in resp.text
|
||||
|
||||
for i in range(8):
|
||||
Booking(event=event).save()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
assert 'full' in resp.body
|
||||
assert not 'overbooking' in resp.body
|
||||
assert 'full' in resp.text
|
||||
assert not 'overbooking' in resp.text
|
||||
|
||||
Booking(event=event).save()
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
assert 'full' in resp.body
|
||||
assert 'overbooking' in resp.body
|
||||
assert 'full' in resp.text
|
||||
assert 'overbooking' in resp.text
|
||||
|
||||
def test_delete_event(app, admin_user):
|
||||
agenda = Agenda(label=u'Foo bar')
|
||||
|
@ -435,21 +438,21 @@ def test_delete_busy_event(app, admin_user):
|
|||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
resp = resp.click(href=r'/manage/events/%s/$' % event.id)
|
||||
resp = resp.click('Delete')
|
||||
assert 'Are you sure you want to delete this?' in resp.body
|
||||
assert 'Are you sure you want to delete this?' in resp.text
|
||||
|
||||
booking = Booking(event=event)
|
||||
booking.save()
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
resp = resp.click(href=r'/manage/events/%s/$' % event.id)
|
||||
resp = resp.click('Delete')
|
||||
assert 'This cannot be removed' in resp.body
|
||||
assert 'This cannot be removed' in resp.text
|
||||
|
||||
booking.cancellation_datetime = now()
|
||||
booking.save()
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
||||
resp = resp.click(href=r'/manage/events/%s/$' % event.id)
|
||||
resp = resp.click('Delete')
|
||||
assert 'Are you sure you want to delete this?' in resp.body
|
||||
assert 'Are you sure you want to delete this?' in resp.text
|
||||
|
||||
# suddenly the booking is no longer cancelled, but the admin clicks on the
|
||||
# delete button.
|
||||
|
@ -482,39 +485,39 @@ def test_import_events(app, admin_user):
|
|||
resp = resp.click('Import Events')
|
||||
sample_csv_resp = resp.click('Download sample file')
|
||||
assert sample_csv_resp.content_type == 'text/csv'
|
||||
assert sample_csv_resp.body.startswith('date,time,')
|
||||
assert sample_csv_resp.text.startswith('date,time,')
|
||||
|
||||
resp.form['events_csv_file'] = Upload('t.csv', sample_csv_resp.body, 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', sample_csv_resp.content, 'text/csv')
|
||||
resp = resp.form.submit(status=302)
|
||||
assert Event.objects.count() == 0
|
||||
|
||||
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
||||
resp.form['events_csv_file'] = Upload('t.csv', 'xx', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'xx', 'text/csv')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Invalid file format.' in resp.body
|
||||
assert 'Invalid file format.' in resp.text
|
||||
|
||||
resp.form['events_csv_file'] = Upload('t.csv', 'xxxx\0\0xxxx', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'xxxx\0\0xxxx', 'text/csv')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Invalid file format.' in resp.body
|
||||
assert 'Invalid file format.' in resp.text
|
||||
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-14-16,18:00', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00', 'text/csv')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Invalid file format.' in resp.body
|
||||
assert 'Invalid file format.' in resp.text
|
||||
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-14-16,18:00,10', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00,10', 'text/csv')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Invalid file format. (date/time format' in resp.body
|
||||
assert 'Invalid file format. (date/time format' in resp.text
|
||||
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-09-16,18:00,blah', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,blah', 'text/csv')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Invalid file format. (number of places,' in resp.body
|
||||
assert 'Invalid file format. (number of places,' in resp.text
|
||||
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-09-16,18:00,10,blah', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,blah', 'text/csv')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Invalid file format. (number of places in waiting list,' in resp.body
|
||||
assert 'Invalid file format. (number of places in waiting list,' in resp.text
|
||||
|
||||
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-09-16,18:00,10', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10', 'text/csv')
|
||||
resp = resp.form.submit(status=302)
|
||||
assert Event.objects.count() == 1
|
||||
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
|
||||
|
@ -522,7 +525,7 @@ def test_import_events(app, admin_user):
|
|||
Event.objects.all().delete()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-09-16,18:00,10,5', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5', 'text/csv')
|
||||
resp = resp.form.submit(status=302)
|
||||
assert Event.objects.count() == 1
|
||||
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
|
||||
|
@ -531,20 +534,21 @@ def test_import_events(app, admin_user):
|
|||
Event.objects.all().delete()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
||||
resp.form['events_csv_file'] = Upload('t.csv', '2016-09-16,18:00,10,5,bla bla bla', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv',
|
||||
u'2016-09-16,18:00,10,5,éléphant'.encode('utf-8'), 'text/csv')
|
||||
resp = resp.form.submit(status=302)
|
||||
assert Event.objects.count() == 1
|
||||
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
|
||||
assert Event.objects.all()[0].places == 10
|
||||
assert Event.objects.all()[0].waiting_list_places == 5
|
||||
assert Event.objects.all()[0].label == 'bla bla bla'
|
||||
assert Event.objects.all()[0].label == u'éléphant'
|
||||
Event.objects.all().delete()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
||||
resp.form['events_csv_file'] = Upload('t.csv', 'date,time,etc.\n'
|
||||
'2016-09-16,18:00,10,5,bla bla bla\n'
|
||||
'\n'
|
||||
'2016-09-19,18:00,10', 'text/csv')
|
||||
resp.form['events_csv_file'] = Upload('t.csv', b'date,time,etc.\n'
|
||||
b'2016-09-16,18:00,10,5,bla bla bla\n'
|
||||
b'\n'
|
||||
b'2016-09-19,18:00,10', 'text/csv')
|
||||
resp = resp.form.submit(status=302)
|
||||
assert Event.objects.count() == 2
|
||||
Event.objects.all().delete()
|
||||
|
@ -560,9 +564,9 @@ def test_add_meetings_agenda(app, admin_user):
|
|||
agenda = Agenda.objects.get(label='Foo bar')
|
||||
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
||||
resp = resp.follow()
|
||||
assert 'Foo bar' in resp.body
|
||||
assert '<h2>Settings' in resp.body
|
||||
assert 'Meeting Types' in resp.body
|
||||
assert 'Foo bar' in resp.text
|
||||
assert '<h2>Settings' in resp.text
|
||||
assert 'Meeting Types' in resp.text
|
||||
agenda = Agenda.objects.get(label='Foo bar')
|
||||
assert agenda.kind == 'meetings'
|
||||
|
||||
|
@ -572,7 +576,7 @@ def test_meetings_agenda_add_meeting_type(app, admin_user):
|
|||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/' % agenda.id).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert "This agenda doesn't have any meeting type yet." in resp.body
|
||||
assert "This agenda doesn't have any meeting type yet." in resp.text
|
||||
resp = resp.click('New Meeting Type')
|
||||
resp.form['label'] = 'Blah'
|
||||
resp.form['duration'] = '60'
|
||||
|
@ -580,7 +584,7 @@ def test_meetings_agenda_add_meeting_type(app, admin_user):
|
|||
assert MeetingType.objects.get(agenda=agenda).label == 'Blah'
|
||||
assert MeetingType.objects.get(agenda=agenda).duration == 60
|
||||
resp = resp.follow()
|
||||
assert 'Blah' in resp.body
|
||||
assert 'Blah' in resp.text
|
||||
|
||||
# and edit
|
||||
resp = resp.click('Blah')
|
||||
|
@ -633,11 +637,11 @@ def test_meetings_agenda_add_time_period(app, admin_user):
|
|||
resp = resp.follow()
|
||||
assert u'Monday / 10 a.m. → 1 p.m.' in resp.text
|
||||
assert u'Wednesday / 10 a.m. → 5 p.m.' in resp.text
|
||||
assert resp.body.index('Monday') < resp.body.index('Wednesday')
|
||||
assert resp.text.index('Monday') < resp.text.index('Wednesday')
|
||||
|
||||
# and edit
|
||||
resp = resp.click(u'Wednesday / 10 a.m. → 5 p.m.')
|
||||
assert 'Edit Time Period' in resp.body
|
||||
assert 'Edit Time Period' in resp.text
|
||||
resp.form['start_time'] = '9:00'
|
||||
resp = resp.form.submit()
|
||||
assert TimePeriod.objects.get(desk=desk, weekday=2).start_time.hour == 9
|
||||
|
@ -679,7 +683,7 @@ def test_meetings_agenda_add_time_period_as_manager(app, manager_user):
|
|||
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
||||
app = login(app, username='manager', password='manager')
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.id)
|
||||
assert not 'Settings' in resp.body
|
||||
assert not 'Settings' in resp.text
|
||||
resp = app.get('/manage/agendas/%d/settings' % agenda.id, status=403)
|
||||
MeetingType(agenda=agenda, label='Blah').save()
|
||||
app.get('/manage/agendas/%d/desk/%d/add-time-period' % (agenda.id, desk.id), status=403)
|
||||
|
@ -695,9 +699,9 @@ def test_meetings_agenda_add_time_period_as_manager(app, manager_user):
|
|||
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.id).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Add a time period' in resp.content
|
||||
assert '/manage/timeperiods/%s/edit' % time_period.id in resp.body
|
||||
assert '/manage/timeperiods/%s/delete' % time_period.id in resp.body
|
||||
assert 'Add a time period' in resp.text
|
||||
assert '/manage/timeperiods/%s/edit' % time_period.id in resp.text
|
||||
assert '/manage/timeperiods/%s/delete' % time_period.id in resp.text
|
||||
|
||||
app.get('/manage/agendas/%d/desk/%d/add-time-period' % (agenda.id, desk.id), status=200)
|
||||
app.get('/manage/timeperiods/%d/edit' % time_period.id, status=200)
|
||||
|
@ -797,11 +801,11 @@ def test_meetings_agenda_add_time_period_exception(app, admin_user):
|
|||
resp.form['end_datetime'] = future.replace(hour=16).strftime(dt_format)
|
||||
resp = resp.form.submit().follow()
|
||||
assert TimePeriodException.objects.count() == 2
|
||||
assert 'Exception 1' in resp.content
|
||||
assert 'Exception 2' not in resp.content
|
||||
assert 'Exception 1' in resp.text
|
||||
assert 'Exception 2' not in resp.text
|
||||
resp = resp.click(href="/manage/time-period-exceptions/%d/exception-list" % agenda.desk_set.first().pk)
|
||||
assert 'Exception 1' in resp.content
|
||||
assert 'Exception 2' in resp.content
|
||||
assert 'Exception 1' in resp.text
|
||||
assert 'Exception 2' in resp.text
|
||||
|
||||
|
||||
def test_meetings_agenda_add_time_period_exception_when_booking_exists(app, admin_user):
|
||||
|
@ -819,12 +823,12 @@ def test_meetings_agenda_add_time_period_exception_when_booking_exists(app, admi
|
|||
resp = resp.click('Add a time period exception')
|
||||
resp = resp.form.submit() # submit empty form
|
||||
# fields should be marked with errors
|
||||
assert resp.body.count('This field is required.') == 2
|
||||
assert resp.text.count('This field is required.') == 2
|
||||
# try again with data in fields
|
||||
resp.form['start_datetime'] = '2017-05-22 08:00'
|
||||
resp.form['end_datetime'] = '2017-05-26 17:30'
|
||||
resp = resp.form.submit()
|
||||
assert 'One or several bookings exists within this time slot.' in resp.content
|
||||
assert 'One or several bookings exists within this time slot.' in resp.text
|
||||
assert TimePeriodException.objects.count() == 0
|
||||
|
||||
# check it's possible to add an exception on another desk
|
||||
|
@ -856,7 +860,7 @@ def test_meetings_agenda_add_time_period_exception_when_cancelled_booking_exists
|
|||
resp.form['start_datetime'] = '2017-05-22 08:00'
|
||||
resp.form['end_datetime'] = '2017-05-26 17:30'
|
||||
resp = resp.form.submit()
|
||||
assert 'One or several bookings exists within this time slot.' not in resp.content
|
||||
assert 'One or several bookings exists within this time slot.' not in resp.text
|
||||
assert TimePeriodException.objects.count() == 1
|
||||
|
||||
def test_meetings_agenda_add_invalid_time_period_exception(app, admin_user):
|
||||
|
@ -872,7 +876,7 @@ def test_meetings_agenda_add_invalid_time_period_exception(app, admin_user):
|
|||
resp.form['start_datetime'] = '2017-05-26 17:30'
|
||||
resp.form['end_datetime'] = '2017-05-22 08:00'
|
||||
resp = resp.form.submit()
|
||||
assert 'End datetime must be greater than start datetime.' in resp.content
|
||||
assert 'End datetime must be greater than start datetime.' in resp.text
|
||||
|
||||
|
||||
def test_meetings_agenda_delete_time_period_exception(app, admin_user):
|
||||
|
@ -908,24 +912,24 @@ def test_agenda_import_time_period_exception_from_ics(app, admin_user):
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' in resp.content
|
||||
assert 'Import exceptions from .ics' in resp.text
|
||||
resp = resp.click('upload')
|
||||
assert "You can upload a file or specify an address to a remote calendar." in resp
|
||||
resp = resp.form.submit(status=302)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
resp = resp.click('upload')
|
||||
resp.form['ics_file'] = Upload('exceptions.ics', 'invalid content', 'text/calendar')
|
||||
resp.form['ics_file'] = Upload('exceptions.ics', b'invalid content', 'text/calendar')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'File format is invalid' in resp.content
|
||||
ics_with_no_start_date = """BEGIN:VCALENDAR
|
||||
assert 'File format is invalid' in resp.text
|
||||
ics_with_no_start_date = b"""BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//foo.bar//EN
|
||||
BEGIN:VEVENT
|
||||
|
@ -935,16 +939,16 @@ END:VEVENT
|
|||
END:VCALENDAR"""
|
||||
resp.form['ics_file'] = Upload('exceptions.ics', ics_with_no_start_date, 'text/calendar')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Event "New Year's Eve" has no start date.' in resp.content
|
||||
ics_with_no_events = """BEGIN:VCALENDAR
|
||||
assert 'Event "New Year's Eve" has no start date.' in resp.text
|
||||
ics_with_no_events = b"""BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//foo.bar//EN
|
||||
END:VCALENDAR"""
|
||||
resp.form['ics_file'] = Upload('exceptions.ics', ics_with_no_events, 'text/calendar')
|
||||
resp = resp.form.submit(status=200)
|
||||
assert "The file doesn't contain any events." in resp.content
|
||||
assert "The file doesn't contain any events." in resp.text
|
||||
|
||||
ics_with_exceptions = """BEGIN:VCALENDAR
|
||||
ics_with_exceptions = b"""BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//foo.bar//EN
|
||||
BEGIN:VEVENT
|
||||
|
@ -960,7 +964,7 @@ END:VCALENDAR"""
|
|||
resp = resp.form.submit(status=302)
|
||||
assert TimePeriodException.objects.filter(desk=desk).count() == 1
|
||||
resp = resp.follow()
|
||||
assert 'An exception has been imported.' in resp.content
|
||||
assert 'An exception has been imported.' in resp.text
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2017-12-01')
|
||||
|
@ -975,7 +979,7 @@ def test_agenda_import_time_period_exception_from_ics_recurrent(app, admin_user)
|
|||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
resp = resp.click('upload')
|
||||
ics_with_recurrent_exceptions = """BEGIN:VCALENDAR
|
||||
ics_with_recurrent_exceptions = b"""BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//foo.bar//EN
|
||||
BEGIN:VEVENT
|
||||
|
@ -998,7 +1002,7 @@ def test_agenda_import_time_period_exception_with_remote_ics(mocked_get, app, ad
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
@ -1042,7 +1046,7 @@ def test_agenda_import_time_period_exception_with_remote_ics_no_events(mocked_ge
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
@ -1087,7 +1091,7 @@ def test_agenda_update_time_period_exception_from_remote_ics(mocked_get, app, ad
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
@ -1142,7 +1146,7 @@ def test_agenda_import_time_period_exception_from_remote_ics_with_connection_err
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
@ -1160,7 +1164,7 @@ def test_agenda_import_time_period_exception_from_remote_ics_with_connection_err
|
|||
raise requests.exceptions.ConnectionError('unreachable')
|
||||
mocked_get.side_effect = mocked_requests_connection_error
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Failed to retrieve remote calendar (unreachable).' in resp.content
|
||||
assert 'Failed to retrieve remote calendar (unreachable).' in resp.text
|
||||
|
||||
@mock.patch('chrono.agendas.models.requests.get')
|
||||
def test_agenda_import_time_period_exception_from_forbidden_remote_ics(mocked_get, app, admin_user):
|
||||
|
@ -1170,7 +1174,7 @@ def test_agenda_import_time_period_exception_from_forbidden_remote_ics(mocked_ge
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
@ -1186,7 +1190,7 @@ def test_agenda_import_time_period_exception_from_forbidden_remote_ics(mocked_ge
|
|||
raise requests.exceptions.HTTPError(response=mocked_response)
|
||||
mocked_get.side_effect = mocked_requests_http_forbidden_error
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Failed to retrieve remote calendar (HTTP error 403).' in resp.content
|
||||
assert 'Failed to retrieve remote calendar (HTTP error 403).' in resp.text
|
||||
|
||||
@mock.patch('chrono.agendas.models.requests.get')
|
||||
def test_agenda_import_time_period_exception_from_remote_ics_with_ssl_error(mocked_get, app, admin_user):
|
||||
|
@ -1196,7 +1200,7 @@ def test_agenda_import_time_period_exception_from_remote_ics_with_ssl_error(mock
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
||||
resp = resp.click('Settings')
|
||||
assert 'Import exceptions from .ics' not in resp.content
|
||||
assert 'Import exceptions from .ics' not in resp.text
|
||||
TimePeriod.objects.create(weekday=1, desk=desk,
|
||||
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
|
||||
|
||||
|
@ -1210,7 +1214,7 @@ def test_agenda_import_time_period_exception_from_remote_ics_with_ssl_error(mock
|
|||
raise requests.exceptions.SSLError('SSL error')
|
||||
mocked_get.side_effect = mocked_requests_http_ssl_error
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Failed to retrieve remote calendar (SSL error).' in resp.content
|
||||
assert 'Failed to retrieve remote calendar (SSL error).' in resp.text
|
||||
|
||||
def test_agenda_day_view(app, admin_user, manager_user, api_user):
|
||||
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
||||
|
@ -1225,25 +1229,25 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user):
|
|||
today = datetime.date.today()
|
||||
assert resp.location.endswith('%s/%s/%s/' % (today.year, today.month, today.day))
|
||||
resp = resp.follow()
|
||||
assert 'No opening hours this day.' in resp.body # no time pediod
|
||||
assert 'No opening hours this day.' in resp.text # no time pediod
|
||||
|
||||
timeperiod = TimePeriod(desk=desk, weekday=today.weekday(),
|
||||
start_time=datetime.time(10, 0),
|
||||
end_time=datetime.time(18, 0))
|
||||
timeperiod.save()
|
||||
resp = app.get('/manage/agendas/%s/' % agenda.id, status=302).follow()
|
||||
assert not 'No opening hours this day.' in resp.body
|
||||
assert not 'div class="booking' in resp.body
|
||||
assert resp.body.count('<tr') == 9 # 10->18 (not included)
|
||||
assert not 'No opening hours this day.' in resp.text
|
||||
assert not 'div class="booking' in resp.text
|
||||
assert resp.text.count('<tr') == 9 # 10->18 (not included)
|
||||
|
||||
timeperiod.end_time = datetime.time(18, 30) # end during an hour
|
||||
timeperiod.save()
|
||||
resp = app.get('/manage/agendas/%s/' % agenda.id, status=302).follow()
|
||||
assert resp.body.count('<tr') == 10 # 10->18 (included)
|
||||
assert resp.text.count('<tr') == 10 # 10->18 (included)
|
||||
|
||||
# check opening hours cells
|
||||
assert '<div class="opening-hours"' in resp.body
|
||||
assert 'style="height: 850%; top: 0%;"' in resp.body
|
||||
assert '<div class="opening-hours"' in resp.text
|
||||
assert 'style="height: 850%; top: 0%;"' in resp.text
|
||||
|
||||
# book some slots
|
||||
app.reset()
|
||||
|
@ -1260,9 +1264,9 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user):
|
|||
date = Booking.objects.all()[0].event.start_datetime
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (
|
||||
agenda.id, date.year, date.month, date.day))
|
||||
assert resp.body.count('div class="booking') == 2
|
||||
assert 'hourspan-2' in resp.body # table CSS class
|
||||
assert 'height: 50%; top: 0%;' in resp.body # booking cells
|
||||
assert resp.text.count('div class="booking') == 2
|
||||
assert 'hourspan-2' in resp.text # table CSS class
|
||||
assert 'height: 50%; top: 0%;' in resp.text # booking cells
|
||||
|
||||
# create a shorter meeting type, this will change the table CSS class
|
||||
# (and visually this will give more room for events)
|
||||
|
@ -1270,8 +1274,8 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user):
|
|||
meetingtype.save()
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (
|
||||
agenda.id, date.year, date.month, date.day))
|
||||
assert resp.body.count('div class="booking') == 2
|
||||
assert 'hourspan-4' in resp.body # table CSS class
|
||||
assert resp.text.count('div class="booking') == 2
|
||||
assert 'hourspan-4' in resp.text # table CSS class
|
||||
|
||||
# cancel a booking
|
||||
app.reset()
|
||||
|
@ -1284,7 +1288,7 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user):
|
|||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (
|
||||
agenda.id, date.year, date.month, date.day))
|
||||
assert resp.body.count('div class="booking') == 1
|
||||
assert resp.text.count('div class="booking') == 1
|
||||
|
||||
# wrong type
|
||||
agenda2 = Agenda(label=u'Foo bar')
|
||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
|||
import pytest
|
||||
|
||||
from django.test import override_settings
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.timezone import localtime, make_aware
|
||||
|
||||
from chrono.agendas.models import Agenda, TimePeriod, TimePeriodException, MeetingType, Desk
|
||||
|
@ -104,25 +105,25 @@ def test_timeperiod_time_slots():
|
|||
@override_settings(LANGUAGE_CODE='fr-fr')
|
||||
def test_time_period_exception_as_string():
|
||||
# single day
|
||||
assert unicode(TimePeriodException(
|
||||
assert force_text(TimePeriodException(
|
||||
start_datetime=make_aware(datetime.datetime(2018, 1, 18)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 1, 19)))
|
||||
) == u'18 jan. 2018'
|
||||
|
||||
# multiple full days
|
||||
assert unicode(TimePeriodException(
|
||||
assert force_text(TimePeriodException(
|
||||
start_datetime=make_aware(datetime.datetime(2018, 1, 18)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 1, 20)))
|
||||
) == u'18 jan. 2018 → 20 jan. 2018'
|
||||
|
||||
# a few hours in a day
|
||||
assert unicode(TimePeriodException(
|
||||
assert force_text(TimePeriodException(
|
||||
start_datetime=make_aware(datetime.datetime(2018, 1, 18, 10, 0)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 1, 18, 12, 0)))
|
||||
) == u'18 jan. 2018 10:00 → 12:00'
|
||||
|
||||
# multiple days and different times
|
||||
assert unicode(TimePeriodException(
|
||||
assert force_text(TimePeriodException(
|
||||
start_datetime=make_aware(datetime.datetime(2018, 1, 18, 10, 0)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 1, 20, 12, 0)))
|
||||
) == u'18 jan. 2018 10:00 → 20 jan. 2018 12:00'
|
||||
|
|
8
tox.ini
8
tox.ini
|
@ -1,5 +1,5 @@
|
|||
[tox]
|
||||
envlist = coverage-django18-pylint,coverage-django111
|
||||
envlist = py2-coverage-django18-pylint,{py2,py3}-coverage-django111
|
||||
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/chrono/
|
||||
|
||||
[testenv]
|
||||
|
@ -22,9 +22,11 @@ deps =
|
|||
pylint<1.8
|
||||
pylint-django<0.9
|
||||
django-webtest<1.9.3
|
||||
django-mellon
|
||||
py2: django-mellon
|
||||
py3: django-mellon>=1.2.35
|
||||
pytest-freezegun
|
||||
commands =
|
||||
./getlasso.sh
|
||||
py2: ./getlasso.sh
|
||||
py3: ./getlasso3.sh
|
||||
py.test {env:COVERAGE:} {posargs:tests/}
|
||||
pylint: ./pylint.sh chrono/
|
||||
|
|
Loading…
Reference in New Issue