B: Prevent oss cross-propagation

This commit is contained in:
Ivan 2024-08-14 23:36:52 +03:00
parent e17056ea10
commit 4716fde331
4 changed files with 67 additions and 8 deletions

View File

@ -201,6 +201,9 @@ class TestOssViewset(EndpointTester):
def test_create_operation_result(self):
self.populateData()
self.operation1.result = None
self.operation1.save()
data = {
'item_data': {
'alias': 'Test4',
@ -223,11 +226,14 @@ class TestOssViewset(EndpointTester):
'alias': 'Test4',
'title': 'Test title',
'comment': 'Comment',
'operation_type': OperationType.INPUT
'operation_type': OperationType.INPUT,
'result': self.ks1.model.pk
},
'create_schema': True,
'positions': [],
}
self.executeBadData(data=data, item=self.owned_id)
data['item_data']['result'] = None
response = self.executeCreated(data=data, item=self.owned_id)
self.owned.refresh_from_db()
new_operation = response.data['new_operation']
@ -341,9 +347,25 @@ class TestOssViewset(EndpointTester):
'target': self.operation1.pk,
'input': self.ks2.model.pk
}
response = self.executeOK(data=data, item=self.owned_id)
self.executeBadData(data=data, item=self.owned_id)
data = {
'positions': [],
'target': self.operation2.pk,
'input': None
}
self.executeOK(data=data, item=self.owned_id)
self.operation2.refresh_from_db()
self.assertEqual(self.operation2.result, self.ks2.model)
self.assertEqual(self.operation2.result, None)
data = {
'positions': [],
'target': self.operation1.pk,
'input': self.ks2.model.pk
}
self.executeOK(data=data, item=self.owned_id)
self.operation1.refresh_from_db()
self.assertEqual(self.operation1.result, self.ks2.model)
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
def test_update_operation(self):

View File

@ -1,7 +1,8 @@
''' Endpoints for OSS. '''
from typing import cast
from typing import Optional, cast
from django.db import transaction
from django.db.models import Q
from django.http import HttpResponse
from drf_spectacular.utils import extend_schema, extend_schema_view
from rest_framework import generics, serializers
@ -109,6 +110,21 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
with transaction.atomic():
oss.update_positions(serializer.validated_data['positions'])
new_operation = oss.create_operation(**serializer.validated_data['item_data'])
schema = new_operation.result
if schema is not None:
connected_operations = \
m.Operation.objects \
.filter(Q(result=schema) & ~Q(pk=new_operation.pk)) \
.only('operation_type', 'oss_id')
for operation in connected_operations:
if operation.operation_type != m.OperationType.INPUT:
raise serializers.ValidationError({
'item_data': msg.operationResultFromAnotherOSS()
})
if operation.oss_id == new_operation.oss_id:
raise serializers.ValidationError({
'item_data': msg.operationInputAlreadyConnected()
})
if new_operation.operation_type == m.OperationType.INPUT and serializer.validated_data['create_schema']:
oss.create_input(new_operation)
if new_operation.operation_type != m.OperationType.INPUT and 'arguments' in serializer.validated_data:
@ -220,11 +236,24 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
)
serializer.is_valid(raise_exception=True)
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
target_operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
schema: Optional[LibraryItem] = serializer.validated_data['input']
if schema is not None:
connected_operations = m.Operation.objects.filter(result=schema).only('operation_type', 'oss_id')
for operation in connected_operations:
if operation.operation_type != m.OperationType.INPUT:
raise serializers.ValidationError({
'input': msg.operationResultFromAnotherOSS()
})
if operation != target_operation and operation.oss_id == target_operation.oss_id:
raise serializers.ValidationError({
'input': msg.operationInputAlreadyConnected()
})
oss = m.OperationSchema(self.get_object())
with transaction.atomic():
oss.update_positions(serializer.validated_data['positions'])
oss.set_input(operation.pk, serializer.validated_data['input'])
oss.set_input(target_operation.pk, schema)
return Response(
status=c.HTTP_200_OK,
data=s.OperationSchemaSerializer(oss.model).data

View File

@ -30,6 +30,14 @@ def operationNotInput(title: str):
return f'Операция не является Загрузкой: {title}'
def operationResultFromAnotherOSS():
return 'Схема является результатом другой ОСС'
def operationInputAlreadyConnected():
return 'Схема уже подключена к другой операции'
def operationNotSynthesis(title: str):
return f'Операция не является Синтезом: {title}'

View File

@ -132,8 +132,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
const positions = getPositions();
if (positions.length == 0) {
target = flow.project({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
}
if (inputs.length <= 1) {
} else if (inputs.length <= 1) {
let inputsNodes = positions.filter(pos =>
controller.schema!.items.find(
operation => operation.operation_type === OperationType.INPUT && operation.id === pos.id
@ -167,6 +166,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
target.y += PARAMETER.ossMinDistance;
}
} while (flagIntersect);
controller.promptCreateOperation({
x: target.x,
y: target.y,