diff --git a/src/pretix/api/views/media.py b/src/pretix/api/views/media.py index fac6c018c0..7b1509128d 100644 --- a/src/pretix/api/views/media.py +++ b/src/pretix/api/views/media.py @@ -119,14 +119,38 @@ class ReusableMediaViewSet(viewsets.ModelViewSet): @transaction.atomic() def perform_update(self, serializer): - ReusableMedium.objects.select_for_update(of=OF_SELF).get(pk=self.get_object().pk) + rm = ReusableMedium.objects.select_for_update(of=OF_SELF).get(pk=self.get_object().pk) + prev_linked_ops_pks = list(rm.linked_orderpositions.values_list("pk", flat=True)) inst = serializer.save(identifier=serializer.instance.identifier, type=serializer.instance.type) - inst.log_action( - 'pretix.reusable_medium.changed', - user=self.request.user, - auth=self.request.auth, - data=self.request.data, - ) + linked_ops_pks = inst.linked_orderpositions.values_list("pk", flat=True) + for op_pk in prev_linked_ops_pks: + if op_pk not in linked_ops_pks: + inst.log_action( + 'pretix.reusable_medium.linked_orderposition.removed', + user=self.request.user, + auth=self.request.auth, + data={ + 'linked_orderposition': op_pk, + } + ) + for op_pk in linked_ops_pks: + if op_pk not in prev_linked_ops_pks: + inst.log_action( + 'pretix.reusable_medium.linked_orderposition.added', + user=self.request.user, + auth=self.request.auth, + data={ + 'linked_orderposition': op_pk, + } + ) + data = {k: v for k, v in self.request.data.items() if k not in ('linked_orderposition', 'linked_orderpositions')} + if data: + inst.log_action( + 'pretix.reusable_medium.changed', + user=self.request.user, + auth=self.request.auth, + data=data, + ) return inst def perform_destroy(self, instance): diff --git a/src/tests/api/test_reusable_media.py b/src/tests/api/test_reusable_media.py index 11e8fb3533..1f91a9f685 100644 --- a/src/tests/api/test_reusable_media.py +++ b/src/tests/api/test_reusable_media.py @@ -529,6 +529,7 @@ def test_medium_patch(token_client, organizer, event, medium, giftcard, customer medium.refresh_from_db() with scopes_disabled(): assert list(medium.linked_orderpositions.values_list('pk', flat=True)) == [op.pk] + assert medium.all_logentries().count() == 2 resp = token_client.patch( '/api/v1/organizers/{}/reusablemedia/{}/'.format(organizer.slug, medium.pk), @@ -541,6 +542,20 @@ def test_medium_patch(token_client, organizer, event, medium, giftcard, customer medium.refresh_from_db() with scopes_disabled(): assert list(medium.linked_orderpositions.values_list('pk', flat=True)) == [op.pk, op2.pk] + assert medium.all_logentries().count() == 3 + + resp = token_client.patch( + '/api/v1/organizers/{}/reusablemedia/{}/'.format(organizer.slug, medium.pk), + { + 'linked_orderpositions': [op2.pk], + }, + format='json' + ) + assert resp.status_code == 200 + medium.refresh_from_db() + with scopes_disabled(): + assert list(medium.linked_orderpositions.values_list('pk', flat=True)) == [op2.pk] + assert medium.all_logentries().count() == 4 resp = token_client.patch( '/api/v1/organizers/{}/reusablemedia/{}/'.format(organizer.slug, medium.pk),