Projet

Général

Profil

0001-api-mark-user-as-present-or-not-38678.patch

Lauréline Guérin, 19 janvier 2021 19:11

Télécharger (12,6 ko)

Voir les différences:

Subject: [PATCH] api: mark user as present or not (#38678)

 .../migrations/0071_booking_attendance.py     |  19 +++
 chrono/agendas/models.py                      |   2 +
 chrono/api/urls.py                            |   2 +-
 chrono/api/views.py                           |  74 ++++++++++-
 tests/test_api.py                             | 117 ++++++++++++++++++
 5 files changed, 210 insertions(+), 4 deletions(-)
 create mode 100644 chrono/agendas/migrations/0071_booking_attendance.py
chrono/agendas/migrations/0071_booking_attendance.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import migrations, models
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('agendas', '0070_auto_20201202_1834'),
11
    ]
12

  
13
    operations = [
14
        migrations.AddField(
15
            model_name='booking',
16
            name='user_was_present',
17
            field=models.NullBooleanField(),
18
        ),
19
    ]
chrono/agendas/models.py
1098 1098
    user_name = models.CharField(max_length=250, blank=True)
1099 1099
    user_email = models.EmailField(blank=True)
1100 1100
    user_phone_number = models.CharField(max_length=16, blank=True)
1101
    user_was_present = models.NullBooleanField()
1102

  
1101 1103
    form_url = models.URLField(blank=True)
1102 1104
    backoffice_url = models.URLField(blank=True)
1103 1105
    cancel_callback_url = models.URLField(blank=True)
chrono/api/urls.py
55 55
        views.meeting_datetimes,
56 56
        name='api-agenda-meeting-datetimes',
57 57
    ),
58
    url(r'^booking/(?P<booking_pk>\w+)/$', views.booking),
58
    url(r'^booking/(?P<booking_pk>\w+)/$', views.booking, name='api-booking'),
59 59
    url(r'^booking/(?P<booking_pk>\w+)/cancel/$', views.cancel_booking, name='api-cancel-booking'),
60 60
    url(r'^booking/(?P<booking_pk>\w+)/accept/$', views.accept_booking, name='api-accept-booking'),
61 61
    url(r'^booking/(?P<booking_pk>\w+)/suspend/$', views.suspend_booking, name='api-suspend-booking'),
chrono/api/views.py
1093 1093
                'slug': primary_booking.event.agenda.slug,
1094 1094
            },
