chrono/tests/api/test_all.py

541 lines
21 KiB
Python

# -*- coding: utf-8 -*-
import datetime
import pytest
from django.db import connection
from django.test.utils import CaptureQueriesContext
from django.utils.timezone import localtime, now
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
Category,
Desk,
Event,
MeetingType,
Resource,
TimePeriodException,
VirtualMember,
)
pytestmark = pytest.mark.django_db
def test_agendas_api(app):
category_a = Category.objects.create(label='Category A')
category_b = Category.objects.create(label='Category B')
group = AbsenceReasonGroup.objects.create(label='Foo')
reason = AbsenceReason.objects.create(group=group, label='Foo bar')
reason2 = AbsenceReason.objects.create(group=group, label='Foo bar baz')
event_agenda = Agenda.objects.create(label='Foo bar', category=category_a, absence_reasons_group=group)
Desk.objects.create(agenda=event_agenda, slug='_exceptions_holder')
event_agenda2 = Agenda.objects.create(label='Foo bar 2', category=category_a)
Desk.objects.create(agenda=event_agenda2, slug='_exceptions_holder')
event_agenda3 = Agenda.objects.create(label='Foo bar 3', absence_reasons_group=group)
Desk.objects.create(agenda=event_agenda3, slug='_exceptions_holder')
meetings_agenda1 = Agenda.objects.create(label='Foo bar Meeting', kind='meetings', category=category_b)
Agenda.objects.create(label='Foo bar Meeting 2', kind='meetings')
resource1 = Resource.objects.create(label='Resource 1', description='Foo bar Resource 1')
resource2 = Resource.objects.create(label='Resource 2', description='Foo bar Resource 2')
Resource.objects.create(label='Resource 3')
meetings_agenda1.resources.add(resource1, resource2)
Agenda.objects.create(
label='Virtual Agenda', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=56
)
resp = app.get('/api/agenda/')
assert resp.json == {
'data': [
{
'text': 'Foo bar',
'id': 'foo-bar',
'slug': 'foo-bar',
'kind': 'events',
'minimal_booking_delay': 1,
'maximal_booking_delay': 56,
'absence_reasons': [
{'id': reason.slug, 'slug': reason.slug, 'text': reason.label, 'label': reason.label},
{'id': reason2.slug, 'slug': reason2.slug, 'text': reason2.label, 'label': reason2.label},
],
'api': {
'datetimes_url': 'http://testserver/api/agenda/foo-bar/datetimes/',
'fillslots_url': 'http://testserver/api/agenda/foo-bar/fillslots/',
},
},
{
'text': 'Foo bar 2',
'id': 'foo-bar-2',
'kind': 'events',
'slug': 'foo-bar-2',
'minimal_booking_delay': 1,
'maximal_booking_delay': 56,
'api': {
'datetimes_url': 'http://testserver/api/agenda/foo-bar-2/datetimes/',
'fillslots_url': 'http://testserver/api/agenda/foo-bar-2/fillslots/',
},
},
{
'text': 'Foo bar 3',
'id': 'foo-bar-3',
'kind': 'events',
'slug': 'foo-bar-3',
'minimal_booking_delay': 1,
'maximal_booking_delay': 56,
'absence_reasons': [
{'id': reason.slug, 'slug': reason.slug, 'text': reason.label, 'label': reason.label},
{'id': reason2.slug, 'slug': reason2.slug, 'text': reason2.label, 'label': reason2.label},
],
'api': {
'datetimes_url': 'http://testserver/api/agenda/foo-bar-3/datetimes/',
'fillslots_url': 'http://testserver/api/agenda/foo-bar-3/fillslots/',
},
},
{
'text': 'Foo bar Meeting',
'id': 'foo-bar-meeting',
'slug': 'foo-bar-meeting',
'minimal_booking_delay': 1,
'maximal_booking_delay': 56,
'kind': 'meetings',
'resources': [
{'id': 'resource-1', 'text': 'Resource 1', 'description': 'Foo bar Resource 1'},
{'id': 'resource-2', 'text': 'Resource 2', 'description': 'Foo bar Resource 2'},
],
'api': {
'meetings_url': 'http://testserver/api/agenda/foo-bar-meeting/meetings/',
'desks_url': 'http://testserver/api/agenda/foo-bar-meeting/desks/',
'resources_url': 'http://testserver/api/agenda/foo-bar-meeting/resources/',
'fillslots_url': 'http://testserver/api/agenda/foo-bar-meeting/fillslots/',
},
},
{
'text': 'Foo bar Meeting 2',
'id': 'foo-bar-meeting-2',
'slug': 'foo-bar-meeting-2',
'minimal_booking_delay': 1,
'maximal_booking_delay': 56,
'kind': 'meetings',
'resources': [],
'api': {
'meetings_url': 'http://testserver/api/agenda/foo-bar-meeting-2/meetings/',
'desks_url': 'http://testserver/api/agenda/foo-bar-meeting-2/desks/',
'resources_url': 'http://testserver/api/agenda/foo-bar-meeting-2/resources/',
'fillslots_url': 'http://testserver/api/agenda/foo-bar-meeting-2/fillslots/',
},
},
{
'text': 'Virtual Agenda',
'id': 'virtual-agenda',
'slug': 'virtual-agenda',
'minimal_booking_delay': 1,
'maximal_booking_delay': 56,
'kind': 'virtual',
'api': {
'meetings_url': 'http://testserver/api/agenda/virtual-agenda/meetings/',
'desks_url': 'http://testserver/api/agenda/virtual-agenda/desks/',
'fillslots_url': 'http://testserver/api/agenda/virtual-agenda/fillslots/',
},
},
]
}
resp = app.get('/api/agenda/', params={'q': 'foo'})
assert len(resp.json['data']) == 5
resp = app.get('/api/agenda/', params={'q': 'MEET'})
assert len(resp.json['data']) == 2
resp = app.get('/api/agenda/', params={'q': ''})
assert len(resp.json['data']) == 0
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/api/agenda/')
assert len(ctx.captured_queries) == 4
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/api/agenda/', params={'q': 'MEET'})
assert len(ctx.captured_queries) == 2
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
resp = app.get('/api/agenda/', params={'category': ''})
assert len(resp.json['data']) == 6
resp = app.get('/api/agenda/', params={'category': '__none__'})
assert len(resp.json['data']) == 3
resp = app.get('/api/agenda/', params={'category': 'category-a'})
assert len(resp.json['data']) == 2
resp = app.get('/api/agenda/', params={'category': 'category-b'})
assert len(resp.json['data']) == 1
resp = app.get('/api/agenda/', params={'category': 'unknown'})
assert len(resp.json['data']) == 0
event1 = Event.objects.create(
start_datetime=(localtime() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
places=20,
agenda=event_agenda,
)
event2 = Event.objects.create(
start_datetime=(localtime() + datetime.timedelta(days=10)).replace(hour=10, minute=0),
places=20,
agenda=event_agenda,
)
event3 = Event.objects.create(
start_datetime=(localtime() + datetime.timedelta(days=15)).replace(hour=10, minute=0),
places=20,
agenda=event_agenda,
)
# all events are free
resp = app.get('/api/agenda/', params={'with_open_events': 'true'})
assert len(resp.json['data']) == 1
# one event is full
Event.objects.filter(pk=event1.pk).update(full=True)
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 1
# all events are full
Event.objects.update(full=True)
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# event1 is not full but too soon
Event.objects.filter(pk=event1.pk).update(full=False)
event_agenda.minimal_booking_delay = 10
event_agenda.save()
assert list(event_agenda.get_open_events()) == [event2, event3]
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# event3 is not full but too late
Event.objects.filter(pk=event3.pk).update(full=False)
event_agenda.maximal_booking_delay = 12
event_agenda.save()
assert list(event_agenda.get_open_events()) == [event2]
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# events are not full but not published
Event.objects.update(full=False)
event_agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20))
assert list(event_agenda.get_open_events()) == []
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# event recurrences are available
Event.objects.create(
start_datetime=now(),
places=10,
agenda=event_agenda,
recurrence_days=list(range(7)),
)
assert len(event_agenda.get_open_events()) == 2
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 1
for _ in range(10):
event_agenda = Agenda.objects.create(label='Foo bar', category=category_a)
Desk.objects.create(agenda=event_agenda, slug='_exceptions_holder')
Event.objects.create(
start_datetime=now(), places=10, agenda=event_agenda, recurrence_days=[now().weekday()]
)
TimePeriodException.objects.create(
desk=event_agenda.desk_set.get(),
start_datetime=now(),
end_datetime=now() + datetime.timedelta(hours=1),
)
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(ctx.captured_queries) == 8
def test_agendas_meetingtypes_api(app, some_data, meetings_agenda):
resp = app.get('/api/agenda/%s/meetings/' % meetings_agenda.slug)
expected_resp = {
'data': [
{
'text': 'Blah',
'id': 'blah',
'duration': 30,
'api': {
'datetimes_url': 'http://testserver/api/agenda/foo-bar-meeting/meetings/blah/datetimes/',
},
}
]
}
assert resp.json == expected_resp
# deleted meeting type does not show up
MeetingType.objects.create(agenda=meetings_agenda, slug='deleted-meeting-type', duration=43, deleted=True)
resp = app.get('/api/agenda/%s/meetings/' % meetings_agenda.slug)
assert resp.json == expected_resp
# wrong kind
agenda1 = Agenda.objects.filter(label=u'Foo bar')[0]
resp = app.get('/api/agenda/%s/meetings/' % agenda1.slug, status=404)
# unknown
resp = app.get('/api/agenda/xxxx/meetings/', status=404)
def test_agendas_meetingtype_api(app):
agenda = Agenda.objects.create(label='Foo bar meeting', kind='meetings')
MeetingType.objects.create(agenda=agenda, label='Blah', duration=30)
resp = app.get('/api/agenda/%s/meetings/blah/' % agenda.slug)
assert resp.json == {
'data': {
'text': 'Blah',
'id': 'blah',
'duration': 30,
'api': {
'datetimes_url': 'http://testserver/api/agenda/foo-bar-meeting/meetings/blah/datetimes/',
},
}
}
# unknown
resp = app.get('/api/agenda/xxxx/meetings/', status=404)
resp = app.get('/api/agenda/%s/meetings/xxxx/' % agenda.slug, status=404)
# wrong kind
agenda.kind = 'virtual'
agenda.save()
resp = app.get('/api/agenda/%s/resources/' % agenda.slug, status=404)
agenda.kind = 'events'
agenda.save()
resp = app.get('/api/agenda/%s/resources/' % agenda.slug, status=404)
def test_agendas_desks_api(app):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
Desk.objects.create(agenda=agenda, label='Desk 1')
resp = app.get('/api/agenda/%s/desks/' % agenda.slug)
assert resp.json == {
'data': [
{
'text': 'Desk 1',
'id': 'desk-1',
}
]
}
# unknown
resp = app.get('/api/agenda/xxxx/resources/', status=404)
# wrong kind
agenda.kind = 'virtual'
agenda.save()
resp = app.get('/api/agenda/%s/resources/' % agenda.slug, status=404)
agenda.kind = 'events'
agenda.save()
resp = app.get('/api/agenda/%s/resources/' % agenda.slug, status=404)
def test_agendas_resources_api(app):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
resource1 = Resource.objects.create(label='Resource 1', description='Foo bar Resource 1')
resource2 = Resource.objects.create(label='Resource 2')
agenda.resources.add(resource1, resource2)
resp = app.get('/api/agenda/%s/resources/' % agenda.slug)
assert resp.json == {
'data': [
{
'text': 'Resource 1',
'id': 'resource-1',
'description': 'Foo bar Resource 1',
},
{
'text': 'Resource 2',
'id': 'resource-2',
'description': '',
},
]
}
# unknown
resp = app.get('/api/agenda/xxxx/resources/', status=404)
# wrong kind
agenda.kind = 'virtual'
agenda.save()
resp = app.get('/api/agenda/%s/resources/' % agenda.slug, status=404)
agenda.kind = 'events'
agenda.save()
resp = app.get('/api/agenda/%s/resources/' % agenda.slug, status=404)
def test_agenda_detail_api(app):
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
event1 = Event.objects.create(
start_datetime=(localtime() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
places=20,
agenda=agenda,
)
event2 = Event.objects.create(
start_datetime=(localtime() + datetime.timedelta(days=10)).replace(hour=10, minute=0),
places=20,
agenda=agenda,
)
event3 = Event.objects.create(
start_datetime=(localtime() + datetime.timedelta(days=15)).replace(hour=10, minute=0),
places=20,
agenda=agenda,
)
resp = app.get('/api/agenda/%s/' % agenda.slug)
data = resp.json['data']
assert data['id'] == 'foo-bar'
assert data['slug'] == 'foo-bar'
assert data['text'] == 'Foo bar'
assert data['kind'] == 'events'
assert data['opened_events_available'] is True
assert data['api']['datetimes_url'] == 'http://testserver/api/agenda/foo-bar/datetimes/'
# one event is full
Event.objects.filter(pk=event1.pk).update(full=True)
resp = app.get('/api/agenda/%s/' % agenda.slug)
assert resp.json['data']['opened_events_available'] is True
# all events are full
Event.objects.update(full=True)
resp = app.get('/api/agenda/%s/' % agenda.slug)
assert resp.json['data']['opened_events_available'] is False
# event1 is not full but too soon
Event.objects.filter(pk=event1.pk).update(full=False)
agenda.minimal_booking_delay = 10
agenda.save()
resp = app.get('/api/agenda/%s/' % agenda.slug)
assert list(agenda.get_open_events()) == [event2, event3]
assert resp.json['data']['opened_events_available'] is False
# event3 is not full but too late
Event.objects.filter(pk=event3.pk).update(full=False)
agenda.maximal_booking_delay = 12
agenda.save()
resp = app.get('/api/agenda/%s/' % agenda.slug)
assert list(agenda.get_open_events()) == [event2]
assert resp.json['data']['opened_events_available'] is False
# events are not full but not published
Event.objects.update(full=False)
agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20))
resp = app.get('/api/agenda/%s/' % agenda.slug)
assert list(agenda.get_open_events()) == []
assert resp.json['data']['opened_events_available'] is False
# unknown
app.get('/api/agenda/whatever/', status=404)
def test_agenda_detail_routing(app, meetings_agenda):
api_url = '/api/agenda/%s/' % meetings_agenda.slug
resp = app.get(api_url)
assert isinstance(resp.json['data'], dict)
# check it doesn't get confused with an agenda with "agenda" in its slug
agenda = Agenda(
label=u'Foo bar Agenda', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=56
)
agenda.save()
api_url = '/api/agenda/%s/' % agenda.slug
resp = app.get(api_url)
assert isinstance(resp.json['data'], dict)
def test_virtual_agenda_detail(app, virtual_meetings_agenda):
resp = app.get('/api/agenda/%s/' % virtual_meetings_agenda.slug)
assert resp.json == {
'data': {
'text': 'Virtual Agenda',
'id': 'virtual-agenda',
'slug': 'virtual-agenda',
'minimal_booking_delay': None,
'maximal_booking_delay': None,
'kind': 'virtual',
'api': {
'meetings_url': 'http://testserver/api/agenda/%s/meetings/' % virtual_meetings_agenda.slug,
'desks_url': 'http://testserver/api/agenda/%s/desks/' % virtual_meetings_agenda.slug,
'fillslots_url': 'http://testserver/api/agenda/%s/fillslots/' % virtual_meetings_agenda.slug,
},
},
}
def test_virtual_agendas_meetingtypes_api(app):
virt_agenda = Agenda.objects.create(label=u'Virtual agenda', kind='virtual')
# No meetings because no real agenda
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {'data': []}
# One real agenda : every meetings exposed
foo_agenda = Agenda.objects.create(label=u'Foo', kind='meetings')
MeetingType.objects.create(agenda=foo_agenda, label='Meeting1', duration=30)
MeetingType.objects.create(agenda=foo_agenda, label='Meeting2', duration=15)
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda)
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {
'data': [
{
'text': 'Meeting1',
'id': 'meeting1',
'duration': 30,
'api': {
'datetimes_url': 'http://testserver/api/agenda/virtual-agenda/meetings/meeting1/datetimes/',
},
},
{
'text': 'Meeting2',
'id': 'meeting2',
'duration': 15,
'api': {
'datetimes_url': 'http://testserver/api/agenda/virtual-agenda/meetings/meeting2/datetimes/',
},
},
]
}
# Several real agendas
bar_agenda = Agenda.objects.create(label=u'Bar', kind='meetings')
MeetingType.objects.create(agenda=bar_agenda, label='Meeting Bar', duration=30)
VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
# Bar agenda has no meeting type: no meetings exposed
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {'data': []}
# Bar agenda has a meetings wih different label, slug, duration: no meetings exposed
mt = MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type Bar', duration=15)
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {'data': []}
# Bar agenda has a meetings wih same label, but different slug and duration: no meetings exposed
mt.label = 'Meeting1'
mt.save()
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {'data': []}
# Bar agenda has a meetings wih same label and slug, but different duration: no meetings exposed
mt.slug = 'meeting1'
mt.save()
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {'data': []}
# Bar agenda has a meetings wih same label, slug and duration: only this meeting exposed
mt.duration = 30
mt.save()
resp = app.get('/api/agenda/%s/meetings/' % virt_agenda.slug)
assert resp.json == {
'data': [
{
'text': 'Meeting1',
'id': 'meeting1',
'duration': 30,
'api': {
'datetimes_url': 'http://testserver/api/agenda/virtual-agenda/meetings/meeting1/datetimes/',
},
},
]
}