diff --git a/chrono/api/serializers.py b/chrono/api/serializers.py index fc52c5d2..485c3029 100644 --- a/chrono/api/serializers.py +++ b/chrono/api/serializers.py @@ -187,11 +187,7 @@ class RecurringFillslotsSerializer(MultipleAgendasEventsSlotsSerializer): class BookingSerializer(serializers.ModelSerializer): user_absence_reason = serializers.CharField(required=False, allow_blank=True, allow_null=True) user_presence_reason = serializers.CharField(required=False, allow_blank=True, allow_null=True) - color = serializers.SlugRelatedField( - many=False, - slug_field='label', - queryset=BookingColor.objects.all(), - ) + use_color_for = serializers.CharField(required=False, allow_blank=True, allow_null=True, source='color') class Meta: model = Booking @@ -205,7 +201,7 @@ class BookingSerializer(serializers.ModelSerializer): 'user_was_present', 'user_absence_reason', 'user_presence_reason', - 'color', + 'use_color_for', 'extra_data', 'creation_datetime', 'cancellation_datetime', @@ -218,6 +214,13 @@ class BookingSerializer(serializers.ModelSerializer): 'cancellation_datetime', ] + def to_internal_value(self, data): + if 'color' in data: + # legacy + data['use_color_for'] = data['color'] + del data['color'] + return super().to_internal_value(data) + def to_representation(self, instance): ret = super().to_representation(instance) check_type_slug = self.instance.user_check_type.slug if self.instance.user_check_type else '' @@ -254,6 +257,10 @@ class BookingSerializer(serializers.ModelSerializer): def validate_user_presence_reason(self, value): return self._validate_check_type('presence', value) + def validate_use_color_for(self, value): + if value: + return BookingColor.objects.get_or_create(label=value)[0] + def validate(self, attrs): super().validate(attrs) if 'user_absence_reason' in attrs and 'user_presence_reason' in attrs: diff --git a/chrono/api/views.py b/chrono/api/views.py index 3fa83cde..1535f78e 100644 --- a/chrono/api/views.py +++ b/chrono/api/views.py @@ -2496,10 +2496,11 @@ class BookingAPI(APIView): 'user_last_name', 'user_email', 'user_phone_number', - 'color', ]: if key in request.data: secondary_bookings_update[key] = getattr(self.booking, key) + if 'use_color_for' in request.data: + secondary_bookings_update['color'] = self.booking.color if 'user_absence_reason' in request.data or 'user_presence_reason' in request.data: secondary_bookings_update['user_check_type'] = self.booking.user_check_type if extra_data: diff --git a/tests/api/test_booking.py b/tests/api/test_booking.py index 126b4c06..ff92eb5c 100644 --- a/tests/api/test_booking.py +++ b/tests/api/test_booking.py @@ -153,7 +153,7 @@ def test_bookings_api(app, user): 'user_was_present': None, 'user_absence_reason': '', 'user_presence_reason': '', - 'color': None, + 'use_color_for': None, 'extra_data': None, 'cancellation_datetime': None, 'creation_datetime': localtime(meetings_booking1.creation_datetime).isoformat(), @@ -168,7 +168,7 @@ def test_bookings_api(app, user): 'user_was_present': None, 'user_absence_reason': '', 'user_presence_reason': '', - 'color': None, + 'use_color_for': None, 'extra_data': None, 'event': resp.json['data'][1]['event'], 'cancellation_datetime': None, @@ -184,7 +184,7 @@ def test_bookings_api(app, user): 'user_was_present': None, 'user_absence_reason': '', 'user_presence_reason': '', - 'color': None, + 'use_color_for': None, 'extra_data': None, 'event': resp.json['data'][1]['event'], 'cancellation_datetime': None, @@ -880,6 +880,7 @@ def test_booking_patch_api_user_fields(app, user): agenda = Agenda.objects.create(kind='events') event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10) BookingColor.objects.create(label='the warmest color') + BookingColor.objects.create(label='the coolest color') color = BookingColor.objects.create(label='meh') booking = Booking.objects.create(event=event, color=color) # make secondary bookings @@ -899,7 +900,8 @@ def test_booking_patch_api_user_fields(app, user): ('user_email', ''), ('user_phone_number', '0606'), ('user_phone_number', ''), - ('color', 'the warmest color'), + ('color', 'the warmest color'), # legacy + ('use_color_for', 'the coolest color'), ] for key, value in to_test: params = { @@ -907,6 +909,8 @@ def test_booking_patch_api_user_fields(app, user): } app.patch_json('/api/booking/%s/' % booking.pk, params=params) booking.refresh_from_db() + if key == 'use_color_for': + key = 'color' assert str(getattr(booking, key)) == value # all secondary bookings are updated for secondary_booking in booking.secondary_booking_set.all(): @@ -914,16 +918,47 @@ def test_booking_patch_api_user_fields(app, user): other_booking.refresh_from_db() assert not getattr(other_booking, key) # not changed - # try again with a non existing color, it should fail + # try again with a non existing color params = { 'color': 'unicorn crimson', } - response = app.patch_json('/api/booking/%s/' % booking.pk, params=params, status=400) + app.patch_json('/api/booking/%s/' % booking.pk, params=params) booking.refresh_from_db() - assert booking.color.label == 'the warmest color' - assert response.json['err_desc'] == 'invalid payload' - assert list(response.json['errors'].keys()) == ['color'] - assert response.json['errors']['color'] == ['Object with label=unicorn crimson does not exist.'] + assert booking.color.label == 'unicorn crimson' + for secondary_booking in booking.secondary_booking_set.all(): + assert secondary_booking.color.label == 'unicorn crimson' + assert BookingColor.objects.count() == 4 + params = { + 'use_color_for': 'unicorn crimson again', + } + app.patch_json('/api/booking/%s/' % booking.pk, params=params) + booking.refresh_from_db() + assert booking.color.label == 'unicorn crimson again' + for secondary_booking in booking.secondary_booking_set.all(): + assert secondary_booking.color.label == 'unicorn crimson again' + assert BookingColor.objects.count() == 5 + + # empty value + params = { + 'color': '', + } + app.patch_json('/api/booking/%s/' % booking.pk, params=params) + booking.refresh_from_db() + assert booking.color is None + for secondary_booking in booking.secondary_booking_set.all(): + assert secondary_booking.color is None + assert BookingColor.objects.count() == 5 + + # none value + params = { + 'color': None, + } + app.patch_json('/api/booking/%s/' % booking.pk, params=params) + booking.refresh_from_db() + assert booking.color is None + for secondary_booking in booking.secondary_booking_set.all(): + assert secondary_booking.color is None + assert BookingColor.objects.count() == 5 def test_booking_patch_api_extra_data(app, user): diff --git a/tests/api/test_event.py b/tests/api/test_event.py index c861200f..32d6e997 100644 --- a/tests/api/test_event.py +++ b/tests/api/test_event.py @@ -990,7 +990,7 @@ def test_events_check_status(app, user): 'user_was_present', 'user_absence_reason', 'user_presence_reason', - 'color', + 'use_color_for', 'extra_data', 'creation_datetime', 'cancellation_datetime', @@ -1204,7 +1204,7 @@ def test_events_check_status_events(app, user): 'check_status': {'check_type': 'foo-reason', 'status': 'presence'}, 'booking': { 'cancellation_datetime': None, - 'color': None, + 'use_color_for': None, 'creation_datetime': localtime(now()).isoformat(), 'extra_data': None, 'id': booking2.pk, @@ -1242,7 +1242,7 @@ def test_events_check_status_events(app, user): 'check_status': {'check_type': 'foo-reason', 'status': 'presence'}, 'booking': { 'cancellation_datetime': None, - 'color': None, + 'use_color_for': None, 'creation_datetime': localtime(now()).isoformat(), 'extra_data': None, 'id': booking1.pk,