1095 1095
            'api': {
1096
                'booking_url': request.build_absolute_uri(
1097
                    reverse('api-booking', kwargs={'booking_pk': primary_booking.id})
1098
                ),
1096 1099
                'cancel_url': request.build_absolute_uri(
1097 1100
                    reverse('api-cancel-booking', kwargs={'booking_pk': primary_booking.id})
1098 1101
                ),
......
1162 1165
fillslot = Fillslot.as_view()
1163 1166

  
1164 1167

  
1168
class BookingSerializer(serializers.ModelSerializer):
1169
    class Meta:
1170
        model = Booking
1171
        fields = ['user_was_present']
1172

  
1173

  
1165 1174
class BookingAPI(APIView):
1166 1175
    permission_classes = (permissions.IsAuthenticated,)
1176
    serializer_class = BookingSerializer
1167 1177

  
1168 1178
    def initial(self, request, *args, **kwargs):
1169
        super(BookingAPI, self).initial(request, *args, **kwargs)
1170
        self.booking = Booking.objects.get(id=kwargs.get('booking_pk'), cancellation_datetime__isnull=True)
1179
        super().initial(request, *args, **kwargs)
1180
        self.booking = get_object_or_404(Booking, pk=kwargs.get('booking_pk'))
1181

  
1182
    def check_booking(self, check_waiting_list=False):
1183
        if self.booking.cancellation_datetime:
1184
            return Response(
1185
                {'err': 1, 'err_class': 'booking is cancelled', 'err_desc': _('booking is cancelled')}
1186
            )
1187

  
1188
        if self.booking.primary_booking is not None:
1189
            return Response({'err': 2, 'err_class': 'secondary booking', 'err_desc': _('secondary booking')})
1190

  
1191
        if check_waiting_list and self.booking.in_waiting_list:
1192
            response = {
1193
                'err': 3,
1194
                'err_class': 'booking is in waiting list',
1195
                'err_desc': _('booking is in waiting list'),
1196
            }
1197
            return Response(response)
1198

  
1199
    def get(self, request, *args, **kwargs):
1200
        response = self.check_booking()
1201
        if response:
1202
            return response
1203

  
1204
        response = {
1205
            'err': 0,
1206
            'booking_id': self.booking.pk,
1207
            'in_waiting_list': self.booking.in_waiting_list,
1208
            'user_was_present': self.booking.user_was_present,
1209
        }
1210
        return Response(response)
1211

  
1212
    def patch(self, request, *args, **kwargs):
1213
        response = self.check_booking(check_waiting_list=True)
1214
        if response:
1215
            return response
1216

  
1217
        serializer = self.serializer_class(self.booking, data=request.data, partial=True)
1218

  
1219
        if not serializer.is_valid():
1220
            return Response(
1221
                {
1222
                    'err': 4,
1223
                    'err_class': 'invalid payload',
1224
                    'err_desc': _('invalid payload'),
1225
                    'errors': serializer.errors,
1226
                },
1227
                status=status.HTTP_400_BAD_REQUEST,
1228
            )
1229

  
1230
        serializer.save()
1231
        self.booking.secondary_booking_set.update(user_was_present=self.booking.user_was_present)
1232

  
1233
        response = {'err': 0, 'booking_id': self.booking.pk}
1234
        return Response(response)
1171 1235

  
1172 1236
    def delete(self, request, *args, **kwargs):
1237
        response = self.check_booking()
1238
        if response:
1239
            return response
1240

  
1173 1241
        self.booking.cancel()
1174
        response = {'err': 0, 'booking_id': self.booking.id}
1242
        response = {'err': 0, 'booking_id': self.booking.pk}
1175 1243
        return Response(response)
1176 1244

  
1177 1245

  
tests/test_api.py
909 909
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.id))
910 910
    Booking.objects.get(id=resp.json['booking_id'])
911 911
    assert resp.json['datetime'] == localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S')
912
    assert 'booking_url' in resp.json['api']
912 913
    assert 'accept_url' in resp.json['api']
913 914
    assert 'suspend_url' in resp.json['api']
914 915
    assert 'cancel_url' in resp.json['api']
915 916
    assert 'ics_url' in resp.json['api']
917
    assert urlparse.urlparse(resp.json['api']['booking_url']).netloc
918
    assert urlparse.urlparse(resp.json['api']['accept_url']).netloc
916 919
    assert urlparse.urlparse(resp.json['api']['suspend_url']).netloc
917 920
    assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
918 921
    assert urlparse.urlparse(resp.json['api']['ics_url']).netloc
......
1117 1120
    primary_booking_id = resp.json['booking_id']
1118 1121
    Booking.objects.get(id=primary_booking_id)
1119 1122
    assert resp.json['datetime'] == localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S')
1123
    assert 'booking_url' in resp.json['api']
1120 1124
    assert 'accept_url' in resp.json['api']
1121 1125
    assert 'suspend_url' in resp.json['api']
1122 1126
    assert 'cancel_url' in resp.json['api']
1127
    assert urlparse.urlparse(resp.json['api']['booking_url']).netloc
1128
    assert urlparse.urlparse(resp.json['api']['accept_url']).netloc
1123 1129
    assert urlparse.urlparse(resp.json['api']['suspend_url']).netloc
1124 1130
    assert urlparse.urlparse(resp.json['api']['cancel_url']).netloc
1125 1131
    assert Booking.objects.count() == 3
......
1904 1910
    assert Booking.objects.count() == 6
1905 1911

  
1906 1912

  
1913
@pytest.mark.parametrize('flag', [True, False, None])
1914
def test_booking_api_present(app, user, flag):
1915
    agenda = Agenda.objects.create(kind='events')
1916
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
1917
    booking = Booking.objects.create(event=event, user_was_present=flag)
1918

  
1919
    app.authorization = ('Basic', ('john.doe', 'password'))
1920
    resp = app.get('/api/booking/%s/' % booking.pk)
1921
    assert resp.json['booking_id'] == booking.pk
1922
    assert resp.json['user_was_present'] == flag
1923

  
1924

  
1925
@pytest.mark.parametrize('flag', [True, False])
1926
def test_booking_api_waiting_list(app, user, flag):
1927
    agenda = Agenda.objects.create(kind='events')
