chrono/tests/manager/test_event.py

3206 lines
130 KiB
Python

import codecs
import datetime
from unittest import mock
import pytest
import requests
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 webtest import Upload
from chrono.agendas.models import Agenda, Booking, Desk, Event, EventsType, Subscription
from chrono.utils.lingo import CheckType
from chrono.utils.timezone import localtime, make_aware, now
from tests.utils import login
pytestmark = pytest.mark.django_db
def test_add_event(app, admin_user):
events_type = EventsType.objects.create(
label='Foo', custom_fields=[{'varname': 'foo', 'label': 'Foo', 'field_type': 'text'}]
)
agenda = Agenda.objects.create(label='Foo bar', maximal_booking_delay=0, events_type=events_type)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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')
assert 'custom_field_foo' not in resp.context['form'].fields
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_datetime 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 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
)
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_add_recurring_event(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('New Event')
resp.form['start_datetime_0'] = '2021-06-01'
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp.form['frequency'] = 'unique' # not a recurring event
resp.form['recurrence_days'] = [1]
resp.form.submit().follow()
event = Event.objects.get()
assert event.recurrence_days is None
event.delete()
# add recurring event
resp.form['frequency'] = 'recurring'
resp.form.submit().follow()
event = Event.objects.get(primary_event__isnull=True)
assert event.recurrence_days == [1]
assert Event.objects.filter(primary_event=event).count() == 49
event.delete()
# add recurring event with end date
resp.form['recurrence_end_date'] = '2021-07-01'
resp.form.submit().follow()
event = Event.objects.get(primary_event__isnull=True)
assert event.recurrence_days == [1]
assert Event.objects.filter(primary_event=event).count() == 5
# add recurring event with end date in a very long time
resp.form['recurrence_end_date'] = '2030-01-01'
resp = resp.form.submit()
assert 'Recurrence end date cannot be more than 3 years from now' in resp.text
def test_add_event_on_missing_agenda(app, admin_user):
app = login(app)
app.get('/manage/agendas/%s/add-event' % '0', status=404)
def test_add_event_as_manager(app, manager_user):
agenda = Agenda(label='Foo bar')
agenda.view_role = manager_user.groups.all()[0]
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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_add_event_third_millennium(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
assert Event.objects.filter(agenda=agenda).count() == 0
app = login(app)
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'] = '0022-02-15'
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp.form['duration'] = 45
resp = resp.form.submit()
assert resp.context['form'].errors['start_datetime'] == ['Year must be after 2000.']
assert Event.objects.filter(agenda=agenda).count() == 0
def test_edit_event(settings, app, admin_user):
settings.LANGUAGE_CODE = 'fr-fr' # check date initial value format
agenda = Agenda.objects.create(label='Foo bar')
event = Event.objects.create(
label='Foo',
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=agenda,
)
event2 = Event.objects.create(
label='Other',
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=agenda,
)
assert event.duration is None
assert event.end_datetime is None
other_agenda = Agenda.objects.create(label='Foo bar')
other_event = Event.objects.create(
label='Foo',
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=other_agenda,
)
assert event.slug == other_event.slug
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_datetime_0'].value == ''
assert resp.form['publication_datetime_1'].value == ''
assert resp.form['duration'].value == ''
assert resp.form['description'].value == ''
resp.form['start_datetime_0'] = '2016-02-16'
resp.form['start_datetime_1'] = '17:00'
resp.form['publication_datetime_0'] = '2020-05-11'
resp.form['publication_datetime_1'] = '12:00'
resp.form['duration'].value = 45
resp.form['places'] = 20
resp.form['description'] = 'A description'
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 str(event.publication_datetime) == '2020-05-11 10:00:00+00:00'
assert str(event.publication_datetime.tzinfo) == 'UTC'
assert event.duration == 45
assert event.end_datetime == event.start_datetime + datetime.timedelta(minutes=45)
assert event.description == 'A description'
assert event.slug == other_event.slug
# check slug edition
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
resp.form['slug'] = event2.slug
resp = resp.form.submit()
assert resp.context['form'].errors['slug'] == ['Another event exists with the same identifier.']
def test_event_digit_slug(app, admin_user):
agenda = Agenda(label='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_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='Foo bar')
agenda.view_role = manager_user.groups.all()[0]
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=agenda,
publication_datetime=make_aware(datetime.datetime(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_datetime_0'].value == '2020-05-11'
assert resp.form['publication_datetime_1'].value == '00:00'
resp.form['start_datetime_0'] = '2016-02-16'
resp.form['start_datetime_1'] = '17:00'
resp.form['publication_datetime_0'] = ''
resp.form['publication_datetime_1'] = ''
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_datetime is None
def test_edit_event_with_custom_fields(app, admin_user):
events_type = EventsType.objects.create(
label='Foo',
custom_fields=[
{'varname': 'text', 'label': 'Text', 'field_type': 'text'},
{'varname': 'textarea', 'label': 'TextArea', 'field_type': 'textarea'},
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
],
)
agenda = Agenda.objects.create(label='Foo', kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert 'custom_field_text' not in resp.context['form'].fields
assert 'custom_field_textarea' not in resp.context['form'].fields
assert 'custom_field_bool' not in resp.context['form'].fields
agenda.events_type = events_type
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert 'custom_field_text' in resp.context['form'].fields
assert 'custom_field_textarea' in resp.context['form'].fields
assert 'custom_field_bool' in resp.context['form'].fields
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': '',
'textarea': '',
'bool': None,
}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
resp.form['custom_field_text'] = 'foo'
resp.form['custom_field_textarea'] = 'foo bar'
resp.form['custom_field_bool'] = 'true'
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': 'foo',
'textarea': 'foo bar',
'bool': True,
}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert resp.form['custom_field_text'].value == 'foo'
assert resp.form['custom_field_textarea'].value == 'foo bar'
assert resp.form['custom_field_bool'].value == 'true'
resp.form['custom_field_text'] = ''
resp.form['custom_field_textarea'] = ''
resp.form['custom_field_bool'] = 'false'
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': '',
'textarea': '',
'bool': False,
}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
resp.form['custom_field_bool'] = 'unknown'
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': '',
'textarea': '',
'bool': None,
}
def test_edit_recurring_event(settings, app, admin_user, freezer):
freezer.move_to('2021-01-12 12:10')
events_type = EventsType.objects.create(
label='Foo', custom_fields=[{'varname': 'foo', 'label': 'Foo', 'field_type': 'text'}]
)
agenda = Agenda.objects.create(
label='Foo bar',
kind='events',
minimal_booking_delay=15,
maximal_booking_delay=30,
events_type=events_type,
)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(start_datetime=now(), places=10, agenda=agenda)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['frequency'] = 'recurring'
resp.form['recurrence_days'] = [localtime().weekday()]
resp = resp.form.submit()
# no end date, events are created for the year to come
assert Event.objects.count() == 54
assert Event.objects.last().start_datetime.strftime('%Y-%m-%d') == '2022-01-11'
# specifying end date removes events
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = '2021-06-01'
resp = resp.form.submit()
assert Event.objects.count() == 21
assert Event.objects.last().start_datetime.strftime('%Y-%m-%d') == '2021-05-25'
# detail page doesn't exist
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.id, event.id), status=404)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'On Tuesdays at 1:10 p.m.' in resp.text
# event is bookable regardless of minimal_booking_delay, since it has bookable recurrences
assert len(resp.pyquery.find('.bookable')) == 1
# maximal_booking_delay is accounted for, because no recurrences are bookable
freezer.move_to('2020-11-12')
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert len(resp.pyquery.find('.not-bookable')) == 1
# editing recurring event updates event recurrences
event.refresh_from_db()
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['places'] = 20
resp.form['custom_field_foo'] = 'bar'
resp = resp.form.submit().follow()
event_recurrence.refresh_from_db()
assert event_recurrence.places == 20
assert event_recurrence.custom_fields == {'foo': 'bar'}
event.refresh_from_db()
assert event.custom_fields == {'foo': 'bar'}
# but some fields should not be updated
assert event_recurrence.slug != event.slug
assert not event_recurrence.recurrence_days
# changing recurrence attribute removes event recurrences
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['frequency'] = 'unique'
resp = resp.form.submit().follow()
assert not Event.objects.filter(primary_event=event).exists()
# same goes with changing slug
event.recurrence_days = [1]
event.save()
event.create_all_recurrences()
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
assert Event.objects.filter(primary_event=event, slug__startswith='foo-bar-event').exists()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['slug'] = 'hop'
resp = resp.form.submit().follow()
assert not Event.objects.filter(primary_event=event, slug__startswith='foo-bar-event').exists()
# changing recurring attribute or slug is forbidden if there are bookings for future recurrences
event_recurrence = Event.objects.get(
primary_event=event, start_datetime=event.start_datetime + datetime.timedelta(days=7)
)
Booking.objects.create(event=event_recurrence)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
assert 'disabled' in resp.form['frequency'].attrs
assert all('disabled' in resp.form.get('recurrence_days', index=i).attrs for i in range(7))
assert 'disabled' in resp.form['recurrence_week_interval'].attrs
assert 'disabled' in resp.form['slug'].attrs
assert 'disabled' in resp.form['start_datetime_0'].attrs
assert 'disabled' in resp.form['start_datetime_1'].attrs
# changing it anyway doesn't work
resp.form['slug'] = 'changed'
resp = resp.form.submit()
assert not Event.objects.filter(slug='changed').exists()
# deletion of event recurrence is not allowed
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.id, event_recurrence.id))
assert 'Delete' not in resp.text
resp = resp.click('Options')
assert 'Delete' not in resp.text
assert {
'slug',
'frequency',
'recurrence_days',
'recurence_weekly_interval',
'recurrence_end_date',
'publication_datetime_0',
'publication_datetime_1',
'custom_field_foo',
}.isdisjoint(resp.form.fields)
resp.form.submit().follow()
# custom fields not changed
event_recurrence.refresh_from_db()
assert event_recurrence.custom_fields == {'foo': 'bar'}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = 'bad-date'
resp = resp.form.submit() # no error
def test_edit_recurring_event_with_end_date(settings, app, admin_user, freezer):
freezer.move_to('2021-01-12 12:10')
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(
start_datetime=now(), places=10, recurrence_days=list(range(7)), agenda=agenda
)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=5)).strftime('%Y-%m-%d')
resp = resp.form.submit()
# recurrences are created automatically
event = Event.objects.get(recurrence_days__isnull=False)
assert Event.objects.filter(primary_event=event).count() == 5
assert Event.objects.filter(primary_event=event, start_datetime=now()).exists()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['start_datetime_1'] = (localtime() + datetime.timedelta(hours=1)).strftime('%H:%M')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 5
assert Event.objects.filter(
primary_event=event, start_datetime=now() + datetime.timedelta(hours=1)
).exists()
# old recurrences were deleted
assert not Event.objects.filter(primary_event=event, start_datetime=now()).exists()
# if start datetime of a recurrence is edited, it stays that way
recurrence = event.recurrences.first()
recurrence.start_datetime += datetime.timedelta(hours=1)
recurrence.save()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 5
assert Event.objects.filter(primary_event=event, start_datetime=recurrence.start_datetime).count() == 1
# ensure recurrence_end_date has not been propagated
assert not Event.objects.filter(primary_event=event, recurrence_end_date__isnull=False).exists()
# editing recurrence_end_date is permitted as long as bookings are not impacted
event_recurrence = Event.objects.get(primary_event=event, start_datetime__day=15)
Booking.objects.create(event=event_recurrence)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=6)).strftime('%Y-%m-%d')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 6
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=4)).strftime('%Y-%m-%d')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 4
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=2)).strftime('%Y-%m-%d')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 4
assert 'Bookings exist after this date' in resp.text
def test_edit_booked_event_disable_frequency_choice(settings, app, admin_user, freezer):
freezer.move_to('2021-01-12 12:10')
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(start_datetime=now(), places=10, agenda=agenda)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
assert 'disabled' not in resp.form['frequency'].attrs
assert 'This field will not be editable once event has bookings.' in resp.text
Booking.objects.create(event=event)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
assert 'disabled' in resp.form['frequency'].attrs
assert 'cannot be modified' in resp.form['frequency'].attrs['title']
assert 'This field will not be editable once event has bookings.' not in resp.text
def test_booked_places(app, admin_user):
agenda = Agenda(label='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/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day), 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='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
for _ in range(2):
Booking(event=event).save()
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'full' not in resp.text
assert 'overbooking' not in resp.text
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' not in resp
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' not in resp
for _ in range(8):
Booking(event=event).save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'full' in resp.text
assert 'overbooking' not in resp.text
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' in resp
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' in resp
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_event_detail_backoffice_url_translation(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
Booking.objects.create(event=event, backoffice_url='publik://default/foo/')
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert 'http://example.org/foo/' in resp.text
def test_delete_event(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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_recurring_event(app, admin_user, freezer):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
start_datetime = now() + datetime.timedelta(days=10)
event = Event.objects.create(
start_datetime=start_datetime,
places=10,
agenda=agenda,
recurrence_days=[start_datetime.weekday()],
recurrence_end_date=start_datetime + datetime.timedelta(days=15),
)
event.create_all_recurrences()
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
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
booking = Booking.objects.create(event=event_recurrence)
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
booking.cancellation_datetime = None
booking.save()
freezer.move_to(now() + datetime.timedelta(days=11))
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
def test_delete_event_as_manager(app, manager_user):
agenda = Agenda(label='Foo bar')
agenda.edit_role = manager_user.groups.all()[0]
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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='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/time,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/time,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 00:00,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/time,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 00:00,90\r\n'
)
def test_export_events_wrong_kind(app, admin_user):
agenda = Agenda.objects.create(label='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='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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, 1st event)' in resp.text
with override_settings(LANGUAGE_CODE='fr-fr'):
resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00,10', 'text/csv')
resp = resp.form.submit(status=200)
# ensure <sup> tag is not escaped
assert '1<sup>er</sup>' 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', '2016-09-16,18:00,10,5,éléphant'.encode(), '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 == 'é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 + '2016-09-16,18:00,10,5,éléphant'.encode(), '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 == 'é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', '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 == 'é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', '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 == '\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_datetime 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 str(event.publication_datetime) == '2016-10-15 22:00:00+00:00'
assert str(event.publication_datetime.tzinfo) == 'UTC'
assert event.duration == 90
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 10:00,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 str(event.publication_datetime) == '2016-10-16 08:00:00+00:00'
assert str(event.publication_datetime.tzinfo) == 'UTC'
assert event.duration == 90
# publication date/time 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/time 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)) == {
'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_event_nested_quotes(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
app = login(app)
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
','.join(
[
"2016-09-16",
"18:00",
"10",
"5",
"éléphant",
"elephant",
# the multiline description and final dot
# and new line after ""éléphants"" are needed to trigger the bug.
'''"Animation:
De nombreux ""éléphants"".
"''',
]
).encode(),
'text/csv',
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert 'De nombreux "éléphants"' in Event.objects.all()[0].description
def test_import_events_existing_event(app, admin_user, freezer):
agenda = Agenda.objects.create(label='Foo bar')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
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 &quot;label&quot; start date has changed. Do not forget to notify the registrants.</li>'
in resp.text
)
else:
assert (
'<li class="warning">Event &quot;label&quot; 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 &quot;label&quot; start date has changed. Do not forget to notify the registrants.'
)
== 1
)
assert (
resp.text.count(
'Event &quot;other_slug&quot; 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='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)
@pytest.mark.freeze_time('2022-05-24')
def test_event_detail(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,
waiting_list_places=2,
agenda=agenda,
)
Booking.objects.create(event=event, user_last_name="User's 1")
Booking.objects.create(event=event, user_last_name='User 2', in_waiting_list=True)
login(app)
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (1/10)' in resp.text
assert 'User&#x27;s 1, May 24, 2022, 2 a.m.' in resp.text
assert 'Waiting List (1/2): 1 remaining place' in resp.text
assert 'User 2, May 24, 2022, 2 a.m.' in resp.text
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (1/10)' in resp.text
assert '&lt;b&gt;User&#x27;s 1&lt;/b&gt; Foo Bar, May 24, 2022, 2 a.m.' in resp.text
assert 'Waiting List (1/2): 1 remaining place' in resp.text
assert '&lt;b&gt;User 2&lt;/b&gt; Foo Bar, May 24, 2022, 2 a.m.' in resp.text
def test_event_detail_redirect(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,
waiting_list_places=2,
agenda=agenda,
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.slug, event.slug), status=302)
assert resp.location.endswith('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
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, user_last_name='User 1')
Booking.objects.create(event=event, user_last_name='User 2')
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 _ in range(5):
Booking.objects.create(event=event, cancel_callback_url='http://example.org/jump/trigger/')
login(app)
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
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/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
assert 'Errors occured during cancellation of event "xyz".' in resp.text
# warning doesn't go away
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
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/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
assert 'Errors occured during cancellation of event "xyz".' not 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_error_report_backofice_url_translation(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 _ in range(5):
Booking.objects.create(
event=event,
cancel_callback_url='http://example.org/jump/trigger/',
backoffice_url='publik://default/',
)
login(app)
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
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/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
assert '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))
assert 'http://example.org/' in resp.text
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 = 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
booking.cancel()
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
assert 'event has bookings with no callback url configured' not in resp.text
assert 'Proceed with cancellation' 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 event.get_booking_form_url() is None
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
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 (
event.get_booking_form_url()
== 'http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s'
% (agenda.slug, event.slug)
)
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.id, day.year, day.month, day.day))
assert (
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s&ReturnURL=%s">Booking form</a>'
% (
agenda.slug,
event.slug,
'http://testserver/manage/agendas/%d/month/%d/%d/%d/' % (agenda.pk, day.year, day.month, day.day),
)
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&ReturnURL=%s">Booking form</a>'
% (agenda.slug, event.slug, 'http://testserver/manage/agendas/%d/events/open/' % agenda.pk)
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&ReturnURL=%s">Booking form</a>'
% (agenda.slug, event.slug, 'http://testserver/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
in resp.text
)
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
# again
app.get('/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, booking.pk), status=404)
# test secondary booking
primary = Booking.objects.create(event=event)
secondary = Booking.objects.create(event=event, primary_booking=primary)
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert 'Bookings (2/10)' in resp.text
assert '/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, primary.pk) in resp.text
assert '/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, secondary.pk) not in resp.text
app.get('/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, secondary.pk), status=404)
app.get('/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, primary.pk)).form.submit()
primary.refresh_from_db()
secondary.refresh_from_db()
assert primary.cancellation_datetime
assert secondary.cancellation_datetime
def test_event_check(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
agenda2 = Agenda.objects.create(label='Events', kind='events')
Desk.objects.create(agenda=agenda2, slug='_exceptions_holder')
event = Event.objects.create(
label='xyz',
start_datetime=now() + datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking1 = Booking.objects.create(
event=event, user_external_id='user:1', user_first_name='User', user_last_name='42'
)
Booking.objects.create(
event=event, user_external_id='user:2', user_first_name="User's", user_last_name='01'
)
Booking.objects.create(
event=event, user_external_id='user:3', user_first_name='User', user_last_name='17'
)
Booking.objects.create(
event=event, user_external_id='user:4', user_first_name='User', user_last_name='35'
)
Booking.objects.create(
event=event, user_external_id='user:5', user_first_name='User', user_last_name='05'
)
booking6 = Booking.objects.create(
event=event, user_external_id='user:6', user_first_name='User', user_last_name='12 Cancelled'
)
booking6.cancel()
booking7 = Booking.objects.create(
event=event,
user_external_id='user:7',
user_first_name='User',
user_last_name='Waiting',
in_waiting_list=True,
)
booking8 = Booking.objects.create(
event=event,
user_external_id='user:8',
user_first_name='User',
user_last_name='Waiting and Cancelled',
in_waiting_list=True,
)
booking8.cancel()
booking9 = Booking.objects.create(
event=event,
user_external_id='user:1',
user_first_name='User',
user_last_name='Secondary',
primary_booking=booking1,
)
login(app)
# event not in past
assert agenda.enable_check_for_future_events is False
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) not in resp
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=404)
# not in past, but check for future events is enabled
agenda.enable_check_for_future_events = True
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) in resp
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=200)
# event is today
agenda.enable_check_for_future_events = False
agenda.save()
event.start_datetime = localtime(now()).replace(hour=22, minute=0) # it's ok all the day
event.save()
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) in resp
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=200)
# unknown agenda
app.get('/manage/agendas/%s/events/%s/check' % (0, event.pk), status=404)
# wrong agenda
app.get('/manage/agendas/%s/events/%s/check' % (agenda2.pk, event.pk), status=404)
resp = resp.click('Check')
assert (
resp.text.index('Bookings (6/10)')
< resp.text.index("User&#x27;s 01")
< resp.text.index('User 05')
< resp.text.index('User 17')
< resp.text.index('User 35')
< resp.text.index('User 42')
< resp.text.index('Waiting List (1/5)')
< resp.text.index('User Waiting')
)
assert 'User 12 Cancelled' not in resp
assert 'User Waiting and Cancelled' not in resp
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:9',
user_first_name='Subscription',
user_last_name='43',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:10',
user_first_name='Subscription',
user_last_name='14',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:7',
user_first_name='Subscription',
user_last_name='Waiting',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:42',
user_first_name='Subscription',
user_last_name='Too soon',
date_start=now() - datetime.timedelta(days=1),
date_end=now(),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:42',
user_first_name='Subscription',
user_last_name='Too late',
date_start=now() + datetime.timedelta(days=1),
date_end=now() + datetime.timedelta(days=2),
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert (
resp.text.index('Bookings (6/10)')
< resp.text.index("User&#x27;s 01")
< resp.text.index('User 05')
< resp.text.index('User 12 Cancelled')
< resp.text.index('Subscription 14')
< resp.text.index('(Not booked)')
< resp.text.index('User 17')
< resp.text.index('User 35')
< resp.text.index('User 42')
< resp.text.index('Subscription 43')
< resp.text.index('Waiting List (1/5)')
< resp.text.index('User Waiting')
< resp.text.index('User Waiting and Cancelled')
)
assert 'Subscription Waiting' not in resp
assert 'Subscription 42' not in resp
assert 'Subscription too soon' not in resp
assert 'Subscription too late' not in resp
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '&lt;b&gt;User&#x27;s 01&lt;/b&gt; Foo Bar' in resp
assert '&lt;b&gt;Subscription 14&lt;/b&gt; Foo Bar' in resp
assert '&lt;b&gt;User Waiting&lt;/b&gt; Foo Bar' in resp
# booking in waiting list
token = resp.context['csrf_token']
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking7.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking7.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# secondary booking
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking9.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking9.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# unknown agenda
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (0, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (0, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# wrong agenda
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda2.pk, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda2.pk, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# cancelled event
event.cancel()
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) not in resp
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=404)
def test_event_checked(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events', booking_check_filters='foo,bar')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
agenda=agenda,
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark the event as checked' not in resp
for i in range(8):
user_was_present = None
if i < 3:
user_was_present = True
elif i < 7:
user_was_present = False
Booking.objects.create(
event=event,
user_was_present=user_was_present,
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark the event as checked' in resp
assert event.checked is False
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
assert 'checked tag' not in resp
urls = [
'/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk),
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
'/manage/agendas/%s/month/%d/%d/%d/'
% (agenda.pk, event.start_datetime.year, event.start_datetime.month, event.start_datetime.day),
'/manage/agendas/%s/week/%d/%d/%d/'
% (agenda.pk, event.start_datetime.year, event.start_datetime.month, event.start_datetime.day),
'/manage/agendas/%s/day/%d/%d/%d/'
% (agenda.pk, event.start_datetime.year, event.start_datetime.month, event.start_datetime.day),
]
for url in urls:
resp = app.get(url)
assert '<span class="checked tag">Checked</span>' not in resp
assert '<span class="meta meta-success">Presents 3</span>' in resp
assert '<span class="meta meta-error">Absents 4</span>' in resp
assert '<span class="meta meta-disabled">Not checked 1</span>' in resp
token = resp.context['csrf_token']
resp = app.post(
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
)
assert resp.location.endswith('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
event.refresh_from_db()
assert event.checked is True
resp = resp.follow()
assert 'Mark the event as checked' not in resp
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
assert 'checked tag' in resp
Booking.objects.filter(user_was_present__isnull=True).update(user_was_present=True)
for url in urls:
resp = app.get(url)
assert '<span class="checked tag">Checked</span>' in resp
assert '<span class="meta meta-success">Presents 4</span>' in resp
assert '<span class="meta meta-error">Absents 4</span>' in resp
assert 'meta meta-disabled' not in resp
# event not in past
agenda.disable_check_update = False
agenda.save()
assert agenda.enable_check_for_future_events is False
event.start_datetime = now() + datetime.timedelta(days=1)
event.save()
app.post(
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# not in past, but check for future events is enabled
agenda.enable_check_for_future_events = True
agenda.save()
app.post(
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_filters(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(
label='Events',
kind='events',
booking_check_filters='foo,bar',
)
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
agenda=agenda,
)
Booking.objects.create(
event=event, user_external_id='user:none', user_first_name='User', user_last_name='none'
)
Booking.objects.create(
event=event,
user_external_id='user:empty',
user_first_name='User',
user_last_name='empty',
extra_data={},
)
Booking.objects.create(
event=event,
user_external_id='user:1',
user_first_name='User',
user_last_name='foo-val1 bar-none presence',
extra_data={'foo': 'val1', 'bar': ['val1']}, # bar is ignored, wrong value
user_was_present=True,
)
Booking.objects.create(
event=event,
user_external_id='user:2',
user_first_name='User',
user_last_name='foo-val2 bar-val1 absence',
extra_data={'foo': 'val2', 'bar': 'val1'},
user_was_present=False,
)
Booking.objects.create(
event=event,
user_external_id='user:3',
user_first_name='User',
user_last_name='foo-val1 bar-val2 not-checked',
extra_data={'foo': 'val1', 'bar': 'val2'},
)
Booking.objects.create(
event=event,
user_external_id='user:4',
user_first_name='User',
user_last_name='foo-none bar-val2 reason-foo',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type_slug='foo-reason',
)
Booking.objects.create(
event=event,
user_external_id='user:5',
user_first_name='User',
user_last_name='foo-none bar-val2 reason-bar',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type_slug='bar-reason',
)
Booking.objects.create(
event=event,
user_external_id='user:6',
user_first_name='User',
user_last_name='foo-none bar-val2 cancelled-absence',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type_slug='foo-reason',
cancellation_datetime=now(),
)
Booking.objects.create(
event=event,
user_external_id='user:7',
user_first_name='User',
user_last_name='foo-none bar-val2 cancelled-presence',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type_slug='bar-reason',
cancellation_datetime=now(),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:none',
user_first_name='Subscription',
user_last_name='none',
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:empty',
user_first_name='Subscription',
user_last_name='empty',
extra_data={},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:1',
user_first_name='Subscription',
user_last_name='foo-val1 bar-none',
extra_data={'foo': 'val1', 'bar': ['val1']}, # bar is ignored, wrong value
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:2',
user_first_name='Subscription',
user_last_name='foo-val2 bar-val1',
extra_data={'foo': 'val2', 'bar': 'val1'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:3',
user_first_name='Subscription',
user_last_name='foo-val1 bar-val2',
extra_data={'foo': 'val1', 'bar': 'val2'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:4',
user_first_name='Subscription',
user_last_name='foo-none bar-val2',
extra_data={'bar': 'val2'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
login(app)
for params in [
{},
{'unknown': 'unknown'},
{'extra-data-unknown': 'unknown'},
{'extra-data-foo': 'unknown'},
]:
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params=params)
assert 'User none' in resp
assert 'User empty' in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' in resp
assert 'User foo-none bar-val2 cancelled-presence' in resp
assert 'Subscription none' in resp
assert 'Subscription empty' in resp
assert 'Subscription foo-val1 bar-none' in resp
assert 'Subscription foo-val2 bar-val1' in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' in resp
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'extra-data-foo': 'val1'}
)
assert len(ctx.captured_queries) == 10
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'extra-data-foo': 'val1', 'extra-data-bar': 'val2'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'extra-data-foo': 'val2', 'extra-data-bar': 'val2'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'booked'}
)
assert 'User none' in resp
assert 'User empty' in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'not-booked'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' in resp
assert 'Subscription empty' in resp
assert 'Subscription foo-val1 bar-none' in resp
assert 'Subscription foo-val2 bar-val1' in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'cancelled'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' in resp
assert 'User foo-none bar-val2 cancelled-presence' in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'not-checked'}
)
assert 'User none' in resp
assert 'User empty' in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'presence'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'absence'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'booking-status': 'absence::foo-reason'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'booking-status': 'presence::bar-reason'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
def test_event_check_ordering(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
Booking.objects.create(
event=event,
user_first_name='BB',
user_last_name='XX',
user_external_id='user:1',
)
Booking.objects.create(
event=event,
user_first_name='AA',
user_last_name='YY',
user_external_id='user:2',
cancellation_datetime=now(),
)
Subscription.objects.create(
agenda=agenda,
user_first_name='CC',
user_last_name='WW',
user_external_id='user:3',
date_start=datetime.date(2022, 2, 1),
date_end=datetime.date(2022, 3, 1),
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert resp.text.index('CC WW') < resp.text.index('BB XX') < resp.text.index('AA YY')
resp = app.get('/manage/agendas/%s/events/%s/check?sort=lastname,firstname' % (agenda.pk, event.pk))
assert resp.text.index('CC WW') < resp.text.index('BB XX') < resp.text.index('AA YY')
resp = app.get('/manage/agendas/%s/events/%s/check?sort=firstname,lastname' % (agenda.pk, event.pk))
assert resp.text.index('AA YY') < resp.text.index('BB XX') < resp.text.index('CC WW')
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_booking(check_types, app, admin_user):
check_types.return_value = []
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
secondary_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', primary_booking=booking
)
assert agenda.mark_event_checked_auto is False
def _test_reset():
resp = app.post(
'/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) not in resp
booking.refresh_from_db()
assert booking.user_was_present is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert resp.pyquery.find('td.booking-status')[0].text.strip() == '-'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 0
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) not in resp
# set as present
token = resp.context['csrf_token']
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) in resp
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
# reset
_test_reset()
agenda.mark_event_checked_auto = True
agenda.save()
# set as absent without check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
]
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
# reset
_test_reset()
# set as absent with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
).follow()
assert 'Foo reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug == 'foo-reason'
assert booking.user_check_type_label == 'Foo reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_check_type_slug == 'foo-reason'
assert secondary_booking.user_check_type_label == 'Foo reason'
event.refresh_from_db()
assert event.checked is True
# reset
_test_reset()
# set as present without check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 1
# reset
_test_reset()
# set as present with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
).follow()
assert 'Bar reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug == 'bar-reason'
assert booking.user_check_type_label == 'Bar reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug == 'bar-reason'
assert secondary_booking.user_check_type_label == 'Bar reason'
event.refresh_from_db()
assert event.checked is True
# event is checked
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) in resp
app.post(
'/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
# event not in past
assert agenda.enable_check_for_future_events is False
event.start_datetime = now() + datetime.timedelta(days=1)
event.save()
app.post(
'/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# not in past, but check for future events is enabled
agenda.enable_check_for_future_events = True
agenda.save()
app.post(
'/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
# now disable check update
agenda.disable_check_update = True
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) not in resp
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_cancelled_booking(check_types, app, admin_user):
check_types.return_value = []
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
secondary_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', primary_booking=booking
)
booking.cancel()
Booking.objects.create(event=event, user_first_name='User', user_last_name='43')
# no suscription: cancelled bookings are not displayed
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-status')) == 1
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) not in resp
token = resp.context['csrf_token']
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-status')) == 2
assert resp.pyquery.find('td.booking-status')[0].text.strip() == '(Cancelled)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 0
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) not in resp
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.cancellation_datetime is None
assert booking.user_was_present is True
secondary_booking.refresh_from_db()
assert secondary_booking.cancellation_datetime is None
assert secondary_booking.user_was_present is True
booking.cancel()
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.cancellation_datetime is None
assert booking.user_was_present is False
secondary_booking.refresh_from_db()
assert secondary_booking.cancellation_datetime is None
assert secondary_booking.user_was_present is False
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_booking_ajax(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
token = resp.context['csrf_token']
# set as present
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n \n (Bar reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
assert '<option value="bar-reason" selected>Bar reason</option>' in resp
# set as absent
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n \n (Foo reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text.startswith('Absence')
assert '<option value="foo-reason" selected>Foo reason</option>' in resp
# reset
resp = app.post(
'/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == '-'
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_subscription(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
subscription = Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
user_email='foo@bar.com',
user_phone_number='06',
extra_data={'foo': 'bar'},
date_start=now() - datetime.timedelta(days=1),
date_end=now(),
)
# existing booking: no check for subscription
booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', user_external_id='user:1'
)
booking2 = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', user_external_id='user:1'
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert (
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk) not in resp
)
assert (
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk) not in resp
)
token = resp.context['csrf_token']
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
booking2.delete()
booking.cancel()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert (
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk) not in resp
)
assert (
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk) not in resp
)
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
booking.delete()
# set as present
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk) in resp
assert '/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk) in resp
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
)
booking = Booking.objects.latest('pk')
assert booking.user_was_present is True
assert booking.user_check_type_slug == 'bar-reason'
assert booking.user_check_type_label == 'Bar reason'
assert booking.event == event
assert booking.user_external_id == subscription.user_external_id
assert booking.user_first_name == subscription.user_first_name
assert booking.user_last_name == subscription.user_last_name
assert booking.user_email == subscription.user_email
assert booking.user_phone_number == subscription.user_phone_number
assert booking.extra_data == subscription.extra_data
booking.delete()
# set as absent
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk) in resp
assert '/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk) in resp
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
)
booking = Booking.objects.latest('pk')
assert booking.user_was_present is False
assert booking.user_check_type_slug == 'foo-reason'
assert booking.user_check_type_label == 'Foo reason'
assert booking.event == event
assert booking.user_external_id == subscription.user_external_id
assert booking.user_first_name == subscription.user_first_name
assert booking.user_last_name == subscription.user_last_name
assert booking.user_email == subscription.user_email
assert booking.user_phone_number == subscription.user_phone_number
assert booking.extra_data == subscription.extra_data
booking.delete()
# mark the event as checked
assert agenda.disable_check_update is False
event.checked = True
event.save()
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
Booking.objects.all().delete()
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
Booking.objects.all().delete()
agenda.disable_check_update = True
agenda.save()
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# check subscription dates
agenda.disable_check_update = False
agenda.save()
subscription.date_start = now() - datetime.timedelta(days=2)
subscription.date_end = now() - datetime.timedelta(days=1)
subscription.save()
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
subscription.date_start = now()
subscription.date_end = now() + datetime.timedelta(days=1)
subscription.save()
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# event not in past
subscription.date_end = now() + datetime.timedelta(days=2)
subscription.save()
assert agenda.enable_check_for_future_events is False
event.start_datetime = now() + datetime.timedelta(days=1)
event.save()
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# not in past, but check for future events is enabled
agenda.enable_check_for_future_events = True
agenda.save()
app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
Booking.objects.all().delete()
app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_extra_user_block(check_types, app, admin_user):
check_types.return_value = []
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
subscription = Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='41',
date_start=now() - datetime.timedelta(days=1),
date_end=now(),
)
booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', user_external_id='user:2'
)
cancelled_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='43', user_external_id='user:3'
)
cancelled_booking.cancel()
waiting_booking = Booking.objects.create(
event=event,
user_first_name='User',
user_last_name='44',
user_external_id='user:4',
in_waiting_list=True,
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/subscriptions/%s/extra-user-block' % (agenda.pk, subscription.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, cancelled_booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, waiting_booking.pk) not in resp
agenda.booking_extra_user_block_template = '{{ booking.user_name }} Foo Bar'
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/subscriptions/%s/extra-user-block' % (agenda.pk, subscription.pk) in resp
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, cancelled_booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, waiting_booking.pk) in resp
Subscription.objects.create(
agenda=agenda,
user_external_id='user:2',
user_first_name='Subscription',
user_last_name='42',
date_start=now() - datetime.timedelta(days=1),
date_end=now(),
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
# booking url, not subscription url
assert '/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, booking.pk) in resp
resp = app.get('/manage/agendas/%s/subscriptions/%s/extra-user-block' % (agenda.pk, subscription.pk))
assert resp.text == 'Subscription 41 Foo Bar'
resp = app.get('/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, booking.pk))
assert resp.text == 'User 42 Foo Bar'
resp = app.get('/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, cancelled_booking.pk))
assert resp.text == 'User 43 Foo Bar'
resp = app.get('/manage/agendas/%s/bookings/%s/extra-user-block' % (agenda.pk, waiting_booking.pk))
assert resp.text == 'User 44 Foo Bar'
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_subscription_ajax(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
subscription = Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=now() - datetime.timedelta(days=1),
date_end=now(),
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
token = resp.context['csrf_token']
# set as present
resp = app.post(
'/manage/agendas/%s/subscriptions/%s/presence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n \n (Bar reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
assert '<option value="bar-reason" selected>Bar reason</option>' in resp
Booking.objects.all().delete()
# set as absent
resp = app.post(
'/manage/agendas/%s/subscriptions/%s/absence/%s' % (agenda.pk, subscription.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n \n (Foo reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text.startswith('Absence')
assert '<option value="foo-reason" selected>Foo reason</option>' in resp
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_all_bookings(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking1 = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
assert agenda.mark_event_checked_auto is False
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
token = resp.context['csrf_token']
assert 'Mark all bookings without status' in resp
assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) in resp
assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) in resp
resp = app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk), params={'csrfmiddlewaretoken': token}
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
agenda.mark_event_checked_auto = True
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' not in resp
assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) not in resp
assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) not in resp
booking2 = Booking.objects.create(event=event, user_first_name='User', user_last_name='35')
secondary_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='35', primary_booking=booking2
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) in resp
assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) in resp
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk), params={'csrfmiddlewaretoken': token}
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
# event is checked
booking3 = Booking.objects.create(event=event, user_first_name='User', user_last_name='51')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type_slug == 'foo-reason'
assert booking3.user_check_type_label == 'Foo reason'
booking4 = Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type_slug == 'foo-reason'
assert booking3.user_check_type_label == 'Foo reason'
booking4.refresh_from_db()
assert booking4.user_was_present is True
assert booking4.user_check_type_slug == 'bar-reason'
assert booking4.user_check_type_label == 'Bar reason'
# now disable check update
agenda.disable_check_update = True
agenda.save()
Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' not in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
status=404,
)
resp = app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
status=404,
)
resp = app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# event not in past
agenda.disable_check_update = False
agenda.save()
assert agenda.enable_check_for_future_events is False
event.start_datetime = now() + datetime.timedelta(days=1)
event.save()
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# not in past, but check for future events is enabled
agenda.enable_check_for_future_events = True
agenda.save()
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
def test_event_check_primary_booking(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,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
Booking.objects.create(event=event, user_first_name='John', user_last_name='Doe')
booking_3 = Booking.objects.create(
event=event, user_first_name='Jane', user_last_name='Doe', in_waiting_list=True
)
# create secondary bookings
Booking.objects.create(event=event, user_first_name='User', user_last_name='42', primary_booking=booking)
Booking.objects.create(event=event, user_first_name='User', user_last_name='42', primary_booking=booking)
Booking.objects.create(
event=event,
user_first_name='Jane',
user_last_name='Doe',
primary_booking=booking_3,
in_waiting_list=True,
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Bookings (4/10)' in resp.text
user_bookings = resp.pyquery.find('td.booking-username.main-list')
assert len(user_bookings) == 2
assert user_bookings[0].text.replace('\n', '').strip() == 'User 42 (3 places)'
assert user_bookings[1].text.replace('\n', '').strip() == 'John Doe'
assert 'Waiting List (2/5)' in resp.text
user_bookings = resp.pyquery.find('td.booking-username.waiting')
assert len(user_bookings) == 1
assert user_bookings[0].text.replace('\n', '').strip() == 'Jane Doe (2 places)'
def test_duplicate_event(app, admin_user):
agenda = Agenda.objects.create(label='Foo Bar', slug='foo-bar', kind='events')
event = Event.objects.create(
agenda=agenda,
start_datetime=now(),
places=10,
waiting_list_places=50,
label='Foo',
duration=45,
pricing='200€',
url="http://example.com",
description='foo',
)
assert Event.objects.count() == 1
new_datetime = localtime(event.start_datetime.replace(year=event.start_datetime.year + 1)).replace(
hour=17, minute=0
)
app = login(app)
resp = app.get(f'/manage/agendas/{agenda.pk}/settings')
resp = resp.click('Duplicate', href='events')
resp.form['label'] = "Bar"
resp.form['start_datetime_0'] = str(new_datetime.date())
resp.form['start_datetime_1'] = '17:00'
resp = resp.form.submit().follow()
assert Event.objects.count() == 2
duplicate = Event.objects.latest('pk')
assert duplicate.start_datetime == new_datetime
assert duplicate.agenda == event.agenda
updated_fields = {"label", "start_datetime"}
identical_fields = {f.name for f in Event._meta.fields} - updated_fields - {'id', 'slug'}
for field in identical_fields:
assert getattr(duplicate, field) == getattr(event, field)
assert 'Event successfully duplicated.' in resp.text
def test_duplicate_event_creates_recurrences(app, admin_user):
agenda = Agenda.objects.create(label='Foo Bar', slug='foo-bar', kind='events')
event_start = now().replace(hour=1, minute=0)
recurring_event = Event.objects.create(
agenda=agenda,
start_datetime=event_start,
recurrence_days=[0, 1, 2, 3, 4, 5, 6],
recurrence_end_date=event_start + datetime.timedelta(days=6),
places=10,
label='Foo',
)
assert Event.objects.count() == 1
app = login(app)
resp = app.get(f'/manage/agendas/{agenda.pk}/settings')
resp = resp.click('Duplicate', href='events')
resp.form['label'] = "Bar"
resp.form['start_datetime_0'] = str(event_start.date())
resp.form['start_datetime_1'] = '17:00'
resp = resp.form.submit().follow()
duplicate = Event.objects.filter(primary_event__isnull=True).latest('pk')
assert duplicate != recurring_event
assert duplicate.recurrences.count() == 6
event_recurrence = duplicate.recurrences.first()
app.get(f'/manage/agendas/{agenda.pk}/events/{event_recurrence.pk}/duplicate', status=404)