0001-api-mark-user-as-present-or-not-38678.patch
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/views.py | ||
---|---|---|
1162 | 1162 |
fillslot = Fillslot.as_view() |
1163 | 1163 | |
1164 | 1164 | |
1165 |
class BookingSerializer(serializers.ModelSerializer): |
|
1166 |
class Meta: |
|
1167 |
model = Booking |
|
1168 |
fields = ['user_was_present'] |
|
1169 | ||
1170 | ||
1165 | 1171 |
class BookingAPI(APIView): |
1166 | 1172 |
permission_classes = (permissions.IsAuthenticated,) |
1173 |
serializer_class = BookingSerializer |
|
1167 | 1174 | |
1168 | 1175 |
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) |
|
1176 |
super().initial(request, *args, **kwargs) |
|
1177 |
self.booking = get_object_or_404(Booking, pk=kwargs.get('booking_pk')) |
|
1178 | ||
1179 |
def check_booking(self, check_waiting_list=False): |
|
1180 |
if self.booking.cancellation_datetime: |
|
1181 |
return Response( |
|
1182 |
{'err': 1, 'err_class': 'booking is cancelled', 'err_desc': _('booking is cancelled')} |
|
1183 |
) |
|
1184 | ||
1185 |
if self.booking.primary_booking is not None: |
|
1186 |
return Response({'err': 2, 'err_class': 'secondary booking', 'err_desc': _('secondary booking')}) |
|
1187 | ||
1188 |
if check_waiting_list and self.booking.in_waiting_list: |
|
1189 |
response = { |
|
1190 |
'err': 3, |
|
1191 |
'err_class': 'booking is in waiting list', |
|
1192 |
'err_desc': _('booking is in waiting list'), |
|
1193 |
} |
|
1194 |
return Response(response) |
|
1195 | ||
1196 |
def get(self, request, *args, **kwargs): |
|
1197 |
response = self.check_booking() |
|
1198 |
if response: |
|
1199 |
return response |
|
1200 | ||
1201 |
response = { |
|
1202 |
'err': 0, |
|
1203 |
'booking_id': self.booking.pk, |
|
1204 |
'in_waiting_list': self.booking.in_waiting_list, |
|
1205 |
'user_was_present': self.booking.user_was_present, |
|
1206 |
} |
|
1207 |
return Response(response) |
|
1208 | ||
1209 |
def patch(self, request, *args, **kwargs): |
|
1210 |
response = self.check_booking(check_waiting_list=True) |
|
1211 |
if response: |
|
1212 |
return response |
|
1213 | ||
1214 |
serializer = self.serializer_class(self.booking, data=request.data, partial=True) |
|
1215 | ||
1216 |
if not serializer.is_valid(): |
|
1217 |
return Response( |
|
1218 |
{ |
|
1219 |
'err': 4, |
|
1220 |
'err_class': 'invalid payload', |
|
1221 |
'err_desc': _('invalid payload'), |
|
1222 |
'errors': serializer.errors, |
|
1223 |
}, |
|
1224 |
status=status.HTTP_400_BAD_REQUEST, |
|
1225 |
) |
|
1226 | ||
1227 |
serializer.save() |
|
1228 |
self.booking.secondary_booking_set.update(user_was_present=self.booking.user_was_present) |
|
1229 | ||
1230 |
response = {'err': 0, 'booking_id': self.booking.pk} |
|
1231 |
return Response(response) |
|
1171 | 1232 | |
1172 | 1233 |
def delete(self, request, *args, **kwargs): |
1234 |
response = self.check_booking() |
|
1235 |
if response: |
|
1236 |
return response |
|
1237 | ||
1173 | 1238 |
self.booking.cancel() |
1174 |
response = {'err': 0, 'booking_id': self.booking.id}
|
|
1239 |
response = {'err': 0, 'booking_id': self.booking.pk}
|
|
1175 | 1240 |
return Response(response) |
1176 | 1241 | |
1177 | 1242 |
tests/test_api.py | ||
---|---|---|
1904 | 1904 |
assert Booking.objects.count() == 6 |
1905 | 1905 | |
1906 | 1906 | |
1907 |
@pytest.mark.parametrize('flag', [True, False, None]) |
|
1908 |
def test_booking_api_present(app, user, flag): |
|
1909 |
agenda = Agenda.objects.create(kind='events') |
|
1910 |
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) |
|
1911 |
booking = Booking.objects.create(event=event, user_was_present=flag) |
|
1912 | ||
1913 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
1914 |
resp = app.get('/api/booking/%s/' % booking.pk) |
|
1915 |
assert resp.json['booking_id'] == booking.pk |
|
1916 |
assert resp.json['user_was_present'] == flag |
|
1917 | ||
1918 | ||
1919 |
@pytest.mark.parametrize('flag', [True, False]) |
|
1920 |
def test_booking_api_waiting_list(app, user, flag): |
|
1921 |
agenda = Agenda.objects.create(kind='events') |
|
1922 |
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) |
|
1923 |
booking = Booking.objects.create(event=event, in_waiting_list=flag) |
|
1924 | ||
1925 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
1926 | ||
1927 |
resp = app.get('/api/booking/%s/' % booking.pk) |
|
1928 |
assert resp.json['booking_id'] == booking.pk |
|
1929 |
assert resp.json['in_waiting_list'] == flag |
|
1930 | ||
1931 | ||
1932 |
def test_booking_api_error(app, user): |
|
1933 |
agenda = Agenda.objects.create(kind='events') |
|
1934 |
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) |
|
1935 |
booking = Booking.objects.create(event=event) |
|
1936 | ||
1937 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
1938 | ||
1939 |
# unknown |
|
1940 |
booking.cancel() |
|
1941 |
for method in ['get', 'delete', 'patch']: |
|
1942 |
getattr(app, method)('/api/booking/0/', status=404) |
|
1943 | ||
1944 |
# cancelled |
|
1945 |
booking.cancel() |
|
1946 |
for method in ['get', 'delete', 'patch']: |
|
1947 |
resp = getattr(app, method)('/api/booking/%s/' % booking.pk) |
|
1948 |
assert resp.json['err'] == 1 |
|
1949 |
assert resp.json['err_desc'] == 'booking is cancelled' |
|
1950 | ||
1951 |
# not a primary booking |
|
1952 |
secondary = Booking.objects.create(event=event, primary_booking=booking) |
|
1953 |
for method in ['get', 'delete', 'patch']: |
|
1954 |
resp = getattr(app, method)('/api/booking/%s/' % secondary.pk) |
|
1955 |
assert resp.json['err'] == 2 |
|
1956 |
assert resp.json['err_desc'] == 'secondary booking' |
|
1957 | ||
1958 |
# in waiting list |
|
1959 |
booking.cancellation_datetime = None |
|
1960 |
booking.in_waiting_list = True |
|
1961 |
booking.save() |
|
1962 |
resp = app.get('/api/booking/%s/' % booking.pk) |
|
1963 |
assert resp.json['err'] == 0 |
|
1964 |
resp = app.patch('/api/booking/%s/' % booking.pk) |
|
1965 |
assert resp.json['err'] == 3 |
|
1966 |
assert resp.json['err_desc'] == 'booking is in waiting list' |
|
1967 |
resp = app.delete('/api/booking/%s/' % booking.pk) |
|
1968 |
assert resp.json['err'] == 0 |
|
1969 | ||
1970 | ||
1971 |
def test_booking_patch_api(app, user): |
|
1972 |
agenda = Agenda.objects.create(kind='events') |
|
1973 |
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) |
|
1974 |
booking = Booking.objects.create(event=event) |
|
1975 | ||
1976 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
1977 | ||
1978 |
resp = app.patch('/api/booking/%s/' % booking.pk) |
|
1979 |
assert resp.json['err'] == 0 |
|
1980 |
resp = app.patch('/api/booking/%s/' % booking.pk, params={'user_was_present': 'foobar'}, status=400) |
|
1981 |
assert resp.json['err'] == 4 |
|
1982 |
assert resp.json['err_desc'] == 'invalid payload' |
|
1983 | ||
1984 | ||
1985 |
@pytest.mark.parametrize('flag', [True, False, None]) |
|
1986 |
def test_booking_patch_api_present(app, user, flag): |
|
1987 |
agenda = Agenda.objects.create(kind='events') |
|
1988 |
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) |
|
1989 |
booking = Booking.objects.create(event=event) |
|
1990 | ||
1991 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
1992 | ||
1993 |
# set flag |
|
1994 |
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag}) |
|
1995 |
booking.refresh_from_db() |
|
1996 |
assert booking.user_was_present == flag |
|
1997 | ||
1998 |
# reset |
|
1999 |
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': None}) |
|
2000 |
booking.refresh_from_db() |
|
2001 |
assert booking.user_was_present is None |
|
2002 | ||
2003 |
# make secondary bookings |
|
2004 |
Booking.objects.create(event=event, primary_booking=booking) |
|
2005 |
Booking.objects.create(event=event, primary_booking=booking) |
|
2006 |
# and other booking |
|
2007 |
other_booking = Booking.objects.create(event=event) |
|
2008 | ||
2009 |
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag}) |
|
2010 |
booking.refresh_from_db() |
|
2011 |
assert booking.user_was_present == flag |
|
2012 |
# all secondary bookings are upadted |
|
2013 |
assert list(booking.secondary_booking_set.values_list('user_was_present', flat=True)) == [flag, flag] |
|
2014 |
other_booking.refresh_from_db() |
|
2015 |
assert other_booking.user_was_present is None # not changed |
|
2016 | ||
2017 | ||
1907 | 2018 |
def test_booking_cancellation_api(app, some_data, user): |
1908 | 2019 |
agenda = Agenda.objects.filter(label=u'Foo bar')[0] |
1909 | 2020 |
event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0] |
1910 |
- |