1928
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
1929
    booking = Booking.objects.create(event=event, in_waiting_list=flag)
1930

  
1931
    app.authorization = ('Basic', ('john.doe', 'password'))
1932

  
1933
    resp = app.get('/api/booking/%s/' % booking.pk)
1934
    assert resp.json['booking_id'] == booking.pk
1935
    assert resp.json['in_waiting_list'] == flag
1936

  
1937

  
1938
def test_booking_api_error(app, user):
1939
    agenda = Agenda.objects.create(kind='events')
1940
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
1941
    booking = Booking.objects.create(event=event)
1942

  
1943
    app.authorization = ('Basic', ('john.doe', 'password'))
1944

  
1945
    # unknown
1946
    booking.cancel()
1947
    for method in ['get', 'delete', 'patch']:
1948
        getattr(app, method)('/api/booking/0/', status=404)
1949

  
1950
    # cancelled
1951
    booking.cancel()
1952
    for method in ['get', 'delete', 'patch']:
1953
        resp = getattr(app, method)('/api/booking/%s/' % booking.pk)
1954
        assert resp.json['err'] == 1
1955
        assert resp.json['err_desc'] == 'booking is cancelled'
1956

  
1957
    # not a primary booking
1958
    secondary = Booking.objects.create(event=event, primary_booking=booking)
1959
    for method in ['get', 'delete', 'patch']:
1960
        resp = getattr(app, method)('/api/booking/%s/' % secondary.pk)
1961
        assert resp.json['err'] == 2
1962
        assert resp.json['err_desc'] == 'secondary booking'
1963

  
1964
    # in waiting list
1965
    booking.cancellation_datetime = None
1966
    booking.in_waiting_list = True
1967
    booking.save()
1968
    resp = app.get('/api/booking/%s/' % booking.pk)
1969
    assert resp.json['err'] == 0
1970
    resp = app.patch('/api/booking/%s/' % booking.pk)
1971
    assert resp.json['err'] == 3
1972
    assert resp.json['err_desc'] == 'booking is in waiting list'
1973
    resp = app.delete('/api/booking/%s/' % booking.pk)
1974
    assert resp.json['err'] == 0
1975

  
1976

  
1977
def test_booking_patch_api(app, user):
1978
    agenda = Agenda.objects.create(kind='events')
1979
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
1980
    booking = Booking.objects.create(event=event)
1981

  
1982
    app.authorization = ('Basic', ('john.doe', 'password'))
1983

  
1984
    resp = app.patch('/api/booking/%s/' % booking.pk)
1985
    assert resp.json['err'] == 0
1986
    resp = app.patch('/api/booking/%s/' % booking.pk, params={'user_was_present': 'foobar'}, status=400)
1987
    assert resp.json['err'] == 4
1988
    assert resp.json['err_desc'] == 'invalid payload'
1989

  
1990

  
1991
@pytest.mark.parametrize('flag', [True, False, None])
1992
def test_booking_patch_api_present(app, user, flag):
1993
    agenda = Agenda.objects.create(kind='events')
1994
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
1995
    booking = Booking.objects.create(event=event)
1996

  
1997
    app.authorization = ('Basic', ('john.doe', 'password'))
1998

  
1999
    # set flag
2000
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag})
2001
    booking.refresh_from_db()
2002
    assert booking.user_was_present == flag
2003

  
2004
    # reset
2005
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': None})
2006
    booking.refresh_from_db()
2007
    assert booking.user_was_present is None
2008

  
2009
    # make secondary bookings
2010
    Booking.objects.create(event=event, primary_booking=booking)
2011
    Booking.objects.create(event=event, primary_booking=booking)
2012
    # and other booking
2013
    other_booking = Booking.objects.create(event=event)
2014

  
2015
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag})
2016
    booking.refresh_from_db()
2017
    assert booking.user_was_present == flag
2018
    # all secondary bookings are upadted
2019
    assert list(booking.secondary_booking_set.values_list('user_was_present', flat=True)) == [flag, flag]
2020
    other_booking.refresh_from_db()
2021
    assert other_booking.user_was_present is None  # not changed
2022

  
2023

  
1907 2024
def test_booking_cancellation_api(app, some_data, user):
1908 2025
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1909 2026
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
1910
-