chrono/tests/api/test_datetimes.py

1945 lines
78 KiB
Python

import datetime
import urllib.parse as urlparse
import pytest
from django.db import connection
from django.test import override_settings
from django.test.utils import CaptureQueriesContext
from django.utils.timezone import localtime, make_aware, make_naive, now
from chrono.agendas.models import Agenda, Booking, Category, Desk, Event, Subscription, TimePeriodException
pytestmark = pytest.mark.django_db
def test_datetimes_api(app, some_data):
agenda = Agenda.objects.filter(label='Foo bar')[0]
def check_bookability(data):
for event in data:
assert Event.objects.get(slug=event['id']).in_bookable_period()
for event in agenda.event_set.all():
if not event.in_bookable_period():
assert event.slug not in [x['id'] for x in data]
resp = app.get('/api/agenda/xxx/datetimes/', status=404)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert 'data' in resp.json
assert len(resp.json['data']) == 3
check_bookability(resp.json['data'])
assert app.get('/api/agenda/%s/datetimes/' % agenda.id).json == resp.json
agenda.minimal_booking_delay = 5
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 0
check_bookability(resp.json['data'])
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
assert len(resp.json['data']) == 3
agenda.minimal_booking_delay = 2
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 2
check_bookability(resp.json['data'])
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
assert len(resp.json['data']) == 3
agenda.minimal_booking_delay = 0
agenda.maximal_booking_delay = 3
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 2
check_bookability(resp.json['data'])
assert resp.json['data'][0]['description'] is None
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
assert len(resp.json['data']) == 3
agenda.event_set.update(publication_datetime=now() + datetime.timedelta(minutes=1))
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 0
check_bookability(resp.json['data'])
agenda.event_set.update(publication_datetime=now())
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 2
check_bookability(resp.json['data'])
# add description, URL and pricing to events
for i, event in enumerate(agenda.event_set.all()):
event.description = 'Description %s' % i
event.url = 'https://www.example.net/%s' % i
event.pricing = '%s' % i
event.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['description']
def test_datetimes_api_wrong_kind(app):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
app.get('/api/agenda/%s/datetimes/' % agenda.slug, status=404)
def test_datetime_api_fr(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
Event.objects.create(
slug='event-slug',
start_datetime=localtime(now() + datetime.timedelta(days=5)).replace(hour=17, minute=0),
places=5,
agenda=agenda,
)
with override_settings(LANGUAGE_CODE='fr-fr'):
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
# no seconds, hh:mm in 24-hour formats
assert resp.json['data'][0]['text'].endswith(' 17:00')
assert resp.json['data'][0]['datetime'].endswith(' 17:00:00')
assert 'data' in resp.json
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetime_api_label(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
event = Event.objects.create(
label='Hello world',
slug='event-slug',
start_datetime=(now() + datetime.timedelta(days=1)),
places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['text'] == 'Hello world'
assert resp.json['data'][0]['label'] == 'Hello world'
agenda.event_display_template = '{{ event.label }} - {{ event.start_datetime }}'
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['text'] == 'Hello world - May 7, 2021, 4 p.m.'
assert resp.json['data'][0]['label'] == 'Hello world'
Booking.objects.create(event=event)
agenda.event_display_template = (
'{{ event.label }} ({{ event.remaining_places }}/{{ event.places }} places remaining)'
)
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['text'] == 'Hello world (4/5 places remaining)'
# invalid template yields default text
invalid_templates = [
'{{ syntax error }}',
'{{ event.label|invalidfilter }}',
'{{ event.label|default:notexist }}',
]
for template in invalid_templates:
agenda.event_display_template = template
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['text'] == 'Hello world'
def test_datetime_api_urls(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
event = Event.objects.create(
slug='event-slug',
start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
places=5,
waiting_list_places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
for datum in resp.json['data']:
assert urlparse.urlparse(datum['api']['bookings_url']).path == '/api/agenda/%s/bookings/%s/' % (
agenda.slug,
event.slug,
)
assert urlparse.urlparse(datum['api']['fillslot_url']).path == '/api/agenda/%s/fillslot/%s/' % (
agenda.slug,
event.slug,
)
assert urlparse.urlparse(datum['api']['status_url']).path == '/api/agenda/%s/status/%s/' % (
agenda.slug,
event.slug,
)
def test_datetime_api_min_places(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(start_datetime=now() + datetime.timedelta(days=7), places=5, agenda=agenda)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?min_places=5' % agenda.slug)
assert not resp.json['data'][0]['disabled']
Booking.objects.create(event=event)
resp = app.get('/api/agenda/%s/datetimes/?min_places=5' % agenda.slug)
assert resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?min_places=' % agenda.slug)
assert not resp.json['data'][0]['disabled']
resp = app.get('/api/agenda/%s/datetimes/?min_places=wrong' % agenda.slug, status=400)
assert resp.json['err'] == 1
@pytest.mark.freeze_time('2021-02-23')
def test_datetimes_api_exclude_slots(app):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
)
event = Event.objects.create(
slug='event-slug',
start_datetime=localtime().replace(hour=10, minute=0),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event, user_external_id='42')
cancelled = Booking.objects.create(event=event, user_external_id='35')
cancelled.cancel()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '35'})
assert resp.json['data'][0]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
assert resp.json['data'][0]['disabled'] is True
assert resp.json['meta']['first_bookable_slot'] is None
assert resp.json['meta']['no_bookable_datetimes'] is True
assert 'booked_for_external_user' not in resp.json['data'][0]
event.delete()
# recurrent event
start_datetime = localtime().replace(hour=12, minute=0)
event = Event.objects.create(
slug='recurrent',
start_datetime=start_datetime,
recurrence_days=[start_datetime.weekday()],
places=2,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['id'] == 'recurrent:2021-02-23-1200'
assert resp.json['data'][0]['places']['full'] is False
assert resp.json['data'][0]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
assert resp.json['data'][0]['id'] == 'recurrent:2021-02-23-1200'
assert resp.json['data'][0]['places']['full'] is False
assert resp.json['data'][0]['disabled'] is False
first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
Booking.objects.create(event=first_recurrence, user_external_id='42')
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
assert resp.json['data'][0]['places']['full'] is False
assert resp.json['data'][0]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
assert resp.json['data'][0]['places']['full'] is False
assert resp.json['data'][0]['disabled'] is True
Booking.objects.create(event=first_recurrence)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
assert resp.json['data'][0]['places']['full'] is True
assert resp.json['data'][0]['disabled'] is True
assert 'booked_for_external_user' not in resp.json['data'][0]
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
assert resp.json['data'][0]['places']['full'] is True
assert resp.json['data'][0]['disabled'] is True
@pytest.mark.freeze_time('2021-02-23')
def test_datetimes_api_user_external_id(app):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
)
event = Event.objects.create(
slug='event-slug',
start_datetime=localtime().replace(hour=10, minute=0),
places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_external_id='42')
cancelled = Booking.objects.create(event=event, user_external_id='35')
cancelled.cancel()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert 'booked_for_external_user' not in resp.json['data'][0]
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '35'})
assert 'booked_for_external_user' not in resp.json['data'][0]
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
assert resp.json['data'][0]['booked_for_external_user'] == 'main-list'
assert resp.json['data'][0]['disabled'] is False
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'user_external_id': '42', 'exclude_user_external_id': '42'},
)
assert resp.json['data'][0]['disabled'] is True
booking.in_waiting_list = True
booking.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
assert resp.json['data'][0]['booked_for_external_user'] == 'waiting-list'
booking.cancel()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
assert 'booked_for_external_user' not in resp.json['data'][0]
event.delete()
# recurrent event
start_datetime = localtime().replace(hour=12, minute=0)
event = Event.objects.create(
slug='recurrent',
start_datetime=start_datetime,
recurrence_days=[start_datetime.weekday()],
places=2,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert 'booked_for_external_user' not in resp.json['data'][0]
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
assert 'booked_for_external_user' not in resp.json['data'][0]
first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
booking = Booking.objects.create(event=first_recurrence, user_external_id='42')
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert 'booked_for_external_user' not in resp.json['data'][0]
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
assert resp.json['data'][0]['booked_for_external_user'] == 'main-list'
booking.in_waiting_list = True
booking.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'user_external_id': '42'})
assert resp.json['data'][0]['booked_for_external_user'] == 'waiting-list'
# mix with exclude_user_external_id
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'user_external_id': '42', 'exclude_user_external_id': '35'},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['user_external_id'] == [
'user_external_id and exclude_user_external_id have different values'
]
def test_datetimes_api_hide_disabled(app):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
)
event = Event.objects.create(
slug='event-slug',
start_datetime=now() + datetime.timedelta(days=3),
places=1,
agenda=agenda,
)
Booking.objects.create(event=event)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['id'] == 'event-slug'
assert resp.json['data'][0]['disabled'] is True
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'hide_disabled': True})
assert resp.json['data'] == []
def test_waiting_list_datetimes(app, some_data, user):
agenda_id = Agenda.objects.filter(label='Foo bar')[0].id
event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0]
event.waiting_list_places = 5
event.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 3
assert event.slug in [x['id'] for x in resp.json['data']]
for _ in range(event.places):
Booking(event=event).save()
# all places are booked but all the dates are still displayed as there is a
# waiting list.
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 3
# fill the waiting list
for _ in range(event.waiting_list_places):
Booking(event=event, in_waiting_list=True).save()
# the event datetime should no longer be returned
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert len([x for x in resp.json['data'] if not x.get('disabled')]) == 2
assert event.slug not in [x['id'] for x in resp.json['data'] if not x.get('disabled')]
assert event.slug in [x['id'] for x in resp.json['data'] if x.get('disabled')]
@pytest.mark.freeze_time('2017-05-20')
def test_agenda_api_date_range(app):
# test range limitation
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
first_datetime = localtime(now()).replace(hour=20, minute=0, second=0, microsecond=0)
first_datetime += datetime.timedelta(days=1)
for i in range(2):
event = Event.objects.create(
start_datetime=first_datetime + datetime.timedelta(days=i), places=20, agenda=agenda
)
base_datetime = agenda.event_set.last().start_datetime
base_datetime = base_datetime + datetime.timedelta(days=1)
for idx in range(7, 10):
if idx == 7:
day_events = ['9:00', '10:00', '11:00']
elif idx == 8:
day_events = ['13:00', '14:00']
else:
day_events = ['8:00']
day = base_datetime.date() + datetime.timedelta(days=idx)
for event in day_events:
event_dt = datetime.datetime.combine(day, datetime.datetime.strptime(event, '%H:%M').time())
Event.objects.create(agenda=agenda, start_datetime=make_aware(event_dt), places=2)
for value in ['foo', '2017-05-42']:
params = {'date_start': value}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params, status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['date_start'] == [
'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD, YYYY-MM-DD hh:mm, YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].'
]
for value in ['foo', '2017-05-42']:
params = {'date_end': value}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params, status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['date_end'] == [
'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD, YYYY-MM-DD hh:mm, YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].'
]
params = {'date_start': base_datetime.date().isoformat()}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 6
date_endtime = base_datetime + datetime.timedelta(days=7)
params = {'date_end': date_endtime.date().isoformat()}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['datetime'] == '2017-05-21 20:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-05-22 20:00:00'
params = {
'date_start': base_datetime.date() + datetime.timedelta(days=8),
'date_end': base_datetime.date() + datetime.timedelta(days=10),
}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['datetime'] == '2017-05-31 13:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-06-01 08:00:00'
# with minimal booking delay changed
agenda.minimal_booking_delay = 3
agenda.save()
params = {'date_start': '2017-05-21'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 6
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-06-01 08:00:00'
# with maximal booking delay changed
agenda.maximal_booking_delay = 11
agenda.save()
params = {'date_end': '2017-06-01'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
# with time
params = {'date_start': '2017-05-21 foo'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params, status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['date_start'] == [
'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD, YYYY-MM-DD hh:mm, YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].'
]
for start in ['2017-05-30 09:00', '2017-05-30 09:00:00']:
params = {'date_start': start}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
for start in ['2017-05-30 09:01', '2017-05-30 09:00:01', '2017-05-30 09:00:01+02:00']:
params = {'date_start': start}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['datetime'] == '2017-05-30 10:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
params = {'date_end': '2017-06-01 foo'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params, status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['date_end'] == [
'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD, YYYY-MM-DD hh:mm, YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].'
]
for end in ['2017-05-30 11:01', '2017-05-30 11:00:01']:
params = {'date_end': end}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-05-30 11:00:00'
for end in ['2017-05-30 11:00', '2017-05-30 11:00:00', '2017-05-30 11:00:00+02:00']:
params = {'date_end': end}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['datetime'] == '2017-05-30 09:00:00'
assert resp.json['data'][-1]['datetime'] == '2017-05-30 10:00:00'
def test_datetimes_api_meta(app, freezer):
# 2017-05-20 -> saturday
freezer.move_to(make_aware(datetime.datetime(year=2017, month=5, day=20, hour=1, minute=12)))
agenda = Agenda.objects.create(label='Foo bar')
first_date = localtime(now()).replace(hour=17, minute=0, second=0, microsecond=0)
first_date += datetime.timedelta(days=1)
for i in range(3):
event = Event(start_datetime=first_date + datetime.timedelta(days=i), places=20, agenda=agenda)
event.save()
# a date in the past
event = Event(start_datetime=first_date - datetime.timedelta(days=10), places=10, agenda=agenda)
event.save()
events = Event.objects.filter(agenda_id=agenda.id).exclude(start_datetime__lt=now())
assert len(events) == 3
api_url = '/api/agenda/%s/datetimes/' % agenda.slug
resp = app.get(api_url)
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 3,
'first_bookable_slot': resp.json['data'][0],
}
def simulate_booking(event, nb_places):
for _ in range(nb_places):
Booking(event=event, user_external_id='42').save()
simulate_booking(events[0], 10)
resp = app.get(api_url)
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 3,
'first_bookable_slot': resp.json['data'][0],
}
resp = app.get(api_url, params={'exclude_user_external_id': '42'})
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 2,
'first_bookable_slot': resp.json['data'][1],
}
resp = app.get(api_url + '?min_places=11')
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 2,
'first_bookable_slot': resp.json['data'][1],
}
simulate_booking(events[0], 10)
resp = app.get(api_url)
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 2,
'first_bookable_slot': resp.json['data'][1],
}
simulate_booking(events[1], 20)
simulate_booking(events[2], 20)
resp = app.get(api_url)
assert len(resp.json['data']) == 3
assert resp.json['meta'] == {
'no_bookable_datetimes': True,
'bookable_datetimes_number_total': 3,
'bookable_datetimes_number_available': 0,
'first_bookable_slot': None,
}
# recurring event
Event.objects.all().delete()
Event.objects.create(
slug='abc',
label='Test',
start_datetime=localtime(),
recurrence_days=[localtime().weekday()],
places=5,
agenda=agenda,
)
resp = app.get(api_url)
assert resp.json['meta']['first_bookable_slot']['text'] == 'Test (May 27, 2017, 1:12 a.m.)'
def test_recurring_events_api(app, user, freezer):
freezer.move_to('2021-01-12 12:05') # Tuesday
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=1, maximal_booking_delay=30
)
base_event = Event.objects.create(
slug='abc',
label="Rock'n roll",
start_datetime=localtime(),
recurrence_days=[localtime().weekday()],
places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
data = resp.json['data']
assert len(data) == 4
assert data[0]['id'] == 'abc:2021-01-19-1305'
assert data[0]['datetime'] == '2021-01-19 13:05:00'
assert data[0]['text'] == "Rock'n roll (Jan. 19, 2021, 1:05 p.m.)"
assert data[3]['id'] == 'abc:2021-02-09-1305'
assert Event.objects.count() == 1
fillslot_url = data[0]['api']['fillslot_url']
app.authorization = ('Basic', ('john.doe', 'password'))
# book first event
resp = app.post(fillslot_url)
assert resp.json['err'] == 0
assert Event.objects.count() == 2
event = Booking.objects.get(pk=resp.json['booking_id']).event
assert event.slug == 'abc--2021-01-19-1305'
# first event is now a real event in datetimes
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
data = resp.json['data']
assert len(data) == 4
assert data[0]['id'] == event.slug
new_fillslot_url = data[0]['api']['fillslot_url']
# booking again with both old and new urls works
resp = app.post(fillslot_url)
assert resp.json['err'] == 0
resp = app.post(new_fillslot_url)
assert resp.json['err'] == 0
assert Event.objects.count() == 2
assert event.booking_set.count() == 3
# status and bookings api also create a real event
status_url = data[1]['api']['status_url']
resp = app.get(status_url)
assert resp.json['places']['total'] == 5
assert Event.objects.count() == 3
bookings_url = data[2]['api']['bookings_url']
resp = app.get(bookings_url, params={'user_external_id': '42'})
assert resp.json['data'] == []
assert Event.objects.count() == 4
# cancelled recurrences do not appear
event.cancel()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'abc--2021-01-26-1305'
# publication date is accounted for
Event.objects.filter(primary_event=base_event).delete()
base_event.publication_datetime = now().replace(day=27)
base_event.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 0
# events follow agenda display template
Event.objects.all().update(publication_datetime=None)
agenda.event_display_template = '{{ event.label }} - {{ event.start_datetime }}'
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert resp.json['data'][0]['text'] == "Rock'n roll - Jan. 19, 2021, 1:05 p.m."
# check querysets
agenda.event_display_template = ''
agenda.save()
base_event.publication_datetime = None
base_event.recurrence_end_date = datetime.date.today() + datetime.timedelta(days=365)
base_event.save()
base_event.create_all_recurrences()
with CaptureQueriesContext(connection) as ctx:
app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(ctx.captured_queries) == 5
# check delays
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 4
assert [e['disabled'] for e in resp.json['data']] == [False] * 4
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
assert len(resp.json['data']) == 53
assert [e['disabled'] for e in resp.json['data']] == [False] * 53
agenda.minimal_booking_delay = 10
agenda.mmaximal_booking_delay = 20
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 3
assert [e['disabled'] for e in resp.json['data']] == [False] * 3
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'bypass_delays': True})
assert len(resp.json['data']) == 53
assert [e['disabled'] for e in resp.json['data']] == [False] * 53
def test_recurring_events_api_various_times(app, user, mock_now):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
event = Event.objects.create(
slug='abc',
start_datetime=localtime(),
recurrence_days=[localtime().weekday()],
places=5,
agenda=agenda,
)
event.refresh_from_db()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 5
fillslot_url = resp.json['data'][0]['api']['fillslot_url']
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post(fillslot_url)
assert resp.json['err'] == 0
new_event = Booking.objects.get(pk=resp.json['booking_id']).event
assert event.start_datetime == new_event.start_datetime
def test_datetimes_dst(app, freezer):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=10
)
event = Event.objects.create(
slug='event-slug',
start_datetime=make_aware(datetime.datetime(2021, 3, 28, 12, 30)),
places=5,
agenda=agenda,
)
freezer.move_to('Fri, 18 Mar 2021 23:59:39 +0100')
# maximal_booking_delay is 10days so last bookable event is on
# 2021-03-28T00:00, so event should not be bookable
assert not event.in_bookable_period()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 0
def test_recurring_events_api_exceptions(app, user, freezer):
freezer.move_to('2021-01-12 12:05') # Tuesday
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=1, maximal_booking_delay=30
)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(
slug='abc',
start_datetime=localtime(),
recurrence_days=[localtime().weekday()],
places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
data = resp.json['data']
assert len(data) == 4
assert data[0]['datetime'] == '2021-01-19 13:05:00'
TimePeriodException.objects.create(
desk=agenda.desk_set.get(),
start_datetime=datetime.date(year=2021, month=1, day=18),
end_datetime=datetime.date(year=2021, month=1, day=20),
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['datetime'] == '2021-01-26 13:05:00'
# try to book excluded event
fillslot_url = data[0]['api']['fillslot_url']
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post(fillslot_url, status=400)
assert resp.json['err'] == 1
def test_past_datetimes(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
event1 = Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
event2 = Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
assert (
data[0]['api']['fillslot_url']
== 'http://testserver/api/agenda/foo-bar/fillslot/today-after-now/?events=future'
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is False
assert (
data[0]['api']['fillslot_url']
== 'http://testserver/api/agenda/foo-bar/fillslot/today-before-now/?events=past'
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
data = resp.json['data']
assert len(data) == 2
assert data[0]['id'] == 'today-before-now'
assert data[1]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert (
data[0]['api']['fillslot_url']
== 'http://testserver/api/agenda/foo-bar/fillslot/today-before-now/?events=all'
)
assert (
data[1]['api']['fillslot_url']
== 'http://testserver/api/agenda/foo-bar/fillslot/today-after-now/?events=all'
)
# check canceled
event1.cancel()
event2.cancel()
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
data = resp.json['data']
assert len(data) == 0
def test_past_datetimes_meta(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
assert len(resp.json['data']) == 1
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 1,
'bookable_datetimes_number_available': 1,
'first_bookable_slot': resp.json['data'][0],
}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'today-before-now'
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 1,
'bookable_datetimes_number_available': 1,
'first_bookable_slot': resp.json['data'][0],
}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'today-before-now'
assert resp.json['data'][1]['id'] == 'today-after-now'
assert resp.json['meta'] == {
'no_bookable_datetimes': False,
'bookable_datetimes_number_total': 2,
'bookable_datetimes_number_available': 2,
'first_bookable_slot': resp.json['data'][0],
}
def test_past_datetimes_date_range(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
Event.objects.create(
label='Yesterday 18H',
start_datetime=localtime(now() - datetime.timedelta(days=1)).replace(hour=18, minute=0),
places=5,
agenda=agenda,
)
Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
Event.objects.create(
label='Tomorrow 16H',
start_datetime=localtime(now() + datetime.timedelta(days=1)).replace(hour=16, minute=0),
places=5,
agenda=agenda,
)
# check date_start
params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'future'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 2
assert data[0]['id'] == 'today-after-now'
assert data[1]['id'] == 'tomorrow-16h'
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'past'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is False
params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'all'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 3
assert data[0]['id'] == 'today-before-now'
assert data[1]['id'] == 'today-after-now'
assert data[2]['id'] == 'tomorrow-16h'
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'future'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'tomorrow-16h'
assert data[0]['disabled'] is False
params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'past'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 0
params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'all'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'tomorrow-16h'
assert data[0]['disabled'] is False
# check date_end
params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'future'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'past'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 2
assert data[0]['id'] == 'yesterday-18h'
assert data[1]['id'] == 'today-before-now'
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'all'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 3
assert data[0]['id'] == 'yesterday-18h'
assert data[1]['id'] == 'today-before-now'
assert data[2]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'future'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 0
params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'past'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'yesterday-18h'
assert data[0]['disabled'] is False
params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'all'}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'yesterday-18h'
assert data[0]['disabled'] is False
# mix
params = {
'date_start': localtime(now() - datetime.timedelta(hours=2)),
'date_end': localtime(now() + datetime.timedelta(hours=2)),
'events': 'future',
}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
params = {
'date_start': localtime(now() - datetime.timedelta(hours=2)),
'date_end': localtime(now() + datetime.timedelta(hours=2)),
'events': 'past',
}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is False
params = {
'date_start': localtime(now() - datetime.timedelta(hours=2)),
'date_end': localtime(now() + datetime.timedelta(hours=2)),
'events': 'all',
}
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
data = resp.json['data']
assert len(data) == 2
assert data[0]['id'] == 'today-before-now'
assert data[1]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
def test_past_datetimes_places(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
event1 = Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=1,
agenda=agenda,
)
event2 = Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=1,
agenda=agenda,
)
Booking.objects.create(event=event1)
Booking.objects.create(event=event2)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert resp.json['data'][0]['places']['full'] is True
assert data[0]['disabled'] is True
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert resp.json['data'][0]['places']['full'] is True
assert data[0]['disabled'] is False # always available if past
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
event1.waiting_list_places = 1
event1.save()
event2.waiting_list_places = 1
event2.save()
Booking.objects.create(event=event1, in_waiting_list=True)
Booking.objects.create(event=event2, in_waiting_list=True)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert resp.json['data'][0]['places']['full'] is True
assert data[0]['disabled'] is True
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert resp.json['data'][0]['places']['full'] is True
assert data[0]['disabled'] is False # always available if past
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
def test_past_datetimes_min_places(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=1,
agenda=agenda,
)
Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=1,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future', 'min_places': 2})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is True
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'min_places': 2})
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is False # always available if past
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
def test_past_datetimes_exclude_slots(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
event1 = Event.objects.create(
label='Today before now',
start_datetime=localtime(now() - datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
event2 = Event.objects.create(
label='Today after now',
start_datetime=localtime(now() + datetime.timedelta(hours=1)),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event1, user_external_id='42')
Booking.objects.create(event=event2, user_external_id='42')
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'events': 'future', 'exclude_user_external_id': '35'},
)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is False
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-after-now'
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'exclude_user_external_id': '35'}
)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is False
assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'events': 'future', 'exclude_user_external_id': '42'},
)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-after-now'
assert data[0]['disabled'] is True
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'exclude_user_external_id': '42'}
)
data = resp.json['data']
assert len(data) == 1
assert data[0]['id'] == 'today-before-now'
assert data[0]['disabled'] is True
def test_past_datetimes_recurring_event(app, user):
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
)
start_datetime = make_aware(make_naive(now()) - datetime.timedelta(days=3 * 7))
event = Event.objects.create(
label='Recurring',
start_datetime=start_datetime,
recurrence_days=[start_datetime.weekday()],
places=5,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
data = resp.json['data']
assert len(data) == 4
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
assert data[3]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
data = resp.json['data']
assert len(data) == 0 # no date_start, not possible to compute recurring events in past
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'events': 'past', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
)
data = resp.json['data']
assert len(data) == 4
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
assert data[3]['disabled'] is False
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
data = resp.json['data']
assert len(data) == 4 # no date_start, not possible to compute recurring events in past
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
assert data[3]['disabled'] is False
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'events': 'all', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
)
data = resp.json['data']
assert len(data) == 8
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
assert data[3]['disabled'] is False
assert data[4]['disabled'] is False
assert data[5]['disabled'] is False
assert data[6]['disabled'] is False
assert data[7]['disabled'] is False
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={
'events': 'all',
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
'date_end': localtime(now() + datetime.timedelta(days=6 * 7)),
},
)
data = resp.json['data']
assert len(data) == 8
assert data[0]['disabled'] is False
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
assert data[3]['disabled'] is False
assert data[4]['disabled'] is False
assert data[5]['disabled'] is False
assert data[6]['disabled'] is False
assert data[7]['disabled'] is False
# check user_external_id
first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
booking = Booking.objects.create(event=first_recurrence, user_external_id='42', in_waiting_list=True)
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={
'events': 'past',
'user_external_id': '42',
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
},
)
data = resp.json['data']
assert data[0]['booked_for_external_user'] == 'waiting-list'
booking.in_waiting_list = False
booking.save()
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={
'events': 'past',
'user_external_id': '42',
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
},
)
data = resp.json['data']
assert data[0]['booked_for_external_user'] == 'main-list'
# check exclude_user_external_id
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={
'events': 'past',
'exclude_user_external_id': '42',
'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
},
)
data = resp.json['data']
assert len(data) == 4
assert data[0]['disabled'] is True
assert data[1]['disabled'] is False
assert data[2]['disabled'] is False
assert data[3]['disabled'] is False
# check canceled
first_recurrence.cancel()
resp = app.get(
'/api/agenda/%s/datetimes/' % agenda.slug,
params={'events': 'all', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
)
data = resp.json['data']
assert len(data) == 7
def test_recurring_events_api_list(app, freezer):
freezer.move_to('2021-09-06 12:00')
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(label='Normal event', start_datetime=now(), places=5, agenda=agenda)
event = Event.objects.create(
label='Example Event',
start_datetime=now(),
recurrence_days=[0, 3, 4], # Monday, Thursday, Friday
places=2,
agenda=agenda,
)
resp = app.get('/api/agendas/recurring-events/', status=400)
# recurring events without recurrence_end_date are not bookable
resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
assert len(resp.json['data']) == 0
event.recurrence_end_date = now() + datetime.timedelta(days=30)
event.save()
start_datetime = now() + datetime.timedelta(days=15)
Event.objects.create(
label='Other',
start_datetime=start_datetime,
recurrence_days=[start_datetime.weekday()],
places=2,
agenda=agenda,
recurrence_end_date=now() + datetime.timedelta(days=45),
)
resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
assert len(resp.json['data']) == 4
assert resp.json['data'][0]['id'] == 'foo-bar@example-event:0'
assert resp.json['data'][0]['text'] == 'Monday: Example Event'
assert resp.json['data'][0]['label'] == 'Example Event'
assert resp.json['data'][0]['day'] == 'Monday'
assert resp.json['data'][1]['id'] == 'foo-bar@other:1'
assert resp.json['data'][1]['text'] == 'Tuesday: Other'
assert resp.json['data'][1]['label'] == 'Other'
assert resp.json['data'][1]['day'] == 'Tuesday'
assert resp.json['data'][2]['id'] == 'foo-bar@example-event:3'
assert resp.json['data'][2]['text'] == 'Thursday: Example Event'
assert resp.json['data'][2]['label'] == 'Example Event'
assert resp.json['data'][2]['day'] == 'Thursday'
assert resp.json['data'][3]['id'] == 'foo-bar@example-event:4'
assert resp.json['data'][3]['text'] == 'Friday: Example Event'
assert resp.json['data'][3]['label'] == 'Example Event'
assert resp.json['data'][3]['day'] == 'Friday'
event.publication_datetime = now() + datetime.timedelta(days=2)
event.save()
resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
assert len(resp.json['data']) == 1
freezer.move_to(event.recurrence_end_date)
resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
assert len(resp.json['data']) == 1
@pytest.mark.freeze_time('2021-09-06 12:00')
def test_recurring_events_api_list_multiple_agendas(app):
agenda = Agenda.objects.create(label='First Agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
start, end = now(), now() + datetime.timedelta(days=30)
Event.objects.create(
label='A',
start_datetime=start,
places=2,
recurrence_end_date=end,
recurrence_days=[0, 2, 5],
agenda=agenda,
)
Event.objects.create(
label='B', start_datetime=start, places=2, recurrence_end_date=end, recurrence_days=[1], agenda=agenda
)
agenda2 = Agenda.objects.create(label='Second Agenda', kind='events')
Desk.objects.create(agenda=agenda2, slug='_exceptions_holder')
Event.objects.create(
label='C',
start_datetime=start,
places=2,
recurrence_end_date=end,
recurrence_days=[2, 3],
agenda=agenda2,
)
resp = app.get('/api/agendas/recurring-events/?agendas=first-agenda,second-agenda')
event_ids = [x['id'] for x in resp.json['data']]
assert event_ids == [
'first-agenda@a:0',
'first-agenda@b:1',
'first-agenda@a:2',
'second-agenda@c:2',
'second-agenda@c:3',
'first-agenda@a:5',
]
assert event_ids.index('first-agenda@a:2') < event_ids.index('second-agenda@c:2')
# sorting depends on querystring order
resp = app.get('/api/agendas/recurring-events/?agendas=second-agenda,first-agenda')
event_ids = [x['id'] for x in resp.json['data']]
assert event_ids.index('first-agenda@a:2') > event_ids.index('second-agenda@c:2')
resp = app.get('/api/agendas/recurring-events/?agendas=second-agenda')
assert [x['id'] for x in resp.json['data']] == ['second-agenda@c:2', 'second-agenda@c:3']
@pytest.mark.freeze_time('2021-09-06 12:00')
def test_recurring_events_api_list_multiple_agendas_queries(app):
for i in range(20):
agenda = Agenda.objects.create(slug=f'{i}', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
start, end = now(), now() + datetime.timedelta(days=30)
Event.objects.create(
start_datetime=start, places=2, recurrence_end_date=end, recurrence_days=[1, 2], agenda=agenda
)
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/api/agendas/recurring-events/?agendas=%s' % ','.join(str(i) for i in range(20)))
assert len(resp.json['data']) == 40
assert len(ctx.captured_queries) == 3
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas(app):
first_agenda = Agenda.objects.create(
label='First agenda', kind='events', minimal_booking_delay=0, maximal_booking_delay=45
)
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=5),
places=5,
agenda=first_agenda,
)
Event.objects.create( # base recurring event not visible in datetimes api
slug='recurring',
start_datetime=now() + datetime.timedelta(hours=1),
recurrence_days=[localtime().weekday()],
recurrence_end_date=now() + datetime.timedelta(days=15),
places=5,
agenda=first_agenda,
) # recurrences do not exist in DB
second_agenda = Agenda.objects.create(
label='Second agenda', kind='events', minimal_booking_delay=0, maximal_booking_delay=45
)
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
event = Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=6),
places=5,
agenda=second_agenda,
)
Booking.objects.create(event=event)
agenda_slugs = '%s,%s' % (first_agenda.slug, second_agenda.slug)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs})
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'first-agenda@recurring:2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][1]['text'] == 'May 11, 2021, 4 p.m.'
assert resp.json['data'][1]['places']['available'] == 5
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][2]['text'] == 'May 12, 2021, 4 p.m.'
assert resp.json['data'][2]['places']['available'] == 4
assert resp.json['data'][3]['id'] == 'first-agenda@recurring:2021-05-13-1700'
assert resp.json['data'][4]['id'] == 'first-agenda@recurring:2021-05-20-1700'
# check user_external_id
Booking.objects.create(event=event, user_external_id='user')
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'user_external_id': 'user'})
assert resp.json['data'][1]['places']['available'] == 5
assert 'booked_for_external_user' not in resp.json['data'][1]
assert resp.json['data'][1]['disabled'] is False
assert resp.json['data'][2]['places']['available'] == 3
assert resp.json['data'][2]['booked_for_external_user'] == 'main-list'
assert resp.json['data'][2]['disabled'] is False
# check exclude_user_external_id
resp = app.get(
'/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'exclude_user_external_id': 'user'}
)
assert 'booked_for_external_user' not in resp.json['data'][1]
assert resp.json['data'][1]['disabled'] is False
assert 'booked_for_external_user' not in resp.json['data'][2]
assert resp.json['data'][2]['disabled'] is True
# check min_places
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4})
assert resp.json['data'][1]['disabled'] is False
assert resp.json['data'][2]['disabled'] is True
# check meta
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'min_places': 4})
assert resp.json['meta']['bookable_datetimes_number_total'] == 5
assert resp.json['meta']['bookable_datetimes_number_available'] == 4
assert resp.json['meta']['first_bookable_slot'] == resp.json['data'][0]
# check date_start
date_start = localtime() + datetime.timedelta(days=5, hours=1)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'date_start': date_start})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'second-agenda@event'
assert resp.json['data'][1]['id'] == 'first-agenda@recurring:2021-05-13-1700'
assert resp.json['data'][2]['id'] == 'first-agenda@recurring:2021-05-20-1700'
# check date_end
date_end = localtime() + datetime.timedelta(days=5, hours=1)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'date_end': date_end})
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'first-agenda@recurring:2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_start': date_start, 'date_end': date_end},
)
assert len(resp.json['data']) == 0
# check delays
Agenda.objects.update(minimal_booking_delay=6, maximal_booking_delay=14)
date_end = localtime() + datetime.timedelta(days=60) # with a date end to have recurring events
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'date_end': date_end})
assert len(resp.json['data']) == 2
assert [d['disabled'] for d in resp.json['data']] == [False, False]
assert resp.json['data'][0]['id'] == 'second-agenda@event'
assert resp.json['data'][1]['id'] == 'first-agenda@recurring:2021-05-13-1700'
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_end': date_end, 'bypass_delays': True},
)
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'first-agenda@recurring:2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][3]['id'] == 'first-agenda@recurring:2021-05-13-1700'
assert resp.json['data'][4]['id'] == 'first-agenda@recurring:2021-05-20-1700'
assert [d['disabled'] for d in resp.json['data']] == [False, False, False, False, False]
Agenda.objects.update(minimal_booking_delay=0, maximal_booking_delay=45)
# invalid slugs
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'xxx'}, status=400)
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx'
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'first-agenda,xxx,yyy'}, status=400)
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx, yyy'
# missing agendas parameter
resp = app.get('/api/agendas/datetimes/', params={}, status=400)
assert resp.json['err_desc'] == 'invalid payload'
# it's possible to show past events
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'first-agenda@recurring:2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][3]['id'] == 'first-agenda@recurring:2021-05-13-1700'
assert resp.json['data'][4]['id'] == 'first-agenda@recurring:2021-05-20-1700'
assert [d['disabled'] for d in resp.json['data']] == [False, False, False, False, False]
# and events out of minimal_booking_delay
Agenda.objects.update(minimal_booking_delay=6, maximal_booking_delay=14)
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 4
assert resp.json['data'][0]['id'] == 'first-agenda@recurring:2021-05-06-1700'
assert resp.json['data'][1]['id'] == 'first-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@event'
assert resp.json['data'][3]['id'] == 'first-agenda@recurring:2021-05-13-1700'
assert [d['disabled'] for d in resp.json['data']] == [True, True, False, False]
Agenda.objects.update(minimal_booking_delay=0, maximal_booking_delay=45)
Event.objects.create(
slug='event-in-past',
start_datetime=now() - datetime.timedelta(days=5),
places=5,
agenda=first_agenda,
)
Event.objects.create( # base recurrring event not visible in datetimes api
slug='recurring-in-past',
start_datetime=now() - datetime.timedelta(days=15, hours=1),
recurrence_days=[localtime().weekday()],
recurrence_end_date=now(),
places=5,
agenda=first_agenda,
) # recurrences do not exist in DB
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 6
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@event-in-past',
'first-agenda@recurring:2021-05-06-1700',
'first-agenda@event',
'second-agenda@event',
'first-agenda@recurring:2021-05-13-1700',
'first-agenda@recurring:2021-05-20-1700',
]
assert [d['disabled'] for d in resp.json['data']] == [True, False, False, False, False, False]
date_start = localtime() - datetime.timedelta(days=10)
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_start': date_start, 'show_past_events': True},
)
assert len(resp.json['data']) == 7
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past:2021-04-29-1500',
'first-agenda@event-in-past',
'first-agenda@recurring:2021-05-06-1700',
'first-agenda@event',
'second-agenda@event',
'first-agenda@recurring:2021-05-13-1700',
'first-agenda@recurring:2021-05-20-1700',
]
date_start = localtime() - datetime.timedelta(days=4)
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': agenda_slugs, 'date_start': date_start, 'show_past_events': True},
)
assert len(resp.json['data']) == 5
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring:2021-05-06-1700',
'first-agenda@event',
'second-agenda@event',
'first-agenda@recurring:2021-05-13-1700',
'first-agenda@recurring:2021-05-20-1700',
]
date_start = localtime() - datetime.timedelta(days=30) # with a date start to have past recurring events
date_end = localtime() + datetime.timedelta(days=5, hours=1)
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': agenda_slugs,
'date_start': date_start,
'date_end': date_end,
'show_past_events': True,
},
)
assert len(resp.json['data']) == 5
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past:2021-04-22-1500',
'first-agenda@recurring-in-past:2021-04-29-1500',
'first-agenda@event-in-past',
'first-agenda@recurring:2021-05-06-1700',
'first-agenda@event',
]
date_end = localtime() - datetime.timedelta(days=8)
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': agenda_slugs,
'date_start': date_start,
'date_end': date_end,
'show_past_events': True,
},
)
assert len(resp.json['data']) == 1
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past:2021-04-22-1500',
]
date_end = localtime() - datetime.timedelta(days=5)
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': agenda_slugs,
'date_start': date_start,
'date_end': date_end,
'show_past_events': True,
},
)
assert len(resp.json['data']) == 2
assert [d['id'] for d in resp.json['data']] == [
'first-agenda@recurring-in-past:2021-04-22-1500',
'first-agenda@recurring-in-past:2021-04-29-1500',
]
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_sort(app):
category = Category.objects.create(label='Category A')
first_agenda = Agenda.objects.create(label='First agenda', kind='events', category=category)
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
Event.objects.create(label='10-05', start_datetime=now().replace(day=10), places=5, agenda=first_agenda)
second_agenda = Agenda.objects.create(label='Second agenda', kind='events', category=category)
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=second_agenda)
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=second_agenda)
category = Category.objects.create(label='Category B')
third_agenda = Agenda.objects.create(label='Third agenda', kind='events', category=category)
Desk.objects.create(agenda=third_agenda, slug='_exceptions_holder')
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=third_agenda)
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=third_agenda)
for agenda in Agenda.objects.all():
Subscription.objects.create(
agenda=agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
# check events are ordered by start_datetime and then by agenda order in querystring
agenda_slugs = ','.join((first_agenda.slug, third_agenda.slug, second_agenda.slug))
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
assert resp.json['data'][1]['id'] == 'second-agenda@09-05'
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
assert len(resp.json['data']) == 5
assert resp.json['data'][0]['id'] == 'third-agenda@04-05'
assert resp.json['data'][1]['id'] == 'second-agenda@04-05'
assert resp.json['data'][2]['id'] == 'third-agenda@09-05'
assert resp.json['data'][3]['id'] == 'second-agenda@09-05'
assert resp.json['data'][4]['id'] == 'first-agenda@10-05'
# check subscribed events are ordered by start_datetime
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'second-agenda@09-05'
assert resp.json['data'][1]['id'] == 'third-agenda@09-05'
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
# and by category slug if specified in querystring
resp = app.get(
'/api/agendas/datetimes/', params={'subscribed': 'category-b,category-a', 'user_external_id': 'xxx'}
)
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
assert resp.json['data'][1]['id'] == 'second-agenda@09-05'
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
# order is stable if same date events are in the same category
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=first_agenda)
resp = app.get(
'/api/agendas/datetimes/', params={'subscribed': 'category-b,category-a', 'user_external_id': 'xxx'}
)
assert len(resp.json['data']) == 4
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
assert resp.json['data'][1]['id'] == 'first-agenda@09-05'
assert resp.json['data'][2]['id'] == 'second-agenda@09-05'
assert resp.json['data'][3]['id'] == 'first-agenda@10-05'
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_queries(app):
category = Category.objects.create(label='Category A')
for i in range(10):
agenda = Agenda.objects.create(label=str(i), kind='events', category=category)
Subscription.objects.create(
agenda=agenda,
user_external_id='xxx',
date_start=now() - datetime.timedelta(days=10),
date_end=now() + datetime.timedelta(days=10),
)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
Event.objects.create(start_datetime=now() - datetime.timedelta(days=5), places=5, agenda=agenda)
Event.objects.create(start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda)
Event.objects.create(start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda)
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': ','.join(str(i) for i in range(10)), 'show_past_events': True},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 7
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'user_external_id': 'xxx', 'show_past_events': True},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 7
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'category-a', 'user_external_id': 'xxx', 'show_past_events': True},
)
assert len(resp.json['data']) == 30
assert len(ctx.captured_queries) == 7
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas_subscribed(app):
first_agenda = Agenda.objects.create(label='First agenda', kind='events')
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=5),
places=5,
agenda=first_agenda,
)
Event.objects.create(
slug='event-2',
start_datetime=now() + datetime.timedelta(days=20),
places=5,
agenda=first_agenda,
)
category = Category.objects.create(label='Category A')
second_agenda = Agenda.objects.create(
label='Second agenda', kind='events', category=category, maximal_booking_delay=400
)
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
Event.objects.create(
slug='event',
start_datetime=now() + datetime.timedelta(days=20),
places=5,
agenda=second_agenda,
)
Event.objects.create(
slug='next-year-event',
start_datetime=now() + datetime.timedelta(days=365),
places=5,
agenda=second_agenda,
)
Subscription.objects.create(
agenda=first_agenda,
user_external_id='yyy',
date_start=now(),
date_end=now() + datetime.timedelta(days=10),
)
# no subscription for user xxx
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 0
# add subscription to first agenda
Subscription.objects.create(
agenda=first_agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=10),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'first-agenda@event'
# no subscription to second agenda
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 0
# add subscription to second agenda
Subscription.objects.create(
agenda=second_agenda,
user_external_id='xxx',
date_start=now() + datetime.timedelta(days=15),
date_end=now() + datetime.timedelta(days=25),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['id'] == 'second-agenda@event'
# add new subscription (disjoint) to second agenda
Subscription.objects.create(
agenda=second_agenda,
user_external_id='xxx',
date_start=now() + datetime.timedelta(days=355),
date_end=now() + datetime.timedelta(days=375),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == 'second-agenda@event'
assert resp.json['data'][1]['id'] == 'second-agenda@next-year-event'
# view events from all subscriptions
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 3
assert resp.json['data'][0]['id'] == 'first-agenda@event'
assert resp.json['data'][1]['id'] == 'second-agenda@event'
assert resp.json['data'][2]['id'] == 'second-agenda@next-year-event'
# overlapping subscription changes nothing
Subscription.objects.create(
agenda=first_agenda,
user_external_id='xxx',
date_start=now() + datetime.timedelta(days=1),
date_end=now() + datetime.timedelta(days=11),
)
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
assert len(resp.json['data']) == 3
# check errors
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all'}, status=400)
assert 'required' in resp.json['errors']['user_external_id'][0]
resp = app.get(
'/api/agendas/datetimes/',
params={'subscribed': 'all', 'agendas': 'first-agenda', 'user_external_id': 'xxx'},
status=400,
)
assert 'mutually exclusive' in resp.json['errors']['non_field_errors'][0]