api: add an endpoint to patch an event (#57305)

This commit is contained in:
Nicolas Roche 2021-09-30 00:23:31 +02:00
parent 9a2272396b
commit 030a355ebf
3 changed files with 259 additions and 0 deletions

View File

@ -49,6 +49,11 @@ urlpatterns = [
views.recurring_fillslots,
name='api-recurring-fillslots',
),
url(
r'^agenda/(?P<agenda_identifier>[\w-]+)/event/(?P<event_identifier>[\w:-]+)/$',
views.events,
name='api-event',
),
url(
r'^agenda/(?P<agenda_identifier>[\w-]+)/status/(?P<event_identifier>[\w:-]+)/$',
views.event_status,

View File

@ -2203,6 +2203,80 @@ class ResizeBooking(APIView):
resize_booking = ResizeBooking.as_view()
class Events(APIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = serializers.EventSerializer
def get_object(self, agenda_identifier, event_identifier):
agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
if ':' in event_identifier:
return get_event_recurrence(agenda, event_identifier)
try:
return agenda.event_set.get(slug=event_identifier)
except Event.DoesNotExist:
raise Http404()
def patch(self, request, agenda_identifier=None, event_identifier=None, format=None):
event = self.get_object(agenda_identifier, event_identifier)
serializer = self.serializer_class(event, data=request.data, partial=True)
if not serializer.is_valid():
raise APIError(
_('invalid payload'),
err_class='invalid payload',
errors=serializer.errors,
http_status=status.HTTP_400_BAD_REQUEST,
)
payload = serializer.validated_data
changed_data = []
for field in serializer.fields.keys():
if field in payload and payload[field] != getattr(event, field):
changed_data.append(field)
if event.primary_event:
for field in changed_data:
if field in (
'recurrence_end_date',
'publication_date',
'recurrence_days',
'recurrence_week_interval',
):
raise APIError(
_('%s cannot be modified on an event recurrence') % field,
err_class='%s cannot be modified on an event recurrence' % field,
http_status=status.HTTP_400_BAD_REQUEST,
)
protected_fields = ['start_datetime', 'recurrence_days', 'recurrence_week_interval']
if event.recurrence_days and event.has_recurrences_booked():
for field in changed_data:
if field in protected_fields:
raise APIError(
_('%s cannot be modified because some recurrences have bookings attached to them.')
% field,
err_class='%s cannot be modified because some recurrences have bookings attached to them.'
% field,
http_status=status.HTTP_400_BAD_REQUEST,
)
if 'recurrence_end_date' in changed_data and event.has_recurrences_booked(
after=payload['recurrence_end_date']
):
raise APIError(
_('recurrence_end_date cannot be modified because bookings exist after this date.'),
err_class='recurrence_end_date cannot be modified because bookings exist after this date.',
http_status=status.HTTP_400_BAD_REQUEST,
)
with event.update_recurrences(
changed_data, payload, protected_fields, protected_fields + ['recurrence_end_date']
):
event = serializer.save()
return Response({'err': 0, 'data': get_event_detail(request, event)})
events = Events.as_view()
class EventStatus(APIView):
permission_classes = (permissions.IsAuthenticated,)

View File

@ -331,3 +331,183 @@ def test_add_event(app, user):
'2021-12-16',
'2021-12-18',
]
def test_update_event(app, user):
api_url = '/api/agenda/%s/event/%s/' % ('nop', 'nop')
# no authentication
resp = app.patch(api_url, status=401)
assert resp.json['detail'] == 'Authentication credentials were not provided.'
# wrong password
app.authorization = ('Basic', ('john.doe', 'wrong'))
resp = app.patch(api_url, status=401)
assert resp.json['detail'] == 'Invalid username/password.'
app.authorization = ('Basic', ('john.doe', 'password'))
# missing agenda
resp = app.patch(api_url, status=404)
assert resp.json['detail'] == 'Not found.'
meeting_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='meetings')
# using meeting agenda
api_url = '/api/agenda/%s/event/%s/' % (meeting_agenda.slug, 'nop')
resp = app.patch(api_url, status=404)
assert resp.json['detail'] == 'Not found.'
agenda = Agenda.objects.create(label='Foo bar')
# missing event
api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'nop')
resp = app.patch(api_url, status=404)
assert resp.json['detail'] == 'Not found.'
# missing recurring event
api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'nop:2021-11-15-1538')
resp = app.patch(api_url, status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'unknown recurring event slug: nop'
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10, waiting_list_places=5)
api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, event.slug)
# update with errors in datetime parts
params = {
'start_datetime': '2021-11-15 minuit',
'recurrence_days': '7, 8',
}
resp = app.patch(api_url, params=params, status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'invalid payload'
assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0]
assert resp.json['errors']['recurrence_days']['0'][0] == 'Ensure this value is less than or equal to 6.'
# update with almost all optional managed fields
params = {
'start_datetime': '2021-11-15 15:38',
'duration': 42,
'publication_date': '2021-09-20',
'places': 8,
'waiting_list_places': 3,
'label': 'FOO camp',
'description': 'An event',
'pricing': 'free',
'url': 'http://example.org/foo/bar/?',
}
resp = app.patch(api_url, params=params)
assert not resp.json['err']
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
assert event.duration == 42
assert event.places == 8
assert event.waiting_list_places == 3
assert event.label == 'FOO camp'
assert event.description == 'An event'
assert event.pricing == 'free'
assert event.url == 'http://example.org/foo/bar/?'
# update event as a recurring event
params = {
'recurrence_days': '0,3,5',
'recurrence_week_interval': 2,
'recurrence_end_date': '2021-12-27',
}
resp = app.patch(api_url, params=params)
assert not resp.json['err']
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
assert event.recurrences.count() == 9
assert [x.places for x in event.recurrences.all()] == [8] * 9
recurrence_slug = event.recurrences.first().slug
assert recurrence_slug == 'foo-bar-event--2021-11-15-1538'
recurrence_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'foo-bar-event:2021-11-15-1538')
# update unprotected fields of one of the event recurrencies
params = {
'start_datetime': '2021-11-14 14:00',
'duration': 43,
'places': 9,
'waiting_list_places': 4,
'label': 'BAR camp',
'description': 'An occurence of an event recurrence',
'pricing': '5€',
'url': 'http://example.org/bar/bar/',
}
resp = app.patch(recurrence_url, params=params)
assert not resp.json['err']
recurrence = Event.objects.filter(agenda=agenda).get(slug=recurrence_slug)
assert recurrence.duration == 43
assert recurrence.places == 9
assert recurrence.waiting_list_places == 4
assert recurrence.label == 'BAR camp'
assert recurrence.description == 'An occurence of an event recurrence'
assert recurrence.pricing == '5€'
assert recurrence.url == 'http://example.org/bar/bar/'
# try to update protected fields of one of the event recurrencies
params = {
'publication_date': '2021-11-15',
}
resp = app.patch(recurrence_url, params=params, status=400)
assert resp.json['err']
assert 'cannot be modified' in resp.json['err_desc']
# update protected fields of one of the event recurrencies providing same value
assert 'cannot be modified' in resp.json['err_desc']
params = {
'recurrence_week_interval': 1,
}
resp = app.patch(recurrence_url, params=params)
assert not resp.json['err']
booking = Booking.objects.create(event=event.recurrences.all()[2])
# update unprotected fields
params = {
'places': 7,
}
resp = app.patch(api_url, params=params)
assert not resp.json['err']
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
assert [x.places for x in event.recurrences.all()] == [7] * 9
# try to update recurring event protected fields
params = {
'recurrence_days': '1,2',
}
resp = app.patch(api_url, params=params, status=400)
assert resp.json['err']
assert 'cannot be modified' in resp.json['err_desc']
assert booking.event.start_datetime.date() == datetime.date(2021, 11, 20)
# try to reduce recurrence end date before booked event
params = {
'recurrence_end_date': '2021-11-20',
}
resp = app.patch(api_url, params=params, status=400)
assert resp.json['err']
assert 'bookings exist after this date.' in resp.json['err_desc']
# reduce recurrence end date after booked event
params = {
'recurrence_end_date': '2021-11-21',
}
resp = app.patch(api_url, params=params)
assert not resp.json['err']
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
assert event.recurrences.count() == 3
booking.cancel()
# update no more protected fields
params = {
'recurrence_days': '1,2,3,4,5',
'recurrence_week_interval': 1,
}
resp = app.patch(api_url, params=params)
assert not resp.json['err']
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
assert event.recurrences.count() == 5