api: add action parameter to recurring fillslots endpoint (#60255)
This commit is contained in:
parent
29413e3a35
commit
ad019b0956
|
@ -244,6 +244,10 @@ class AgendaOrSubscribedSlugsSerializer(AgendaOrSubscribedSlugsMixin, serializer
|
|||
pass
|
||||
|
||||
|
||||
class RecurringFillslotsQueryStringSerializer(AgendaOrSubscribedSlugsSerializer):
|
||||
action = serializers.ChoiceField(required=True, choices=['update'])
|
||||
|
||||
|
||||
class RecurringEventsListSerializer(AgendaOrSubscribedSlugsSerializer):
|
||||
sort = serializers.ChoiceField(required=False, choices=['day'])
|
||||
|
||||
|
|
|
@ -1605,7 +1605,7 @@ class RecurringFillslots(APIView):
|
|||
if not start_datetime or start_datetime < now():
|
||||
start_datetime = now()
|
||||
|
||||
serializer = serializers.AgendaOrSubscribedSlugsSerializer(
|
||||
serializer = serializers.RecurringFillslotsQueryStringSerializer(
|
||||
data=request.query_params, context={'user_external_id': request.data.get('user_external_id')}
|
||||
)
|
||||
if not serializer.is_valid():
|
||||
|
@ -1623,38 +1623,12 @@ class RecurringFillslots(APIView):
|
|||
user_external_id = payload['user_external_id']
|
||||
agendas = Agenda.prefetch_events_and_exceptions(data['agendas'], user_external_id=user_external_id)
|
||||
|
||||
event_filter = Q()
|
||||
for agenda_slug, days_by_event in payload['slots'].items():
|
||||
for event_slug, days in days_by_event.items():
|
||||
lookups = {
|
||||
'agenda__slug': agenda_slug,
|
||||
'primary_event__slug': event_slug,
|
||||
'start_datetime__week_day__in': days,
|
||||
}
|
||||
if 'subscribed' in request.query_params:
|
||||
lookups.update(
|
||||
{
|
||||
'agenda__subscriptions__user_external_id': user_external_id,
|
||||
'agenda__subscriptions__date_start__lt': F('start_datetime'),
|
||||
'agenda__subscriptions__date_end__gt': F('start_datetime'),
|
||||
}
|
||||
)
|
||||
event_filter |= Q(**lookups)
|
||||
if data['action'] == 'update':
|
||||
events_to_book = self.get_event_recurrences(
|
||||
payload['slots'], start_datetime, end_datetime, user_external_id
|
||||
)
|
||||
events_to_unbook = self.get_events_to_unbook(agendas, events_to_book)
|
||||
|
||||
events_to_book = Event.objects.filter(event_filter) if event_filter else Event.objects.none()
|
||||
events_to_book = events_to_book.filter(start_datetime__gte=start_datetime, cancelled=False)
|
||||
if end_datetime:
|
||||
events_to_book = events_to_book.filter(start_datetime__lte=end_datetime)
|
||||
|
||||
events_to_book_ids = set(events_to_book.values_list('pk', flat=True))
|
||||
events_to_unbook = [
|
||||
e.pk
|
||||
for agenda in agendas
|
||||
for e in agenda.prefetched_events
|
||||
if (e.user_places_count or e.user_waiting_places_count)
|
||||
and e.primary_event_id
|
||||
and e.pk not in events_to_book_ids
|
||||
]
|
||||
events_to_book = events_to_book.exclude(booking__user_external_id=user_external_id)
|
||||
|
||||
full_events = list(events_to_book.filter(full=True))
|
||||
|
@ -1688,6 +1662,44 @@ class RecurringFillslots(APIView):
|
|||
]
|
||||
return Response(response)
|
||||
|
||||
def get_event_recurrences(self, slots, start_datetime, end_datetime, user_external_id):
|
||||
event_filter = Q()
|
||||
for agenda_slug, days_by_event in slots.items():
|
||||
for event_slug, days in days_by_event.items():
|
||||
lookups = {
|
||||
'agenda__slug': agenda_slug,
|
||||
'primary_event__slug': event_slug,
|
||||
'start_datetime__week_day__in': days,
|
||||
}
|
||||
if 'subscribed' in self.request.query_params:
|
||||
lookups.update(
|
||||
{
|
||||
'agenda__subscriptions__user_external_id': user_external_id,
|
||||
'agenda__subscriptions__date_start__lt': F('start_datetime'),
|
||||
'agenda__subscriptions__date_end__gt': F('start_datetime'),
|
||||
}
|
||||
)
|
||||
event_filter |= Q(**lookups)
|
||||
|
||||
events = Event.objects.filter(event_filter) if event_filter else Event.objects.none()
|
||||
events = events.filter(start_datetime__gte=start_datetime, cancelled=False)
|
||||
if end_datetime:
|
||||
events = events.filter(start_datetime__lte=end_datetime)
|
||||
|
||||
return events
|
||||
|
||||
def get_events_to_unbook(self, agendas, events_to_book):
|
||||
events_to_book_ids = set(events_to_book.values_list('pk', flat=True))
|
||||
events_to_unbook = [
|
||||
e.pk
|
||||
for agenda in agendas
|
||||
for e in agenda.prefetched_events
|
||||
if (e.user_places_count or e.user_waiting_places_count)
|
||||
and e.primary_event_id
|
||||
and e.pk not in events_to_book_ids
|
||||
]
|
||||
return events_to_unbook
|
||||
|
||||
|
||||
recurring_fillslots = RecurringFillslots.as_view()
|
||||
|
||||
|
|
|
@ -2175,7 +2175,7 @@ def test_recurring_events_api_fillslots(app, user, freezer):
|
|||
assert len(resp.json['data']) == 5
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?agendas=%s' % agenda.slug
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?agendas=%s&action=update' % agenda.slug
|
||||
params = {'user_external_id': 'user_id'}
|
||||
# Book Monday and Thursday of first event and Sunday of second event
|
||||
params['slots'] = 'foo-bar@event:0,foo-bar@event:3,foo-bar@sunday-event:6'
|
||||
|
@ -2254,6 +2254,17 @@ def test_recurring_events_api_fillslots(app, user, freezer):
|
|||
assert resp.json['err'] == 1
|
||||
assert resp.json['errors']['slots'] == ['Invalid format for slot foo-bar']
|
||||
|
||||
missing_action_url = '/api/agendas/recurring-events/fillslots/?agendas=%s' % agenda.slug
|
||||
resp = app.post_json(missing_action_url, params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'invalid payload'
|
||||
assert resp.json['errors']['action'] == ['This field is required.']
|
||||
|
||||
resp = app.post_json(missing_action_url + '&action=invalid', params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'invalid payload'
|
||||
assert resp.json['errors']['action'] == ['"invalid" is not a valid choice.']
|
||||
|
||||
|
||||
def test_recurring_events_api_fillslots_waiting_list(app, user, freezer):
|
||||
freezer.move_to('2021-09-06 12:00')
|
||||
|
@ -2279,7 +2290,9 @@ def test_recurring_events_api_fillslots_waiting_list(app, user, freezer):
|
|||
|
||||
# check that new bookings are put in waiting list despite free slots on main list
|
||||
params = {'user_external_id': 'user_id', 'slots': 'foo-bar@event:0'}
|
||||
resp = app.post_json('/api/agendas/recurring-events/fillslots/?agendas=%s' % agenda.slug, params=params)
|
||||
resp = app.post_json(
|
||||
'/api/agendas/recurring-events/fillslots/?agendas=%s&action=update' % agenda.slug, params=params
|
||||
)
|
||||
assert resp.json['booking_count'] == 5
|
||||
assert events.filter(booked_waiting_list_places=2).count() == 5
|
||||
|
||||
|
@ -2300,7 +2313,7 @@ def test_recurring_events_api_fillslots_change_bookings(app, user, freezer):
|
|||
event.create_all_recurrences()
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?agendas=%s' % agenda.slug
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?agendas=%s&action=update' % agenda.slug
|
||||
params = {'user_external_id': 'user_id'}
|
||||
# Book Monday and Thursday
|
||||
params['slots'] = 'foo-bar@event:0,foo-bar@event:3'
|
||||
|
@ -2417,10 +2430,11 @@ def test_recurring_events_api_fillslots_subscribed(app, user):
|
|||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?action=update&subscribed=%s'
|
||||
params = {'user_external_id': 'xxx'}
|
||||
# book Monday and Thursday of first event, in subscription range
|
||||
params['slots'] = 'first-agenda@event:0,first-agenda@event:3'
|
||||
resp = app.post_json('/api/agendas/recurring-events/fillslots/?subscribed=category-a', params=params)
|
||||
resp = app.post_json(fillslots_url % 'category-a', params=params)
|
||||
assert resp.json['booking_count'] == 8
|
||||
assert Booking.objects.count() == 8
|
||||
assert Booking.objects.filter(event__primary_event=event).count() == 8
|
||||
|
@ -2428,15 +2442,11 @@ def test_recurring_events_api_fillslots_subscribed(app, user):
|
|||
assert Booking.objects.last().event.start_datetime.strftime('%d/%m') == '18/10'
|
||||
|
||||
# wrong category
|
||||
resp = app.post_json(
|
||||
'/api/agendas/recurring-events/fillslots/?subscribed=category-b', params=params, status=400
|
||||
)
|
||||
resp = app.post_json(fillslots_url % 'category-b', params=params, status=400)
|
||||
|
||||
# not subscribed category
|
||||
params['slots'] = 'second-agenda@sunday-event:6'
|
||||
resp = app.post_json(
|
||||
'/api/agendas/recurring-events/fillslots/?subscribed=category-b', params=params, status=400
|
||||
)
|
||||
resp = app.post_json(fillslots_url % 'category-b', params=params, status=400)
|
||||
|
||||
# update bookings
|
||||
Subscription.objects.create(
|
||||
|
@ -2446,7 +2456,7 @@ def test_recurring_events_api_fillslots_subscribed(app, user):
|
|||
date_end=now() + datetime.timedelta(days=150), # Thursday 03/02
|
||||
)
|
||||
params['slots'] = 'first-agenda@event:1,second-agenda@sunday-event:6'
|
||||
resp = app.post_json('/api/agendas/recurring-events/fillslots/?subscribed=all', params=params)
|
||||
resp = app.post_json(fillslots_url % 'all', params=params)
|
||||
assert resp.json['booking_count'] == 11
|
||||
assert resp.json['cancelled_booking_count'] == 8
|
||||
assert Booking.objects.count() == 11
|
||||
|
@ -2474,7 +2484,7 @@ def test_recurring_events_api_fillslots_subscribed(app, user):
|
|||
date_end=now() + datetime.timedelta(days=70),
|
||||
)
|
||||
params = {'user_external_id': 'yyy', 'slots': 'second-agenda@sunday-event:6'}
|
||||
resp = app.post_json('/api/agendas/recurring-events/fillslots/?subscribed=category-b', params=params)
|
||||
resp = app.post_json(fillslots_url % 'category-b', params=params)
|
||||
assert resp.json['booking_count'] == 3
|
||||
assert Booking.objects.count() == 14
|
||||
booked_events_user_yyy = Event.objects.filter(primary_event=sunday_event, booking__user_external_id='yyy')
|
||||
|
@ -2517,7 +2527,7 @@ def test_recurring_events_api_fillslots_multiple_agendas(app, user):
|
|||
assert len(resp.json['data']) == 6
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?agendas=%s'
|
||||
fillslots_url = '/api/agendas/recurring-events/fillslots/?action=update&agendas=%s'
|
||||
params = {'user_external_id': 'user_id', 'slots': 'first-agenda@a:0,first-agenda@a:5,second-agenda@c:3'}
|
||||
resp = app.post_json(fillslots_url % 'first-agenda,second-agenda', params=params)
|
||||
assert resp.json['booking_count'] == 13
|
||||
|
@ -2557,13 +2567,13 @@ def test_recurring_events_api_fillslots_multiple_agendas_queries(app, user):
|
|||
event.create_all_recurrences()
|
||||
|
||||
agenda_slugs = ','.join(str(i) for i in range(20))
|
||||
resp = app.get('/api/agendas/recurring-events/?agendas=%s' % agenda_slugs)
|
||||
resp = app.get('/api/agendas/recurring-events/?action=update&agendas=%s' % agenda_slugs)
|
||||
events_to_book = [x['id'] for x in resp.json['data']]
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.post_json(
|
||||
'/api/agendas/recurring-events/fillslots/?agendas=%s' % agenda_slugs,
|
||||
'/api/agendas/recurring-events/fillslots/?action=update&agendas=%s' % agenda_slugs,
|
||||
params={'slots': events_to_book, 'user_external_id': 'user'},
|
||||
)
|
||||
assert resp.json['booking_count'] == 180
|
||||
|
|
Loading…
Reference in New Issue