chrono/tests/manager/test_resource.py

1037 lines
42 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import datetime
import freezegun
import pytest
from django.db import connection
from django.test.utils import CaptureQueriesContext
from chrono.agendas.models import Agenda, Booking, Desk, Event, MeetingType, Resource, TimePeriod
from chrono.utils.timezone import localtime, make_aware, now
from tests.utils import login
pytestmark = pytest.mark.django_db
def test_list_resources_as_manager(app, manager_user):
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/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='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='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='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_redirect(app, admin_user):
resource = Resource.objects.create(label='Resource 1')
app = login(app)
# old month/week/days views
resp = app.get('/manage/resource/%s/2022/12/15/' % resource.pk, status=302)
assert resp.location.endswith('/manage/resource/%s/' % resource.pk)
resp = app.get('/manage/resource/%s/2022/12/' % resource.pk, status=302)
assert resp.location.endswith('/manage/resource/%s/' % resource.pk)
resp = app.get('/manage/resource/%s/2022/week/1/' % resource.pk, status=302)
assert resp.location.endswith('/manage/resource/%s/' % resource.pk)
def test_resource_day_view(app, admin_user):
today = now().date()
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)
app.get('/manage/resource/%s/day/%d/%d/%d/' % (resource.pk, today.year, 42, today.day), status=404)
resp = app.get('/manage/resource/%s/day/%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/day/%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/day/%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)
if hour == 10:
Booking.objects.create(event=event)
else:
Booking.objects.create(event=event, label='foo', user_last_name="bar's")
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/manage/resource/%s/day/%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 resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
assert 'foo - bar&#x27;s' in resp
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
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/resource/%s/day/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day))
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
assert '&lt;b&gt;bar&#x27;s&lt;/b&gt; Foo Bar' in resp
# 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/day/%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/day/%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/day/%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/day/%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/day/%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/day/%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/day/%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/day/%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='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/day/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day), status=403
)
@freezegun.freeze_time('2020-06-15')
def test_resource_week_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
app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, 72, today.day), status=404)
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert '<div class="booking' not in resp.text
assert resp.text.count('<tr') == 9
assert 'Week45' in resp.text
# 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)
if hour == 10:
Booking.objects.create(event=event)
else:
Booking.objects.create(event=event, label='foo', user_last_name="bar's")
today = datetime.date.today()
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day)
)
assert len(ctx.captured_queries) == 8
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
assert 'foo - bar&#x27;s' in resp
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
assert '&lt;b&gt;bar&#x27;s&lt;/b&gt; Foo Bar' in resp
# cancel booking
booking = Booking.objects.first()
booking.cancel()
# make sure the are not
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert resp.text.count('<div class="booking"') == 1
def test_resource_week_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)
)
login(app)
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, 2019, 1, 1))
assert 'Sunday' not in resp.text
assert 'Saturday' not in resp.text
# Month starts a Tuesday, but monday is displayed
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '31 December 2018 04 January 2019' in resp.text
resp = app.get(
'/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1)
) # month starts a Saturday
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '27 31 May 2019' in resp.text
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/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
assert 'Sunday' not in resp.text
assert 'Saturday' in resp.text
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '27 May 01 June 2019' in resp.text
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/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '27 May 02 June 2019' in resp.text
timeperiod_sat.delete()
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '27 May 02 June 2019' in resp.text
def test_resource_week_view_opening_not_even_an_hour(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=15)
TimePeriod.objects.create(
desk=desk, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(10, 30)
)
login(app)
today = datetime.date(2018, 11, 10) # fixed day
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert '<div class="booking' not in resp.text
assert resp.text.count('<tr') == 2
# book a slot
event = Event.objects.create(
agenda=agenda,
places=1,
desk=desk,
meeting_type=meetingtype,
start_datetime=datetime.datetime(today.year, today.month, today.day, hour=10, minute=0),
)
event.resources.add(resource)
Booking.objects.create(event=event)
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert resp.text.count('<div class="booking" style="height:25.0%;') == 1 # booking cell
def test_resource_week_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/week/%s/%s/%s/' % (resource.pk, 2019, 10, 2))
assert resp.text.count('height:50.0%;top:100.0%') == 1
def test_resource_week_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/week/%s/%s/%s/' % (resource.pk, year, 1, 1))
assert resp.text.count('<th class="weeknum">') == 1
def test_resource_week_view_event_outside_timeperiod(app, admin_user):
middle_day = now().replace(day=15)
middle_day = middle_day + datetime.timedelta(days=4 - middle_day.weekday())
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
assert 'No bookings this week.' 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(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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
assert resp.text.count('div class="booking') == 0
# create an event on saturday
Booking.objects.update(cancellation_datetime=None) # reset
middle_day = now().replace(day=15)
middle_day = middle_day + datetime.timedelta(days=5 - middle_day.weekday())
event = Event.objects.create(
agenda=agenda,
places=1,
desk=desk,
meeting_type=meetingtype,
start_datetime=localtime(now().replace(day=middle_day.day, hour=10, minute=0)),
)
event.resources.add(resource)
Booking.objects.create(event=event)
resp = app.get(
'/manage/resource/%s/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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)
middle_day = middle_day + datetime.timedelta(days=6 - middle_day.weekday())
event = Event.objects.create(
agenda=agenda,
places=1,
desk=desk,
meeting_type=meetingtype,
start_datetime=localtime(now().replace(day=middle_day.day, hour=10, minute=0)),
)
event.resources.add(resource)
Booking.objects.create(event=event)
resp = app.get(
'/manage/resource/%s/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
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/week/%s/%s/%s/'
% (resource.pk, middle_day.year, middle_day.month, middle_day.day)
)
assert resp.text.count('div class="booking') == 4
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
def test_week_view_resource_as_manager(app, manager_user):
agenda = Agenda.objects.create(label='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/week/%s/%s/%s/' % (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
app.get('/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, today.year, 42, today.day), status=404)
resp = app.get('/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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)
if hour == 10:
Booking.objects.create(event=event)
else:
Booking.objects.create(event=event, label='foo', user_last_name="bar's")
today = datetime.date.today()
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day)
)
assert len(ctx.captured_queries) == 8
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
assert 'foo - bar&#x27;s' in resp
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
assert '&lt;b&gt;bar&#x27;s&lt;/b&gt; Foo Bar' in resp
# cancel booking
booking = Booking.objects.first()
booking.cancel()
# make sure the are not
resp = app.get('/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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)
)
login(app)
resp = app.get('/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, 2019, 1, 1))
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
resp = app.get(
'/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, 2019, 12, 1)
) # month starts a Sunday
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
resp = app.get(
'/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, 2019, 6, 1)
) # month starts a Saturday
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/month/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
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/month/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
timeperiod_sat.delete()
resp = app.get('/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
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/month/%s/%s/%s/' % (resource.pk, 2019, 10, 1))
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/month/%s/%s/%s/' % (resource.pk, year, 1, 1))
assert resp.text.count('<th class="weeknum">') in (4, 5)
def test_resource_month_view_event_outside_timeperiod(app, admin_user):
today = now().date()
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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)).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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
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='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/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day), 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='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='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_agenda_resources(app, admin_user):
agenda = Agenda.objects.create(label='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='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#open:resources' % 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#open:resources' % 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
@pytest.mark.parametrize(
'view',
(
'/manage/resource/%(resource)s/day/%(year)d/%(month)d/%(day)d/',
'/manage/resource/%(resource)s/month/%(year)d/%(month)d/%(day)d/',
),
)
def test_agenda_day_month_view_backoffice_url_translation(
app, admin_user, manager_user, api_user, settings, view
):
today = now().date()
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.objects.create(
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(18, 30)
)
login(app)
url = view % {'resource': resource.id, 'year': today.year, 'month': today.month, 'day': today.day}
# 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, backoffice_url='publik://default/foo/')
resp = app.get(url)
assert 'http://example.org/foo/' in resp.text
def test_resource_access_permission(app, manager_user):
agenda = Agenda.objects.create(label='Foo Bar', kind='meetings')
resource = Resource.objects.create(label='Resource 1', agenda=agenda)
resource2 = Resource.objects.create(label='Resource 2')
agenda.resources.add(resource)
app = login(app, username='manager', password='manager')
assert app.get('/manage/resource/%s/' % resource.pk, status=403)
assert app.get('/manage/resource/%s/' % resource2.pk, status=403)
agenda.edit_role = manager_user.groups.all()[0]
agenda.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
resp = resp.click('Resource 1')
assert 'Edit' not in resp.text
assert 'Delete' not in resp.text
assert resp.click('Month')
assert resp.click('Week')
assert resp.click('Day')
assert app.get('/manage/resource/%s/' % resource2.pk, status=403)
@freezegun.freeze_time('2020-10-01')
def test_resource_today_button(app, admin_user):
agenda = Agenda.objects.create(label='Foo Bar', kind='meetings')
resource = Resource.objects.create(label='Resource 1', agenda=agenda)
today = datetime.date.today()
login(app)
resp = app.get('/manage/resource/%s/day/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert 'Today' in resp.pyquery('a.active').text()
resp = resp.click('Next day')
assert 'Today' not in resp.pyquery('a.active').text()
resp = resp.click('Today')
assert 'Today' in resp.pyquery('a.active').text()
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
assert 'Today' not in resp.pyquery('a.active').text()