B: Fix propagate attribution creation

This commit is contained in:
Ivan 2025-11-07 23:36:52 +03:00
parent d2782d70fc
commit b94e643043
4 changed files with 39 additions and 12 deletions

View File

@ -135,10 +135,10 @@ class PropagationEngine:
return return
for child_id in children: for child_id in children:
if not exclude or child_id not in exclude: if not exclude or child_id not in exclude:
self.inherit_association(child_id, items) self.inherit_attribution(child_id, items)
def inherit_association(self, target: int, items: list[Attribution]) -> None: def inherit_attribution(self, target: int, items: list[Attribution]) -> None:
''' Execute inheritance of Associations. ''' ''' Execute inheritance of Attributions. '''
operation = self.cache.operation_by_id[target] operation = self.cache.operation_by_id[target]
if operation.result is None or not items: if operation.result is None or not items:
return return
@ -153,8 +153,8 @@ class PropagationEngine:
new_attributions: list[Attribution] = [] new_attributions: list[Attribution] = []
for attrib in items: for attrib in items:
new_container = self.cache.get_inheritor(attrib.container_id, target) new_container = self.cache.get_successor(attrib.container_id, target)
new_attribute = self.cache.get_inheritor(attrib.attribute_id, target) new_attribute = self.cache.get_successor(attrib.attribute_id, target)
if new_container is None or new_attribute is None \ if new_container is None or new_attribute is None \
or new_attribute == new_container \ or new_attribute == new_container \
or (new_container, new_attribute) in existing_attributions: or (new_container, new_attribute) in existing_attributions:
@ -199,8 +199,8 @@ class PropagationEngine:
deleted: list[Attribution] = [] deleted: list[Attribution] = []
for attr in attributions: for attr in attributions:
new_container = self.cache.get_inheritor(attr.container_id, child_id) new_container = self.cache.get_successor(attr.container_id, child_id)
new_attribute = self.cache.get_inheritor(attr.attribute_id, child_id) new_attribute = self.cache.get_successor(attr.attribute_id, child_id)
if new_container is None or new_attribute is None: if new_container is None or new_attribute is None:
continue continue
deleted_assoc = Attribution.objects.filter( deleted_assoc = Attribution.objects.filter(

View File

@ -1,7 +1,7 @@
''' Testing API: Change constituents in OSS. ''' ''' Testing API: Change constituents in OSS. '''
from apps.oss.models import OperationSchema, OperationType from apps.oss.models import OperationSchema, OperationType
from apps.rsform.models import Constituenta, CstType, RSForm from apps.rsform.models import Attribution, Constituenta, CstType, RSForm
from shared.EndpointTester import EndpointTester, decl_endpoint from shared.EndpointTester import EndpointTester, decl_endpoint
@ -125,7 +125,7 @@ class TestChangeConstituents(EndpointTester):
'crucial': True, 'crucial': True,
} }
} }
response = self.executeOK(data, schema=self.ks1.model.pk) self.executeOK(data, schema=self.ks1.model.pk)
self.ks1X1.refresh_from_db() self.ks1X1.refresh_from_db()
d2.refresh_from_db() d2.refresh_from_db()
inherited_cst = Constituenta.objects.get(as_child__parent_id=self.ks1X1.pk) inherited_cst = Constituenta.objects.get(as_child__parent_id=self.ks1X1.pk)
@ -145,7 +145,7 @@ class TestChangeConstituents(EndpointTester):
@decl_endpoint('/api/rsforms/{schema}/delete-multiple-cst', method='patch') @decl_endpoint('/api/rsforms/{schema}/delete-multiple-cst', method='patch')
def test_delete_constituenta(self): def test_delete_constituenta(self):
data = {'items': [self.ks2X1.pk]} data = {'items': [self.ks2X1.pk]}
response = self.executeOK(data, schema=self.ks2.model.pk) self.executeOK(data, schema=self.ks2.model.pk)
inherited_cst = Constituenta.objects.get(as_child__parent_id=self.ks2D1.pk) inherited_cst = Constituenta.objects.get(as_child__parent_id=self.ks2D1.pk)
self.ks2D1.refresh_from_db() self.ks2D1.refresh_from_db()
self.assertEqual(self.ks2.constituentsQ().count(), 1) self.assertEqual(self.ks2.constituentsQ().count(), 1)
@ -168,3 +168,30 @@ class TestChangeConstituents(EndpointTester):
self.assertEqual(self.ks3.constituentsQ().count(), 4) self.assertEqual(self.ks3.constituentsQ().count(), 4)
self.assertEqual(self.ks1X2.order, 0) self.assertEqual(self.ks1X2.order, 0)
self.assertEqual(d2.definition_formal, r'X2\X2\X3') self.assertEqual(d2.definition_formal, r'X2\X2\X3')
@decl_endpoint('/api/rsforms/{schema}/create-attribution', method='post')
def test_create_attribution(self):
data = {'container': self.ks1X1.pk, 'attribute': self.ks1X2.pk}
self.executeCreated(data, schema=self.ks1.model.pk)
x1_child = Constituenta.objects.get(as_child__parent_id=self.ks1X1.pk)
x2_child = Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk)
self.assertTrue(Attribution.objects.filter(container=x1_child, attribute=x2_child).exists())
@decl_endpoint('/api/rsforms/{schema}/create-attribution', method='post')
def test_create_attribution_substitution(self):
self.operation3.result.delete()
self.owned.set_substitutions(self.operation3.pk, [{
'original': self.ks1X1,
'substitution': self.ks2X1
}])
self.owned.execute_operation(self.operation3)
self.operation3.refresh_from_db()
self.ks3 = RSForm(self.operation3.result)
data = {'container': self.ks1X1.pk, 'attribute': self.ks1X2.pk}
self.executeCreated(data, schema=self.ks1.model.pk)
x1_child = Constituenta.objects.get(as_child__parent_id=self.ks2X1.pk)
x2_child = Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk)
self.assertTrue(Attribution.objects.filter(container=x1_child, attribute=x2_child).exists())

View File

@ -42,7 +42,7 @@ class TestAttributionsEndpoints(EndpointTester):
self.executeBadData(data, item=self.owned_id) self.executeBadData(data, item=self.owned_id)
data = {'container': self.n1.pk, 'attribute': self.x1.pk} data = {'container': self.n1.pk, 'attribute': self.x1.pk}
self.executeBadData(data, item=self.unowned_id) self.executeForbidden(data, item=self.unowned_id)
response = self.executeCreated(data, item=self.owned_id) response = self.executeCreated(data, item=self.owned_id)
attributions = response.data['attribution'] attributions = response.data['attribution']

View File

@ -49,7 +49,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
'restore_order', 'restore_order',
'reset_aliases', 'reset_aliases',
'produce_structure', 'produce_structure',
'add_attribution', 'create_attribution',
'delete_attribution', 'delete_attribution',
'clear_attributions' 'clear_attributions'
]: ]: