api: filter by subscriptions in recurring events list (#58446)

This commit is contained in:
Valentin Deniaud 2021-12-01 14:20:20 +01:00
parent 2e7d87ffe7
commit 270daa2202
3 changed files with 129 additions and 6 deletions

View File

@ -205,6 +205,7 @@ class AgendaOrSubscribedSlugsMixin(metaclass=serializers.SerializerMetaclass):
subscribed = CommaSeparatedStringField(
required=False, child=serializers.SlugField(max_length=160, allow_blank=False)
)
user_external_id = serializers.CharField(required=False, max_length=250, allow_blank=False)
def validate(self, attrs):
super().validate(attrs)

View File

@ -1084,10 +1084,12 @@ class RecurringEventsList(APIView):
if not settings.ENABLE_RECURRING_EVENT_BOOKING:
raise Http404()
agenda_slugs = get_agendas_from_request(request)
agendas = get_objects_from_slugs(agenda_slugs, qs=Agenda.objects.filter(kind='events'))
agendas = Agenda.prefetch_recurring_events(agendas)
serializer = serializers.AgendaOrSubscribedSlugsSerializer(data=request.query_params)
if not serializer.is_valid():
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
data = serializer.validated_data
agendas = Agenda.prefetch_recurring_events(data['agendas']).select_related('category')
events = []
for agenda in agendas:
for event in agenda.get_open_recurring_events():
@ -1096,8 +1098,24 @@ class RecurringEventsList(APIView):
event.day = day
events.append(event)
agenda_querystring_indexes = {agenda_slug: i for i, agenda_slug in enumerate(agenda_slugs)}
events.sort(key=lambda event: (event.day, agenda_querystring_indexes[event.agenda.slug]))
if 'agendas' in request.query_params:
agenda_querystring_indexes = {
agenda_slug: i for i, agenda_slug in enumerate(data['agenda_slugs'])
}
events.sort(
key=lambda event: (event.day, agenda_querystring_indexes[event.agenda.slug], event.slug)
)
elif 'subscribed' in request.query_params:
category_querystring_indexes = {category: i for i, category in enumerate(data['subscribed'])}
sort_by_category = bool(data['subscribed'] != ['all'])
events.sort(
key=lambda event: (
event.day,
category_querystring_indexes[event.agenda.category.slug] if sort_by_category else None,
event.agenda.slug,
event.slug,
)
)
return Response(
{

View File

@ -1448,18 +1448,122 @@ def test_recurring_events_api_list_multiple_agendas(app):
@pytest.mark.freeze_time('2021-09-06 12:00')
def test_recurring_events_api_list_multiple_agendas_queries(app):
category = Category.objects.create(label='Category A')
for i in range(20):
agenda = Agenda.objects.create(slug=f'{i}', kind='events')
agenda = Agenda.objects.create(slug=f'{i}', kind='events', category=category)
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
)
Subscription.objects.create(
agenda=agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=60),
)
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
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/api/agendas/recurring-events/?subscribed=category-a&user_external_id=xxx')
assert len(resp.json['data']) == 40
assert len(ctx.captured_queries) == 3
@pytest.mark.freeze_time('2021-09-06 12:00')
def test_recurring_events_api_list_subscribed(app, user):
category = Category.objects.create(label='Category A')
first_agenda = Agenda.objects.create(label='First agenda', kind='events', category=category)
category = Category.objects.create(label='Category B')
second_agenda = Agenda.objects.create(label='Second agenda', kind='events', category=category)
Event.objects.create(
slug='event',
start_datetime=now(),
recurrence_days=[0, 1, 3, 6], # Monday, Tuesday, Thursday, Friday
places=2,
agenda=first_agenda,
recurrence_end_date=now() + datetime.timedelta(days=364),
)
Event.objects.create(
slug='sunday-event',
start_datetime=now(),
recurrence_days=[5],
places=2,
agenda=second_agenda,
recurrence_end_date=now() + datetime.timedelta(days=364),
)
Subscription.objects.create(
agenda=first_agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
resp = app.get('/api/agendas/recurring-events/?user_external_id=xxx&subscribed=all')
assert len(resp.json['data']) == 4
assert all(event['id'].startswith('first-agenda') for event in resp.json['data'])
resp = app.get('/api/agendas/recurring-events/?user_external_id=xxx&subscribed=category-a')
assert len(resp.json['data']) == 4
assert all(event['id'].startswith('first-agenda') for event in resp.json['data'])
resp = app.get('/api/agendas/recurring-events/?user_external_id=xxx&subscribed=category-b')
assert len(resp.json['data']) == 0
Subscription.objects.create(
agenda=second_agenda,
user_external_id='xxx',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
resp = app.get('/api/agendas/recurring-events/?user_external_id=xxx&subscribed=all')
assert len(resp.json['data']) == 5
# events are sorted by day
assert [x['id'] for x in resp.json['data']] == [
'first-agenda@event:0',
'first-agenda@event:1',
'first-agenda@event:3',
'second-agenda@sunday-event:5',
'first-agenda@event:6',
]
resp = app.get('/api/agendas/recurring-events/?user_external_id=xxx&subscribed=category-b')
assert len(resp.json['data']) == 1
# other user
resp = app.get('/api/agendas/recurring-events/?user_external_id=yyy&subscribed=all')
assert len(resp.json['data']) == 0
Subscription.objects.create(
agenda=second_agenda,
user_external_id='yyy',
date_start=now(),
date_end=now() + datetime.timedelta(days=30),
)
resp = app.get('/api/agendas/recurring-events/?user_external_id=yyy&subscribed=all')
assert len(resp.json['data']) == 1
# sorting depends on querystring order
Event.objects.create(
slug='event',
start_datetime=now(),
recurrence_days=[0],
places=2,
agenda=second_agenda,
recurrence_end_date=now() + datetime.timedelta(days=364),
)
resp = app.get('/api/agendas/recurring-events/?subscribed=category-a,category-b&user_external_id=xxx')
event_ids = [x['id'] for x in resp.json['data']]
assert event_ids.index('first-agenda@event:0') < event_ids.index('second-agenda@event:0')
resp = app.get('/api/agendas/recurring-events/?subscribed=category-b,category-a&user_external_id=xxx')
event_ids = [x['id'] for x in resp.json['data']]
assert event_ids.index('first-agenda@event:0') > event_ids.index('second-agenda@event:0')
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_datetimes_multiple_agendas(app):