summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLauréline Guérin <zebuline@entrouvert.com>2020-02-21 15:15:12 (GMT)
committerLauréline Guérin <zebuline@entrouvert.com>2020-02-21 15:15:12 (GMT)
commit8d327c0dfe2c1b8fa59e4238ed6127db18052d03 (patch)
treead851f20d1a7958bdd594835a980702e7ae633e4
parent22ee5647308fb2151f979bbcd219997c15e936fb (diff)
downloadchrono-master.zip
chrono-master.tar.gz
chrono-master.tar.bz2
api: add a suspend action on Booking (#40018)HEADwip/40018-booking-in-waiting-listmaster
-rw-r--r--chrono/agendas/models.py6
-rw-r--r--chrono/api/urls.py1
-rw-r--r--chrono/api/views.py38
-rw-r--r--tests/test_api.py35
4 files changed, 80 insertions, 0 deletions
diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py
index 79ee1a8..c2135df 100644
--- a/chrono/agendas/models.py
+++ b/chrono/agendas/models.py
@@ -475,6 +475,12 @@ class Booking(models.Model):
self.secondary_booking_set.update(in_waiting_list=False)
self.save()
+ def suspend(self):
+ self.in_waiting_list = True
+ with transaction.atomic():
+ self.secondary_booking_set.update(in_waiting_list=True)
+ self.save()
+
def get_ics(self, request=None):
ics = vobject.iCalendar()
ics.add('prodid').value = '-//Entr\'ouvert//NON SGML Publik'
diff --git a/chrono/api/urls.py b/chrono/api/urls.py
index 0fd391c..119210a 100644
--- a/chrono/api/urls.py
+++ b/chrono/api/urls.py
@@ -48,5 +48,6 @@ urlpatterns = [
url(r'^booking/(?P<booking_pk>\w+)/$', views.booking),
url(r'^booking/(?P<booking_pk>\w+)/cancel/$', views.cancel_booking, name='api-cancel-booking'),
url(r'^booking/(?P<booking_pk>\w+)/accept/$', views.accept_booking, name='api-accept-booking'),
+ url(r'^booking/(?P<booking_pk>\w+)/suspend/$', views.suspend_booking, name='api-suspend-booking'),
url(r'^booking/(?P<booking_pk>\w+)/ics/$', views.booking_ics, name='api-booking-ics'),
]
diff --git a/chrono/api/views.py b/chrono/api/views.py
index 2eaec49..6a664c1 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -658,6 +658,10 @@ class Fillslots(APIView):
response['api']['accept_url'] = request.build_absolute_uri(
reverse('api-accept-booking', kwargs={'booking_pk': primary_booking.id})
)
+ else:
+ response['api']['suspend_url'] = request.build_absolute_uri(
+ reverse('api-suspend-booking', kwargs={'booking_pk': primary_booking.pk})
+ )
if agenda.kind == 'meetings':
response['end_datetime'] = format_response_datetime(events[-1].end_datetime)
response['duration'] = (events[-1].end_datetime - events[-1].start_datetime).seconds // 60
@@ -776,6 +780,40 @@ class AcceptBooking(APIView):
accept_booking = AcceptBooking.as_view()
+class SuspendBooking(APIView):
+ '''
+ Suspend a accepted booking.
+
+ It will return error codes if the booking was cancelled before (code 1) and
+ if the bookingis already in waiting list (code 2).
+ '''
+
+ permission_classes = (permissions.IsAuthenticated,)
+
+ def post(self, request, booking_pk=None, format=None):
+ booking = get_object_or_404(Booking, pk=booking_pk)
+ if booking.cancellation_datetime:
+ response = {
+ 'err': 1,
+ 'err_class': 'booking is cancelled',
+ 'err_desc': _('booking is cancelled'),
+ }
+ return Response(response)
+ if booking.in_waiting_list:
+ response = {
+ 'err': 2,
+ 'err_class': 'booking is already in waiting list',
+ 'err_desc': _('booking is already in waiting list'),
+ }
+ return Response(response)
+ booking.suspend()
+ response = {'err': 0, 'booking_id': booking.pk}
+ return Response(response)
+
+
+suspend_booking = SuspendBooking.as_view()
+
+
class SlotStatus(APIView):
permission_classes = (permissions.IsAuthenticated,)
diff --git a/tests/test_api.py b/tests/test_api.py
index 4155fb9..4555ed7 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -410,8 +410,10 @@ def test_booking_api(app, some_data, user):
Booking.objects.get(id=resp.json['booking_id'])
assert resp.json['datetime'] == localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S')
assert 'accept_url' not in resp.json['api']
+ assert 'suspend_url' in resp.json['api']
assert 'cancel_url' in resp.json['api']
assert 'ics_url' in resp.json['api']
+ assert urlparse.urlparse(resp.json['api']['suspend_url']).netloc
assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
assert urlparse.urlparse(resp.json['api']['ics_url']).netloc
assert Booking.objects.count() == 1
@@ -606,7 +608,9 @@ def test_booking_api_fillslots(app, some_data, user):
Booking.objects.get(id=primary_booking_id)
assert resp.json['datetime'] == localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S')
assert 'accept_url' not in resp.json['api']
+ assert 'suspend_url' in resp.json['api']
assert 'cancel_url' in resp.json['api']
+ assert urlparse.urlparse(resp.json['api']['suspend_url']).netloc
assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
assert Booking.objects.count() == 3
# these 3 bookings are related, the first is the primary one
@@ -1201,6 +1205,7 @@ def test_waiting_list_booking(app, some_data, user):
assert resp.json['err'] == 0
assert resp.json['in_waiting_list'] is True
assert 'accept_url' in resp.json['api']
+ assert 'suspend_url' not in resp.json['api']
assert 'cancel_url' in resp.json['api']
assert 'ics_url' in resp.json['api']
assert urlparse.urlparse(resp.json['api']['accept_url']).netloc
@@ -1263,6 +1268,36 @@ def test_accept_booking(app, some_data, user):
assert Booking.objects.filter(in_waiting_list=False).count() == 0
+def test_suspend_booking(app, some_data, user):
+ agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
+ event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0]
+ event.waiting_list_places = 5
+ event.save()
+
+ # create a booking not on the waiting list
+ booking = Booking.objects.create(event=event, in_waiting_list=False)
+ assert booking.in_waiting_list is False
+
+ app.authorization = ('Basic', ('john.doe', 'password'))
+ resp = app.post('/api/booking/%s/suspend/' % booking.pk)
+ booking.refresh_from_db()
+ assert booking.in_waiting_list is True
+
+ # suspend a booking that doesn't exist
+ resp = app.post('/api/booking/0/suspend/', status=404)
+
+ # suspend a booking that is in the waiting list
+ resp = app.post('/api/booking/%s/suspend/' % booking.pk, status=200)
+ assert resp.json['err'] == 2
+
+ # suspend a booking that was cancelled before
+ booking.in_waiting_list = False
+ booking.cancel()
+ resp = app.post('/api/booking/%s/suspend/' % booking.pk, status=200)
+ assert resp.json['err'] == 1
+ assert booking.in_waiting_list is False
+
+
def test_multiple_booking_api(app, some_data, user):
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]