mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-25 20:40:36 +03:00
F: Implement delete-block and update-block backend
This commit is contained in:
parent
227b0dd72c
commit
3b26457b83
|
@ -92,26 +92,26 @@ class OperationSchema:
|
|||
)
|
||||
|
||||
def update_layout(self, data: dict) -> None:
|
||||
''' Update positions. '''
|
||||
''' Update graphical layout. '''
|
||||
layout = self.layout()
|
||||
layout.data = data
|
||||
layout.save()
|
||||
|
||||
def create_operation(self, **kwargs) -> Operation:
|
||||
''' Insert new operation. '''
|
||||
''' Create Operation. '''
|
||||
result = Operation.objects.create(oss=self.model, **kwargs)
|
||||
self.cache.insert_operation(result)
|
||||
self.save(update_fields=['time_update'])
|
||||
return result
|
||||
|
||||
def create_block(self, **kwargs) -> Block:
|
||||
''' Insert new block. '''
|
||||
''' Create Block. '''
|
||||
result = Block.objects.create(oss=self.model, **kwargs)
|
||||
self.save(update_fields=['time_update'])
|
||||
return result
|
||||
|
||||
def delete_operation(self, target: int, keep_constituents: bool = False):
|
||||
''' Delete operation. '''
|
||||
''' Delete Operation. '''
|
||||
self.cache.ensure_loaded()
|
||||
operation = self.cache.operation_by_id[target]
|
||||
schema = self.cache.get_schema(operation)
|
||||
|
@ -139,6 +139,20 @@ class OperationSchema:
|
|||
operation.delete()
|
||||
self.save(update_fields=['time_update'])
|
||||
|
||||
def delete_block(self, target: Block):
|
||||
''' Delete Block. '''
|
||||
new_parent = target.parent
|
||||
if new_parent is not None:
|
||||
for block in Block.objects.filter(parent=target):
|
||||
if block != new_parent:
|
||||
block.parent = new_parent
|
||||
block.save(update_fields=['parent'])
|
||||
for operation in Operation.objects.filter(parent=target):
|
||||
operation.parent = new_parent
|
||||
operation.save(update_fields=['parent'])
|
||||
target.delete()
|
||||
self.save(update_fields=['time_update'])
|
||||
|
||||
def set_input(self, target: int, schema: Optional[LibraryItem]) -> None:
|
||||
''' Set input schema for operation. '''
|
||||
operation = self.cache.operation_by_id[target]
|
||||
|
@ -165,7 +179,7 @@ class OperationSchema:
|
|||
self.save(update_fields=['time_update'])
|
||||
|
||||
def set_arguments(self, target: int, arguments: list[Operation]) -> None:
|
||||
''' Set arguments to operation. '''
|
||||
''' Set arguments of target Operation. '''
|
||||
self.cache.ensure_loaded()
|
||||
operation = self.cache.operation_by_id[target]
|
||||
processed: list[Operation] = []
|
||||
|
@ -198,7 +212,7 @@ class OperationSchema:
|
|||
self.save(update_fields=['time_update'])
|
||||
|
||||
def set_substitutions(self, target: int, substitutes: list[dict]) -> None:
|
||||
''' Clear all arguments for operation. '''
|
||||
''' Clear all arguments for target Operation. '''
|
||||
self.cache.ensure_loaded()
|
||||
operation = self.cache.operation_by_id[target]
|
||||
schema = self.cache.get_schema(operation)
|
||||
|
@ -237,7 +251,7 @@ class OperationSchema:
|
|||
self.save(update_fields=['time_update'])
|
||||
|
||||
def create_input(self, operation: Operation) -> RSForm:
|
||||
''' Create input RSForm. '''
|
||||
''' Create input RSForm for given Operation. '''
|
||||
schema = RSForm.create(
|
||||
owner=self.model.owner,
|
||||
alias=operation.alias,
|
||||
|
@ -254,7 +268,7 @@ class OperationSchema:
|
|||
return schema
|
||||
|
||||
def execute_operation(self, operation: Operation) -> bool:
|
||||
''' Execute target operation. '''
|
||||
''' Execute target Operation. '''
|
||||
schemas = [
|
||||
arg.argument.result
|
||||
for arg in operation.getQ_arguments().order_by('order')
|
||||
|
@ -301,7 +315,7 @@ class OperationSchema:
|
|||
return True
|
||||
|
||||
def relocate_down(self, source: RSForm, destination: RSForm, items: list[Constituenta]):
|
||||
''' Move list of constituents to specific schema inheritor. '''
|
||||
''' Move list of Constituents to destination Schema inheritor. '''
|
||||
self.cache.ensure_loaded()
|
||||
self.cache.insert_schema(source)
|
||||
self.cache.insert_schema(destination)
|
||||
|
@ -315,7 +329,7 @@ class OperationSchema:
|
|||
Inheritance.objects.filter(operation_id=operation.pk, parent__in=items).delete()
|
||||
|
||||
def relocate_up(self, source: RSForm, destination: RSForm, items: list[Constituenta]) -> list[Constituenta]:
|
||||
''' Move list of constituents to specific schema upstream. '''
|
||||
''' Move list of Constituents upstream to destination Schema. '''
|
||||
self.cache.ensure_loaded()
|
||||
self.cache.insert_schema(source)
|
||||
self.cache.insert_schema(destination)
|
||||
|
@ -345,7 +359,7 @@ class OperationSchema:
|
|||
cst_list: list[Constituenta],
|
||||
exclude: Optional[list[int]] = None
|
||||
) -> None:
|
||||
''' Trigger cascade resolutions when new constituent is created. '''
|
||||
''' Trigger cascade resolutions when new Constituenta is created. '''
|
||||
self.cache.insert_schema(source)
|
||||
inserted_aliases = [cst.alias for cst in cst_list]
|
||||
depend_aliases: set[str] = set()
|
||||
|
@ -361,13 +375,13 @@ class OperationSchema:
|
|||
self._cascade_inherit_cst(operation.pk, source, cst_list, alias_mapping, exclude)
|
||||
|
||||
def after_change_cst_type(self, source: RSForm, target: Constituenta) -> None:
|
||||
''' Trigger cascade resolutions when constituenta type is changed. '''
|
||||
''' Trigger cascade resolutions when Constituenta type is changed. '''
|
||||
self.cache.insert_schema(source)
|
||||
operation = self.cache.get_operation(source.model.pk)
|
||||
self._cascade_change_cst_type(operation.pk, target.pk, cast(CstType, target.cst_type))
|
||||
|
||||
def after_update_cst(self, source: RSForm, target: Constituenta, data: dict, old_data: dict) -> None:
|
||||
''' Trigger cascade resolutions when constituenta data is changed. '''
|
||||
''' Trigger cascade resolutions when Constituenta data is changed. '''
|
||||
self.cache.insert_schema(source)
|
||||
operation = self.cache.get_operation(source.model.pk)
|
||||
depend_aliases = self._extract_data_references(data, old_data)
|
||||
|
@ -385,13 +399,13 @@ class OperationSchema:
|
|||
)
|
||||
|
||||
def before_delete_cst(self, source: RSForm, target: list[Constituenta]) -> None:
|
||||
''' Trigger cascade resolutions before constituents are deleted. '''
|
||||
''' Trigger cascade resolutions before Constituents are deleted. '''
|
||||
self.cache.insert_schema(source)
|
||||
operation = self.cache.get_operation(source.model.pk)
|
||||
self._cascade_delete_inherited(operation.pk, target)
|
||||
|
||||
def before_substitute(self, source: RSForm, substitutions: CstSubstitution) -> None:
|
||||
''' Trigger cascade resolutions before constituents are substituted. '''
|
||||
''' Trigger cascade resolutions before Constituents are substituted. '''
|
||||
self.cache.insert_schema(source)
|
||||
operation = self.cache.get_operation(source.model.pk)
|
||||
self._cascade_before_substitute(substitutions, operation)
|
||||
|
|
|
@ -17,7 +17,7 @@ class PropagationFacade:
|
|||
|
||||
@staticmethod
|
||||
def after_create_cst(source: RSForm, new_cst: list[Constituenta], exclude: Optional[list[int]] = None) -> None:
|
||||
''' Trigger cascade resolutions when new constituent is created. '''
|
||||
''' Trigger cascade resolutions when new constituenta is created. '''
|
||||
hosts = _get_oss_hosts(source.model)
|
||||
for host in hosts:
|
||||
if exclude is None or host.pk not in exclude:
|
||||
|
|
|
@ -3,16 +3,18 @@
|
|||
from .basics import LayoutSerializer, SubstitutionExSerializer
|
||||
from .data_access import (
|
||||
ArgumentSerializer,
|
||||
BlockCreateSerializer,
|
||||
BlockSerializer,
|
||||
OperationCreateSerializer,
|
||||
CreateBlockSerializer,
|
||||
CreateOperationSerializer,
|
||||
DeleteBlockSerializer,
|
||||
OperationDeleteSerializer,
|
||||
OperationSchemaSerializer,
|
||||
OperationSerializer,
|
||||
OperationTargetSerializer,
|
||||
OperationUpdateSerializer,
|
||||
RelocateConstituentsSerializer,
|
||||
SetOperationInputSerializer
|
||||
SetOperationInputSerializer,
|
||||
UpdateBlockSerializer,
|
||||
UpdateOperationSerializer
|
||||
)
|
||||
from .responses import (
|
||||
ConstituentaReferenceResponse,
|
||||
|
|
|
@ -41,7 +41,7 @@ class ArgumentSerializer(serializers.ModelSerializer):
|
|||
fields = ('operation', 'argument')
|
||||
|
||||
|
||||
class BlockCreateSerializer(serializers.Serializer):
|
||||
class CreateBlockSerializer(serializers.Serializer):
|
||||
''' Serializer: Block creation. '''
|
||||
class BlockCreateData(serializers.ModelSerializer):
|
||||
''' Serializer: Block creation data. '''
|
||||
|
@ -52,7 +52,6 @@ class BlockCreateSerializer(serializers.Serializer):
|
|||
fields = 'title', 'description', 'parent'
|
||||
|
||||
layout = LayoutSerializer()
|
||||
|
||||
item_data = BlockCreateData()
|
||||
width = serializers.FloatField()
|
||||
height = serializers.FloatField()
|
||||
|
@ -84,9 +83,9 @@ class BlockCreateSerializer(serializers.Serializer):
|
|||
return attrs
|
||||
|
||||
|
||||
class OperationCreateSerializer(serializers.Serializer):
|
||||
class CreateOperationSerializer(serializers.Serializer):
|
||||
''' Serializer: Operation creation. '''
|
||||
class OperationCreateData(serializers.ModelSerializer):
|
||||
class CreateOperationData(serializers.ModelSerializer):
|
||||
''' Serializer: Operation creation data. '''
|
||||
alias = serializers.CharField()
|
||||
operation_type = serializers.ChoiceField(OperationType.choices)
|
||||
|
@ -99,8 +98,7 @@ class OperationCreateSerializer(serializers.Serializer):
|
|||
'description', 'result', 'parent'
|
||||
|
||||
layout = LayoutSerializer()
|
||||
|
||||
item_data = OperationCreateData()
|
||||
item_data = CreateOperationData()
|
||||
position_x = serializers.FloatField()
|
||||
position_y = serializers.FloatField()
|
||||
create_schema = serializers.BooleanField(default=False, required=False)
|
||||
|
@ -120,23 +118,23 @@ class OperationCreateSerializer(serializers.Serializer):
|
|||
for operation in attrs['arguments']:
|
||||
if operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'arguments': msg.operationNotInOSS(oss.title)
|
||||
'arguments': msg.operationNotInOSS()
|
||||
})
|
||||
return attrs
|
||||
|
||||
|
||||
class OperationUpdateSerializer(serializers.Serializer):
|
||||
class UpdateOperationSerializer(serializers.Serializer):
|
||||
''' Serializer: Operation update. '''
|
||||
class OperationUpdateData(serializers.ModelSerializer):
|
||||
class UpdateOperationData(serializers.ModelSerializer):
|
||||
''' Serializer: Operation update data. '''
|
||||
class Meta:
|
||||
''' serializer metadata. '''
|
||||
model = Operation
|
||||
fields = 'alias', 'title', 'description'
|
||||
fields = 'alias', 'title', 'description', 'parent'
|
||||
|
||||
layout = LayoutSerializer()
|
||||
layout = LayoutSerializer(required=False)
|
||||
target = PKField(many=False, queryset=Operation.objects.all())
|
||||
item_data = OperationUpdateData()
|
||||
item_data = UpdateOperationData()
|
||||
arguments = PKField(many=True, queryset=Operation.objects.all().only('oss_id', 'result_id'), required=False)
|
||||
substitutions = serializers.ListField(
|
||||
child=SubstitutionSerializerBase(),
|
||||
|
@ -145,6 +143,12 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
|
||||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
target = cast(Block, attrs['target'])
|
||||
if target.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS()
|
||||
})
|
||||
|
||||
if 'parent' in attrs['item_data'] and attrs['item_data']['parent'].oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'parent': msg.parentNotInOSS()
|
||||
|
@ -160,7 +164,7 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
for operation in attrs['arguments']:
|
||||
if operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'arguments': msg.operationNotInOSS(oss.title)
|
||||
'arguments': msg.operationNotInOSS()
|
||||
})
|
||||
|
||||
if 'substitutions' not in attrs:
|
||||
|
@ -192,17 +196,51 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
return attrs
|
||||
|
||||
|
||||
class OperationTargetSerializer(serializers.Serializer):
|
||||
''' Serializer: Target single operation. '''
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'result_id'))
|
||||
class UpdateBlockSerializer(serializers.Serializer):
|
||||
''' Serializer: Block update. '''
|
||||
class UpdateBlockData(serializers.ModelSerializer):
|
||||
''' Serializer: Block update data. '''
|
||||
class Meta:
|
||||
''' serializer metadata. '''
|
||||
model = Block
|
||||
fields = 'title', 'description', 'parent'
|
||||
|
||||
layout = LayoutSerializer(required=False)
|
||||
target = PKField(many=False, queryset=Block.objects.all())
|
||||
item_data = UpdateBlockData()
|
||||
|
||||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
operation = cast(Operation, attrs['target'])
|
||||
if oss and operation.oss_id != oss.pk:
|
||||
block = cast(Block, attrs['target'])
|
||||
if block.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS(oss.title)
|
||||
'target': msg.blockNotInOSS()
|
||||
})
|
||||
|
||||
if 'parent' in attrs['item_data'] and \
|
||||
attrs['item_data']['parent'] is not None:
|
||||
if attrs['item_data']['parent'].oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'parent': msg.parentNotInOSS()
|
||||
})
|
||||
if attrs['item_data']['parent'] == attrs['target']:
|
||||
raise serializers.ValidationError({
|
||||
'parent': msg.blockSelfParent()
|
||||
})
|
||||
return attrs
|
||||
|
||||
|
||||
class DeleteBlockSerializer(serializers.Serializer):
|
||||
''' Serializer: Delete block. '''
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Block.objects.all().only('oss_id'))
|
||||
|
||||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
block = cast(Block, attrs['target'])
|
||||
if block.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.blockNotInOSS()
|
||||
})
|
||||
return attrs
|
||||
|
||||
|
@ -217,9 +255,24 @@ class OperationDeleteSerializer(serializers.Serializer):
|
|||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
operation = cast(Operation, attrs['target'])
|
||||
if oss and operation.oss_id != oss.pk:
|
||||
if operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS(oss.title)
|
||||
'target': msg.operationNotInOSS()
|
||||
})
|
||||
return attrs
|
||||
|
||||
|
||||
class OperationTargetSerializer(serializers.Serializer):
|
||||
''' Serializer: Target single operation. '''
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'result_id'))
|
||||
|
||||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
operation = cast(Operation, attrs['target'])
|
||||
if operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS()
|
||||
})
|
||||
return attrs
|
||||
|
||||
|
@ -240,7 +293,7 @@ class SetOperationInputSerializer(serializers.Serializer):
|
|||
operation = cast(Operation, attrs['target'])
|
||||
if oss and operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS(oss.title)
|
||||
'target': msg.operationNotInOSS()
|
||||
})
|
||||
if operation.operation_type != OperationType.INPUT:
|
||||
raise serializers.ValidationError({
|
||||
|
|
|
@ -27,6 +27,10 @@ class TestOssBlocks(EndpointTester):
|
|||
self.block1 = self.owned.create_block(
|
||||
title='1',
|
||||
)
|
||||
self.block2 = self.owned.create_block(
|
||||
title='2',
|
||||
parent=self.block1
|
||||
)
|
||||
self.operation1 = self.owned.create_operation(
|
||||
alias='1',
|
||||
operation_type=OperationType.INPUT,
|
||||
|
@ -35,15 +39,12 @@ class TestOssBlocks(EndpointTester):
|
|||
self.operation2 = self.owned.create_operation(
|
||||
alias='2',
|
||||
operation_type=OperationType.INPUT,
|
||||
parent=self.block2,
|
||||
)
|
||||
self.operation3 = self.unowned.create_operation(
|
||||
alias='3',
|
||||
operation_type=OperationType.INPUT
|
||||
)
|
||||
self.block2 = self.owned.create_block(
|
||||
title='2',
|
||||
parent=self.block1
|
||||
)
|
||||
self.block3 = self.unowned.create_block(
|
||||
title='3',
|
||||
parent=self.block1
|
||||
|
@ -165,3 +166,73 @@ class TestOssBlocks(EndpointTester):
|
|||
self.block1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.parent.pk, new_block['id'])
|
||||
self.assertEqual(self.block1.parent.pk, new_block['id'])
|
||||
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/delete-block', method='patch')
|
||||
def test_delete_block(self):
|
||||
self.populateData()
|
||||
self.executeNotFound(item=self.invalid_id)
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.block3.pk
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.block2.pk
|
||||
self.logout()
|
||||
self.executeForbidden(data=data)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation2.refresh_from_db()
|
||||
self.assertEqual(len(response.data['blocks']), 1)
|
||||
self.assertEqual(self.operation2.parent.pk, self.block1.pk)
|
||||
|
||||
data['target'] = self.block1.pk
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.operation2.refresh_from_db()
|
||||
self.assertEqual(len(response.data['blocks']), 0)
|
||||
self.assertEqual(self.operation1.parent, None)
|
||||
self.assertEqual(self.operation2.parent, None)
|
||||
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-block', method='patch')
|
||||
def test_update_block(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'target': self.invalid_id,
|
||||
'item_data': {
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod',
|
||||
'parent': None
|
||||
},
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.block3.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.block2.pk
|
||||
self.logout()
|
||||
self.executeForbidden(data=data)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.block2.refresh_from_db()
|
||||
self.assertEqual(self.block2.title, data['item_data']['title'])
|
||||
self.assertEqual(self.block2.description, data['item_data']['description'])
|
||||
self.assertEqual(self.block2.parent, data['item_data']['parent'])
|
||||
|
||||
data['layout'] = self.layout_data
|
||||
self.executeOK(data=data)
|
||||
|
|
|
@ -226,9 +226,8 @@ class TestOssOperations(EndpointTester):
|
|||
|
||||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_operation(self):
|
||||
self.executeNotFound(item=self.invalid_id)
|
||||
|
||||
self.populateData()
|
||||
self.executeNotFound(item=self.invalid_id)
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
|
@ -371,7 +370,6 @@ class TestOssOperations(EndpointTester):
|
|||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'layout': self.layout_data,
|
||||
'arguments': [self.operation2.pk, self.operation1.pk],
|
||||
'substitutions': [
|
||||
{
|
||||
|
@ -403,6 +401,10 @@ class TestOssOperations(EndpointTester):
|
|||
self.assertEqual(sub.original.pk, data['substitutions'][0]['original'])
|
||||
self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution'])
|
||||
|
||||
data['layout'] = self.layout_data
|
||||
self.executeOK(data=data)
|
||||
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
|
||||
def test_update_operation_sync(self):
|
||||
self.populateData()
|
||||
|
|
|
@ -40,9 +40,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
'create_operation',
|
||||
'create_block',
|
||||
'delete_operation',
|
||||
'delete_block',
|
||||
'update_operation',
|
||||
'update_block',
|
||||
'create_input',
|
||||
'set_input',
|
||||
'update_operation',
|
||||
'execute_operation',
|
||||
'relocate_constituents'
|
||||
]:
|
||||
|
@ -94,7 +96,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
@extend_schema(
|
||||
summary='create operation',
|
||||
tags=['OSS'],
|
||||
request=s.OperationCreateSerializer(),
|
||||
request=s.CreateOperationSerializer(),
|
||||
responses={
|
||||
c.HTTP_201_CREATED: s.NewOperationResponse,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
|
@ -104,8 +106,8 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
)
|
||||
@action(detail=True, methods=['post'], url_path='create-operation')
|
||||
def create_operation(self, request: Request, pk) -> HttpResponse:
|
||||
''' Create new operation. '''
|
||||
serializer = s.OperationCreateSerializer(
|
||||
''' Create Operation. '''
|
||||
serializer = s.CreateOperationSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
)
|
||||
|
@ -155,7 +157,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
@extend_schema(
|
||||
summary='create block',
|
||||
tags=['OSS'],
|
||||
request=s.BlockCreateSerializer(),
|
||||
request=s.CreateBlockSerializer(),
|
||||
responses={
|
||||
c.HTTP_201_CREATED: s.NewBlockResponse,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
|
@ -165,8 +167,8 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
)
|
||||
@action(detail=True, methods=['post'], url_path='create-block')
|
||||
def create_block(self, request: Request, pk) -> HttpResponse:
|
||||
''' Create new block. '''
|
||||
serializer = s.BlockCreateSerializer(
|
||||
''' Create Block. '''
|
||||
serializer = s.CreateBlockSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
)
|
||||
|
@ -216,7 +218,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
)
|
||||
@action(detail=True, methods=['patch'], url_path='delete-operation')
|
||||
def delete_operation(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Delete operation. '''
|
||||
''' Endpoint: Delete Operation. '''
|
||||
serializer = s.OperationDeleteSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
|
@ -243,6 +245,119 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='delete block',
|
||||
tags=['OSS'],
|
||||
request=s.DeleteBlockSerializer,
|
||||
responses={
|
||||
c.HTTP_200_OK: s.OperationSchemaSerializer,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='delete-block')
|
||||
def delete_block(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Delete Block. '''
|
||||
serializer = s.DeleteBlockSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
block = cast(m.Block, serializer.validated_data['target'])
|
||||
layout = serializer.validated_data['layout']
|
||||
layout['blocks'] = [x for x in layout['blocks'] if x['id'] != block.pk]
|
||||
with transaction.atomic():
|
||||
oss.delete_block(block)
|
||||
oss.update_layout(layout)
|
||||
|
||||
return Response(
|
||||
status=c.HTTP_200_OK,
|
||||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='update operation',
|
||||
tags=['OSS'],
|
||||
request=s.UpdateOperationSerializer(),
|
||||
responses={
|
||||
c.HTTP_200_OK: s.OperationSchemaSerializer,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='update-operation')
|
||||
def update_operation(self, request: Request, pk) -> HttpResponse:
|
||||
''' Update Operation arguments and parameters. '''
|
||||
serializer = s.UpdateOperationSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
with transaction.atomic():
|
||||
if 'layout' in serializer.validated_data:
|
||||
oss.update_layout(serializer.validated_data['layout'])
|
||||
operation.alias = serializer.validated_data['item_data']['alias']
|
||||
operation.title = serializer.validated_data['item_data']['title']
|
||||
operation.description = serializer.validated_data['item_data']['description']
|
||||
operation.save(update_fields=['alias', 'title', 'description'])
|
||||
|
||||
if operation.result is not None:
|
||||
can_edit = permissions.can_edit_item(request.user, operation.result)
|
||||
if can_edit or operation.operation_type == m.OperationType.SYNTHESIS:
|
||||
operation.result.alias = operation.alias
|
||||
operation.result.title = operation.title
|
||||
operation.result.description = operation.description
|
||||
operation.result.save()
|
||||
if 'arguments' in serializer.validated_data:
|
||||
oss.set_arguments(operation.pk, serializer.validated_data['arguments'])
|
||||
if 'substitutions' in serializer.validated_data:
|
||||
oss.set_substitutions(operation.pk, serializer.validated_data['substitutions'])
|
||||
return Response(
|
||||
status=c.HTTP_200_OK,
|
||||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='update block',
|
||||
tags=['OSS'],
|
||||
request=s.UpdateBlockSerializer(),
|
||||
responses={
|
||||
c.HTTP_200_OK: s.OperationSchemaSerializer,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='update-block')
|
||||
def update_block(self, request: Request, pk) -> HttpResponse:
|
||||
''' Update Block. '''
|
||||
serializer = s.UpdateBlockSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
block: m.Block = cast(m.Block, serializer.validated_data['target'])
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
with transaction.atomic():
|
||||
if 'layout' in serializer.validated_data:
|
||||
oss.update_layout(serializer.validated_data['layout'])
|
||||
block.title = serializer.validated_data['item_data']['title']
|
||||
block.description = serializer.validated_data['item_data']['description']
|
||||
block.parent = serializer.validated_data['item_data']['parent']
|
||||
block.save(update_fields=['title', 'description', 'parent'])
|
||||
return Response(
|
||||
status=c.HTTP_200_OK,
|
||||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='create input schema for target operation',
|
||||
tags=['OSS'],
|
||||
|
@ -256,7 +371,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
)
|
||||
@action(detail=True, methods=['patch'], url_path='create-input')
|
||||
def create_input(self, request: Request, pk) -> HttpResponse:
|
||||
''' Create new input RSForm. '''
|
||||
''' Create input RSForm. '''
|
||||
serializer = s.OperationTargetSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
|
@ -333,51 +448,6 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='update operation',
|
||||
tags=['OSS'],
|
||||
request=s.OperationUpdateSerializer(),
|
||||
responses={
|
||||
c.HTTP_200_OK: s.OperationSchemaSerializer,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='update-operation')
|
||||
def update_operation(self, request: Request, pk) -> HttpResponse:
|
||||
''' Update operation arguments and parameters. '''
|
||||
serializer = s.OperationUpdateSerializer(
|
||||
data=request.data,
|
||||
context={'oss': self.get_object()}
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
with transaction.atomic():
|
||||
oss.update_layout(serializer.validated_data['layout'])
|
||||
operation.alias = serializer.validated_data['item_data']['alias']
|
||||
operation.title = serializer.validated_data['item_data']['title']
|
||||
operation.description = serializer.validated_data['item_data']['description']
|
||||
operation.save(update_fields=['alias', 'title', 'description'])
|
||||
|
||||
if operation.result is not None:
|
||||
can_edit = permissions.can_edit_item(request.user, operation.result)
|
||||
if can_edit or operation.operation_type == m.OperationType.SYNTHESIS:
|
||||
operation.result.alias = operation.alias
|
||||
operation.result.title = operation.title
|
||||
operation.result.description = operation.description
|
||||
operation.result.save()
|
||||
if 'arguments' in serializer.validated_data:
|
||||
oss.set_arguments(operation.pk, serializer.validated_data['arguments'])
|
||||
if 'substitutions' in serializer.validated_data:
|
||||
oss.set_substitutions(operation.pk, serializer.validated_data['substitutions'])
|
||||
return Response(
|
||||
status=c.HTTP_200_OK,
|
||||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='execute operation',
|
||||
tags=['OSS'],
|
||||
|
|
|
@ -137,7 +137,7 @@ class RSForm:
|
|||
return result
|
||||
|
||||
def create_cst(self, data: dict, insert_after: Optional[Constituenta] = None) -> Constituenta:
|
||||
''' Create new cst from data. '''
|
||||
''' Create constituenta from data. '''
|
||||
if insert_after is None:
|
||||
position = INSERT_LAST
|
||||
else:
|
||||
|
|
|
@ -77,7 +77,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
)
|
||||
@action(detail=True, methods=['post'], url_path='create-cst')
|
||||
def create_cst(self, request: Request, pk) -> HttpResponse:
|
||||
''' Create new constituenta. '''
|
||||
''' Create Constituenta. '''
|
||||
serializer = s.CstCreateSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
data = serializer.validated_data
|
||||
|
@ -254,7 +254,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
)
|
||||
@action(detail=True, methods=['patch'], url_path='delete-multiple-cst')
|
||||
def delete_multiple_cst(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Delete multiple constituents. '''
|
||||
''' Endpoint: Delete multiple Constituents. '''
|
||||
model = self._get_item()
|
||||
serializer = s.CstListSerializer(
|
||||
data=request.data,
|
||||
|
@ -284,7 +284,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
)
|
||||
@action(detail=True, methods=['patch'], url_path='move-cst')
|
||||
def move_cst(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Move multiple constituents. '''
|
||||
''' Endpoint: Move multiple Constituents. '''
|
||||
model = self._get_item()
|
||||
serializer = s.CstMoveSerializer(
|
||||
data=request.data,
|
||||
|
@ -334,7 +334,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
)
|
||||
@action(detail=True, methods=['patch'], url_path='restore-order')
|
||||
def restore_order(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Restore order based on types and term graph. '''
|
||||
''' Endpoint: Restore order based on types and Term graph. '''
|
||||
model = self._get_item()
|
||||
m.RSForm(model).restore_order()
|
||||
return Response(
|
||||
|
@ -449,7 +449,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
)
|
||||
@action(detail=True, methods=['post'], url_path='check-constituenta')
|
||||
def check_constituenta(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Check RSLang expression against schema context. '''
|
||||
''' Endpoint: Check RSLang expression against Schema context. '''
|
||||
serializer = s.ConstituentaCheckSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
expression = serializer.validated_data['definition_formal']
|
||||
|
@ -474,7 +474,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
)
|
||||
@action(detail=True, methods=['post'], url_path='resolve')
|
||||
def resolve(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Resolve references in text against schema terms context. '''
|
||||
''' Endpoint: Resolve references in text against Schema terms context. '''
|
||||
serializer = s.TextSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
text = serializer.validated_data['text']
|
||||
|
@ -543,7 +543,7 @@ class TrsImportView(views.APIView):
|
|||
|
||||
|
||||
@extend_schema(
|
||||
summary='create new RSForm empty or from file',
|
||||
summary='create RSForm empty or from file',
|
||||
tags=['RSForm'],
|
||||
request=LibraryItemSerializer,
|
||||
responses={
|
||||
|
|
|
@ -7,15 +7,23 @@ def constituentaNotInRSform(title: str):
|
|||
|
||||
|
||||
def constituentaNotFromOperation():
|
||||
return f'Конституента не соответствую аргументам операции'
|
||||
return 'Конституента не соответствую аргументам операции'
|
||||
|
||||
|
||||
def operationNotInOSS(title: str):
|
||||
return f'Операция не принадлежит ОСС: {title}'
|
||||
def operationNotInOSS():
|
||||
return 'Операция не принадлежит ОСС'
|
||||
|
||||
|
||||
def blockNotInOSS():
|
||||
return 'Блок не принадлежит ОСС'
|
||||
|
||||
|
||||
def parentNotInOSS():
|
||||
return f'Родительский блок не принадлежит ОСС'
|
||||
return 'Родительский блок не принадлежит ОСС'
|
||||
|
||||
|
||||
def blockSelfParent():
|
||||
return 'Попытка создания циклического вложения'
|
||||
|
||||
|
||||
def childNotInOSS():
|
||||
|
|
|
@ -9,7 +9,7 @@ export type IUserProfile = z.infer<typeof schemaUserProfile>;
|
|||
/** Represents user reference information. */
|
||||
export type IUserInfo = z.infer<typeof schemaUserInfo>;
|
||||
|
||||
/** Represents signup data, used to create new users. */
|
||||
/** Represents signup data, used to create users. */
|
||||
export type IUserSignupDTO = z.infer<typeof schemaUserSignup>;
|
||||
|
||||
/** Represents user data, intended to update user profile in persistent storage. */
|
||||
|
|
Loading…
Reference in New Issue
Block a user