Projet

Général

Profil

0002-api-make-recurring-events-list-endpoint-work-with-mu.patch

Valentin Deniaud, 25 octobre 2021 15:47

Télécharger (10,2 ko)

Voir les différences:

Subject: [PATCH 2/5] api: make recurring events list endpoint work with
 multiple agendas (#57957)

 chrono/api/urls.py          |  6 +--
 chrono/api/views.py         | 35 ++++++++-----
 tests/api/test_datetimes.py | 98 ++++++++++++++++++++++++++++++-------
 3 files changed, 105 insertions(+), 34 deletions(-)
chrono/api/urls.py
21 21
urlpatterns = [
22 22
    url(r'^agenda/$', views.agendas),
23 23
    url(r'^agendas/datetimes/$', views.agendas_datetimes, name='api-agendas-datetimes'),
24
    url(r'^agendas/recurring-events/$', views.recurring_events_list, name='api-agenda-recurring-events'),
24 25
    url(
25 26
        r'^agendas/events/fillslots/$',
26 27
        views.agendas_events_fillslots,
......
39 40
        views.events_fillslots,
40 41
        name='api-agenda-events-fillslots',
41 42
    ),
42
    url(
43
        r'^agenda/(?P<agenda_identifier>[\w-]+)/recurring-events/$',
44
        views.recurring_events_list,
45
        name='api-agenda-recurring-events',
46
    ),
47 43
    url(
48 44
        r'^agenda/(?P<agenda_identifier>[\w-]+)/recurring-events/fillslots/$',
49 45
        views.recurring_fillslots,
chrono/api/views.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import collections
18
import copy
18 19
import datetime
19 20
import itertools
20 21
import uuid
......
1066 1067
        if not settings.ENABLE_RECURRING_EVENT_BOOKING:
1067 1068
            raise Http404()
1068 1069

  
1069
        agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
1070
        entries = agenda.get_open_recurring_events()
1070
        agenda_slugs = get_agendas_from_request(request)
1071
        agendas = get_objects_from_slugs(agenda_slugs, qs=Agenda.objects.filter(kind='events'))
1071 1072

  
1072 1073
        events = []
1073
        for event in entries:
1074
            for day in event.recurrence_days:
1075
                slug = '%s:%s' % (event.slug, day)
1076
                events.append(
1074
        for agenda in agendas:
1075
            for event in agenda.get_open_recurring_events():
1076
                for day in event.recurrence_days:
1077
                    event = copy.copy(event)
1078
                    event.day = day
1079
                    events.append(event)
1080

  
1081
        agenda_querystring_indexes = {agenda_slug: i for i, agenda_slug in enumerate(agenda_slugs)}
1082
        events.sort(key=lambda event: (event.day, agenda_querystring_indexes[event.agenda.slug]))
1083

  
1084
        return Response(
1085
            {
1086
                'data': [
1077 1087
                    {
1078
                        'id': slug,
1079
                        'text': get_event_text(event, agenda, day),
1088
                        'id': '%s@%s:%s' % (event.agenda.slug, event.slug, event.day),
1089
                        'text': get_event_text(event, event.agenda, event.day),
1080 1090
                        'label': event.label or '',
1081
                        'day': WEEKDAYS[day].capitalize(),
1091
                        'day': WEEKDAYS[event.day].capitalize(),
1082 1092
                        'date': format_response_date(event.start_datetime),
1083 1093
                        'datetime': format_response_datetime(event.start_datetime),
1084 1094
                        'description': event.description,
1085 1095
                        'pricing': event.pricing,
1086 1096
                        'url': event.url,
1087 1097
                    }
1088
                )
1089

  
1090
        return Response({'data': events})
1098
                    for event in events
1099
                ]
1100
            }
1101
        )
1091 1102

  
1092 1103

  
1093 1104
recurring_events_list = RecurringEventsList.as_view()
tests/api/test_datetimes.py
1318 1318
def test_recurring_events_api_list(app, freezer):
1319 1319
    freezer.move_to('2021-09-06 12:00')
1320 1320
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
1321
    Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
1321 1322
    Event.objects.create(label='Normal event', start_datetime=now(), places=5, agenda=agenda)
1322 1323
    event = Event.objects.create(
1323 1324
        label='Example Event',
......
1327 1328
        agenda=agenda,
1328 1329
    )
1329 1330

  
1330
    resp = app.get('/api/agenda/xxx/recurring-events/', status=404)
1331
    resp = app.get('/api/agendas/recurring-events/', status=400)
1331 1332

  
1332 1333
    # recurring events without recurrence_end_date are not bookable
1333
    resp = app.get('/api/agenda/%s/recurring-events/' % agenda.slug)
1334
    resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
1334 1335
    assert len(resp.json['data']) == 0
1335 1336

  
1336 1337
    event.recurrence_end_date = now() + datetime.timedelta(days=30)
......
1345 1346
        recurrence_end_date=now() + datetime.timedelta(days=45),
1346 1347
    )
1347 1348

  
1348
    resp = app.get('/api/agenda/%s/recurring-events/' % agenda.slug)
1349
    resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
1349 1350
    assert len(resp.json['data']) == 4
1350
    assert resp.json['data'][0]['id'] == 'example-event:0'
1351
    assert resp.json['data'][0]['id'] == 'foo-bar@example-event:0'
1351 1352
    assert resp.json['data'][0]['text'] == 'Monday: Example Event'
1352 1353
    assert resp.json['data'][0]['label'] == 'Example Event'
1353 1354
    assert resp.json['data'][0]['day'] == 'Monday'
1354
    assert resp.json['data'][1]['id'] == 'example-event:3'
1355
    assert resp.json['data'][1]['text'] == 'Thursday: Example Event'
1356
    assert resp.json['data'][1]['label'] == 'Example Event'
1357
    assert resp.json['data'][1]['day'] == 'Thursday'
1358
    assert resp.json['data'][2]['id'] == 'example-event:4'
1359
    assert resp.json['data'][2]['text'] == 'Friday: Example Event'
1355
    assert resp.json['data'][1]['id'] == 'foo-bar@other:1'
1356
    assert resp.json['data'][1]['text'] == 'Tuesday: Other'
1357
    assert resp.json['data'][1]['label'] == 'Other'
1358
    assert resp.json['data'][1]['day'] == 'Tuesday'
1359
    assert resp.json['data'][2]['id'] == 'foo-bar@example-event:3'
1360
    assert resp.json['data'][2]['text'] == 'Thursday: Example Event'
1360 1361
    assert resp.json['data'][2]['label'] == 'Example Event'
1361
    assert resp.json['data'][2]['day'] == 'Friday'
1362
    assert resp.json['data'][3]['id'] == 'other:1'
1363
    assert resp.json['data'][3]['text'] == 'Tuesday: Other'
1364
    assert resp.json['data'][3]['label'] == 'Other'
1365
    assert resp.json['data'][3]['day'] == 'Tuesday'
1362
    assert resp.json['data'][2]['day'] == 'Thursday'
1363
    assert resp.json['data'][3]['id'] == 'foo-bar@example-event:4'
1364
    assert resp.json['data'][3]['text'] == 'Friday: Example Event'
1365
    assert resp.json['data'][3]['label'] == 'Example Event'
1366
    assert resp.json['data'][3]['day'] == 'Friday'
1366 1367

  
1367 1368
    event.publication_datetime = now() + datetime.timedelta(days=2)
1368 1369
    event.save()
1369
    resp = app.get('/api/agenda/%s/recurring-events/' % agenda.slug)
1370
    resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
1370 1371
    assert len(resp.json['data']) == 1
1371 1372

  
1372 1373
    freezer.move_to(event.recurrence_end_date)
1373
    resp = app.get('/api/agenda/%s/recurring-events/' % agenda.slug)
1374
    resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda.slug)
1374 1375
    assert len(resp.json['data']) == 1
1375 1376

  
1376 1377

  
1378
@pytest.mark.freeze_time('2021-09-06 12:00')
1379
def test_recurring_events_api_list_multiple_agendas(app):
1380
    agenda = Agenda.objects.create(label='First Agenda', kind='events')
1381
    Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
1382
    start, end = now(), now() + datetime.timedelta(days=30)
1383
    Event.objects.create(
1384
        label='A',
1385
        start_datetime=start,
1386
        places=2,
1387
        recurrence_end_date=end,
1388
        recurrence_days=[0, 2, 5],
1389
        agenda=agenda,
1390
    )
1391
    Event.objects.create(
1392
        label='B', start_datetime=start, places=2, recurrence_end_date=end, recurrence_days=[1], agenda=agenda
1393
    )
1394
    agenda2 = Agenda.objects.create(label='Second Agenda', kind='events')
1395
    Desk.objects.create(agenda=agenda2, slug='_exceptions_holder')
1396
    Event.objects.create(
1397
        label='C',
1398
        start_datetime=start,
1399
        places=2,
1400
        recurrence_end_date=end,
1401
        recurrence_days=[2, 3],
1402
        agenda=agenda2,
1403
    )
1404

  
1405
    resp = app.get('/api/agendas/recurring-events/?agendas=first-agenda,second-agenda')
1406
    event_ids = [x['id'] for x in resp.json['data']]
1407
    assert event_ids == [
1408
        'first-agenda@a:0',
1409
        'first-agenda@b:1',
1410
        'first-agenda@a:2',
1411
        'second-agenda@c:2',
1412
        'second-agenda@c:3',
1413
        'first-agenda@a:5',
1414
    ]
1415
    assert event_ids.index('first-agenda@a:2') < event_ids.index('second-agenda@c:2')
1416

  
1417
    # sorting depends on querystring order
1418
    resp = app.get('/api/agendas/recurring-events/?agendas=second-agenda,first-agenda')
1419
    event_ids = [x['id'] for x in resp.json['data']]
1420
    assert event_ids.index('first-agenda@a:2') > event_ids.index('second-agenda@c:2')
1421

  
1422
    resp = app.get('/api/agendas/recurring-events/?agendas=second-agenda')
1423
    assert [x['id'] for x in resp.json['data']] == ['second-agenda@c:2', 'second-agenda@c:3']
1424

  
1425

  
1426
@pytest.mark.freeze_time('2021-09-06 12:00')
1427
def test_recurring_events_api_list_multiple_agendas_queries(app):
1428
    for i in range(20):
1429
        agenda = Agenda.objects.create(slug=f'{i}', kind='events')
1430
        Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
1431
        start, end = now(), now() + datetime.timedelta(days=30)
1432
        Event.objects.create(
1433
            start_datetime=start, places=2, recurrence_end_date=end, recurrence_days=[1, 2], agenda=agenda
1434
        )
1435
    with CaptureQueriesContext(connection) as ctx:
1436
        resp = app.get('/api/agendas/recurring-events/?agendas=%s' % ','.join(str(i) for i in range(20)))
1437
        assert len(resp.json['data']) == 40
1438
        assert len(ctx.captured_queries) == 23
1439

  
1440

  
1377 1441
@pytest.mark.freeze_time('2021-05-06 14:00')
1378 1442
def test_datetimes_multiple_agendas(app):
1379 1443
    first_agenda = Agenda.objects.create(label='First agenda', kind='events')
1380
-