4876 lines
199 KiB
Python
4876 lines
199 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from __future__ import unicode_literals
|
|
import codecs
|
|
import copy
|
|
import datetime
|
|
import json
|
|
import mock
|
|
import os
|
|
|
|
from django.contrib.auth.models import User, Group
|
|
from django.core.management import call_command
|
|
from django.db import connection
|
|
from django.test import override_settings
|
|
from django.test.utils import CaptureQueriesContext
|
|
from django.urls import reverse
|
|
from django.utils.encoding import force_text
|
|
from django.utils.timezone import make_aware, now, localtime
|
|
|
|
import freezegun
|
|
import pytest
|
|
import requests
|
|
from webtest import Upload
|
|
|
|
from chrono.agendas.models import (
|
|
Agenda,
|
|
Booking,
|
|
Category,
|
|
Desk,
|
|
Event,
|
|
MeetingType,
|
|
Resource,
|
|
TimePeriod,
|
|
TimePeriodException,
|
|
TimePeriodExceptionSource,
|
|
VirtualMember,
|
|
AgendaReminderSettings,
|
|
UnavailabilityCalendar,
|
|
)
|
|
from chrono.manager.forms import TimePeriodExceptionForm
|
|
from chrono.utils.signature import check_query
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
@pytest.fixture
|
|
def simple_user():
|
|
try:
|
|
user = User.objects.get(username='user')
|
|
except User.DoesNotExist:
|
|
user = User.objects.create_user('user', password='user')
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def managers_group():
|
|
group, _ = Group.objects.get_or_create(name='Managers')
|
|
return group
|
|
|
|
|
|
@pytest.fixture
|
|
def manager_user(managers_group):
|
|
try:
|
|
user = User.objects.get(username='manager')
|
|
except User.DoesNotExist:
|
|
user = User.objects.create_user('manager', password='manager')
|
|
user.groups.set([managers_group])
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def admin_user():
|
|
try:
|
|
user = User.objects.get(username='admin')
|
|
except User.DoesNotExist:
|
|
user = User.objects.create_superuser('admin', email=None, password='admin')
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def api_user():
|
|
try:
|
|
user = User.objects.get(username='api-user')
|
|
except User.DoesNotExist:
|
|
user = User.objects.create(
|
|
username='john.doe', first_name=u'John', last_name=u'Doe', email='john.doe@example.net'
|
|
)
|
|
user.set_password('password')
|
|
user.save()
|
|
return user
|
|
|
|
|
|
def login(app, username='admin', password='admin'):
|
|
login_page = app.get('/login/')
|
|
login_form = login_page.forms[0]
|
|
login_form['username'] = username
|
|
login_form['password'] = password
|
|
resp = login_form.submit()
|
|
assert resp.status_int == 302
|
|
return app
|
|
|
|
|
|
def test_unlogged_access(app):
|
|
# connect while not being logged in
|
|
assert app.get('/manage/', status=302).location.endswith('/login/?next=/manage/')
|
|
|
|
|
|
def test_simple_user_access(app, simple_user):
|
|
# connect while being logged as a simple user, access should be forbidden
|
|
app = login(app, username='user', password='user')
|
|
assert app.get('/manage/', status=403)
|
|
|
|
|
|
def test_manager_user_access(app, manager_user):
|
|
# connect while being logged as a manager user, access should be granted if
|
|
# there's at least an agenda that is viewable or editable.
|
|
app = login(app, username='manager', password='manager')
|
|
assert app.get('/manage/', status=403)
|
|
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
assert app.get('/manage/', status=403)
|
|
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.edit_role = None
|
|
agenda.save()
|
|
assert app.get('/manage/', status=200)
|
|
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.view_role = None
|
|
agenda.save()
|
|
assert app.get('/manage/', status=200)
|
|
|
|
|
|
def test_home_redirect(app):
|
|
assert app.get('/', status=302).location.endswith('/manage/')
|
|
|
|
|
|
def test_access(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
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)
|
|
app.get('/logout/')
|
|
assert app.get('/manage/', status=302).location.endswith('/login/?next=/manage/')
|
|
|
|
|
|
def test_menu_json(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/menu.json', status=200)
|
|
assert resp.content_type == 'application/json'
|
|
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.text == 'Q(%s);' % resp.text
|
|
assert resp2.content_type == 'application/javascript'
|
|
|
|
|
|
def test_events_agenda_redirect(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='events')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/month/' % agenda.pk)
|
|
|
|
agenda.default_view = 'open_events'
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/events/open/' % agenda.pk)
|
|
|
|
|
|
@freezegun.freeze_time('2020-07-12')
|
|
def test_events_agenda_month_redirect(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='events')
|
|
|
|
app = login(app)
|
|
# no event, redirect to current month
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/7/' % agenda.pk)
|
|
|
|
# only past events, redirect to last event month
|
|
Event.objects.create(
|
|
agenda=agenda, places=1, start_datetime=now() - datetime.timedelta(days=60),
|
|
)
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/5/' % agenda.pk)
|
|
Event.objects.create(
|
|
agenda=agenda, places=1, start_datetime=now() - datetime.timedelta(days=30),
|
|
)
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/6/' % agenda.pk)
|
|
|
|
# future events
|
|
Event.objects.create(
|
|
agenda=agenda, places=1, start_datetime=now() + datetime.timedelta(days=60),
|
|
)
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/9/' % agenda.pk)
|
|
Event.objects.create(
|
|
agenda=agenda, places=1, start_datetime=now() + datetime.timedelta(days=30),
|
|
)
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/8/' % agenda.pk)
|
|
|
|
# wrong kind
|
|
agenda.kind = 'virtual'
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/' % agenda.pk)
|
|
agenda.kind = 'meetings'
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/month/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/' % agenda.pk)
|
|
|
|
|
|
@freezegun.freeze_time('2020-07-12')
|
|
def test_meetings_agenda_redirect(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/7/12/' % agenda.pk)
|
|
|
|
|
|
@freezegun.freeze_time('2020-07-12')
|
|
def test_virtual_agenda_redirect(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='virtual')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/' % agenda.pk, status=302)
|
|
assert resp.location.endswith('/manage/agendas/%s/2020/7/12/' % agenda.pk)
|
|
|
|
|
|
def test_view_agendas_as_admin(app, admin_user):
|
|
Agenda.objects.create(label=u'Bar Foo')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
assert 'Bar Foo <span class="identifier">[identifier: bar-foo]</span>' in resp.text
|
|
|
|
|
|
def test_view_agendas_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
|
|
agenda2 = Agenda(label=u'Bar Foo')
|
|
agenda2.save()
|
|
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/', status=200)
|
|
assert 'Foo Bar' in resp.text
|
|
assert 'Bar Foo <span class="identifier">[identifier: bar-foo]</span>' not 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)
|
|
|
|
# check there's no access to the settings page for "events" agenda
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=403)
|
|
app.get('/manage/agendas/%s/add-event' % agenda.id, status=403)
|
|
app.get('/manage/agendas/%s/edit' % agenda.id, status=403)
|
|
|
|
# check it doesn't give access for "meetings" agenda
|
|
agenda.kind = 'meetings'
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=403)
|
|
# or virtual agenda
|
|
agenda.kind = 'virtual'
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=403)
|
|
|
|
# check it gives a 404 on unknown agendas
|
|
resp = app.get('/manage/agendas/0/settings', status=404)
|
|
|
|
|
|
def test_list_resources_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/resources/', status=403)
|
|
|
|
resp = app.get('/manage/', status=200)
|
|
assert 'Resources' not in resp.text
|
|
|
|
|
|
def test_add_resource(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Resources')
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp = resp.form.submit()
|
|
resource = Resource.objects.latest('pk')
|
|
assert resp.location.endswith('/manage/resource/%s/' % resource.pk)
|
|
assert resource.label == 'Foo bar'
|
|
assert resource.slug == 'foo-bar'
|
|
|
|
|
|
def test_add_resource_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/resource/add/', status=403)
|
|
|
|
|
|
def test_view_resource(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/resource/%s/' % resource.pk, status=200)
|
|
assert '/manage/agendas/%s/settings' % agenda.pk not in resp.text
|
|
|
|
agenda.resources.add(resource)
|
|
resp = app.get('/manage/resource/%s/' % resource.pk, status=200)
|
|
assert '/manage/agendas/%s/settings' % agenda.pk in resp.text
|
|
|
|
|
|
def test_view_resource_as_manager(app, manager_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/resource/%s/' % resource.pk, status=403)
|
|
|
|
|
|
def test_resource_day_view(app, admin_user):
|
|
today = datetime.date.today()
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
timeperiod = TimePeriod.objects.create(
|
|
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert 'div class="booking' not in resp.text
|
|
assert 'No bookings this day.' in resp.text
|
|
|
|
agenda.resources.add(resource)
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert 'div class="booking' not in resp.text
|
|
assert resp.text.count('<tr') == 8 # 10->18 (not included)
|
|
|
|
timeperiod.end_time = datetime.time(18, 30) # end during an hour
|
|
timeperiod.save()
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('<tr') == 9 # 10->18 (included)
|
|
|
|
# book some slots
|
|
for hour, minute in [(10, 30), (14, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=now().replace(hour=hour, minute=minute),
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert len(ctx.captured_queries) == 7
|
|
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
|
|
assert 'height: 50%; top: 50%;' 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)
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Baz', duration=15)
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('div class="booking') == 2
|
|
assert 'hourspan-4' in resp.text # table CSS class
|
|
|
|
# cancel a booking
|
|
booking = Booking.objects.first()
|
|
booking.cancel()
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('div class="booking') == 1
|
|
|
|
|
|
def test_resource_day_view_late_meeting(app, admin_user):
|
|
today = datetime.date.today()
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(23, 30)
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('<tr') == 14
|
|
assert '<th class="hour">midnight</th>' not in resp.text
|
|
assert '<th class="hour">11 p.m.</th>' in resp.text
|
|
|
|
|
|
def test_resource_invalid_day_view(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
|
|
login(app)
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, 2018, 11, 31), status=302)
|
|
assert resp.location.endswith('2018/11/30/')
|
|
|
|
|
|
def test_resource_day_view_event_outside_timeperiod(app, admin_user):
|
|
today = datetime.date.today()
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
login(app)
|
|
|
|
# no time period - no events
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert 'No bookings this day.' in resp.text
|
|
assert 'div class="booking' not in resp.text
|
|
|
|
# book some slots
|
|
for hour, minute in [(9, 0), (17, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(hour=hour, minute=minute),
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
|
|
# no time period - events are displayed
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('div class="booking') == 2
|
|
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert 'No bookings this day.' in resp.text
|
|
assert resp.text.count('div class="booking') == 0
|
|
|
|
# events outside time period
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(16, 0)
|
|
)
|
|
resp = app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('div class="booking') == 2
|
|
|
|
|
|
def test_day_view_resource_as_manager(app, manager_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
app = login(app, username='manager', password='manager')
|
|
today = datetime.date.today()
|
|
app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day), status=403)
|
|
|
|
|
|
@freezegun.freeze_time('2020-06-15')
|
|
def test_resource_month_view(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=20)
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
|
|
login(app)
|
|
today = datetime.date(2018, 11, 10) # fixed day
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month))
|
|
assert '<div class="booking' not in resp.text
|
|
first_month_day = today.replace(day=1)
|
|
last_month_day = today.replace(day=1, month=today.month + 1) - datetime.timedelta(days=1)
|
|
start_week_number = first_month_day.isocalendar()[1]
|
|
end_week_number = last_month_day.isocalendar()[1]
|
|
weeks_number = end_week_number - start_week_number + 1
|
|
assert resp.text.count('<tr') == 9 * weeks_number
|
|
|
|
# book some slots
|
|
for hour, minute in [(10, 30), (14, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=now().replace(hour=hour, minute=minute),
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
|
|
today = datetime.date.today()
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month))
|
|
assert len(ctx.captured_queries) == 8
|
|
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
|
|
|
|
# cancel booking
|
|
booking = Booking.objects.first()
|
|
booking.cancel()
|
|
|
|
# make sure the are not
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('<div class="booking"') == 1
|
|
|
|
|
|
def test_resource_month_view_weekend(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
monday = 0
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=monday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
month, year = 1, 2019
|
|
|
|
login(app)
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, year, month))
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' not in resp.text
|
|
# No Monday on first row since month starts a Tuesday
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 1
|
|
|
|
# When weekend is hidden, do not display an empty first week
|
|
month, year = 12, 2019 # month starts a Sunday
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, year, month))
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
|
|
|
month, year = 6, 2019 # month starts a Saturday
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, year, month))
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
|
|
|
saturday = 5
|
|
timeperiod_sat = TimePeriod.objects.create(
|
|
desk=desk, weekday=saturday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, year, month))
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' in resp.text
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 5
|
|
|
|
sunday = 6
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=sunday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, year, month))
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
timeperiod_sat.delete()
|
|
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, year, month))
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
|
|
def test_resource_month_view_dst_change(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=0, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
|
|
login(app)
|
|
# book some slots
|
|
with freezegun.freeze_time('2019-10-01'):
|
|
for start_datetime in [
|
|
make_aware(datetime.datetime(2019, 10, 2, 10, 0)),
|
|
make_aware(datetime.datetime(2019, 10, 29, 10, 0)),
|
|
]:
|
|
event = Event.objects.create(
|
|
agenda=agenda, places=1, desk=desk, meeting_type=meetingtype, start_datetime=start_datetime,
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
|
|
# check booked slots are similarly aligned
|
|
resp = app.get('/manage/resource/%s/2019/10/' % resource.pk)
|
|
assert resp.text.count('height:50.0%;top:100.0%') == 2
|
|
|
|
|
|
def test_resource_month_view_januaries(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
TimePeriod(desk=desk, weekday=2, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save()
|
|
|
|
for year in range(2020, 2030):
|
|
date = datetime.date(year, 1, 1)
|
|
with freezegun.freeze_time(date):
|
|
login(app)
|
|
resp = app.get('/manage/resource/%s/%s/1/' % (resource.pk, date.year))
|
|
assert resp.text.count('<th></th>') in (4, 5)
|
|
|
|
|
|
def test_resource_month_view_event_outside_timeperiod(app, admin_user):
|
|
today = datetime.date.today()
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
agenda.resources.add(resource)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
login(app)
|
|
|
|
# no time period - no events
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert 'No bookings this month.' in resp.text
|
|
assert 'div class="booking' not in resp.text
|
|
|
|
# book some slots
|
|
middle_day = now().replace(day=15)
|
|
for hour, minute in [(9, 0), (17, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(
|
|
day=middle_day.day - middle_day.weekday() + 2, hour=hour, minute=minute
|
|
),
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
|
|
# no time period - events are displayed
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 2
|
|
|
|
# events outside time period
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(16, 0)
|
|
)
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 2
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' not in resp.text
|
|
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 0
|
|
|
|
# create an event on saturday
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(
|
|
day=middle_day.day - middle_day.weekday() + 5, hour=10, minute=0
|
|
),
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 3
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' in resp.text
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 0
|
|
# and a timeperiod
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=5, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 3
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
# create an event on sunday
|
|
middle_day = now().replace(day=15)
|
|
event = Event.objects.create(
|
|
agenda=agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(
|
|
day=middle_day.day - middle_day.weekday() + 6, hour=10, minute=0
|
|
),
|
|
)
|
|
event.resources.add(resource)
|
|
Booking.objects.create(event=event)
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 4
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 0
|
|
# and a timeperiod
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=6, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
resp = app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 4
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
|
|
def test_month_view_resource_as_manager(app, manager_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
app = login(app, username='manager', password='manager')
|
|
today = datetime.date.today()
|
|
app.get('/manage/resource/%s/%d/%d/' % (resource.pk, today.year, today.month), status=403)
|
|
|
|
|
|
def test_edit_resource(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/resource/%s/' % resource.pk, status=200)
|
|
resp = resp.click('Edit')
|
|
resp.form['label'] = 'Foo bar baz'
|
|
resp.form['slug'] = 'baz'
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/resource/%s/' % resource.pk)
|
|
resource.refresh_from_db()
|
|
assert resource.label == 'Foo bar baz'
|
|
assert resource.slug == 'baz'
|
|
|
|
|
|
def test_edit_resource_as_manager(app, manager_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/resource/%s/edit/' % resource.pk, status=403)
|
|
|
|
|
|
def test_delete_resource(app, admin_user):
|
|
resource = Resource.objects.create(label='Foo bar')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/resource/%s/' % resource.pk, status=200)
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/resources/')
|
|
assert Resource.objects.exists() is False
|
|
|
|
|
|
def test_delete_resource_as_manager(app, manager_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/resource/%s/delete/' % resource.pk, status=403)
|
|
|
|
|
|
def test_list_categories_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/categories/', status=403)
|
|
|
|
resp = app.get('/manage/', status=200)
|
|
assert 'Categories' not in resp.text
|
|
|
|
|
|
def test_add_category(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Categories')
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp = resp.form.submit()
|
|
category = Category.objects.latest('pk')
|
|
assert resp.location.endswith('/manage/categories/')
|
|
assert category.label == 'Foo bar'
|
|
assert category.slug == 'foo-bar'
|
|
|
|
|
|
def test_add_category_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/category/add/', status=403)
|
|
|
|
|
|
def test_edit_category(app, admin_user):
|
|
category = Category.objects.create(label='Foo bar')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/categories/', status=200)
|
|
resp = resp.click(href='/manage/category/%s/edit/' % category.pk)
|
|
resp.form['label'] = 'Foo bar baz'
|
|
resp.form['slug'] = 'baz'
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/categories/')
|
|
category.refresh_from_db()
|
|
assert category.label == 'Foo bar baz'
|
|
assert category.slug == 'baz'
|
|
|
|
|
|
def test_edit_category_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
category = Category.objects.create(label='Foo bar')
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/category/%s/edit/' % category.pk, status=403)
|
|
|
|
|
|
def test_delete_category(app, admin_user):
|
|
category = Category.objects.create(label='Foo bar')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/categories/', status=200)
|
|
resp = resp.click(href='/manage/category/%s/delete/' % category.pk)
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/categories/')
|
|
assert Category.objects.exists() is False
|
|
|
|
|
|
def test_delete_category_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo Bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
category = Category.objects.create(label='Foo bar')
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/category/%s/delete/' % category.pk, status=403)
|
|
|
|
|
|
def test_add_agenda(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp = resp.form.submit()
|
|
|
|
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.text
|
|
assert '<h2>Settings' in resp.text
|
|
assert agenda.minimal_booking_delay == 1
|
|
assert agenda.maximal_booking_delay == 56
|
|
|
|
|
|
def test_add_agenda_as_manager(app, manager_user):
|
|
# open /manage/ access to manager_user, and check agenda creation is not
|
|
# allowed.
|
|
agenda = Agenda(label='Foo bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/agendas/add/', status=403)
|
|
|
|
|
|
def test_options_agenda(app, admin_user):
|
|
agenda_events = Agenda.objects.create(label=u'Foo bar', kind='events')
|
|
agenda_meetings = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
agenda_virtual = Agenda.objects.create(label=u'Foo bar', kind='virtual')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/edit' % agenda_events.pk)
|
|
assert resp.form['label'].value == 'Foo bar'
|
|
resp.form['label'] = 'Foo baz'
|
|
resp.form['anonymize_delay'] = 365
|
|
assert 'default_view' in resp.context['form'].fields
|
|
assert 'booking_form_url' in resp.context['form'].fields
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda_events.pk)
|
|
resp = resp.follow()
|
|
assert 'has_resources' not in resp.context
|
|
assert 'Foo baz' in resp.text
|
|
assert '<h2>Settings' in resp.text
|
|
agenda_events.refresh_from_db()
|
|
assert agenda_events.anonymize_delay == 365
|
|
|
|
resp = app.get('/manage/agendas/%s/edit' % agenda_meetings.pk)
|
|
assert 'default_view' not in resp.context['form'].fields
|
|
assert 'booking_form_url' not in resp.context['form'].fields
|
|
resp = app.get('/manage/agendas/%s/edit' % agenda_virtual.pk)
|
|
assert 'default_view' not in resp.context['form'].fields
|
|
assert 'booking_form_url' not in resp.context['form'].fields
|
|
|
|
|
|
def test_options_agenda_cant_unset_delays(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar')
|
|
assert agenda.minimal_booking_delay == 1
|
|
app = login(app)
|
|
url = '/manage/agendas/%s/edit' % agenda.pk
|
|
resp = app.get(url)
|
|
resp.form['minimal_booking_delay'] = None
|
|
resp = resp.form.submit()
|
|
agenda = Agenda.objects.get(label=u'Foo bar')
|
|
assert agenda.minimal_booking_delay == 1
|
|
|
|
|
|
def test_options_virtuale_agenda_can_unset_delays(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='virtual', maximal_booking_delay=2)
|
|
assert agenda.maximal_booking_delay == 2
|
|
app = login(app)
|
|
url = '/manage/agendas/%s/edit' % agenda.pk
|
|
resp = app.get(url)
|
|
resp.form['maximal_booking_delay'] = None
|
|
resp = resp.form.submit()
|
|
agenda = Agenda.objects.get(label=u'Foo bar')
|
|
assert agenda.maximal_booking_delay is None
|
|
|
|
|
|
def test_options_agenda_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Foo bar').follow().follow()
|
|
assert 'Settings' not in resp.text
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=403)
|
|
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)
|
|
|
|
agenda.kind = 'events'
|
|
agenda.save()
|
|
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Options')
|
|
assert resp.form['label'].value == 'Foo bar'
|
|
resp.form['label'] = 'Foo baz'
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
resp = resp.follow()
|
|
assert 'Foo baz' in resp.text
|
|
assert '<h2>Settings' in resp.text
|
|
|
|
|
|
def test_options_meetings_agenda_num_queries(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
for i in range(0, 10):
|
|
MeetingType.objects.create(agenda=agenda, label='MT %s' % i)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk %s' % i)
|
|
for weekday in (0, 6):
|
|
TimePeriod.objects.create(
|
|
weekday=weekday, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
# exception starts and ends in the past
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=now() - datetime.timedelta(days=2),
|
|
end_datetime=now() - datetime.timedelta(days=1),
|
|
)
|
|
if i % 2:
|
|
# exception starts in the past but ends in the futur
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=now() - datetime.timedelta(days=1),
|
|
end_datetime=now() + datetime.timedelta(days=1),
|
|
)
|
|
else:
|
|
# exception in more than 2 weeks
|
|
TimePeriodException.objects.create(
|
|
desk=desk,
|
|
start_datetime=now() + datetime.timedelta(days=20),
|
|
end_datetime=now() + datetime.timedelta(days=21),
|
|
)
|
|
|
|
app = login(app)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert len(ctx.captured_queries) == 10
|
|
|
|
|
|
def test_agenda_resources(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='events')
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
app = login(app)
|
|
# not for events agenda
|
|
app.get('/manage/agendas/%s/add-resource/' % agenda.pk, status=404)
|
|
app.get('/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk), status=404)
|
|
|
|
|
|
def test_meetings_agenda_resources(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert 'has_resources' in resp.context
|
|
assert resp.context['has_resources'] is False
|
|
assert 'Add resource' not in resp.text
|
|
|
|
resource = Resource.objects.create(label='Resource 1')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert 'has_resources' in resp.context
|
|
assert resp.context['has_resources'] is True
|
|
assert '/manage/resource/%s/' % resource.pk not in resp.text
|
|
assert '/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk) not in resp.text
|
|
resp = resp.click('Add resource')
|
|
assert list(resp.context['form'].fields['resource'].queryset) == [resource]
|
|
resp.form['resource'] = resource.pk
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert list(agenda.resources.all()) == [resource]
|
|
resp = resp.follow()
|
|
assert '/manage/resource/%s/' % resource.pk in resp.text
|
|
assert '/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk) in resp.text
|
|
resp = resp.click('Add resource')
|
|
assert list(resp.context['form'].fields['resource'].queryset) == []
|
|
|
|
resp = app.get('/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk))
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert list(agenda.resources.all()) == []
|
|
resp = resp.follow()
|
|
assert '/manage/resource/%s/' % resource.pk not in resp.text
|
|
assert '/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk) not in resp.text
|
|
|
|
|
|
def test_delete_agenda(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/')
|
|
resp = resp.follow()
|
|
assert 'Foo bar' not in resp.text
|
|
|
|
|
|
def test_delete_busy_agenda(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
event = Event(start_datetime=now() + datetime.timedelta(days=10), places=10, agenda=agenda)
|
|
event.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
resp = resp.click('Delete')
|
|
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)
|
|
resp = resp.click('Delete')
|
|
assert 'This cannot be removed' in resp.text
|
|
|
|
booking.cancellation_datetime = now()
|
|
booking.save()
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
resp = resp.click('Delete')
|
|
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.
|
|
booking.cancellation_datetime = None
|
|
booking.save()
|
|
resp = resp.form.submit(status=403)
|
|
|
|
|
|
def test_delete_agenda_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert 'Options' in resp.text
|
|
assert 'Delete' not in resp.text
|
|
resp = app.get('/manage/agendas/%s/delete' % agenda.id, status=403)
|
|
|
|
|
|
def test_delete_busy_desk(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar', kind='meetings')
|
|
agenda.save()
|
|
desk_a = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
desk_b = Desk.objects.create(agenda=agenda, label='Desk B')
|
|
|
|
event = Event(start_datetime=now() + datetime.timedelta(days=10), places=10, agenda=agenda, desk=desk_a)
|
|
event.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
desk_page = resp.click('Desk A')
|
|
desk_delete_page = desk_page.click('Delete')
|
|
assert 'Are you sure you want to delete this?' in desk_delete_page.text
|
|
# make sure the deleting is not disabled
|
|
assert 'disabled' not in desk_delete_page.text
|
|
|
|
booking = Booking(event=event)
|
|
booking.save()
|
|
|
|
resp = desk_page.click('Delete')
|
|
assert 'This cannot be removed' in resp.text
|
|
# the button is disabled
|
|
assert 'disabled' in resp.text
|
|
app.post('/manage/desks/%s/delete' % desk_a.pk, status=403)
|
|
|
|
|
|
def test_add_event(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.maximal_booking_delay = 0
|
|
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.text
|
|
year = now().year + 1
|
|
resp = resp.click('New Event')
|
|
resp.form['start_datetime_0'] = '%s-02-15' % year
|
|
resp.form['start_datetime_1'] = '17:00'
|
|
resp.form['places'] = 10
|
|
resp = resp.form.submit()
|
|
resp = resp.follow()
|
|
event = Event.objects.get(places=10)
|
|
assert event.publication_date is None
|
|
assert "This agenda doesn't have any event yet." not in resp.text
|
|
assert '/manage/agendas/%s/events/%s/' % (agenda.id, event.id) in resp.text
|
|
assert ('Feb. 15, %s, 5 p.m.' % year) 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
|
|
assert resp_datetimes.json['data'][0]['datetime'] == '%s-02-15 17:00:00' % year
|
|
|
|
# add with a description
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click('New Event')
|
|
resp.form['start_datetime_0'] = '%s-02-15' % year
|
|
resp.form['start_datetime_1'] = '18:00'
|
|
resp.form['publication_date'] = '2020-05-11'
|
|
resp.form['places'] = 11
|
|
resp.form['description'] = 'A description'
|
|
resp = resp.form.submit()
|
|
resp = resp.follow()
|
|
event = Event.objects.get(places=11)
|
|
assert event.description == 'A description'
|
|
assert event.publication_date == datetime.date(2020, 5, 11)
|
|
|
|
# add with errors in datetime parts
|
|
for parts in (
|
|
('', ''),
|
|
('invalid', ''),
|
|
('', 'invalid'),
|
|
('2019-02-24', 'invalid'),
|
|
('invalid', '17:00'),
|
|
):
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click('New Event')
|
|
resp.form['start_datetime_0'] = parts[0]
|
|
resp.form['start_datetime_1'] = parts[1]
|
|
resp.form['places'] = 10
|
|
resp = resp.form.submit()
|
|
assert (
|
|
resp.text.count('Enter a valid date')
|
|
or resp.text.count('Enter a valid time') == 1
|
|
or resp.text.count('This field is required.') == 1
|
|
)
|
|
|
|
|
|
def test_add_event_on_missing_agenda(app, admin_user):
|
|
app = login(app)
|
|
app.get('/manage/agendas/%s/add-event' % '999', status=404)
|
|
|
|
|
|
def test_add_event_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/' % agenda.id, status=302)
|
|
app.get('/manage/agendas/%s/add-event' % agenda.id, status=403)
|
|
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert '<h2>Settings' in resp.text
|
|
resp = resp.click('New Event')
|
|
resp.form['start_datetime_0'] = '2016-02-15'
|
|
resp.form['start_datetime_1'] = '17:00'
|
|
resp.form['places'] = 10
|
|
resp = resp.form.submit()
|
|
resp = resp.follow()
|
|
event = Event.objects.get(places=10)
|
|
assert "This agenda doesn't have any event yet." not in resp.text
|
|
assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
|
|
assert 'Feb. 15, 2016, 5 p.m.' in resp.text
|
|
assert event.duration is None
|
|
assert event.end_datetime is None
|
|
|
|
resp = resp.click('New Event')
|
|
resp.form['start_datetime_0'] = '2016-02-15'
|
|
resp.form['start_datetime_1'] = '17:00'
|
|
resp.form['duration'] = 45
|
|
resp.form['places'] = 12
|
|
resp = resp.form.submit()
|
|
resp = resp.follow()
|
|
event = Event.objects.get(places=12)
|
|
assert event.duration == 45
|
|
assert event.end_datetime == event.start_datetime + datetime.timedelta(minutes=45)
|
|
|
|
|
|
def test_edit_event(settings, app, admin_user):
|
|
settings.LANGUAGE_CODE = 'fr-fr' # check date initial value format
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=20, agenda=agenda)
|
|
event.save()
|
|
assert event.duration is None
|
|
assert event.end_datetime is None
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
|
|
assert resp.form['start_datetime_0'].value == '2016-02-15'
|
|
assert resp.form['start_datetime_1'].value == '17:00'
|
|
assert resp.form['publication_date'].value == ''
|
|
assert resp.form['duration'].value == ''
|
|
resp.form['start_datetime_0'] = '2016-02-16'
|
|
resp.form['start_datetime_1'] = '17:00'
|
|
resp.form['publication_date'] = '2020-05-11'
|
|
resp.form['duration'].value = 45
|
|
resp.form['places'] = 20
|
|
resp = resp.form.submit()
|
|
settings.LANGUAGE_CODE = 'en'
|
|
resp = resp.follow()
|
|
assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
|
|
assert 'Feb. 16, 2016, 5 p.m.' in resp.text
|
|
event.refresh_from_db()
|
|
assert event.places == 20
|
|
assert event.publication_date == datetime.date(2020, 5, 11)
|
|
assert event.duration == 45
|
|
assert event.end_datetime == event.start_datetime + datetime.timedelta(minutes=45)
|
|
|
|
|
|
def test_edit_missing_event(app, admin_user):
|
|
app = login(app)
|
|
app.get('/manage/agendas/999/', status=404)
|
|
|
|
|
|
def test_edit_event_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
event = Event.objects.create(
|
|
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
|
|
places=20,
|
|
agenda=agenda,
|
|
publication_date=datetime.date(2020, 5, 11),
|
|
)
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id), status=403)
|
|
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click('Feb. 15, 2016, 5 p.m.')
|
|
assert resp.form['start_datetime_0'].value == '2016-02-15'
|
|
assert resp.form['start_datetime_1'].value == '17:00'
|
|
assert resp.form['publication_date'].value == '2020-05-11'
|
|
resp.form['start_datetime_0'] = '2016-02-16'
|
|
resp.form['start_datetime_1'] = '17:00'
|
|
resp.form['publication_date'] = ''
|
|
resp.form['places'] = 20
|
|
resp = resp.form.submit()
|
|
resp = resp.follow()
|
|
assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
|
|
assert 'Feb. 16, 2016, 5 p.m.' in resp.text
|
|
event.refresh_from_db()
|
|
assert event.publication_date is None
|
|
|
|
|
|
def test_booked_places(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
|
|
event.save()
|
|
Booking(event=event).save()
|
|
Booking(event=event).save()
|
|
app = login(app)
|
|
|
|
day = event.start_datetime
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month), status=200)
|
|
assert '8 remaining places' in resp.text
|
|
assert '(2/10 bookings)' in resp.text
|
|
|
|
|
|
def test_event_classes(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
|
|
event.save()
|
|
for i in range(2):
|
|
Booking(event=event).save()
|
|
app = login(app)
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
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.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.text
|
|
assert 'overbooking' in resp.text
|
|
|
|
|
|
def test_delete_event(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
|
|
event.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert Event.objects.count() == 0
|
|
|
|
|
|
def test_delete_busy_event(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
event = Event(start_datetime=now() + datetime.timedelta(days=10), places=10, agenda=agenda)
|
|
event.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
|
|
resp = resp.click('Delete')
|
|
assert 'Are you sure you want to delete this event?' in resp.text
|
|
|
|
booking = Booking(event=event)
|
|
booking.save()
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
|
|
resp = resp.click('Delete')
|
|
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='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
|
|
resp = resp.click('Delete')
|
|
assert 'Are you sure you want to delete this event?' in resp.text
|
|
|
|
# suddenly the booking is no longer cancelled, but the admin clicks on the
|
|
# delete button.
|
|
booking.cancellation_datetime = None
|
|
booking.save()
|
|
resp = resp.form.submit(status=403)
|
|
|
|
|
|
def test_delete_event_as_manager(app, manager_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
|
|
event.save()
|
|
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert Event.objects.count() == 0
|
|
|
|
|
|
def test_export_events(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/export-events' % agenda.id)
|
|
csv_export = resp.text
|
|
assert (
|
|
csv_export
|
|
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
|
|
)
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,00:30,10', 'text/csv')
|
|
resp.form.submit(status=302)
|
|
|
|
resp = app.get('/manage/agendas/%s/export-events' % agenda.id)
|
|
csv_export = resp.text
|
|
assert (
|
|
csv_export
|
|
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
|
|
'2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
|
|
)
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv',
|
|
b'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90',
|
|
'text/csv',
|
|
)
|
|
resp.form.submit(status=302)
|
|
resp = app.get('/manage/agendas/%s/export-events' % agenda.id)
|
|
csv_export = resp.text
|
|
assert (
|
|
csv_export
|
|
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
|
|
'2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
|
|
'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90\r\n'
|
|
)
|
|
|
|
|
|
def test_export_events_wrong_kind(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
|
|
app = login(app)
|
|
app.get('/manage/agendas/%s/export-events' % agenda.id, status=404)
|
|
agenda.kind = 'virtual'
|
|
agenda.save()
|
|
app.get('/manage/agendas/%s/export-events' % agenda.id, status=404)
|
|
|
|
|
|
def test_import_events(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
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.text.startswith('date,time')
|
|
|
|
resp.form['events_csv_file'] = Upload('t.csv', sample_csv_resp.content, 'text/csv')
|
|
resp = resp.form.submit(status=302)
|
|
assert Event.objects.count() == 1
|
|
Event.objects.all().delete()
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'xx', 'text/csv')
|
|
resp = resp.form.submit(status=200)
|
|
assert 'Invalid file format.' in resp.text
|
|
|
|
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.text
|
|
|
|
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.text
|
|
|
|
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.text
|
|
|
|
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.text
|
|
|
|
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.text
|
|
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,' + b'x' * 151, 'text/csv')
|
|
resp = resp.form.submit(status=200)
|
|
assert 'Ensure this value has at most 150' in resp.text
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
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))
|
|
assert Event.objects.all()[0].places == 10
|
|
Event.objects.all().delete()
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
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))
|
|
assert Event.objects.all()[0].places == 10
|
|
assert Event.objects.all()[0].waiting_list_places == 5
|
|
Event.objects.all().delete()
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
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 == u'éléphant'
|
|
Event.objects.all().delete()
|
|
|
|
# BOM
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv', codecs.BOM_UTF8 + 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 == 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', u'2016-09-16,18:00,10,5,éléphant'.encode('iso-8859-15'), '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 == 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', u'2016-09-16,18:00,10,5,éléphant'.encode('eucjp'), '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 == u'\x8f«±l\x8f«±phant' # eucjp interpreted as iso-8859-15
|
|
Event.objects.all().delete()
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
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()
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv',
|
|
'"date"\t"time"\t"etc."\n'
|
|
'"2016-09-16"\t"18:00"\t"10"\t"5"\t"éléphant"\n'
|
|
'"2016-09-19"\t"18:00"\t"10"'.encode('iso-8859-15'),
|
|
'text/csv',
|
|
)
|
|
resp = resp.form.submit(status=302)
|
|
assert Event.objects.count() == 2
|
|
Event.objects.all().delete()
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
|
|
resp = resp.form.submit(status=302)
|
|
assert Event.objects.count() == 1
|
|
event = Event.objects.latest('pk')
|
|
assert event.start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
|
|
assert event.places == 10
|
|
assert event.waiting_list_places == 5
|
|
assert event.label == 'label'
|
|
assert event.slug == 'slug'
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
|
|
resp = resp.form.submit(status=302)
|
|
assert Event.objects.count() == 1
|
|
event = Event.objects.latest('pk')
|
|
assert event.slug == 'slug'
|
|
|
|
# additional optional attributes
|
|
Event.objects.all().delete()
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug,,,,,', 'text/csv')
|
|
resp = resp.form.submit(status=302)
|
|
assert Event.objects.count() == 1
|
|
event = Event.objects.get()
|
|
assert event.description == ''
|
|
assert event.pricing == ''
|
|
assert event.url == ''
|
|
assert event.publication_date is None
|
|
assert event.duration is None
|
|
Event.objects.all().delete()
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv',
|
|
b'2016-09-16,18:00,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90',
|
|
'text/csv',
|
|
)
|
|
resp = resp.form.submit(status=302)
|
|
assert Event.objects.count() == 1
|
|
event = Event.objects.get()
|
|
assert event.description == 'description\nfoobar'
|
|
assert event.pricing == 'pricing'
|
|
assert event.url == 'url'
|
|
assert event.publication_date == datetime.date(2016, 10, 16)
|
|
assert event.duration == 90
|
|
|
|
# publication date bad format
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv', b'2016-09-16,18:00,10,5,label,slug,description,pricing,url,foobar', 'text/csv'
|
|
)
|
|
resp = resp.form.submit(status=200)
|
|
assert 'Invalid file format. (date format' in resp.text
|
|
|
|
# duration bad format
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv', b'2016-09-16,18:00,10,5,label,slug,description,pricing,url,2016-09-16,foobar', 'text/csv'
|
|
)
|
|
resp = resp.form.submit(status=200)
|
|
assert 'Invalid file format. (duration' in resp.text
|
|
|
|
# import events with empty slugs
|
|
Event.objects.all().delete()
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv',
|
|
b'2016-09-16,18:00,10,5,labela,labelb,,pricing,\n'
|
|
b'2016-09-17,18:00,10,5,labela,labelb-1,,pricing,\n'
|
|
b'2016-09-18,18:00,10,5,labela,labelb-2,,pricing,\n'
|
|
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n'
|
|
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n',
|
|
'text/csv',
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = resp.form.submit(status=302)
|
|
assert len(ctx.captured_queries) == 22
|
|
assert Event.objects.count() == 5
|
|
assert set(Event.objects.values_list('slug', flat=True)) == set(
|
|
['labelb', 'labelb-1', 'labelb-2', 'labelb-3', 'labelb-4']
|
|
)
|
|
|
|
# forbidden numerical slug
|
|
Event.objects.all().delete()
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,1234', 'text/csv')
|
|
resp = resp.form.submit(status=200)
|
|
assert 'value cannot be a number' in resp.text
|
|
assert 'Identifier:' in resp.text # verbose_name is shown, not field name ('slug:')
|
|
|
|
|
|
def test_import_events_existing_event(app, admin_user, freezer):
|
|
agenda = Agenda.objects.create(label=u'Foo bar')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv', b'2016-09-16,18:00,10,5,label,slug\n2016-09-16,18:00,10,5,label,slug\n', 'text/csv',
|
|
)
|
|
resp.form.submit(status=302)
|
|
assert agenda.event_set.count() == 1
|
|
event = Event.objects.latest('pk')
|
|
|
|
def check_import(date, time, with_alert):
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv', b'%s,%s,10,5,label,slug\n' % (date.encode(), time.encode()), 'text/csv',
|
|
)
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert agenda.event_set.count() == 1
|
|
event.refresh_from_db()
|
|
if with_alert:
|
|
assert (
|
|
'<li class="warning">Event "label" start date has changed. Do not forget to notify the registrants.</li>'
|
|
in resp.text
|
|
)
|
|
else:
|
|
assert (
|
|
'<li class="warning">Event "label" start date has changed. Do not forget to notify the registrants.</li>'
|
|
not in resp.text
|
|
)
|
|
assert event.start_datetime == make_aware(
|
|
datetime.datetime(*[int(v) for v in date.split('-')], *[int(v) for v in time.split(':')])
|
|
)
|
|
|
|
# change date or time
|
|
# event in the past, no alert, with or without booking
|
|
Booking.objects.create(
|
|
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30))
|
|
)
|
|
check_import('2016-09-15', '18:00', False) # change date
|
|
check_import('2016-09-15', '17:00', False) # change time
|
|
# available booking
|
|
Booking.objects.create(event=event)
|
|
check_import('2016-09-14', '17:00', False) # change date
|
|
check_import('2016-09-14', '16:00', False) # change time
|
|
|
|
# date in the future
|
|
freezer.move_to('2016-09-01')
|
|
# warn if available booking only
|
|
check_import('2016-09-13', '16:00', True) # change date
|
|
check_import('2016-09-13', '15:00', True) # change time
|
|
# no available booking
|
|
Booking.objects.all().delete()
|
|
Booking.objects.create(
|
|
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30))
|
|
)
|
|
check_import('2016-09-12', '15:00', False) # change date
|
|
check_import('2016-09-12', '14:00', False) # change time
|
|
|
|
# check there is a message per changed event
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv', b'2016-09-16,18:00,10,5,label,slug\n2016-09-16,19:00,10,5,label,other_slug\n', 'text/csv',
|
|
)
|
|
resp.form.submit(status=302)
|
|
assert agenda.event_set.count() == 2
|
|
event2 = Event.objects.latest('pk')
|
|
Booking.objects.create(event=event)
|
|
Booking.objects.create(event=event2)
|
|
|
|
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
|
|
resp.form['events_csv_file'] = Upload(
|
|
't.csv',
|
|
b'2016-09-17,18:00,10,5,label,slug\n2016-09-17,19:00,10,5,,other_slug\n2016-09-17,20:00,10,5,,other_slug\n',
|
|
'text/csv',
|
|
)
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert agenda.event_set.count() == 2
|
|
assert (
|
|
resp.text.count(
|
|
'Event "label" start date has changed. Do not forget to notify the registrants.'
|
|
)
|
|
== 1
|
|
)
|
|
assert (
|
|
resp.text.count(
|
|
'Event "other_slug" start date has changed. Do not forget to notify the registrants.'
|
|
)
|
|
== 1
|
|
)
|
|
|
|
|
|
def test_import_events_wrong_kind(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
|
|
app = login(app)
|
|
app.get('/manage/agendas/%s/import-events' % agenda.id, status=404)
|
|
agenda.kind = 'virtual'
|
|
agenda.save()
|
|
app.get('/manage/agendas/%s/import-events' % agenda.id, status=404)
|
|
|
|
|
|
def test_add_meetings_agenda(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp.form['kind'] = 'meetings'
|
|
resp = resp.form.submit()
|
|
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.text
|
|
assert '<h2>Settings' in resp.text
|
|
assert 'Meeting Types' in resp.text
|
|
agenda = Agenda.objects.get(label='Foo bar')
|
|
assert agenda.kind == 'meetings'
|
|
|
|
|
|
def test_meetings_agenda_add_meeting_type(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar', kind='meetings')
|
|
agenda.save()
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
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'
|
|
assert 'deleted' not in resp.form.fields
|
|
resp = resp.form.submit()
|
|
meeeting_type = MeetingType.objects.get(agenda=agenda)
|
|
assert meeeting_type.label == 'Blah'
|
|
assert meeeting_type.duration == 60
|
|
assert meeeting_type.deleted is False
|
|
resp = resp.follow()
|
|
assert 'Blah' in resp.text
|
|
|
|
# and edit
|
|
resp = resp.click('Blah')
|
|
resp.form['duration'] = '30'
|
|
assert 'deleted' not in resp.form.fields
|
|
resp = resp.form.submit()
|
|
meeeting_type = MeetingType.objects.get(agenda=agenda)
|
|
assert meeeting_type.duration == 30
|
|
|
|
|
|
def test_meetings_agenda_delete_meeting_type(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar', kind='meetings')
|
|
agenda.save()
|
|
|
|
meeting_type = MeetingType(agenda=agenda, label='Blah')
|
|
meeting_type.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Blah')
|
|
resp = resp.click('Delete')
|
|
assert 'Are you sure you want to delete this?' in resp.text
|
|
assert 'disabled' not in resp.text
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
meeting_type.refresh_from_db()
|
|
assert meeting_type.deleted is True
|
|
assert '__deleted__' in meeting_type.slug
|
|
|
|
# meeting type not showing up anymore
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert 'Meeting Type Foo' not in resp.text
|
|
|
|
# it is possible to add a new meeting type with the same slug
|
|
new_meeting_type = MeetingType.objects.create(agenda=agenda, label='Blah')
|
|
assert new_meeting_type.slug == 'blah'
|
|
|
|
|
|
def test_meetings_agenda_add_time_period(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType.objects.create(agenda=agenda, label='Blah')
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Add a time period$')
|
|
resp.form['weekdays-2'].checked = True
|
|
resp.form['start_time'] = '10:00'
|
|
resp.form['end_time'] = '17:00'
|
|
resp = resp.form.submit()
|
|
assert TimePeriod.objects.get(desk=desk).weekday == 2
|
|
assert TimePeriod.objects.get(desk=desk).start_time.hour == 10
|
|
assert TimePeriod.objects.get(desk=desk).start_time.minute == 0
|
|
assert TimePeriod.objects.get(desk=desk).end_time.hour == 17
|
|
assert TimePeriod.objects.get(desk=desk).end_time.minute == 0
|
|
resp = resp.follow()
|
|
|
|
# add a second time period
|
|
resp = resp.click('Add a time period', index=0)
|
|
resp.form['weekdays-0'].checked = True
|
|
resp.form['start_time'] = '10:00'
|
|
resp.form['end_time'] = '13:00'
|
|
resp = resp.form.submit()
|
|
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.text.index('Monday') < resp.text.index('Wednesday')
|
|
|
|
# invert start and end
|
|
resp2 = resp.click('Add a time period', index=0)
|
|
resp2.form['weekdays-0'].checked = True
|
|
resp2.form['start_time'] = '13:00'
|
|
resp2.form['end_time'] = '10:00'
|
|
resp2 = resp2.form.submit()
|
|
assert 'End time must come after start time.' in resp2.text
|
|
|
|
# and edit
|
|
resp = resp.click(u'Wednesday / 10 a.m. → 5 p.m.')
|
|
assert 'Edit Time Period' in resp.text
|
|
resp.form['start_time'] = '9:00'
|
|
resp = resp.form.submit()
|
|
resp = resp.follow()
|
|
assert TimePeriod.objects.get(desk=desk, weekday=2).start_time.hour == 9
|
|
|
|
# and edit with inverted start/end
|
|
resp2 = resp.click(u'Wednesday / 9 a.m. → 5 p.m.')
|
|
resp2.form['start_time'] = '18:00'
|
|
resp2 = resp2.form.submit()
|
|
assert 'End time must come after start time.' in resp2.text
|
|
|
|
# and add same time periods on multiple days
|
|
resp = resp.click('Add a time period', index=0)
|
|
resp.form['weekdays-4'].checked = True
|
|
resp.form['weekdays-5'].checked = True
|
|
resp.form['start_time'] = '10:00'
|
|
resp.form['end_time'] = '13:00'
|
|
resp = resp.form.submit()
|
|
assert TimePeriod.objects.filter(desk=desk).count() == 4
|
|
|
|
|
|
def test_meetings_agenda_delete_time_period(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar', kind='meetings')
|
|
agenda.save()
|
|
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
time_period = TimePeriod(
|
|
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
time_period.save()
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
|
|
resp = resp.click('Wednesday')
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert TimePeriod.objects.count() == 0
|
|
|
|
|
|
def test_meetings_agenda_add_time_period_on_missing_desk(app, admin_user):
|
|
app = login(app)
|
|
agenda = Agenda(label=u'Foo bar', kind='meetings')
|
|
agenda.save()
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
app.get('/manage/agendas/1/desk/777/add-time-period', status=404)
|
|
|
|
|
|
def test_meetings_agenda_add_time_period_as_manager(app, manager_user):
|
|
agenda = Agenda(label='Foo bar', kind='meetings')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
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.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)
|
|
time_period = TimePeriod(
|
|
desk=desk, weekday=0, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
time_period.save()
|
|
resp = app.get('/manage/agendas/%d/' % agenda.id)
|
|
app.get('/manage/timeperiods/%d/edit' % time_period.id, status=403)
|
|
app.get('/manage/timeperiods/%d/delete' % time_period.id, status=403)
|
|
# grant edit right to manager
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
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)
|
|
|
|
|
|
def test_meetings_agenda_add_desk(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp.form['kind'] = 'meetings'
|
|
resp = resp.form.submit()
|
|
assert Desk.objects.count() == 1
|
|
assert str(Desk.objects.first()) == 'Desk 1'
|
|
agenda = Agenda.objects.get(slug='foo-bar')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('New Desk')
|
|
resp.form['label'] = 'Desk A'
|
|
resp = resp.form.submit().follow()
|
|
assert Desk.objects.count() == 2
|
|
desk = Desk.objects.latest('pk')
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
resp = resp.click('New Desk')
|
|
resp.form['label'] = 'Desk A'
|
|
resp = resp.form.submit().follow()
|
|
assert Desk.objects.count() == 3
|
|
assert Desk.objects.filter(slug='desk-a-1').count() == 1
|
|
assert 'Desk A' in resp.text
|
|
new_desk = Desk.objects.latest('pk')
|
|
assert new_desk.timeperiod_set.count() == 0
|
|
|
|
resp = resp.click('Desk A', index=1)
|
|
resp.form['label'] = 'Desk B'
|
|
resp = resp.form.submit().follow()
|
|
assert 'Desk A' in resp.text
|
|
assert 'Desk B' in resp.text
|
|
|
|
|
|
def test_meetings_agenda_add_desk_from_another(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
assert Desk.objects.count() == 1
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('New Desk')
|
|
resp.form['label'] = 'Desk B'
|
|
resp.form['copy_from'] = desk.pk
|
|
resp = resp.form.submit().follow()
|
|
assert Desk.objects.count() == 2
|
|
new_desk = Desk.objects.latest('pk')
|
|
assert new_desk.label == 'Desk B'
|
|
assert new_desk.timeperiod_set.count() == 1
|
|
|
|
|
|
def test_meetings_agenda_delete_desk(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp.form['kind'] = 'meetings'
|
|
resp = resp.form.submit()
|
|
assert Desk.objects.count() == 1
|
|
agenda = Agenda.objects.get(slug='foo-bar')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('New Desk')
|
|
resp.form['label'] = 'Desk A'
|
|
resp = resp.form.submit().follow()
|
|
assert Desk.objects.count() == 2
|
|
resp = resp.click('Desk A', index=0)
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert Desk.objects.count() == 1
|
|
|
|
|
|
def test_meetings_agenda_add_time_period_exception(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType.objects.create(agenda=agenda, label='Blah')
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Add a time period exception')
|
|
today = datetime.datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
tomorrow = make_aware(today + datetime.timedelta(days=1))
|
|
dt_format = '%Y-%m-%d %H:%M'
|
|
resp.form['label'] = 'Exception 1'
|
|
resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
|
|
resp.form['start_datetime_1'] = '08:00'
|
|
resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
|
|
resp.form['end_datetime_1'] = '16:00'
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 1
|
|
time_period_exception = TimePeriodException.objects.first()
|
|
assert localtime(time_period_exception.start_datetime).strftime(dt_format) == tomorrow.replace(
|
|
hour=8
|
|
).strftime(dt_format)
|
|
assert localtime(time_period_exception.end_datetime).strftime(dt_format) == tomorrow.replace(
|
|
hour=16
|
|
).strftime(dt_format)
|
|
# add an exception beyond 2 weeks and make sure it isn't listed
|
|
resp = resp.click('Add a time period exception', index=1)
|
|
future = tomorrow + datetime.timedelta(days=15)
|
|
resp.form['label'] = 'Exception 2'
|
|
resp.form['start_datetime_0'] = future.strftime('%Y-%m-%d')
|
|
resp.form['start_datetime_1'] = '00:00'
|
|
resp.form['end_datetime_0'] = future.strftime('%Y-%m-%d')
|
|
resp.form['end_datetime_1'] = '16:00'
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 2
|
|
assert 'Exception 1' in resp.text
|
|
assert 'Exception 2' not in resp.text
|
|
resp = resp.click(href="/manage/time-period-exceptions/%d/exception-extract-list" % desk.pk)
|
|
assert 'Exception 1' in resp.text
|
|
assert 'Exception 2' in resp.text
|
|
|
|
# add global time exception
|
|
# only one desk: no option to apply to all desks
|
|
resp = app.get('/manage/agendas/%s/desk/%s/add-time-period-exception' % (agenda.pk, desk.pk))
|
|
assert 'all_desks' not in resp.context['form'].fields
|
|
# more than one desk
|
|
agenda2 = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
Desk.objects.create(agenda=agenda2, label='Other Desk') # check exception is not created for this one
|
|
desk2 = Desk.objects.create(agenda=agenda, label='Desk B')
|
|
event = Event.objects.create(
|
|
agenda=agenda, places=1, desk=desk2, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 30))
|
|
)
|
|
Booking.objects.create(event=event)
|
|
resp = app.get('/manage/agendas/%s/desk/%s/add-time-period-exception' % (agenda.pk, desk.pk))
|
|
future = tomorrow + datetime.timedelta(days=35)
|
|
resp.form['label'] = 'Exception 3'
|
|
resp.form['start_datetime_0'] = '2017-05-22'
|
|
resp.form['start_datetime_1'] = '08:00'
|
|
resp.form['end_datetime_0'] = '2017-05-26'
|
|
resp.form['end_datetime_1'] = '17:30'
|
|
resp.form['all_desks'] = True
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 4
|
|
assert 'Exceptions added. Note: one or several bookings exists within this time slot.' in resp.text
|
|
|
|
exception = TimePeriodException.objects.first()
|
|
resp = app.get('/manage/time-period-exceptions/%s/edit' % exception.pk)
|
|
assert 'all_desks' not in resp.context['form'].fields
|
|
|
|
|
|
def test_meetings_agenda_add_time_period_exception_when_booking_exists(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
event = Event.objects.create(
|
|
agenda=agenda, places=1, desk=desk, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 30))
|
|
)
|
|
Booking.objects.create(event=event)
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Add a time period exception')
|
|
resp = resp.form.submit() # submit empty form
|
|
# fields should be marked with errors
|
|
assert resp.text.count('This field is required.') == 2
|
|
# try again with data in fields
|
|
resp.form['start_datetime_0'] = '2017-05-22'
|
|
resp.form['start_datetime_1'] = '08:00'
|
|
resp.form['end_datetime_0'] = '2017-05-26'
|
|
resp.form['end_datetime_1'] = '17:30'
|
|
resp = resp.form.submit().follow()
|
|
assert 'Exception added. Note: one or several bookings exists within this time slot.' in resp.text
|
|
assert TimePeriodException.objects.count() == 1
|
|
|
|
|
|
def test_meetings_agenda_add_time_period_exception_when_cancelled_booking_exists(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
event = Event.objects.create(
|
|
agenda=agenda, places=1, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 10, 30))
|
|
)
|
|
Booking.objects.create(
|
|
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30))
|
|
)
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Add a time period exception')
|
|
resp.form['start_datetime_0'] = '2017-05-22'
|
|
resp.form['start_datetime_1'] = '08:00'
|
|
resp.form['end_datetime_0'] = '2017-05-26'
|
|
resp.form['end_datetime_1'] = '17:30'
|
|
resp = resp.form.submit().follow()
|
|
assert 'Exception added. Note: 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():
|
|
form = TimePeriodExceptionForm(
|
|
data={
|
|
'start_datetime_0': '2017-05-26',
|
|
'start_datetime_1': '17:30',
|
|
'end_datetime_0': '2017-05-22',
|
|
'end_datetime_1': '08:00',
|
|
}
|
|
)
|
|
assert form.is_valid() is False
|
|
assert form.errors['end_datetime'] == ['End datetime must be greater than start datetime.']
|
|
|
|
# start_datetime is invalid
|
|
form = TimePeriodExceptionForm(
|
|
data={
|
|
'start_datetime_0': '2017-05-26',
|
|
'start_datetime_1': 'foo',
|
|
'end_datetime_0': '2017-05-22',
|
|
'end_datetime_1': '08:00',
|
|
}
|
|
)
|
|
assert form.is_valid() is False
|
|
|
|
# end_datetime is invalid
|
|
form = TimePeriodExceptionForm(
|
|
data={
|
|
'start_datetime_0': '2017-05-26',
|
|
'start_datetime_1': '17:30',
|
|
'end_datetime_0': 'bar',
|
|
'end_datetime_1': '08:00',
|
|
}
|
|
)
|
|
assert form.is_valid() is False
|
|
|
|
|
|
def test_meetings_agenda_delete_time_period_exception(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Add a time period exception')
|
|
today = datetime.datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
tomorrow = make_aware(today + datetime.timedelta(days=15))
|
|
dt_format = '%Y-%m-%d %H:%M'
|
|
resp.form['label'] = 'Exception 1'
|
|
resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
|
|
resp.form['start_datetime_1'] = '08:00'
|
|
resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
|
|
resp.form['end_datetime_1'] = '16:00'
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 1
|
|
time_period_exception = TimePeriodException.objects.first()
|
|
assert localtime(time_period_exception.start_datetime).strftime(dt_format) == tomorrow.replace(
|
|
hour=8
|
|
).strftime(dt_format)
|
|
assert localtime(time_period_exception.end_datetime).strftime(dt_format) == tomorrow.replace(
|
|
hour=16
|
|
).strftime(dt_format)
|
|
resp = resp.click(href='/manage/time-period-exceptions/%d/edit' % time_period_exception.id)
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 0
|
|
assert resp.request.url.endswith('/manage/agendas/%d/settings' % agenda.pk)
|
|
|
|
# stay on exception list
|
|
time_period_exception = TimePeriodException.objects.create(
|
|
label='Future Exception',
|
|
desk=desk,
|
|
start_datetime=now() + datetime.timedelta(days=1),
|
|
end_datetime=now() + datetime.timedelta(days=2),
|
|
)
|
|
resp = app.get('/manage/time-period-exceptions/%d/exception-list' % desk.pk)
|
|
resp = resp.click(href='/manage/time-period-exceptions/%d/delete' % time_period_exception.pk)
|
|
resp = resp.form.submit(
|
|
extra_environ={'HTTP_REFERER': str('/manage/time-period-exceptions/%d/exception-list' % desk.pk)}
|
|
).follow()
|
|
assert resp.request.url.endswith('/manage/time-period-exceptions/%d/exception-list' % desk.pk)
|
|
|
|
|
|
def test_exception_list(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
past_exception = TimePeriodException.objects.create(
|
|
label='Past Exception',
|
|
desk=desk,
|
|
start_datetime=now() - datetime.timedelta(days=2),
|
|
end_datetime=now() - datetime.timedelta(days=1),
|
|
)
|
|
current_exception = TimePeriodException.objects.create(
|
|
label='Current Exception',
|
|
desk=desk,
|
|
start_datetime=now() - datetime.timedelta(days=1),
|
|
end_datetime=now() + datetime.timedelta(days=1),
|
|
)
|
|
future_exception = TimePeriodException.objects.create(
|
|
label='Future Exception',
|
|
desk=desk,
|
|
start_datetime=now() + datetime.timedelta(days=1),
|
|
end_datetime=now() + datetime.timedelta(days=2),
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
assert '/manage/time-period-exceptions/%d/edit' % past_exception.pk not in resp.text
|
|
assert '/manage/time-period-exceptions/%d/edit' % current_exception.pk in resp.text
|
|
assert '/manage/time-period-exceptions/%d/edit' % future_exception.pk in resp.text
|
|
|
|
resp = resp.click(href="/manage/time-period-exceptions/%d/exception-extract-list" % desk.pk)
|
|
assert '/manage/time-period-exceptions/%d/edit' % past_exception.pk not in resp.text
|
|
assert '/manage/time-period-exceptions/%d/edit' % current_exception.pk in resp.text
|
|
assert '/manage/time-period-exceptions/%d/edit' % future_exception.pk in resp.text
|
|
|
|
resp = resp.click(href="/manage/time-period-exceptions/%d/exception-list" % desk.pk)
|
|
assert '/manage/time-period-exceptions/%d/edit' % past_exception.pk not in resp.text
|
|
assert '/manage/time-period-exceptions/%d/edit' % current_exception.pk in resp.text
|
|
assert '/manage/time-period-exceptions/%d/edit' % future_exception.pk in resp.text
|
|
|
|
|
|
def test_agenda_import_time_period_exception_from_ics(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Test Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Foo')
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
assert 'Manage exception sources' in resp.text
|
|
resp = resp.click('manage exceptions')
|
|
assert "To add new exceptions, you can upload a file or specify an address to a remote calendar." in resp
|
|
resp = resp.form.submit(status=200)
|
|
assert 'Please provide an ICS File or an URL.' in resp.text
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
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.text
|
|
ics_with_no_start_date = b"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
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.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.text
|
|
|
|
ics_with_exceptions = b"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_file'] = Upload('exceptions.ics', ics_with_exceptions, 'text/calendar')
|
|
resp = resp.form.submit(status=302)
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 1
|
|
assert TimePeriodExceptionSource.objects.filter(desk=desk).count() == 1
|
|
source = TimePeriodExceptionSource.objects.latest('pk')
|
|
exception = TimePeriodException.objects.latest('pk')
|
|
assert exception.source == source
|
|
assert source.ics_filename == 'exceptions.ics'
|
|
assert 'exceptions.ics' in source.ics_file.name
|
|
assert source.ics_url is None
|
|
resp = resp.follow()
|
|
assert 'An exception has been imported.' in resp.text
|
|
|
|
|
|
@pytest.mark.freeze_time('2017-12-01')
|
|
def test_agenda_import_time_period_exception_from_ics_recurrent(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Test Desk')
|
|
MeetingType(agenda=agenda, label='Foo').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
ics_with_recurrent_exceptions = b"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
RRULE:FREQ=YEARLY
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
resp.form['ics_file'] = Upload('exceptions.ics', ics_with_recurrent_exceptions, 'text/calendar')
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 2
|
|
|
|
|
|
@mock.patch('chrono.agendas.models.requests.get')
|
|
def test_agenda_import_time_period_exception_with_remote_ics(mocked_get, app, admin_user):
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar')
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
|
|
assert 'ics_file' in resp.form.fields
|
|
assert 'ics_url' in resp.form.fields
|
|
resp.form['ics_url'] = 'http://example.com/foo.ics'
|
|
mocked_response = mock.Mock()
|
|
mocked_response.text = """BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
mocked_get.return_value = mocked_response
|
|
resp = resp.form.submit(status=302)
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 1
|
|
exception = TimePeriodException.objects.get(desk=desk)
|
|
assert TimePeriodExceptionSource.objects.filter(desk=desk).count() == 1
|
|
source = TimePeriodExceptionSource.objects.latest('pk')
|
|
exception = TimePeriodException.objects.latest('pk')
|
|
assert exception.source == source
|
|
assert source.ics_filename is None
|
|
assert source.ics_file.name == ''
|
|
assert source.ics_url == 'http://example.com/foo.ics'
|
|
|
|
|
|
@mock.patch('chrono.agendas.models.requests.get')
|
|
def test_agenda_import_time_period_exception_with_remote_ics_no_events(mocked_get, app, admin_user):
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar')
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_url'] = 'http://example.com/foo.ics'
|
|
mocked_response = mock.Mock()
|
|
mocked_response.text = """BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
mocked_get.return_value = mocked_response
|
|
resp = resp.form.submit(status=302)
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 1
|
|
|
|
|
|
@mock.patch('chrono.agendas.models.requests.get')
|
|
def test_agenda_import_time_period_exception_from_remote_ics_with_connection_error(
|
|
mocked_get, app, admin_user
|
|
):
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar')
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
|
|
assert 'ics_file' in resp.form.fields
|
|
assert 'ics_url' in resp.form.fields
|
|
resp.form['ics_url'] = 'http://example.com/foo.ics'
|
|
mocked_response = mock.Mock()
|
|
mocked_get.return_value = mocked_response
|
|
|
|
def mocked_requests_connection_error(*args, **kwargs):
|
|
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 (http://example.com/foo.ics, 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):
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar')
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_url'] = 'http://example.com/foo.ics'
|
|
mocked_response = mock.Mock()
|
|
mocked_response.status_code = 403
|
|
mocked_get.return_value = mocked_response
|
|
|
|
def mocked_requests_http_forbidden_error(*args, **kwargs):
|
|
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://example.com/foo.ics, 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):
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar')
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_url'] = 'https://example.com/foo.ics'
|
|
mocked_response = mock.Mock()
|
|
mocked_get.return_value = mocked_response
|
|
|
|
def mocked_requests_http_ssl_error(*args, **kwargs):
|
|
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 (https://example.com/foo.ics, SSL error).' in resp.text
|
|
|
|
|
|
def test_meetings_agenda_delete_time_period_exception_source(app, admin_user, freezer):
|
|
freezer.move_to('2019-12-01')
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
login(app)
|
|
# import a source
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
ics_with_recurrent_exceptions = b"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
RRULE:FREQ=YEARLY
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
resp.form['ics_file'] = Upload('exceptions.ics', ics_with_recurrent_exceptions, 'text/calendar')
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 2
|
|
source1 = TimePeriodExceptionSource.objects.latest('pk')
|
|
assert source1.timeperiodexception_set.count() == 2
|
|
|
|
# import another one
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_file'] = Upload('exceptions.ics', ics_with_recurrent_exceptions, 'text/calendar')
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 4
|
|
source2 = TimePeriodExceptionSource.objects.latest('pk')
|
|
assert source2.timeperiodexception_set.count() == 2
|
|
|
|
# delete the second one
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp = resp.click(href='/manage/time-period-exceptions-source/%d/delete' % source2.pk)
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 2
|
|
assert source1.timeperiodexception_set.count() == 2
|
|
assert TimePeriodExceptionSource.objects.filter(pk=source2.pk).exists() is False
|
|
|
|
# delete the first one
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp = resp.click(href='/manage/time-period-exceptions-source/%d/delete' % source1.pk)
|
|
resp = resp.form.submit().follow()
|
|
assert TimePeriodException.objects.count() == 0
|
|
assert TimePeriodExceptionSource.objects.filter(pk=source1.pk).exists() is False
|
|
|
|
|
|
def test_meetings_agenda_replace_time_period_exception_source(app, admin_user, freezer):
|
|
freezer.move_to('2019-12-01')
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
ics_file_content = b"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
RRULE:FREQ=YEARLY
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
|
|
login(app)
|
|
# import a source from a file
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_file'] = Upload('exceptions.ics', ics_file_content, 'text/calendar')
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 2
|
|
source = TimePeriodExceptionSource.objects.latest('pk')
|
|
assert source.timeperiodexception_set.count() == 2
|
|
exceptions = list(source.timeperiodexception_set.order_by('pk'))
|
|
old_ics_file_path = source.ics_file.path
|
|
|
|
# replace the source
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp = resp.click(href='/manage/time-period-exceptions-source/%d/replace' % source.pk)
|
|
resp.form['ics_newfile'] = Upload('exceptions.ics', ics_file_content, 'text/calendar')
|
|
resp = resp.form.submit().follow()
|
|
source.refresh_from_db()
|
|
assert source.ics_file.path != old_ics_file_path
|
|
assert os.path.exists(old_ics_file_path) is False
|
|
assert TimePeriodException.objects.count() == 2
|
|
assert source.timeperiodexception_set.count() == 2
|
|
new_exceptions = list(source.timeperiodexception_set.order_by('pk'))
|
|
assert exceptions[0].pk != new_exceptions[0].pk
|
|
assert exceptions[1].pk != new_exceptions[1].pk
|
|
|
|
|
|
@mock.patch('chrono.agendas.models.requests.get')
|
|
def test_meetings_agenda_refresh_time_period_exception_source(mocked_get, app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
ics_url_content = """BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//foo.bar//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20180101
|
|
DTEND:20180101
|
|
SUMMARY:New Year's Eve
|
|
END:VEVENT
|
|
END:VCALENDAR"""
|
|
|
|
login(app)
|
|
# import a source from an url
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
resp.form['ics_url'] = 'http://example.com/foo.ics'
|
|
mocked_response = mock.Mock()
|
|
mocked_response.text = ics_url_content
|
|
mocked_get.return_value = mocked_response
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert TimePeriodException.objects.filter(desk=desk).count() == 1
|
|
source = TimePeriodExceptionSource.objects.latest('pk')
|
|
assert source.timeperiodexception_set.count() == 1
|
|
exceptions = list(source.timeperiodexception_set.order_by('pk'))
|
|
|
|
# refresh the source
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('manage exceptions')
|
|
mocked_response = mock.Mock()
|
|
mocked_response.text = ics_url_content
|
|
mocked_get.return_value = mocked_response
|
|
resp = resp.click(href='/manage/time-period-exceptions-source/%d/refresh' % source.pk)
|
|
assert TimePeriodException.objects.count() == 1
|
|
assert source.timeperiodexception_set.count() == 1
|
|
new_exceptions = list(source.timeperiodexception_set.order_by('pk'))
|
|
assert exceptions[0].pk != new_exceptions[0].pk
|
|
|
|
|
|
@override_settings(
|
|
EXCEPTIONS_SOURCES={'holidays': {'class': 'workalendar.europe.France', 'label': 'Holidays'},}
|
|
)
|
|
def test_meetings_agenda_time_period_exception_source_from_settings(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
assert TimePeriodException.objects.exists()
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
|
resp = resp.click('Settings')
|
|
resp = resp.click('manage exceptions')
|
|
assert 'Holidays' in resp.text
|
|
assert 'disabled' not in resp.text
|
|
assert 'refresh' not in resp.text
|
|
|
|
resp = resp.click('disable').follow()
|
|
assert not TimePeriodException.objects.exists()
|
|
|
|
resp = resp.click('manage exceptions')
|
|
assert 'Holidays' in resp.text
|
|
assert 'disabled' in resp.text
|
|
|
|
resp = resp.click('enable').follow()
|
|
assert TimePeriodException.objects.exists()
|
|
|
|
resp = resp.click('manage exceptions')
|
|
assert 'disabled' not in resp.text
|
|
|
|
|
|
def test_meetings_agenda_time_period_exception_source_try_disable_ics(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
source = TimePeriodExceptionSource.objects.create(desk=desk, ics_url='https://example.com/test.ics')
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
|
resp = resp.click('Settings')
|
|
resp = resp.click('manage exceptions')
|
|
assert 'test.ics' in resp.text
|
|
|
|
assert app.get('/manage/time-period-exceptions-source/%s/toggle' % source.pk, status=404)
|
|
|
|
|
|
@override_settings(
|
|
EXCEPTIONS_SOURCES={'holidays': {'class': 'workalendar.europe.France', 'label': 'Holidays'},}
|
|
)
|
|
def test_meetings_agenda_time_period_exception_source_external(app, admin_user, freezer):
|
|
freezer.move_to('2020-01-01')
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType(agenda=agenda, label='Blah').save()
|
|
TimePeriod.objects.create(
|
|
weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
new_year = desk.timeperiodexception_set.filter(label='New year').first()
|
|
remove_url = reverse('chrono-manager-time-period-exception-delete', kwargs={'pk': new_year.pk})
|
|
edit_url = reverse('chrono-manager-time-period-exception-edit', kwargs={'pk': new_year.pk})
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
|
|
resp = resp.click('Settings')
|
|
assert 'New year' in resp.text
|
|
assert not remove_url in resp.text and not edit_url in resp.text
|
|
|
|
resp = resp.click('see all')
|
|
assert 'New year' in resp.text
|
|
assert not remove_url in resp.text and not edit_url in resp.text
|
|
|
|
app.get(remove_url, status=404)
|
|
|
|
|
|
def test_agenda_day_view(app, admin_user, manager_user, api_user):
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
desk.save()
|
|
today = datetime.date.today()
|
|
|
|
meetingtype = MeetingType(agenda=agenda, label='Bar', duration=30)
|
|
meetingtype.save()
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
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/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'No opening hours this day.' not in resp.text
|
|
assert 'div class="booking' not 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/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('<tr') == 10 # 10->18 (included)
|
|
|
|
# check opening hours cells
|
|
assert '<div class="opening-hours"' in resp.text
|
|
assert 'style="height: 850%; top: 0%;"' in resp.text
|
|
|
|
# book some slots
|
|
app.reset()
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meetingtype.slug))
|
|
booking_url = resp.json['data'][0]['api']['fillslot_url']
|
|
booking_url2 = resp.json['data'][2]['api']['fillslot_url']
|
|
resp = app.post(booking_url)
|
|
resp = app.post_json(booking_url2, params={'label': 'foo', 'user': 'bar', 'url': 'http://baz/'})
|
|
|
|
app.reset()
|
|
login(app)
|
|
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.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)
|
|
meetingtype = MeetingType(agenda=agenda, label='Baz', duration=15)
|
|
meetingtype.save()
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
|
|
assert resp.text.count('div class="booking') == 2
|
|
assert 'hourspan-4' in resp.text # table CSS class
|
|
|
|
# cancel a booking
|
|
app.reset()
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
booking = Booking.objects.all()[0]
|
|
resp = app.post('/api/booking/%s/cancel/' % booking.id)
|
|
assert Booking.objects.filter(cancellation_datetime__isnull=False).count() == 1
|
|
|
|
app.reset()
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
|
|
assert resp.text.count('div class="booking') == 1
|
|
|
|
# wrong type
|
|
agenda2 = Agenda(label=u'Foo bar')
|
|
agenda2.save()
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda2.id, date.year, date.month, date.day), status=404)
|
|
|
|
# not enough permissions
|
|
agenda2.view_role = manager_user.groups.all()[0]
|
|
agenda2.save()
|
|
app.reset()
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=403)
|
|
|
|
# just enough permissions
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200)
|
|
|
|
# display exception
|
|
TimePeriodException.objects.create(
|
|
label='Exception for the afternoon',
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 13, 0)),
|
|
end_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 23, 0)),
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(
|
|
'/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200
|
|
)
|
|
assert len(ctx.captured_queries) == 14
|
|
# day is displaying rows from 10am to 6pm,
|
|
# opening hours, 10am to 1pm gives top: 300%
|
|
# rest of the day, 1pm to 6(+1)pm gives 600%
|
|
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
|
'class': 'exception-hours',
|
|
'style': 'height: 600%; top: 300%;',
|
|
}
|
|
assert resp.pyquery.find('.exception-hours span')[0].text == 'Exception for the afternoon'
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_day_view_late_meeting(app, admin_user, kind):
|
|
today = datetime.date.today()
|
|
if kind == 'meetings':
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
else:
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=real_agenda, label='Bar', duration=30)
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(23, 30)
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('<tr') == 15
|
|
assert '<th class="hour">11 p.m.</th>' in resp.text
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_invalid_day_view(app, admin_user, kind):
|
|
if kind == 'meetings':
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
Desk.objects.create(agenda=agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
else:
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=real_agenda, label='Bar', duration=30)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, 2018, 11, 31), status=302)
|
|
assert resp.location.endswith('2018/11/30/')
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_day_view_event_outside_timeperiod(app, admin_user, kind):
|
|
if kind == 'meetings':
|
|
today = datetime.date.today()
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
else:
|
|
today = datetime.date.today()
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='Bar', duration=30)
|
|
|
|
login(app)
|
|
|
|
# no time period - no events
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'No opening hours this day.' in resp.text
|
|
assert 'div class="booking' not in resp.text
|
|
|
|
# book some slots
|
|
for hour, minute in [(9, 0), (17, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=desk.agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(hour=hour, minute=minute),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
# no time period - events are displayed
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('div class="booking') == 2
|
|
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'No opening hours this day.' in resp.text
|
|
assert resp.text.count('div class="booking') == 0
|
|
|
|
# events outside time period
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(16, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('div class="booking') == 2
|
|
assert '<div class="opening-hours"' in resp.text
|
|
assert 'style="height: 600%; top: 100%;"' in resp.text
|
|
|
|
|
|
def test_agenda_events_month_view(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
today = datetime.date.today()
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
|
assert "This month doesn't have any event configured." in resp.text
|
|
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month))
|
|
|
|
# add event in a future month
|
|
event = Event.objects.create(
|
|
label='xyz', start_datetime=now() + datetime.timedelta(days=40), places=10, agenda=agenda
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
app.get(
|
|
'/manage/agendas/%s/%s/%s/' % (agenda.id, event.start_datetime.year, event.start_datetime.month)
|
|
)
|
|
assert len(ctx.captured_queries) == 6
|
|
|
|
# current month still doesn't have events
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert "This month doesn't have any event configured." in resp.text
|
|
|
|
|
|
def test_agenda_open_events_view(app, admin_user, manager_user):
|
|
agenda = Agenda.objects.create(
|
|
label='Events', kind='events', minimal_booking_delay=2, maximal_booking_delay=5
|
|
)
|
|
today = datetime.date.today()
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month))
|
|
assert 'Open events' in resp.text
|
|
|
|
resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk)
|
|
assert 'Month view' in resp.text
|
|
assert "This agenda doesn't have any open event configured." in resp.text
|
|
|
|
# create some events
|
|
# past event
|
|
Event.objects.create(
|
|
agenda=agenda, label='event A', start_datetime=now() - datetime.timedelta(days=1), places=42
|
|
)
|
|
# too late
|
|
Event.objects.create(
|
|
agenda=agenda, label='event B', start_datetime=now() + datetime.timedelta(days=1), places=42
|
|
)
|
|
# too soon
|
|
Event.objects.create(
|
|
agenda=agenda, label='event C', start_datetime=now() + datetime.timedelta(days=6), places=42
|
|
)
|
|
# in range
|
|
Event.objects.create(
|
|
agenda=agenda, label='event D', start_datetime=now() + datetime.timedelta(days=3), places=42
|
|
)
|
|
# publication date in future
|
|
Event.objects.create(
|
|
agenda=agenda,
|
|
label='event E',
|
|
start_datetime=now() + datetime.timedelta(days=3),
|
|
publication_date=today + datetime.timedelta(days=1),
|
|
places=42,
|
|
)
|
|
# publication date in past
|
|
Event.objects.create(
|
|
agenda=agenda,
|
|
label='event F',
|
|
start_datetime=now() + datetime.timedelta(days=3),
|
|
publication_date=today - datetime.timedelta(days=1),
|
|
places=42,
|
|
)
|
|
resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk)
|
|
assert 'event A' not in resp.text
|
|
assert 'event B' not in resp.text
|
|
assert 'event C' not in resp.text
|
|
assert 'event D' in resp.text
|
|
assert 'event E' not in resp.text
|
|
assert 'event F' in resp.text
|
|
|
|
# not enough permissions
|
|
app.reset()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/agendas/%s/events/open/' % agenda.pk, status=403)
|
|
|
|
# just enough permissions
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app.get('/manage/agendas/%s/events/open/' % agenda.pk)
|
|
|
|
# wrong kind
|
|
agenda.kind = 'meetings'
|
|
agenda.save()
|
|
app.get('/manage/agendas/%s/events/open/' % agenda.pk, status=404)
|
|
agenda.kind = 'virtual'
|
|
agenda.save()
|
|
app.get('/manage/agendas/%s/events/open/' % agenda.pk, status=404)
|
|
|
|
|
|
def test_agenda_month_view(app, admin_user, manager_user, api_user):
|
|
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
today = datetime.date.today()
|
|
|
|
meetingtype = MeetingType(agenda=agenda, label='passeport', duration=20)
|
|
meetingtype.save()
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'Month view' in resp.text
|
|
resp = resp.click('Month view')
|
|
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month))
|
|
|
|
assert 'Day view' in resp.text # date view link should be present
|
|
assert 'No opening hours this month.' in resp.text
|
|
|
|
today = datetime.date(2018, 11, 10) # fixed day
|
|
timeperiod_weekday = today.weekday()
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
timeperiod.save()
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert 'No opening hours this month.' not in resp.text
|
|
assert '<div class="booking' not in resp.text
|
|
first_month_day = today.replace(day=1)
|
|
last_month_day = today.replace(day=1, month=today.month + 1) - datetime.timedelta(days=1)
|
|
start_week_number = first_month_day.isocalendar()[1]
|
|
end_week_number = last_month_day.isocalendar()[1]
|
|
weeks_number = end_week_number - start_week_number + 1
|
|
assert resp.text.count('<tr') == 9 * weeks_number
|
|
|
|
# check opening hours cells
|
|
assert '<div class="opening-hours" style="height:800.0%;top:0.0%;width:97.0%;left:1.0%' in resp.text
|
|
|
|
# book some slots
|
|
app.reset()
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meetingtype.slug))
|
|
booking_url = resp.json['data'][0]['api']['fillslot_url']
|
|
booking_url2 = resp.json['data'][2]['api']['fillslot_url']
|
|
booking = app.post(booking_url)
|
|
booking_2 = app.post_json(booking_url2, params={'label': 'foo', 'user': 'bar', 'url': 'http://baz/'})
|
|
|
|
app.reset()
|
|
login(app)
|
|
date = Booking.objects.all()[0].event.start_datetime
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
|
|
assert resp.text.count('<div class="booking" style="left:1.0%;height:33.0%;') == 2 # booking cells
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk B')
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
timeperiod.save()
|
|
|
|
app.reset()
|
|
booking_3 = app.post(booking_url)
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
|
|
# count occurences of timeperiod weekday in current month
|
|
d = first_month_day
|
|
weekdays = 0
|
|
while d <= last_month_day:
|
|
if d.weekday() == timeperiod_weekday:
|
|
weekdays += 1
|
|
d += datetime.timedelta(days=1)
|
|
|
|
assert resp.text.count('<div class="opening-hours"') == 2 * weekdays
|
|
current_month = today.strftime('%Y-%m')
|
|
if current_month in booking_url or current_month in booking_url2:
|
|
assert resp.text.count('<div class="booking"') == 3
|
|
|
|
# cancel bookings
|
|
app.reset()
|
|
app.post(booking.json['api']['cancel_url'])
|
|
app.post(booking_2.json['api']['cancel_url'])
|
|
app.post(booking_3.json['api']['cancel_url'])
|
|
|
|
# make sure the are not
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert resp.text.count('<div class="booking"') == 0
|
|
|
|
# check December is correctly displayed
|
|
today = datetime.date(2018, 12, 10)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert 'No opening hours this month.' not in resp.text
|
|
|
|
# display exception
|
|
TimePeriodException.objects.create(
|
|
label='Exception for a December day',
|
|
desk=desk,
|
|
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)),
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert len(ctx.captured_queries) == 9
|
|
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
|
'class': 'exception-hours',
|
|
'style': 'height:800.0%;top:0.0%;width:48.0%;left:50.0%;',
|
|
'title': 'Exception for a December day',
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_month_view_weekend(app, admin_user, kind):
|
|
month, year = 1, 2019
|
|
monday = 0
|
|
if kind == 'meetings':
|
|
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
else:
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=monday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, year, month))
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' not in resp.text
|
|
# No Monday on first row since month starts a Tuesday
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 1
|
|
|
|
# When weekend is hidden, do not display an empty first week
|
|
month, year = 12, 2019 # month starts a Sunday
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, year, month))
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
|
|
|
month, year = 6, 2019 # month starts a Saturday
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, year, month))
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
|
|
|
saturday = 5
|
|
timeperiod_sat = TimePeriod.objects.create(
|
|
desk=desk, weekday=saturday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, year, month))
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' in resp.text
|
|
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 5
|
|
|
|
sunday = 6
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=sunday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, year, month))
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
timeperiod_sat.delete()
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, year, month))
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_month_view_dst_change(app, admin_user, kind):
|
|
if kind == 'meetings':
|
|
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='passeport', duration=20)
|
|
else:
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='passeport', duration=20)
|
|
|
|
for weekday in range(0, 7): # open all mornings
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=weekday, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
|
|
login(app)
|
|
for date in ('2019-10-01', '2019-10-31'):
|
|
with freezegun.freeze_time(date):
|
|
resp = app.get('/manage/agendas/%s/2019/10/' % agenda.id)
|
|
# check all days are correctly aligned
|
|
assert resp.text.count('height:300.0%;top:0.0%') == 31
|
|
|
|
# book some slots
|
|
for date_tuple in [(2019, 10, 2, 10, 0), (2019, 10, 29, 10, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=desk.agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(make_aware(datetime.datetime(*date_tuple))),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
# check booked slots are similarly aligned
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/2019/10/' % agenda.id)
|
|
assert resp.text.count('height:33.0%;top:100.0%;') == 2
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_month_view_januaries(app, admin_user, kind):
|
|
if kind == 'meetings':
|
|
agenda = Agenda.objects.create(label='Passports', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
MeetingType.objects.create(agenda=agenda, label='passport', duration=20)
|
|
else:
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
MeetingType.objects.create(agenda=real_agenda, label='passport', duration=20)
|
|
TimePeriod(desk=desk, weekday=2, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save()
|
|
|
|
for year in range(2020, 2030):
|
|
date = datetime.date(year, 1, 1)
|
|
with freezegun.freeze_time(date):
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/1/' % (agenda.id, date.year))
|
|
assert resp.text.count('<th></th>') in (4, 5)
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
|
def test_agenda_month_view_event_outside_timeperiod(app, admin_user, kind):
|
|
today = datetime.date.today()
|
|
if kind == 'meetings':
|
|
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
|
else:
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
|
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
|
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='passport', duration=20)
|
|
login(app)
|
|
|
|
# no time period - no events
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert 'No opening hours this month.' in resp.text
|
|
assert 'div class="booking' not in resp.text
|
|
|
|
# book some slots
|
|
middle_day = now().replace(day=15)
|
|
for hour, minute in [(9, 0), (17, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=desk.agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now().replace(day=middle_day.day - middle_day.weekday() + 2)).replace(
|
|
hour=hour, minute=minute
|
|
),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
# no time period - events are displayed
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 2
|
|
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert 'No opening hours this month.' in resp.text
|
|
assert resp.text.count('div class="booking') == 0
|
|
|
|
# events outside time period
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(16, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 2
|
|
assert '<div class="opening-hours" style="height:600.0%;top:100.0%;width:97.0%;left:1.0%' in resp.text
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' not in resp.text
|
|
|
|
# create an event on saturday
|
|
event = Event.objects.create(
|
|
agenda=desk.agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(
|
|
day=middle_day.day - middle_day.weekday() + 5, hour=10, minute=0
|
|
),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 3
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' in resp.text
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 0
|
|
# and a timeperiod
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=5, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 3
|
|
assert 'Sunday' not in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
# create an event on sunday
|
|
middle_day = now().replace(day=15)
|
|
event = Event.objects.create(
|
|
agenda=desk.agenda,
|
|
places=1,
|
|
desk=desk,
|
|
meeting_type=meetingtype,
|
|
start_datetime=localtime(now()).replace(
|
|
day=middle_day.day - middle_day.weekday() + 6, hour=10, minute=0
|
|
),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 4
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
# bookings are cancelled
|
|
Booking.objects.update(cancellation_datetime=now())
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 0
|
|
# and a timeperiod
|
|
Booking.objects.update(cancellation_datetime=None) # reset
|
|
TimePeriod.objects.create(
|
|
desk=desk, weekday=6, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.pk, today.year, today.month))
|
|
assert resp.text.count('div class="booking') == 4
|
|
assert 'Sunday' in resp.text
|
|
assert 'Saturday' in resp.text
|
|
|
|
|
|
def test_agenda_view_event(app, manager_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
event = Event.objects.create(
|
|
label='xyz',
|
|
start_datetime=make_aware(datetime.datetime(2019, 12, 22, 17, 0)),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
for i in range(8):
|
|
Booking.objects.create(event=event)
|
|
Booking.objects.create(event=event, cancellation_datetime=now())
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/2019/12/' % agenda.id, status=200)
|
|
resp = resp.click('xyz')
|
|
assert 'Bookings (8/10): 2 remaining places' in resp.text
|
|
assert 'Waiting' not in resp.text
|
|
assert 'This event is overbooked.' not in resp.text
|
|
assert 'This event is full.' not in resp.text
|
|
event.waiting_list_places = 5
|
|
event.save()
|
|
resp = app.get(resp.request.url)
|
|
assert 'Waiting List (0/5): 5 remaining places' in resp.text
|
|
|
|
booking = Booking.objects.order_by('pk')[0]
|
|
booking.in_waiting_list = True
|
|
booking.save()
|
|
booking = Booking.objects.order_by('pk')[1]
|
|
booking.in_waiting_list = True
|
|
booking.save()
|
|
resp = app.get(resp.request.url)
|
|
assert 'Waiting List (2/5): 3 remaining places' in resp.text
|
|
assert 'Bookings (6/10): 4 remaining places' in resp.text
|
|
assert list(resp.context['booked']) == list(Booking.objects.order_by('creation_datetime')[2:8])
|
|
assert list(resp.context['waiting']) == list(Booking.objects.order_by('creation_datetime')[0:2])
|
|
|
|
event.places = 5
|
|
event.save()
|
|
resp = app.get(resp.request.url)
|
|
assert 'This event is overbooked.' in resp.text
|
|
assert 'This event is full.' not in resp.text
|
|
|
|
event.places = 6
|
|
event.save()
|
|
resp = app.get(resp.request.url)
|
|
assert 'This event is overbooked.' not in resp.text
|
|
assert 'This event is full.' in resp.text
|
|
|
|
|
|
def test_agenda_view_edit_event(app, manager_user):
|
|
test_agenda_view_event(app, manager_user)
|
|
agenda = Agenda.objects.first()
|
|
resp = app.get('/manage/agendas/%s/2019/12/' % agenda.id, status=200)
|
|
resp = resp.click('xyz')
|
|
assert 'Options' not in resp.text
|
|
assert 'Delete' not in resp.text
|
|
|
|
agenda.edit_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
event_url = resp.request.url
|
|
resp = app.get(event_url)
|
|
assert 'Options' in resp.text
|
|
resp = resp.click('Options')
|
|
resp.form['start_datetime_0'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d')
|
|
resp.form['start_datetime_1'] = agenda.event_set.first().start_datetime.strftime('%H:%M')
|
|
resp = resp.form.submit(status=302).follow()
|
|
assert event_url == resp.request.url
|
|
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert Event.objects.count() == 0
|
|
|
|
|
|
def test_import_agenda_as_manager(app, manager_user):
|
|
# open /manage/ access to manager_user, and check agenda import is not
|
|
# allowed.
|
|
agenda = Agenda(label='Foo bar')
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/', status=200)
|
|
app.get('/manage/agendas/import/', status=403)
|
|
|
|
|
|
def test_import_agenda(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.save()
|
|
|
|
app = login(app)
|
|
with freezegun.freeze_time('2020-06-15'):
|
|
resp = app.get('/manage/agendas/%s/export' % agenda.id)
|
|
assert resp.headers['content-type'] == 'application/json'
|
|
assert resp.headers['content-disposition'] == 'attachment; filename="export_agenda_foo-bar_20200615.json"'
|
|
agenda_export = resp.text
|
|
|
|
# invalid json
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', b'garbage', 'application/json')
|
|
resp = resp.form.submit()
|
|
assert 'File is not in the expected JSON format.' in resp.text
|
|
|
|
# empty json
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', b'{}', 'application/json')
|
|
resp = resp.form.submit().follow()
|
|
assert 'No agendas were found.' in resp.text
|
|
|
|
# existing agenda
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', agenda_export.encode('utf-8'), 'application/json')
|
|
resp = resp.form.submit().follow()
|
|
assert 'No agenda created. An agenda has been updated.' in resp.text
|
|
assert Agenda.objects.count() == 1
|
|
|
|
# new agenda
|
|
Agenda.objects.all().delete()
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', agenda_export.encode('utf-8'), 'application/json')
|
|
resp = resp.form.submit().follow()
|
|
assert 'An agenda has been created. No agenda updated.' in resp.text
|
|
assert Agenda.objects.count() == 1
|
|
|
|
# multiple agendas
|
|
agendas = json.loads(agenda_export)
|
|
agendas['agendas'].append(copy.copy(agendas['agendas'][0]))
|
|
agendas['agendas'].append(copy.copy(agendas['agendas'][0]))
|
|
agendas['agendas'][1]['label'] = 'Foo bar 2'
|
|
agendas['agendas'][1]['slug'] = 'foo-bar-2'
|
|
agendas['agendas'][2]['label'] = 'Foo bar 3'
|
|
agendas['agendas'][2]['slug'] = 'foo-bar-3'
|
|
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', json.dumps(agendas).encode('utf-8'), 'application/json')
|
|
resp = resp.form.submit().follow()
|
|
assert '2 agendas have been created. An agenda has been updated.' in resp.text
|
|
assert Agenda.objects.count() == 3
|
|
|
|
Agenda.objects.all().delete()
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', json.dumps(agendas).encode('utf-8'), 'application/json')
|
|
resp = resp.form.submit().follow()
|
|
assert '3 agendas have been created. No agenda updated.' in resp.text
|
|
assert Agenda.objects.count() == 3
|
|
|
|
# reference to unknown group
|
|
agenda_export_dict = json.loads(force_text(agenda_export))
|
|
agenda_export_dict['agendas'][0]['permissions']['view'] = u'gé1'
|
|
agenda_export = json.dumps(agenda_export_dict).encode('utf-8')
|
|
Agenda.objects.all().delete()
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', agenda_export, 'application/json')
|
|
resp = resp.form.submit()
|
|
assert u'Missing roles: "gé1"' in resp.text
|
|
del agenda_export_dict['agendas'][0]['permissions']['view']
|
|
|
|
# missing field
|
|
del agenda_export_dict['agendas'][0]['kind']
|
|
agenda_export = json.dumps(agenda_export_dict).encode('utf-8')
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', agenda_export, 'application/json')
|
|
resp = resp.form.submit()
|
|
assert resp.context['form'].errors['agendas_json'] == ['Key "kind" is missing.']
|
|
|
|
|
|
def test_import_does_not_delete_bookings(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Foo', kind='meetings')
|
|
meeting_type = MeetingType.objects.create(agenda=agenda, label='Meeting Type', duration=30)
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk', slug='desk')
|
|
event = Event(start_datetime=now(), places=10, meeting_type=meeting_type, desk=desk, agenda=agenda)
|
|
event.save()
|
|
booking = Booking(event=event)
|
|
booking.save()
|
|
assert Booking.objects.count() == 1
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
resp = resp.click('Export')
|
|
assert resp.headers['content-type'] == 'application/json'
|
|
agenda_export = resp.text
|
|
|
|
# existing agenda
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('Import')
|
|
resp.form['agendas_json'] = Upload('export.json', agenda_export.encode('utf-8'), 'application/json')
|
|
resp = resp.form.submit().follow()
|
|
assert 'No agenda created. An agenda has been updated.' in resp.text
|
|
assert Agenda.objects.count() == 1
|
|
assert Booking.objects.count() == 1
|
|
|
|
|
|
def test_virtual_agenda_add(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/', status=200)
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Virtual agenda'
|
|
resp.form['kind'] = 'virtual'
|
|
resp = resp.form.submit()
|
|
agenda = Agenda.objects.get(label='Virtual agenda')
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert agenda.minimal_booking_delay is None
|
|
assert agenda.maximal_booking_delay is None
|
|
|
|
|
|
def test_virtual_agenda_day_view(app, admin_user, manager_user):
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda_1 = Agenda.objects.create(label='Real 1', kind='meetings')
|
|
real_agenda_2 = Agenda.objects.create(label='Real 2', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_1)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_2)
|
|
|
|
desk1 = Desk.objects.create(agenda=real_agenda_1, label='New Desk')
|
|
desk2 = Desk.objects.create(agenda=real_agenda_2, label='New Desk')
|
|
today = datetime.date.today()
|
|
|
|
meetingtype1 = MeetingType.objects.create(agenda=real_agenda_1, label='Bar', duration=30)
|
|
meetingtype2 = MeetingType.objects.create(agenda=real_agenda_2, label='Bar', duration=30)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'No opening hours this day.' in resp.text # no time pediod
|
|
|
|
timeperiod = TimePeriod.objects.create(
|
|
desk=desk1, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'No opening hours this day.' not in resp.text
|
|
assert 'div class="booking' not 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/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert resp.text.count('<tr') == 10 # 10->18 (included)
|
|
|
|
# check opening hours cells
|
|
assert '<div class="opening-hours"' in resp.text
|
|
assert 'style="height: 850%; top: 0%;"' in resp.text
|
|
|
|
# book some slots
|
|
for hour, minute in [(10, 30), (14, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=real_agenda_1,
|
|
places=1,
|
|
desk=desk1,
|
|
meeting_type=meetingtype1,
|
|
start_datetime=now().replace(hour=hour, minute=minute),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
event = Event.objects.create(
|
|
agenda=real_agenda_2,
|
|
places=1,
|
|
desk=desk2,
|
|
meeting_type=meetingtype2,
|
|
start_datetime=now().replace(hour=hour, minute=minute),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
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.text.count('div class="booking') == 4
|
|
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)
|
|
MeetingType.objects.create(agenda=real_agenda_1, label='Baz', duration=15)
|
|
MeetingType.objects.create(agenda=real_agenda_2, label='Baz', duration=15)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
|
|
assert resp.text.count('div class="booking') == 4
|
|
assert 'hourspan-4' in resp.text # table CSS class
|
|
|
|
# cancel a booking
|
|
booking = Booking.objects.first()
|
|
booking.cancel()
|
|
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
|
|
assert resp.text.count('div class="booking') == 3
|
|
|
|
# not enough permissions
|
|
app.reset()
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=403)
|
|
|
|
# just enough permissions
|
|
agenda.view_role = manager_user.groups.all()[0]
|
|
agenda.save()
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200)
|
|
|
|
# display exception
|
|
TimePeriodException.objects.create(
|
|
label='Exception for the afternoon',
|
|
desk=desk1,
|
|
start_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 13, 0)),
|
|
end_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 23, 0)),
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(
|
|
'/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200
|
|
)
|
|
assert len(ctx.captured_queries) == 15
|
|
# day is displaying rows from 10am to 6pm,
|
|
# opening hours, 10am to 1pm gives top: 300%
|
|
# rest of the day, 1pm to 6(+1)pm gives 600%
|
|
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
|
'class': 'exception-hours',
|
|
'style': 'height: 600%; top: 300%;',
|
|
}
|
|
assert resp.pyquery.find('.exception-hours span')[0].text == 'Exception for the afternoon'
|
|
|
|
|
|
def test_virtual_agenda_month_view(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
real_agenda_1 = Agenda.objects.create(label='Real 1', kind='meetings')
|
|
real_agenda_2 = Agenda.objects.create(label='Real 2', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_1)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_2)
|
|
|
|
desk1 = Desk.objects.create(agenda=real_agenda_1, label='New Desk')
|
|
desk2 = Desk.objects.create(agenda=real_agenda_2, label='New Desk')
|
|
today = datetime.date.today()
|
|
|
|
meetingtype1 = MeetingType.objects.create(agenda=real_agenda_1, label='Bar', duration=30)
|
|
meetingtype2 = MeetingType.objects.create(agenda=real_agenda_2, label='Bar', duration=30)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
assert 'Month view' in resp.text
|
|
resp = resp.click('Month view')
|
|
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month))
|
|
|
|
assert 'Day view' in resp.text # date view link should be present
|
|
assert 'No opening hours this month.' in resp.text
|
|
|
|
today = datetime.date(2018, 11, 10) # fixed day
|
|
timeperiod_weekday = today.weekday()
|
|
TimePeriod.objects.create(
|
|
desk=desk1, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert 'No opening hours this month.' not in resp.text
|
|
assert '<div class="booking' not in resp.text
|
|
first_month_day = today.replace(day=1)
|
|
last_month_day = today.replace(day=1, month=today.month + 1) - datetime.timedelta(days=1)
|
|
start_week_number = first_month_day.isocalendar()[1]
|
|
end_week_number = last_month_day.isocalendar()[1]
|
|
weeks_number = end_week_number - start_week_number + 1
|
|
assert resp.text.count('<tr') == 9 * weeks_number
|
|
|
|
# check opening hours cells
|
|
assert '<div class="opening-hours" style="height:800.0%;top:0.0%;width:48.0%;left:1.0%' in resp.text
|
|
|
|
# book some slots
|
|
for hour, minute in [(10, 30), (14, 0)]:
|
|
event = Event.objects.create(
|
|
agenda=real_agenda_1,
|
|
places=1,
|
|
desk=desk1,
|
|
meeting_type=meetingtype1,
|
|
start_datetime=now().replace(hour=hour, minute=minute),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
event = Event.objects.create(
|
|
agenda=real_agenda_2,
|
|
places=1,
|
|
desk=desk2,
|
|
meeting_type=meetingtype2,
|
|
start_datetime=now().replace(hour=hour, minute=minute),
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
date = Booking.objects.all()[0].event.start_datetime
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
|
|
assert resp.text.count('<div class="booking" style="left:1.0%;height:50.0%;') == 2 # booking cells
|
|
assert (
|
|
resp.text.count('<div class="booking" style="left:50.0%;height:50.0%;min-height:50.0%;') == 2
|
|
) # booking cells
|
|
|
|
# cancel a booking
|
|
booking = Booking.objects.first()
|
|
booking.cancel()
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, date.year, date.month))
|
|
assert resp.text.count('<div class="booking"') == 3
|
|
|
|
# check December is correctly displayed
|
|
today = datetime.date(2018, 12, 10)
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert 'No opening hours this month.' not in resp.text
|
|
|
|
# display exception
|
|
TimePeriodException.objects.create(
|
|
label='Exception for a December day',
|
|
desk=desk1,
|
|
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
|
|
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)),
|
|
)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
|
|
assert len(ctx.captured_queries) == 10
|
|
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
|
'class': 'exception-hours',
|
|
'style': 'height:800.0%;top:0.0%;width:48.0%;left:1.0%;',
|
|
'title': 'Exception for a December day',
|
|
}
|
|
|
|
|
|
def test_virtual_agenda_settings_empty(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert 'Include Agenda' in resp.text
|
|
assert 'Options' in resp.text
|
|
assert 'Export' in resp.text
|
|
assert 'Delete' in resp.text
|
|
assert 'Included Agendas' in resp.text
|
|
assert 'Add Excluded Period' in resp.text
|
|
assert "This virtual agenda doesn't include any agenda yet" in resp.text
|
|
# No meeting types yet
|
|
assert 'Meeting Types' not in resp.text
|
|
# No absence yet
|
|
assert 'Excluded Periods' not in resp.text
|
|
|
|
|
|
def test_virtual_agenda_settings(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
|
meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
|
|
MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
|
|
mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
|
|
TimePeriod.objects.create(
|
|
agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert "This virtual agenda doesn't include any agenda yet" not in resp.text
|
|
for real_agenda in [meeting_agenda_1, meeting_agenda_2]:
|
|
assert real_agenda.label in resp.text
|
|
assert '/manage/agendas/%s/settings' % real_agenda.pk in resp.text
|
|
|
|
assert 'Meeting Types' in resp.text
|
|
assert 'MT' in resp.text
|
|
assert 'mt' in resp.text
|
|
assert '10' in resp.text
|
|
|
|
assert 'Excluded Periods' in resp.text
|
|
assert 'Monday' in resp.text
|
|
|
|
# Error message when incompatible meeting types
|
|
mt2.delete()
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert "This virtual agenda doesn't have any meeting type." in resp.text
|
|
|
|
|
|
def test_virtual_agenda_settings_include(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
Agenda.objects.create(label='Event agenda', kind='events')
|
|
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
|
MeetingType.objects.create(label='MT', duration=30, agenda=meeting_agenda_1)
|
|
Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Include Agenda')
|
|
# Only meetings agenda are proposed (2) + 1 empty choice = 3
|
|
assert len(resp.form['real_agenda'].options) == 3
|
|
# Include a real agenda
|
|
resp.form['real_agenda'].value = meeting_agenda_1.pk
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert VirtualMember.objects.get(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
|
|
|
|
resp = resp.follow()
|
|
resp = resp.click('Include Agenda')
|
|
# The previously include agenda is not proposed any more
|
|
assert len(resp.form['real_agenda'].options) == 2
|
|
|
|
|
|
def test_virtual_agenda_settings_add_excluded_period(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Add Excluded Period')
|
|
|
|
resp.form['weekdays-0'].checked = True
|
|
resp.form['start_time'] = '10:00'
|
|
resp.form['end_time'] = '17:00'
|
|
resp = resp.form.submit()
|
|
tp = TimePeriod.objects.get(agenda=agenda)
|
|
assert tp.weekday == 0
|
|
assert tp.start_time.hour == 10
|
|
assert tp.start_time.minute == 0
|
|
assert tp.end_time.hour == 17
|
|
assert tp.end_time.minute == 0
|
|
|
|
resp = resp.follow()
|
|
assert u'Monday / 10 a.m. → 5 p.m.' in resp.text
|
|
|
|
|
|
def test_virtual_agenda_settings_edit_excluded_period(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
tp = TimePeriod.objects.create(
|
|
agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
url = '/manage/timeperiods/%s/edit' % tp.pk
|
|
resp = resp.click(href=url)
|
|
resp.form['start_time'] = '11:00'
|
|
resp = resp.form.submit()
|
|
tp = TimePeriod.objects.get(agenda=agenda)
|
|
assert tp.weekday == 0
|
|
assert tp.start_time.hour == 11
|
|
assert tp.start_time.minute == 0
|
|
assert tp.end_time.hour == 18
|
|
assert tp.end_time.minute == 0
|
|
|
|
|
|
def test_virtual_agenda_settings_delete_excluded_period(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
tp = TimePeriod.objects.create(
|
|
agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
url = '/manage/timeperiods/%s/delete' % tp.pk
|
|
resp = resp.click(href=url)
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
|
assert TimePeriod.objects.count() == 0
|
|
|
|
|
|
def test_virtual_agenda_settings_include_incompatible_agenda(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
|
MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
|
|
meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
|
|
app = login(app)
|
|
|
|
# refused because different slug
|
|
mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mtt', duration=10)
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert 'This agenda does not have the same meeting types provided by the virtual agenda.' in resp.text
|
|
assert 'Meeting type "MT" (10 minutes) (identifier: mt) does no exist.' in resp.text
|
|
assert meeting_agenda_2.virtual_agendas.count() == 0
|
|
mt.delete()
|
|
|
|
# refused because different duration
|
|
mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=15)
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert 'This agenda does not have the same meeting types provided by the virtual agenda.' in resp.text
|
|
assert 'Meeting type "MT" (10 minutes) (identifier: mt) does no exist.' in resp.text
|
|
assert meeting_agenda_2.virtual_agendas.count() == 0
|
|
mt.delete()
|
|
|
|
# refused because different label
|
|
mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MTT', slug='mt', duration=10)
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert 'This agenda does not have the same meeting types provided by the virtual agenda.' in resp.text
|
|
assert 'Meeting type "MT" (10 minutes) (identifier: mt) does no exist.' in resp.text
|
|
assert meeting_agenda_2.virtual_agendas.count() == 0
|
|
mt.delete()
|
|
|
|
# refused because has one more meeting type
|
|
mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
|
|
mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='AA', slug='aa', duration=30)
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert 'This agenda does not have the same meeting types provided by the virtual agenda.' in resp.text
|
|
assert 'Extra meeting type, "AA".' in resp.text
|
|
assert meeting_agenda_2.virtual_agendas.count() == 0
|
|
|
|
# ok because mt2 is marked as deleted
|
|
mt2.deleted = True
|
|
mt2.save()
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert meeting_agenda_2.virtual_agendas.count() == 1
|
|
VirtualMember.objects.filter(real_agenda=meeting_agenda_2).delete()
|
|
mt.delete()
|
|
mt2.delete()
|
|
|
|
# refused because has one less meeting type
|
|
mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
|
|
mt2 = MeetingType.objects.create(agenda=meeting_agenda_1, label='AA', slug='aa', duration=30)
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert 'This agenda does not have the same meeting types provided by the virtual agenda.' in resp.text
|
|
assert 'Meeting type "AA" (30 minutes) (identifier: aa) does no exist.' in resp.text
|
|
assert meeting_agenda_2.virtual_agendas.count() == 0
|
|
mt.delete()
|
|
mt2.delete()
|
|
|
|
# deleted meeting type is not checked
|
|
mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10, deleted=True)
|
|
resp = app.get('/manage/agendas/%s/add-virtual-member' % agenda.pk)
|
|
resp.form['real_agenda'].value = meeting_agenda_2.pk
|
|
resp = resp.form.submit()
|
|
assert 'This agenda does not have the same meeting types provided by the virtual agenda.' in resp.text
|
|
assert 'Meeting type "MT" (10 minutes) (identifier: mt) does no exist.' in resp.text
|
|
assert meeting_agenda_2.virtual_agendas.count() == 0
|
|
mt.delete()
|
|
|
|
|
|
def test_cant_delete_meetingtype_used_by_virtual_agenda(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
|
mt1 = MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
|
|
|
|
# ok because there is only one agenda in the virtual agenda
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % meeting_agenda_1.pk)
|
|
resp = resp.click('MT')
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert not meeting_agenda_1.iter_meetingtypes()
|
|
mt1.deleted = False
|
|
mt1.save()
|
|
|
|
meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
|
|
mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % meeting_agenda_2.pk)
|
|
resp = resp.click('MT')
|
|
resp = resp.click('Delete')
|
|
assert 'This cannot be removed as it used by a virtual agenda' in resp.text
|
|
assert 'disabled' in resp.text
|
|
resp = app.post('/manage/meetingtypes/%s/delete' % mt2.pk, status=403)
|
|
|
|
|
|
def test_cant_modify_meetingtype_used_by_virtual_agenda(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
|
mt1 = MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
|
|
app = login(app)
|
|
|
|
# ok because there is only one agenda in the virtual agenda
|
|
resp = app.get('/manage/meetingtypes/%s/edit' % mt1.pk)
|
|
resp.form['label'].value = 'MTT'
|
|
resp = resp.form.submit()
|
|
assert MeetingType.objects.get(agenda=meeting_agenda_1, label='MTT', slug='mt', duration=10)
|
|
|
|
meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
|
|
mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MTT', slug='mt', duration=10)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/meetingtypes/%s/edit' % mt2.pk)
|
|
resp.form['label'].value = 'Oho'
|
|
resp = resp.form.submit()
|
|
assert 'This meetingtype is used by a virtual agenda' in resp.text
|
|
mt = MeetingType.objects.get(pk=mt2.pk)
|
|
assert mt.label == 'MTT'
|
|
|
|
|
|
def test_cant_add_meetingtype_if_virtual_agenda(app, admin_user):
|
|
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
|
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
|
MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
|
|
app = login(app)
|
|
|
|
# ok because there is only one agenda in the virtual agenda
|
|
resp = app.get('/manage/agendas/%s/add-meeting-type' % meeting_agenda_1.pk)
|
|
resp.form['duration'].value = '12'
|
|
resp.form['label'].value = 'Oho'
|
|
resp = resp.form.submit()
|
|
assert MeetingType.objects.filter(agenda=meeting_agenda_1).count() == 2
|
|
MeetingType.objects.get(agenda=meeting_agenda_1, label='Oho').delete()
|
|
|
|
meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
|
|
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
|
|
MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/add-meeting-type' % meeting_agenda_1.pk)
|
|
resp.form['duration'].value = '12'
|
|
resp.form['label'].value = 'Oho'
|
|
resp = resp.form.submit()
|
|
assert 'Can't add a meetingtype to an agenda that is included in a virtual agenda.' in resp.text
|
|
assert MeetingType.objects.filter(agenda=meeting_agenda_1).count() == 1
|
|
|
|
|
|
def test_event_digit_slug(app, admin_user):
|
|
agenda = Agenda(label=u'Foo bar')
|
|
agenda.maximal_booking_delay = 0
|
|
agenda.save()
|
|
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
|
|
app = login(app)
|
|
|
|
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
|
|
resp.form['slug'] = 42
|
|
resp = resp.form.submit()
|
|
assert 'value cannot be a number' in resp.text
|
|
|
|
|
|
def test_duplicate_agenda(app, admin_user):
|
|
agenda = Agenda.objects.create(label=u'Foo Bar', slug='foo-bar', kind='meetings')
|
|
assert Agenda.objects.count() == 1
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = resp.click('Duplicate')
|
|
resp = resp.form.submit()
|
|
assert Agenda.objects.count() == 2
|
|
|
|
new_agenda = Agenda.objects.exclude(pk=agenda.pk).first()
|
|
assert resp.location == '/manage/agendas/%s/settings' % new_agenda.pk
|
|
assert new_agenda.pk != agenda.pk
|
|
|
|
resp = resp.follow()
|
|
assert 'copy-of-foo-bar' in resp.text
|
|
|
|
resp = resp.click('Duplicate')
|
|
resp.form['label'] = 'hop'
|
|
resp = resp.form.submit().follow()
|
|
assert 'hop' in resp.text
|
|
|
|
|
|
def test_booking_cancellation_meetings_agenda(app, admin_user, manager_user, api_user):
|
|
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
|
meetingtype = MeetingType(agenda=agenda, label='passeport', duration=20)
|
|
meetingtype.save()
|
|
today = datetime.date(2018, 11, 10) # fixed day
|
|
timeperiod_weekday = today.weekday()
|
|
timeperiod = TimePeriod(
|
|
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
|
)
|
|
timeperiod.save()
|
|
|
|
# book a slot
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
bookings_resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meetingtype.slug))
|
|
booking_url = bookings_resp.json['data'][0]['api']['fillslot_url']
|
|
booking_json = app.post_json(booking_url, params={'backoffice_url': 'http://example.org/'}).json
|
|
|
|
app.reset()
|
|
login(app)
|
|
booking = Booking.objects.get(pk=booking_json['booking_id'])
|
|
date = booking.event.start_datetime
|
|
month_view_url = '/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month)
|
|
resp = app.get(month_view_url)
|
|
assert len(resp.pyquery.find('div.booking a.cancel')) == 1 # cancel button is shown
|
|
|
|
resp = resp.click('Cancel')
|
|
# no callback url was provided at booking, warn user cancellation is forbidden
|
|
assert 'no callback url' in resp.text
|
|
assert not 'Proceed with cancellation' in resp.text
|
|
booking.delete()
|
|
|
|
# provide callback url this time
|
|
booking_url2 = bookings_resp.json['data'][1]['api']['fillslot_url']
|
|
booking_json2 = app.post_json(
|
|
booking_url2, params={'cancel_callback_url': 'http://example.org/jump/trigger/'}
|
|
).json
|
|
resp = app.get(month_view_url)
|
|
resp = resp.click('Cancel')
|
|
assert not 'no callback url' in resp.text
|
|
|
|
# a signed request is sent to callback_url
|
|
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
|
mock_response = mock.Mock(status_code=200)
|
|
mock_send.return_value = mock_response
|
|
resp = resp.form.submit()
|
|
url = mock_send.call_args[0][0].url
|
|
assert check_query(url.split('?', 1)[-1], 'chrono')
|
|
|
|
booking2 = Booking.objects.get(pk=booking_json2['booking_id'])
|
|
resp = resp.follow()
|
|
assert not resp.pyquery.find('div.booking')
|
|
assert booking2.cancellation_datetime
|
|
|
|
# request fails
|
|
booking_url3 = bookings_resp.json['data'][2]['api']['fillslot_url']
|
|
booking_json3 = app.post_json(
|
|
booking_url3, params={'cancel_callback_url': 'http://example.org/jump/trigger/'}
|
|
).json
|
|
booking3 = Booking.objects.get(pk=booking_json3['booking_id'])
|
|
|
|
def mocked_requests_connection_error(*args, **kwargs):
|
|
raise requests.exceptions.ConnectionError('unreachable')
|
|
|
|
resp = app.get(month_view_url)
|
|
resp = resp.click('Cancel')
|
|
assert resp.form['disable_trigger'].attrs['type'] == 'hidden'
|
|
|
|
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
|
mock_response = mock.Mock(status_code=200)
|
|
mock_send.return_value = mock_response
|
|
mock_send.side_effect = mocked_requests_connection_error
|
|
resp = resp.form.submit()
|
|
|
|
assert 'error' in resp.text
|
|
booking3.refresh_from_db()
|
|
assert not booking3.cancellation_datetime
|
|
|
|
# there is an option to force cancellation
|
|
resp.form['disable_trigger'] = True
|
|
resp = resp.form.submit()
|
|
booking3.refresh_from_db()
|
|
assert booking3.cancellation_datetime
|
|
|
|
# test day view
|
|
day_view_url = '/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day)
|
|
booking_url4 = bookings_resp.json['data'][3]['api']['fillslot_url']
|
|
booking_json4 = app.post(booking_url4).json
|
|
resp = app.get(day_view_url)
|
|
resp = resp.click('Cancel')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith(day_view_url)
|
|
|
|
booking4 = Booking.objects.get(pk=booking_json4['booking_id'])
|
|
assert booking4.cancellation_datetime
|
|
|
|
|
|
def test_booking_cancellation_events_agenda(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event(label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda)
|
|
event.save()
|
|
booking = Booking.objects.create(event=event)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.id, event.id))
|
|
assert 'Bookings (1/10)' in resp.text
|
|
|
|
resp = resp.click('Cancel', href='bookings/')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/agendas/%s/events/%s/' % (agenda.id, event.id))
|
|
|
|
booking.refresh_from_db()
|
|
assert booking.cancellation_datetime
|
|
|
|
resp = resp.follow()
|
|
assert 'Bookings (0/10)' in resp.text
|
|
|
|
|
|
def test_event_cancellation(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(
|
|
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
|
assert 'Bookings (0/10)' in resp.text
|
|
|
|
resp = resp.click('Cancel', href='/cancel')
|
|
assert 'related bookings' not in resp.text
|
|
|
|
Booking.objects.create(event=event)
|
|
Booking.objects.create(event=event)
|
|
|
|
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
|
assert 'Bookings (2/10)' in resp.text
|
|
|
|
resp = resp.click('Cancel', href='manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
|
|
assert '2 related bookings will also be cancelled.' in resp.text
|
|
|
|
resp = resp.form.submit().follow()
|
|
assert 'Cancelled' in resp.text
|
|
assert 'Bookings (0/10)' in resp.text
|
|
assert Booking.objects.filter(event=event, cancellation_datetime__isnull=False).count() == 2
|
|
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
|
assert '/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk) not in resp.text
|
|
|
|
|
|
def test_event_cancellation_error_report(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(
|
|
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
|
)
|
|
day = event.start_datetime
|
|
|
|
def mocked_requests_connection_error(*args, **kwargs):
|
|
raise requests.exceptions.ConnectionError('unreachable')
|
|
|
|
for i in range(5):
|
|
Booking.objects.create(event=event, cancel_callback_url='http://example.org/jump/trigger/')
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
|
resp = resp.click('Cancellation error reports')
|
|
assert 'No error report' in resp.text
|
|
|
|
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
|
|
resp = resp.form.submit().follow()
|
|
assert 'Cancellation in progress' in resp.text
|
|
|
|
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
|
mock_response = mock.Mock(status_code=200)
|
|
mock_send.return_value = mock_response
|
|
mock_send.side_effect = mocked_requests_connection_error
|
|
call_command('cancel_events')
|
|
|
|
event.refresh_from_db()
|
|
assert not event.cancelled and not event.cancellation_scheduled
|
|
assert not Booking.objects.filter(cancellation_datetime__isnull=False).exists()
|
|
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
|
assert 'Errors occured during cancellation of event "xyz".' in resp.text
|
|
|
|
# warning doesn't go away
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
|
assert 'Errors occured during cancellation of event "xyz".' in resp.text
|
|
|
|
resp = resp.click('Details')
|
|
assert resp.text.count('unreachable') == 5
|
|
|
|
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
|
assert not 'Errors occured during cancellation of event "xyz".' in resp.text
|
|
|
|
resp = resp.click('Cancellation error reports')
|
|
assert '(5 failures)' in resp.text
|
|
|
|
resp = resp.click(str(event))
|
|
resp = resp.click('Force cancellation')
|
|
resp = resp.form.submit().follow()
|
|
event.refresh_from_db()
|
|
assert event.cancelled and not event.cancellation_scheduled
|
|
assert Booking.objects.filter(cancellation_datetime__isnull=False).count() == 5
|
|
|
|
|
|
def test_event_cancellation_forbidden(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(
|
|
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
|
)
|
|
Booking.objects.create(event=event)
|
|
Booking.objects.create(event=event, backoffice_url='http://example.org/backoffice/xx/')
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
|
|
assert 'event has bookings with no callback url configured' in resp.text
|
|
assert 'Proceed with cancellation' not in resp.text
|
|
|
|
|
|
def test_event_booking_form_url(settings, app, admin_user):
|
|
settings.TEMPLATE_VARS = {'eservices_url': 'http://demarches/'}
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(
|
|
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
|
)
|
|
day = event.start_datetime
|
|
|
|
login(app)
|
|
|
|
assert agenda.get_booking_form_url() is None
|
|
resp = app.get('/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month))
|
|
assert 'Booking form' not in resp.text
|
|
resp = app.get('/manage/agendas/%d/events/open/' % agenda.pk)
|
|
assert 'Booking form' not in resp.text
|
|
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
|
assert 'Booking form' not in resp.text
|
|
|
|
agenda.booking_form_url = '{{ eservices_url }}backoffice/submission/inscription-aux-activites/'
|
|
agenda.save()
|
|
assert (
|
|
agenda.get_booking_form_url() == 'http://demarches/backoffice/submission/inscription-aux-activites/'
|
|
)
|
|
resp = app.get('/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month))
|
|
assert (
|
|
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s">Booking form</a>'
|
|
% (agenda.slug, event.slug)
|
|
in resp.text
|
|
)
|
|
resp = app.get('/manage/agendas/%d/events/open/' % agenda.pk)
|
|
assert (
|
|
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s">Booking form</a>'
|
|
% (agenda.slug, event.slug)
|
|
in resp.text
|
|
)
|
|
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
|
assert (
|
|
'<a href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s">Booking form</a>'
|
|
% (agenda.slug, event.slug)
|
|
in resp.text
|
|
)
|
|
|
|
|
|
def test_agenda_notifications(app, admin_user, managers_group):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
|
|
assert 'Notifications' in resp.text
|
|
assert 'Notifications are disabled' in resp.text
|
|
|
|
resp = resp.click('Configure', href='notifications')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
assert 'Notifications are disabled' in resp.text
|
|
|
|
resp = resp.click('Configure', href='notifications')
|
|
resp.form['cancelled_event'] = 'use-email-field'
|
|
resp = resp.form.submit().follow()
|
|
assert 'Notifications are disabled' in resp.text
|
|
|
|
agenda.view_role = managers_group
|
|
agenda.save()
|
|
|
|
resp = resp.click('Configure', href='notifications')
|
|
resp.form['cancelled_event_emails'] = 'hop@entrouvert.com, top@entrouvert.com'
|
|
resp.form['almost_full_event'] = 'edit-role'
|
|
option = resp.form['almost_full_event'].selectedIndex
|
|
assert resp.form['almost_full_event'].options[option][2] == 'Edit Role (undefined)'
|
|
resp.form['full_event'] = 'view-role'
|
|
option = resp.form['full_event'].selectedIndex
|
|
assert resp.form['full_event'].options[option][2] == 'View Role (Managers)'
|
|
resp = resp.form.submit().follow()
|
|
|
|
settings = agenda.notifications_settings
|
|
assert settings.almost_full_event == 'edit-role'
|
|
assert settings.full_event == 'view-role'
|
|
assert settings.cancelled_event == 'use-email-field'
|
|
assert settings.cancelled_event_emails == ['hop@entrouvert.com', 'top@entrouvert.com']
|
|
|
|
assert 'Cancelled event: hop@entrouvert.com, top@entrouvert.com will be notified' in resp.text
|
|
assert 'Almost full event (90%): Edit Role (undefined) will be notified' in resp.text
|
|
assert 'Full event: View Role (Managers) will be notified' in resp.text
|
|
|
|
agenda.edit_role = Group.objects.create(name='hop')
|
|
agenda.save()
|
|
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
assert 'Almost full event (90%): Edit Role (hop) will be notified' in resp.text
|
|
|
|
|
|
def test_agenda_notifications_no_old_events(app, admin_user, mailoutbox):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10, label='Old event')
|
|
event.cancelled = True
|
|
event.save()
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
|
|
resp = resp.click('Configure', href='notifications')
|
|
resp.form['cancelled_event'] = 'use-email-field'
|
|
resp.form['cancelled_event_emails'] = 'hop@entrouvert.com'
|
|
resp.form.submit()
|
|
|
|
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10, label='New event')
|
|
event.cancelled = True
|
|
event.save()
|
|
|
|
call_command('send_email_notifications')
|
|
# no notification is sent for old event
|
|
assert len(mailoutbox) == 1
|
|
assert 'New event' in mailoutbox[0].subject
|
|
|
|
|
|
def test_manager_reminders(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
|
|
assert 'Booking reminders' in resp.text
|
|
assert 'Reminders are disabled' in resp.text
|
|
|
|
resp = resp.click('Configure', href='reminder')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
assert 'Reminders are disabled' in resp.text
|
|
|
|
resp = resp.click('Configure', href='reminder')
|
|
assert not 'SMS' in resp.text
|
|
|
|
resp.form['days'] = 3
|
|
resp.form['send_email'] = True
|
|
resp.form['email_extra_info'] = 'test'
|
|
resp = resp.form.submit().follow()
|
|
|
|
assert 'Users will be reminded of their booking by email, 3 days in advance.' in resp.text
|
|
|
|
with override_settings(SMS_URL='https://passerelle.test.org/sms/send/', SMS_SENDER='EO'):
|
|
resp = resp.click('Configure', href='reminder')
|
|
resp.form['send_sms'] = True
|
|
resp = resp.form.submit().follow()
|
|
assert 'Users will be reminded of their booking both by email and by SMS, 3 days in advance.' in resp.text
|
|
|
|
agenda = Agenda.objects.create(label='Meetings', kind='meetings')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
assert 'Booking reminders' in resp.text
|
|
|
|
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
assert not 'Booking reminders' in resp.text
|
|
|
|
|
|
def test_manager_reminders_preview(app, admin_user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
AgendaReminderSettings.objects.create(
|
|
agenda=agenda,
|
|
days=1,
|
|
send_email=True,
|
|
email_extra_info='An ID will be required in order to process your form.',
|
|
send_sms=True,
|
|
sms_extra_info='Take ID card.',
|
|
)
|
|
|
|
login(app)
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
|
assert (
|
|
'Users will be reminded of their booking both by email and by SMS, one day in advance.' in resp.text
|
|
)
|
|
|
|
resp = resp.click('Preview email')
|
|
assert 'Users will receive the following email:' in resp.text
|
|
assert len(resp.pyquery.find('p.email-subject')) == 1
|
|
assert '<strong>Subject:</strong> Reminder for your booking tomorrow at 2:30 p.m.' in resp.text
|
|
assert 'You have a booking for event "{{ event_label }}", on Tuesday 2 June at 2:30 p.m..' in resp.text
|
|
assert 'An ID will be required' in resp.text
|
|
|
|
resp = resp.click('Return to settings')
|
|
resp = resp.click('Preview SMS')
|
|
assert 'Users will receive the following SMS:' in resp.text
|
|
assert (
|
|
'Reminder: you have a booking for event "{{ event_label }}", on 02/06 at 2:30 p.m.. Take ID card.'
|
|
in resp.text
|
|
)
|
|
|
|
|
|
def test_no_unavailability_calendar(app, admin_user):
|
|
app = login(app)
|
|
|
|
# empty unavailability calendars list
|
|
resp = app.get('/manage/')
|
|
resp = resp.click('Unavailability calendars')
|
|
assert "This site doesn't have any unavailability calendar yet" in resp.text
|
|
|
|
# on the agenda settings page, no unavailability calendar reference
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
|
assert 'unavailability calendar' not in resp.text
|
|
|
|
|
|
def test_add_unavailability_calendar(app, admin_user):
|
|
app = login(app)
|
|
resp = app.get('/manage/')
|
|
resp = resp.click('Unavailability calendars')
|
|
resp = resp.click('New')
|
|
resp.form['label'] = 'Foo bar'
|
|
resp = resp.form.submit()
|
|
unavailability_calendar = UnavailabilityCalendar.objects.latest('pk')
|
|
assert resp.location.endswith('/manage/unavailability-calendar/%s/' % unavailability_calendar.pk)
|
|
assert unavailability_calendar.label == 'Foo bar'
|
|
assert unavailability_calendar.slug == 'foo-bar'
|
|
resp = resp.follow()
|
|
assert 'This unavailability calendar is not used yet.' in resp.text
|
|
resp = app.get('/manage/unavailability-calendars/')
|
|
assert 'Foo bar' in resp.text
|
|
assert 'foo-bar' in resp.text
|
|
|
|
|
|
def test_used_unavailability_calendar(app, admin_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
|
agenda = Agenda.objects.create(label='Foo', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
|
|
app = login(app)
|
|
url = '/manage/unavailability-calendar/%s/' % unavailability_calendar.pk
|
|
resp = app.get(url)
|
|
assert 'This unavailability calendar is not used yet.' in resp.text
|
|
assert 'Foo' not in resp.text
|
|
|
|
desk.unavailability_calendars.add(unavailability_calendar)
|
|
resp = app.get(url)
|
|
assert 'This unavailability calendar is not used yet.' not in resp.text
|
|
assert 'Foo' in resp.text
|
|
|
|
|
|
def test_edit_unavailability_calendar(app, admin_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
|
|
app = login(app)
|
|
settings_url = '/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk
|
|
resp = app.get(settings_url)
|
|
resp = resp.click('Options')
|
|
resp.form['label'] = 'Bar'
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith(settings_url)
|
|
resp = resp.follow()
|
|
assert 'Bar' in resp.text
|
|
unavailability_calendar.refresh_from_db()
|
|
assert unavailability_calendar.label == 'Bar'
|
|
|
|
|
|
def test_delete_unavailability_calendar(app, admin_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
|
|
app = login(app)
|
|
resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
|
|
resp = resp.click('Delete')
|
|
resp = resp.form.submit()
|
|
assert resp.location.endswith('/manage/unavailability-calendars/')
|
|
resp = resp.follow()
|
|
assert 'Foo' not in resp.text
|
|
assert UnavailabilityCalendar.objects.count() == 0
|
|
|
|
|
|
def test_unavailability_calendar_add_time_period_exeptions(app, admin_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
|
|
app = login(app)
|
|
resp = app.get('/manage/unavailability-calendar/%s/' % unavailability_calendar.pk)
|
|
resp = resp.click('Settings')
|
|
assert 'There is no unavailabilities yet' in resp.text
|
|
resp = resp.click('Add Unavailability')
|
|
assert 'all_desks' not in resp.form.fields
|
|
today = datetime.datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
tomorrow = make_aware(today + datetime.timedelta(days=1))
|
|
resp.form['label'] = 'Exception 1'
|
|
resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
|
|
resp.form['start_datetime_1'] = '08:00'
|
|
resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d')
|
|
resp.form['end_datetime_1'] = '16:00'
|
|
resp = resp.form.submit().follow()
|
|
assert 'Exception 1' in resp.text
|
|
|
|
time_period_exception = TimePeriodException.objects.first()
|
|
assert time_period_exception.unavailability_calendar == unavailability_calendar
|
|
assert time_period_exception.desk is None
|
|
assert time_period_exception.label == 'Exception 1'
|
|
|
|
|
|
def test_unavailability_calendar_edit_time_period_exeptions(app, admin_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
|
|
time_period_exception = TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
label='Exception 1',
|
|
start_datetime=now() - datetime.timedelta(days=2),
|
|
end_datetime=now() - datetime.timedelta(days=1),
|
|
)
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
|
|
assert 'Exception 1' in resp.text
|
|
resp = resp.click(href='/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
|
|
assert 'all_desks' not in resp.form.fields
|
|
resp.form['label'] = 'Exception foo'
|
|
resp = resp.form.submit().follow()
|
|
assert 'Exception foo' in resp.text
|
|
time_period_exception.refresh_from_db()
|
|
assert 'Exception foo' == time_period_exception.label
|
|
|
|
# with an error
|
|
resp = app.get('/manage/time-period-exceptions/%s/edit' % time_period_exception.pk)
|
|
resp.form['start_datetime_0'] = now().strftime('%Y-%m-%d')
|
|
resp.form['end_datetime_0'] = now().strftime('%Y-%m-%d')
|
|
resp = resp.form.submit()
|
|
assert '<ul class="errorlist">' in resp.text
|
|
|
|
|
|
def test_unavailability_calendar_delete_time_period_exeptions(app, admin_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Foo')
|
|
time_period_exception = TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
label='Exception 1',
|
|
start_datetime=now() - datetime.timedelta(days=2),
|
|
end_datetime=now() - datetime.timedelta(days=1),
|
|
)
|
|
|
|
app = login(app)
|
|
resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
|
|
assert 'Exception 1' in resp.text
|
|
resp = resp.click(href='/manage/time-period-exceptions/%s/delete' % time_period_exception.pk)
|
|
resp = resp.form.submit().follow()
|
|
assert 'Exception foo' not in resp.text
|
|
assert unavailability_calendar.timeperiodexception_set.count() == 0
|
|
|
|
|
|
def test_activate_unavailability_calendar_in_desk(app, admin_user):
|
|
app = login(app)
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
exceptions_url = '/manage/agendas/desk/%s/import-exceptions-from-ics/' % desk.pk
|
|
resp = app.get(exceptions_url)
|
|
assert 'calendar' in resp.text
|
|
assert 'enable' in resp.text
|
|
resp = resp.click(
|
|
href='/manage/desk/%s/unavailability-calendar/%s/toogle/' % (desk.pk, unavailability_calendar.pk)
|
|
)
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = app.get(exceptions_url)
|
|
assert 'calendar' in resp.text
|
|
assert 'disable' in resp.text
|
|
assert desk.unavailability_calendars.get(pk=unavailability_calendar.pk)
|
|
|
|
|
|
def test_deactivate_unavailability_calendar_in_desk(app, admin_user):
|
|
app = login(app)
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
|
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
|
desk = Desk.objects.create(agenda=agenda, label='desk')
|
|
desk.unavailability_calendars.add(unavailability_calendar)
|
|
exceptions_url = '/manage/agendas/desk/%s/import-exceptions-from-ics/' % desk.pk
|
|
resp = app.get(exceptions_url)
|
|
assert 'calendar' in resp.text
|
|
assert 'disable' in resp.text
|
|
resp = resp.click(
|
|
href='/manage/desk/%s/unavailability-calendar/%s/toogle/' % (desk.pk, unavailability_calendar.pk)
|
|
)
|
|
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
|
|
resp = app.get(exceptions_url)
|
|
assert 'calendar' in resp.text
|
|
assert 'enable' in resp.text
|
|
assert desk.unavailability_calendars.count() == 0
|
|
|
|
|
|
def test_unavailability_calendar_homepage_permission(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
resp = app.get('/manage/', status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
resp = app.get('/manage/')
|
|
resp = resp.click('Unavailability calendars')
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
resp = app.get('/manage/')
|
|
resp = resp.click('Unavailability calendars')
|
|
|
|
|
|
def test_unavailability_calendar_list_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
app.get('/manage/unavailability-calendars/', status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
resp = app.get('/manage/unavailability-calendars/')
|
|
assert 'Calendar 1' in resp.text
|
|
assert 'New' not in resp.text
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
assert 'Calendar 1' in resp.text
|
|
assert 'New' not in resp.text
|
|
|
|
|
|
def test_unavailability_calendar_add_permissions(app, manager_user):
|
|
app = login(app, username='manager', password='manager')
|
|
url = '/manage/unavailability-calendar/add/'
|
|
app.get(url, status=403)
|
|
|
|
|
|
def test_unavailability_calendar_detail_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
detail_url = '/manage/unavailability-calendar/%s/' % unavailability_calendar.pk
|
|
resp = app.get(detail_url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
resp = app.get(detail_url)
|
|
assert 'Settings' not in resp.text
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
resp = app.get(detail_url)
|
|
assert 'Settings' in resp.text
|
|
|
|
|
|
def test_unavailability_calendar_edit_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
url = '/manage/unavailability-calendar/%s/edit/' % unavailability_calendar.pk
|
|
app.get(url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
app.get(url, status=403)
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
app.get(url)
|
|
|
|
|
|
def test_unavailability_calendar_delete_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
url = '/manage/unavailability-calendar/%s/delete/' % unavailability_calendar.pk
|
|
app.get(url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
app.get(url, status=403)
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
app.get(url, status=403)
|
|
|
|
|
|
def test_unavailability_calendar_settings_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
settings_url = '/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk
|
|
app.get(settings_url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
app.get(settings_url, status=403)
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
app.get(settings_url)
|
|
|
|
|
|
def test_unavailability_calendar_add_unavailability_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
app = login(app, username='manager', password='manager')
|
|
url = '/manage/unavailability-calendar/%s/add-unavailability' % unavailability_calendar.pk
|
|
app.get(url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
app.get(url, status=403)
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
app.get(url)
|
|
|
|
|
|
def test_unavailability_calendar_edit_unavailability_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
time_period_exception = TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
start_datetime=now() - datetime.timedelta(days=2),
|
|
end_datetime=now() - datetime.timedelta(days=1),
|
|
)
|
|
app = login(app, username='manager', password='manager')
|
|
url = '/manage/time-period-exceptions/%s/edit' % time_period_exception.pk
|
|
app.get(url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
app.get(url, status=403)
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
app.get(url)
|
|
|
|
|
|
def test_unavailability_calendar_delete_unavailability_permissions(app, manager_user):
|
|
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
|
time_period_exception = TimePeriodException.objects.create(
|
|
unavailability_calendar=unavailability_calendar,
|
|
start_datetime=now() - datetime.timedelta(days=2),
|
|
end_datetime=now() - datetime.timedelta(days=1),
|
|
)
|
|
app = login(app, username='manager', password='manager')
|
|
url = '/manage/time-period-exceptions/%s/delete' % time_period_exception.pk
|
|
app.get(url, status=403)
|
|
group = manager_user.groups.all()[0]
|
|
unavailability_calendar.view_role = group
|
|
unavailability_calendar.edit_role = None
|
|
unavailability_calendar.save()
|
|
app.get(url, status=403)
|
|
unavailability_calendar.view_role = None
|
|
unavailability_calendar.edit_role = group
|
|
unavailability_calendar.save()
|
|
app.get(url)
|