From c35841564254e715870f9d12d655912bd5db1876 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:04:54 +0300 Subject: [PATCH] B: Copy attributions when cloning --- .../apps/library/tests/s_views/t_library.py | 4 +++- rsconcept/backend/apps/library/views/library.py | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/rsconcept/backend/apps/library/tests/s_views/t_library.py b/rsconcept/backend/apps/library/tests/s_views/t_library.py index d5b35e57..c06b9f9c 100644 --- a/rsconcept/backend/apps/library/tests/s_views/t_library.py +++ b/rsconcept/backend/apps/library/tests/s_views/t_library.py @@ -9,7 +9,7 @@ from apps.library.models import ( LibraryTemplate, LocationHead ) -from apps.rsform.models import RSForm +from apps.rsform.models import Attribution, RSForm from shared.EndpointTester import EndpointTester, decl_endpoint from shared.testing_utils import response_contains @@ -343,6 +343,7 @@ class TestLibraryViewset(EndpointTester): term_raw='@{X12|plur}', term_resolved='люди' ) + Attribution.objects.create(container=d2, attribute=x12) data = {'item_data': {'title': 'Title1337'}, 'items': []} self.executeNotFound(data, item=self.invalid_item) @@ -351,6 +352,7 @@ class TestLibraryViewset(EndpointTester): response = self.executeCreated(data, item=self.owned.pk) self.assertEqual(response.data['title'], data['item_data']['title']) self.assertEqual(len(response.data['items']), 2) + self.assertEqual(len(response.data['attribution']), 1) self.assertEqual(response.data['items'][0]['alias'], x12.alias) self.assertEqual(response.data['items'][0]['term_raw'], x12.term_raw) self.assertEqual(response.data['items'][0]['term_resolved'], x12.term_resolved) diff --git a/rsconcept/backend/apps/library/views/library.py b/rsconcept/backend/apps/library/views/library.py index 9a97582b..fb6af1a4 100644 --- a/rsconcept/backend/apps/library/views/library.py +++ b/rsconcept/backend/apps/library/views/library.py @@ -14,7 +14,7 @@ from rest_framework.request import Request from rest_framework.response import Response from apps.oss.models import Layout, Operation, OperationSchema, PropagationFacade -from apps.rsform.models import RSFormCached +from apps.rsform.models import Attribution, RSFormCached from apps.rsform.serializers import RSFormParseSerializer from apps.users.models import User from shared import permissions @@ -157,8 +157,8 @@ class LibraryViewSet(viewsets.ModelViewSet): serializer = s.LibraryItemCloneSerializer(data=request.data, context={'schema': item}) serializer.is_valid(raise_exception=True) - data = serializer.validated_data['item_data'] + with transaction.atomic(): clone = deepcopy(item) clone.pk = None @@ -171,12 +171,24 @@ class LibraryViewSet(viewsets.ModelViewSet): clone.access_policy = data.get('access_policy', m.AccessPolicy.PUBLIC) clone.location = data.get('location', m.LocationHead.USER) clone.save() + + cst_map: dict[int, int] = {} + cst_list: list[int] = [] need_filter = 'items' in request.data and request.data['items'] for cst in RSFormCached(item).constituentsQ(): if not need_filter or cst.pk in request.data['items']: + old_pk = cst.pk cst.pk = None cst.schema = clone cst.save() + cst_map[old_pk] = cst.pk + cst_list.append(old_pk) + for attr in Attribution.objects.filter(container__in=cst_list, attribute__in=cst_list): + attr.pk = None + attr.container_id = cst_map[attr.container_id] + attr.attribute_id = cst_map[attr.attribute_id] + attr.save() + return Response( status=c.HTTP_201_CREATED, data=RSFormParseSerializer(clone).data