R: Restructuring layout data pt1
This commit is contained in:
parent
f1faffd063
commit
3271d9244c
|
@ -9,6 +9,7 @@ from apps.library.models import (
|
|||
LibraryTemplate,
|
||||
LocationHead
|
||||
)
|
||||
from apps.oss.models import OperationSchema
|
||||
from apps.rsform.models import RSForm
|
||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||
from shared.testing_utils import response_contains
|
||||
|
@ -58,6 +59,8 @@ class TestLibraryViewset(EndpointTester):
|
|||
'read_only': True
|
||||
}
|
||||
response = self.executeCreated(data=data)
|
||||
oss = OperationSchema(LibraryItem.objects.get(pk=response.data['id']))
|
||||
self.assertEqual(oss.model.owner, self.user)
|
||||
self.assertEqual(response.data['owner'], self.user.pk)
|
||||
self.assertEqual(response.data['item_type'], data['item_type'])
|
||||
self.assertEqual(response.data['title'], data['title'])
|
||||
|
@ -65,6 +68,8 @@ class TestLibraryViewset(EndpointTester):
|
|||
self.assertEqual(response.data['access_policy'], data['access_policy'])
|
||||
self.assertEqual(response.data['visible'], data['visible'])
|
||||
self.assertEqual(response.data['read_only'], data['read_only'])
|
||||
self.assertEqual(oss.layout().data['operations'], [])
|
||||
self.assertEqual(oss.layout().data['blocks'], [])
|
||||
|
||||
self.logout()
|
||||
data = {'title': 'Title2'}
|
||||
|
|
|
@ -13,7 +13,7 @@ from rest_framework.decorators import action
|
|||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
||||
from apps.oss.models import Operation, OperationSchema, PropagationFacade
|
||||
from apps.oss.models import Layout, Operation, OperationSchema, PropagationFacade
|
||||
from apps.rsform.models import RSForm
|
||||
from apps.rsform.serializers import RSFormParseSerializer
|
||||
from apps.users.models import User
|
||||
|
@ -40,6 +40,8 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
|||
serializer.save(owner=self.request.user)
|
||||
else:
|
||||
serializer.save()
|
||||
if serializer.data.get('item_type') == m.LibraryItemType.OPERATION_SCHEMA:
|
||||
Layout.objects.create(oss=serializer.instance, data={'operations': [], 'blocks': []})
|
||||
|
||||
def perform_update(self, serializer) -> None:
|
||||
instance = serializer.save()
|
||||
|
|
|
@ -15,11 +15,24 @@ class OperationAdmin(admin.ModelAdmin):
|
|||
'alias',
|
||||
'title',
|
||||
'description',
|
||||
'position_x',
|
||||
'position_y']
|
||||
'parent']
|
||||
search_fields = ['id', 'operation_type', 'title', 'alias']
|
||||
|
||||
|
||||
class BlockAdmin(admin.ModelAdmin):
|
||||
''' Admin model: Block. '''
|
||||
ordering = ['oss']
|
||||
list_display = ['id', 'oss', 'title', 'description', 'parent']
|
||||
search_fields = ['oss']
|
||||
|
||||
|
||||
class LayoutAdmin(admin.ModelAdmin):
|
||||
''' Admin model: Layout. '''
|
||||
ordering = ['oss']
|
||||
list_display = ['id', 'oss', 'data']
|
||||
search_fields = ['oss']
|
||||
|
||||
|
||||
class ArgumentAdmin(admin.ModelAdmin):
|
||||
''' Admin model: Operation arguments. '''
|
||||
ordering = ['operation']
|
||||
|
@ -42,6 +55,8 @@ class InheritanceAdmin(admin.ModelAdmin):
|
|||
|
||||
|
||||
admin.site.register(models.Operation, OperationAdmin)
|
||||
admin.site.register(models.Block, BlockAdmin)
|
||||
admin.site.register(models.Layout, LayoutAdmin)
|
||||
admin.site.register(models.Argument, ArgumentAdmin)
|
||||
admin.site.register(models.Substitution, SynthesisSubstitutionAdmin)
|
||||
admin.site.register(models.Inheritance, InheritanceAdmin)
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
# Generated by Django 5.1.7 on 2025-03-26 16:04
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_layout(apps, schema_editor):
|
||||
LibraryItem = apps.get_model('library', 'LibraryItem')
|
||||
Operation = apps.get_model('oss', 'Operation')
|
||||
Layout = apps.get_model('oss', 'Layout')
|
||||
|
||||
for library_item in LibraryItem.objects.filter(item_type='oss'):
|
||||
layout_data = {'operations': [], 'blocks': []}
|
||||
|
||||
operations = Operation.objects.filter(oss=library_item)
|
||||
for operation in operations:
|
||||
layout_data['operations'].append({
|
||||
'id': operation.id,
|
||||
'x': operation.position_x,
|
||||
'y': operation.position_y
|
||||
})
|
||||
|
||||
Layout.objects.create(oss=library_item, data=layout_data)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('library', '0007_rename_libraryitem_comment_libraryitem_description'),
|
||||
('oss', '0010_rename_comment_operation_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Layout',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('data', models.JSONField(default=dict, verbose_name='Расположение')),
|
||||
('oss', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='layout', to='library.libraryitem', verbose_name='Схема синтеза')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Схема расположения',
|
||||
'verbose_name_plural': 'Схемы расположения',
|
||||
},
|
||||
),
|
||||
migrations.RunPython(migrate_layout),
|
||||
migrations.RemoveField(
|
||||
model_name='operation',
|
||||
name='position_x',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='operation',
|
||||
name='position_y',
|
||||
),
|
||||
|
||||
migrations.CreateModel(
|
||||
name='Block',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.TextField(blank=True, verbose_name='Название')),
|
||||
('description', models.TextField(blank=True, verbose_name='Описание')),
|
||||
('oss', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='blocks', to='library.libraryitem', verbose_name='Схема синтеза')),
|
||||
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='as_child_block', to='oss.block', verbose_name='Содержащий блок')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Блок',
|
||||
'verbose_name_plural': 'Блоки',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='parent',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='as_child_operation',
|
||||
to='oss.block',
|
||||
verbose_name='Содержащий блок'),
|
||||
),
|
||||
]
|
39
rsconcept/backend/apps/oss/models/Block.py
Normal file
39
rsconcept/backend/apps/oss/models/Block.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
''' Models: Content Block in OSS. '''
|
||||
# pylint: disable=duplicate-code
|
||||
from django.db.models import CASCADE, SET_NULL, ForeignKey, Model, TextField
|
||||
|
||||
|
||||
class Block(Model):
|
||||
''' Block of content in OSS.'''
|
||||
oss = ForeignKey(
|
||||
verbose_name='Схема синтеза',
|
||||
to='library.LibraryItem',
|
||||
on_delete=CASCADE,
|
||||
related_name='blocks'
|
||||
)
|
||||
|
||||
title = TextField(
|
||||
verbose_name='Название',
|
||||
blank=True
|
||||
)
|
||||
description = TextField(
|
||||
verbose_name='Описание',
|
||||
blank=True
|
||||
)
|
||||
|
||||
parent = ForeignKey(
|
||||
verbose_name='Содержащий блок',
|
||||
to='oss.Block',
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=SET_NULL,
|
||||
related_name='as_child_block'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
''' Model metadata. '''
|
||||
verbose_name = 'Блок'
|
||||
verbose_name_plural = 'Блоки'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'Блок {self.title}'
|
25
rsconcept/backend/apps/oss/models/Layout.py
Normal file
25
rsconcept/backend/apps/oss/models/Layout.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
''' Models: Content Block in OSS. '''
|
||||
from django.db.models import CASCADE, ForeignKey, JSONField, Model
|
||||
|
||||
|
||||
class Layout(Model):
|
||||
''' Node layout in OSS.'''
|
||||
oss = ForeignKey(
|
||||
verbose_name='Схема синтеза',
|
||||
to='library.LibraryItem',
|
||||
on_delete=CASCADE,
|
||||
related_name='layout'
|
||||
)
|
||||
|
||||
data = JSONField(
|
||||
verbose_name='Расположение',
|
||||
default=dict
|
||||
)
|
||||
|
||||
class Meta:
|
||||
''' Model metadata. '''
|
||||
verbose_name = 'Схема расположения'
|
||||
verbose_name_plural = 'Схемы расположения'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'Схема расположения {self.oss.alias}'
|
|
@ -1,9 +1,9 @@
|
|||
''' Models: Operation in OSS. '''
|
||||
# pylint: disable=duplicate-code
|
||||
from django.db.models import (
|
||||
CASCADE,
|
||||
SET_NULL,
|
||||
CharField,
|
||||
FloatField,
|
||||
ForeignKey,
|
||||
Model,
|
||||
QuerySet,
|
||||
|
@ -44,6 +44,15 @@ class Operation(Model):
|
|||
related_name='producer'
|
||||
)
|
||||
|
||||
parent = ForeignKey(
|
||||
verbose_name='Содержащий блок',
|
||||
to='oss.Block',
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=SET_NULL,
|
||||
related_name='as_child_operation'
|
||||
)
|
||||
|
||||
alias = CharField(
|
||||
verbose_name='Шифр',
|
||||
max_length=255,
|
||||
|
@ -58,15 +67,6 @@ class Operation(Model):
|
|||
blank=True
|
||||
)
|
||||
|
||||
position_x = FloatField(
|
||||
verbose_name='Положение по горизонтали',
|
||||
default=0
|
||||
)
|
||||
position_y = FloatField(
|
||||
verbose_name='Положение по вертикали',
|
||||
default=0
|
||||
)
|
||||
|
||||
class Meta:
|
||||
''' Model metadata. '''
|
||||
verbose_name = 'Операция'
|
||||
|
|
|
@ -20,6 +20,7 @@ from apps.rsform.models import (
|
|||
|
||||
from .Argument import Argument
|
||||
from .Inheritance import Inheritance
|
||||
from .Layout import Layout
|
||||
from .Operation import Operation
|
||||
from .Substitution import Substitution
|
||||
|
||||
|
@ -38,6 +39,7 @@ class OperationSchema:
|
|||
def create(**kwargs) -> 'OperationSchema':
|
||||
''' Create LibraryItem via OperationSchema. '''
|
||||
model = LibraryItem.objects.create(item_type=LibraryItemType.OPERATION_SCHEMA, **kwargs)
|
||||
Layout.objects.create(oss=model, data={'operations': [], 'blocks': []})
|
||||
return OperationSchema(model)
|
||||
|
||||
@staticmethod
|
||||
|
@ -62,6 +64,12 @@ class OperationSchema:
|
|||
''' Operation arguments. '''
|
||||
return Argument.objects.filter(operation__oss=self.model)
|
||||
|
||||
def layout(self) -> Layout:
|
||||
''' OSS layout. '''
|
||||
result = Layout.objects.filter(oss=self.model).first()
|
||||
assert result is not None
|
||||
return result
|
||||
|
||||
def substitutions(self) -> QuerySet[Substitution]:
|
||||
''' Operation substitutions. '''
|
||||
return Substitution.objects.filter(operation__oss=self.model)
|
||||
|
@ -78,15 +86,11 @@ class OperationSchema:
|
|||
location=self.model.location
|
||||
)
|
||||
|
||||
def update_positions(self, data: list[dict]) -> None:
|
||||
def update_layout(self, data: dict) -> None:
|
||||
''' Update positions. '''
|
||||
lookup = {x['id']: x for x in data}
|
||||
operations = self.operations()
|
||||
for item in operations:
|
||||
if item.pk in lookup:
|
||||
item.position_x = lookup[item.pk]['position_x']
|
||||
item.position_y = lookup[item.pk]['position_y']
|
||||
Operation.objects.bulk_update(operations, ['position_x', 'position_y'])
|
||||
layout = self.layout()
|
||||
layout.data = data
|
||||
layout.save()
|
||||
|
||||
def create_operation(self, **kwargs) -> Operation:
|
||||
''' Insert new operation. '''
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
''' Django: Models. '''
|
||||
|
||||
from .Argument import Argument
|
||||
from .Block import Block
|
||||
from .Inheritance import Inheritance
|
||||
from .Layout import Layout
|
||||
from .Operation import Operation, OperationType
|
||||
from .OperationSchema import OperationSchema
|
||||
from .PropagationFacade import PropagationFacade
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
''' REST API: Serializers. '''
|
||||
|
||||
from .basics import OperationPositionSerializer, PositionsSerializer, SubstitutionExSerializer
|
||||
from .basics import LayoutSerializer, SubstitutionExSerializer
|
||||
from .data_access import (
|
||||
ArgumentSerializer,
|
||||
OperationCreateSerializer,
|
||||
|
|
|
@ -2,17 +2,29 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
|
||||
class OperationPositionSerializer(serializers.Serializer):
|
||||
class OperationNodeSerializer(serializers.Serializer):
|
||||
''' Operation position. '''
|
||||
id = serializers.IntegerField()
|
||||
position_x = serializers.FloatField()
|
||||
position_y = serializers.FloatField()
|
||||
x = serializers.FloatField()
|
||||
y = serializers.FloatField()
|
||||
|
||||
|
||||
class PositionsSerializer(serializers.Serializer):
|
||||
''' Operations position for OperationSchema. '''
|
||||
positions = serializers.ListField(
|
||||
child=OperationPositionSerializer()
|
||||
class BlockNodeSerializer(serializers.Serializer):
|
||||
''' Block position. '''
|
||||
id = serializers.IntegerField()
|
||||
x = serializers.FloatField()
|
||||
y = serializers.FloatField()
|
||||
width = serializers.FloatField()
|
||||
height = serializers.FloatField()
|
||||
|
||||
|
||||
class LayoutSerializer(serializers.Serializer):
|
||||
''' Layout for OperationSchema. '''
|
||||
blocks = serializers.ListField(
|
||||
child=BlockNodeSerializer()
|
||||
)
|
||||
operations = serializers.ListField(
|
||||
child=OperationNodeSerializer()
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ from apps.rsform.serializers import SubstitutionSerializerBase
|
|||
from shared import messages as msg
|
||||
|
||||
from ..models import Argument, Inheritance, Operation, OperationSchema, OperationType
|
||||
from .basics import OperationPositionSerializer, SubstitutionExSerializer
|
||||
from .basics import LayoutSerializer, SubstitutionExSerializer
|
||||
|
||||
|
||||
class OperationSerializer(serializers.ModelSerializer):
|
||||
|
@ -44,17 +44,16 @@ class OperationCreateSerializer(serializers.Serializer):
|
|||
model = Operation
|
||||
fields = \
|
||||
'alias', 'operation_type', 'title', \
|
||||
'description', 'result', 'position_x', 'position_y'
|
||||
'description', 'result', 'parent'
|
||||
|
||||
layout = LayoutSerializer()
|
||||
position_x = serializers.FloatField()
|
||||
position_y = serializers.FloatField()
|
||||
|
||||
create_schema = serializers.BooleanField(default=False, required=False)
|
||||
item_data = OperationCreateData()
|
||||
create_schema = serializers.BooleanField(default=False, required=False)
|
||||
arguments = PKField(many=True, queryset=Operation.objects.all().only('pk'), required=False)
|
||||
|
||||
positions = serializers.ListField(
|
||||
child=OperationPositionSerializer(),
|
||||
default=[]
|
||||
)
|
||||
|
||||
|
||||
class OperationUpdateSerializer(serializers.Serializer):
|
||||
''' Serializer: Operation update. '''
|
||||
|
@ -65,6 +64,7 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
model = Operation
|
||||
fields = 'alias', 'title', 'description'
|
||||
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Operation.objects.all())
|
||||
item_data = OperationUpdateData()
|
||||
arguments = PKField(many=True, queryset=Operation.objects.all().only('oss_id', 'result_id'), required=False)
|
||||
|
@ -73,11 +73,6 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
required=False
|
||||
)
|
||||
|
||||
positions = serializers.ListField(
|
||||
child=OperationPositionSerializer(),
|
||||
default=[]
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
if 'arguments' not in attrs:
|
||||
return attrs
|
||||
|
@ -120,11 +115,8 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
|
||||
class OperationTargetSerializer(serializers.Serializer):
|
||||
''' Serializer: Target single operation. '''
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'result_id'))
|
||||
positions = serializers.ListField(
|
||||
child=OperationPositionSerializer(),
|
||||
default=[]
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
|
@ -138,11 +130,8 @@ class OperationTargetSerializer(serializers.Serializer):
|
|||
|
||||
class OperationDeleteSerializer(serializers.Serializer):
|
||||
''' Serializer: Delete operation. '''
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'result'))
|
||||
positions = serializers.ListField(
|
||||
child=OperationPositionSerializer(),
|
||||
default=[]
|
||||
)
|
||||
keep_constituents = serializers.BooleanField(default=False, required=False)
|
||||
delete_schema = serializers.BooleanField(default=False, required=False)
|
||||
|
||||
|
@ -158,6 +147,7 @@ class OperationDeleteSerializer(serializers.Serializer):
|
|||
|
||||
class SetOperationInputSerializer(serializers.Serializer):
|
||||
''' Serializer: Set input schema for operation. '''
|
||||
layout = LayoutSerializer()
|
||||
target = PKField(many=False, queryset=Operation.objects.all())
|
||||
input = PKField(
|
||||
many=False,
|
||||
|
@ -165,10 +155,6 @@ class SetOperationInputSerializer(serializers.Serializer):
|
|||
allow_null=True,
|
||||
default=None
|
||||
)
|
||||
positions = serializers.ListField(
|
||||
child=OperationPositionSerializer(),
|
||||
default=[]
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
|
@ -195,6 +181,7 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
|
|||
substitutions = serializers.ListField(
|
||||
child=SubstitutionExSerializer()
|
||||
)
|
||||
layout = LayoutSerializer()
|
||||
|
||||
class Meta:
|
||||
''' serializer metadata. '''
|
||||
|
@ -205,6 +192,7 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
|
|||
result = LibraryItemDetailsSerializer(instance).data
|
||||
del result['versions']
|
||||
oss = OperationSchema(instance)
|
||||
result['layout'] = oss.layout().data
|
||||
result['items'] = []
|
||||
for operation in oss.operations().order_by('pk'):
|
||||
result['items'].append(OperationSerializer(operation).data)
|
||||
|
|
|
@ -25,9 +25,8 @@ class TestOperation(TestCase):
|
|||
def test_create_default(self):
|
||||
self.assertEqual(self.operation.oss, self.oss.model)
|
||||
self.assertEqual(self.operation.operation_type, OperationType.INPUT)
|
||||
self.assertEqual(self.operation.parent, None)
|
||||
self.assertEqual(self.operation.result, None)
|
||||
self.assertEqual(self.operation.alias, 'KS1')
|
||||
self.assertEqual(self.operation.title, '')
|
||||
self.assertEqual(self.operation.description, '')
|
||||
self.assertEqual(self.operation.position_x, 0)
|
||||
self.assertEqual(self.operation.position_y, 0)
|
||||
|
|
|
@ -58,6 +58,18 @@ class TestChangeAttributes(EndpointTester):
|
|||
self.operation3.refresh_from_db()
|
||||
self.ks3 = RSForm(self.operation3.result)
|
||||
|
||||
self.layout_data = {
|
||||
'operations': [
|
||||
{'id': self.operation1.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation2.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation3.pk, 'x': 0, 'y': 0},
|
||||
],
|
||||
'blocks': []
|
||||
}
|
||||
layout = self.owned.layout()
|
||||
layout.data = self.layout_data
|
||||
layout.save()
|
||||
|
||||
@decl_endpoint('/api/library/{item}/set-owner', method='patch')
|
||||
def test_set_owner(self):
|
||||
data = {'user': self.user3.pk}
|
||||
|
@ -142,7 +154,7 @@ class TestChangeAttributes(EndpointTester):
|
|||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'positions': [],
|
||||
'layout': self.layout_data
|
||||
}
|
||||
|
||||
response = self.executeOK(data=data, item=self.owned_id)
|
||||
|
|
|
@ -57,6 +57,18 @@ class TestChangeConstituents(EndpointTester):
|
|||
self.ks3 = RSForm(self.operation3.result)
|
||||
self.assertEqual(self.ks3.constituents().count(), 4)
|
||||
|
||||
self.layout_data = {
|
||||
'operations': [
|
||||
{'id': self.operation1.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation2.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation3.pk, 'x': 0, 'y': 0},
|
||||
],
|
||||
'blocks': []
|
||||
}
|
||||
layout = self.owned.layout()
|
||||
layout.data = self.layout_data
|
||||
layout.save()
|
||||
|
||||
@decl_endpoint('/api/rsforms/{item}/details', method='get')
|
||||
def test_retrieve_inheritance(self):
|
||||
response = self.executeOK(item=self.ks3.model.pk)
|
||||
|
|
|
@ -106,6 +106,20 @@ class TestChangeOperations(EndpointTester):
|
|||
convention='KS5D4'
|
||||
)
|
||||
|
||||
self.layout_data = {
|
||||
'operations': [
|
||||
{'id': self.operation1.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation2.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation3.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation4.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation5.pk, 'x': 0, 'y': 0},
|
||||
],
|
||||
'blocks': []
|
||||
}
|
||||
layout = self.owned.layout()
|
||||
layout.data = self.layout_data
|
||||
layout.save()
|
||||
|
||||
def test_oss_setup(self):
|
||||
self.assertEqual(self.ks1.constituents().count(), 3)
|
||||
self.assertEqual(self.ks2.constituents().count(), 3)
|
||||
|
@ -117,7 +131,7 @@ class TestChangeOperations(EndpointTester):
|
|||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_input_operation(self):
|
||||
data = {
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation2.pk
|
||||
}
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
|
@ -137,7 +151,7 @@ class TestChangeOperations(EndpointTester):
|
|||
@decl_endpoint('/api/oss/{item}/set-input', method='patch')
|
||||
def test_set_input_null(self):
|
||||
data = {
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation2.pk,
|
||||
'input': None
|
||||
}
|
||||
|
@ -169,7 +183,7 @@ class TestChangeOperations(EndpointTester):
|
|||
ks6D1 = ks6.insert_new('D1', definition_formal='X1 X2', convention='KS6D1')
|
||||
|
||||
data = {
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation2.pk,
|
||||
'input': ks6.model.pk
|
||||
}
|
||||
|
@ -211,7 +225,7 @@ class TestChangeOperations(EndpointTester):
|
|||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_operation_and_constituents(self):
|
||||
data = {
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation1.pk,
|
||||
'keep_constituents': False,
|
||||
'delete_schema': True
|
||||
|
@ -232,7 +246,7 @@ class TestChangeOperations(EndpointTester):
|
|||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_operation_keep_constituents(self):
|
||||
data = {
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation1.pk,
|
||||
'keep_constituents': True,
|
||||
'delete_schema': True
|
||||
|
@ -253,7 +267,7 @@ class TestChangeOperations(EndpointTester):
|
|||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_operation_keep_schema(self):
|
||||
data = {
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation1.pk,
|
||||
'keep_constituents': True,
|
||||
'delete_schema': False
|
||||
|
@ -283,7 +297,7 @@ class TestChangeOperations(EndpointTester):
|
|||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'substitutions': [
|
||||
{
|
||||
'original': self.ks1X1.pk,
|
||||
|
@ -317,7 +331,7 @@ class TestChangeOperations(EndpointTester):
|
|||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'positions': [],
|
||||
'layout': self.layout_data,
|
||||
'arguments': [self.operation1.pk],
|
||||
}
|
||||
|
||||
|
@ -356,7 +370,7 @@ class TestChangeOperations(EndpointTester):
|
|||
|
||||
data = {
|
||||
'target': self.operation4.pk,
|
||||
'positions': []
|
||||
'layout': self.layout_data
|
||||
}
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
self.operation4.refresh_from_db()
|
||||
|
|
|
@ -106,6 +106,20 @@ class TestChangeSubstitutions(EndpointTester):
|
|||
convention='KS5D4'
|
||||
)
|
||||
|
||||
self.layout_data = {
|
||||
'operations': [
|
||||
{'id': self.operation1.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation2.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation3.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation4.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation5.pk, 'x': 0, 'y': 0},
|
||||
],
|
||||
'blocks': []
|
||||
}
|
||||
layout = self.owned.layout()
|
||||
layout.data = self.layout_data
|
||||
layout.save()
|
||||
|
||||
|
||||
def test_oss_setup(self):
|
||||
self.assertEqual(self.ks1.constituents().count(), 3)
|
||||
|
@ -139,10 +153,12 @@ class TestChangeSubstitutions(EndpointTester):
|
|||
|
||||
@decl_endpoint('/api/rsforms/{schema}/substitute', method='patch')
|
||||
def test_substitute_substitution(self):
|
||||
data = {'substitutions': [{
|
||||
'original': self.ks2S1.pk,
|
||||
'substitution': self.ks2X1.pk
|
||||
}]}
|
||||
data = {
|
||||
'substitutions': [{
|
||||
'original': self.ks2S1.pk,
|
||||
'substitution': self.ks2X1.pk
|
||||
}]
|
||||
}
|
||||
self.executeOK(data=data, schema=self.ks2.model.pk)
|
||||
self.ks4D1.refresh_from_db()
|
||||
self.ks4D2.refresh_from_db()
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
''' Tests for REST API. '''
|
||||
from .t_operations import *
|
||||
from .t_oss import *
|
||||
|
|
447
rsconcept/backend/apps/oss/tests/s_views/t_operations.py
Normal file
447
rsconcept/backend/apps/oss/tests/s_views/t_operations.py
Normal file
|
@ -0,0 +1,447 @@
|
|||
''' Testing API: Operation Schema. '''
|
||||
from apps.library.models import AccessPolicy, Editor, LibraryItem, LibraryItemType
|
||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
||||
from apps.rsform.models import Constituenta, RSForm
|
||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||
|
||||
|
||||
class TestOssOperations(EndpointTester):
|
||||
''' Testing OSS view - operations. '''
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
||||
self.owned_id = self.owned.model.pk
|
||||
self.unowned = OperationSchema.create(title='Test2', alias='T2')
|
||||
self.unowned_id = self.unowned.model.pk
|
||||
self.private = OperationSchema.create(title='Test2', alias='T2', access_policy=AccessPolicy.PRIVATE)
|
||||
self.private_id = self.private.model.pk
|
||||
self.invalid_id = self.private.model.pk + 1337
|
||||
|
||||
def populateData(self):
|
||||
self.ks1 = RSForm.create(
|
||||
alias='KS1',
|
||||
title='Test1',
|
||||
owner=self.user
|
||||
)
|
||||
self.ks1X1 = self.ks1.insert_new(
|
||||
'X1',
|
||||
term_raw='X1_1',
|
||||
term_resolved='X1_1'
|
||||
)
|
||||
self.ks2 = RSForm.create(
|
||||
alias='KS2',
|
||||
title='Test2',
|
||||
owner=self.user
|
||||
)
|
||||
self.ks2X1 = self.ks2.insert_new(
|
||||
'X2',
|
||||
term_raw='X1_2',
|
||||
term_resolved='X1_2'
|
||||
)
|
||||
|
||||
self.operation1 = self.owned.create_operation(
|
||||
alias='1',
|
||||
operation_type=OperationType.INPUT,
|
||||
result=self.ks1.model
|
||||
)
|
||||
self.operation2 = self.owned.create_operation(
|
||||
alias='2',
|
||||
operation_type=OperationType.INPUT,
|
||||
result=self.ks2.model
|
||||
)
|
||||
self.operation3 = self.owned.create_operation(
|
||||
alias='3',
|
||||
operation_type=OperationType.SYNTHESIS
|
||||
)
|
||||
self.layout_data = {
|
||||
'operations': [
|
||||
{'id': self.operation1.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation2.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation3.pk, 'x': 0, 'y': 0},
|
||||
],
|
||||
'blocks': []
|
||||
}
|
||||
layout = self.owned.layout()
|
||||
layout.data = self.layout_data
|
||||
layout.save()
|
||||
|
||||
self.owned.set_arguments(self.operation3.pk, [self.operation1, self.operation2])
|
||||
self.owned.set_substitutions(self.operation3.pk, [{
|
||||
'original': self.ks1X1,
|
||||
'substitution': self.ks2X1
|
||||
}])
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test3',
|
||||
'title': 'Test title',
|
||||
'description': 'Тест кириллицы',
|
||||
|
||||
},
|
||||
'layout': self.layout_data,
|
||||
'position_x': 1,
|
||||
'position_y': 1
|
||||
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['item_data']['operation_type'] = 'invalid'
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['item_data']['operation_type'] = OperationType.INPUT
|
||||
self.executeNotFound(data=data, item=self.invalid_id)
|
||||
|
||||
response = self.executeCreated(data=data, item=self.owned_id)
|
||||
self.assertEqual(len(response.data['oss']['items']), 4)
|
||||
new_operation = response.data['new_operation']
|
||||
layout = response.data['oss']['layout']
|
||||
item = [item for item in layout['operations'] if item['id'] == new_operation['id']][0]
|
||||
self.assertEqual(new_operation['alias'], data['item_data']['alias'])
|
||||
self.assertEqual(new_operation['operation_type'], data['item_data']['operation_type'])
|
||||
self.assertEqual(new_operation['title'], data['item_data']['title'])
|
||||
self.assertEqual(new_operation['description'], data['item_data']['description'])
|
||||
self.assertEqual(new_operation['result'], None)
|
||||
self.assertEqual(new_operation['parent'], None)
|
||||
self.assertEqual(item['x'], data['position_x'])
|
||||
self.assertEqual(item['y'], data['position_y'])
|
||||
self.operation1.refresh_from_db()
|
||||
|
||||
self.executeForbidden(data=data, item=self.unowned_id)
|
||||
self.toggle_admin(True)
|
||||
self.executeCreated(data=data, item=self.unowned_id)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_arguments(self):
|
||||
self.populateData()
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
'operation_type': OperationType.SYNTHESIS
|
||||
},
|
||||
'layout': self.layout_data,
|
||||
'position_x': 1,
|
||||
'position_y': 1,
|
||||
'arguments': [self.operation1.pk, self.operation3.pk]
|
||||
}
|
||||
response = self.executeCreated(data=data, item=self.owned_id)
|
||||
self.owned.refresh_from_db()
|
||||
new_operation = response.data['new_operation']
|
||||
arguments = self.owned.arguments()
|
||||
self.assertTrue(arguments.filter(operation__id=new_operation['id'], argument=self.operation1))
|
||||
self.assertTrue(arguments.filter(operation__id=new_operation['id'], argument=self.operation3))
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_result(self):
|
||||
self.populateData()
|
||||
|
||||
self.operation1.result = None
|
||||
self.operation1.save()
|
||||
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
'operation_type': OperationType.INPUT,
|
||||
'result': self.ks1.model.pk
|
||||
},
|
||||
'layout': self.layout_data,
|
||||
'position_x': 1,
|
||||
'position_y': 1
|
||||
}
|
||||
response = self.executeCreated(data=data, item=self.owned_id)
|
||||
self.owned.refresh_from_db()
|
||||
new_operation = response.data['new_operation']
|
||||
self.assertEqual(new_operation['result'], self.ks1.model.pk)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_schema(self):
|
||||
self.populateData()
|
||||
Editor.add(self.owned.model.pk, self.user2.pk)
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
'title': 'Test title',
|
||||
'description': 'Comment',
|
||||
'operation_type': OperationType.INPUT,
|
||||
'result': self.ks1.model.pk
|
||||
},
|
||||
'create_schema': True,
|
||||
'layout': self.layout_data,
|
||||
'position_x': 1,
|
||||
'position_y': 1
|
||||
}
|
||||
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']
|
||||
schema = LibraryItem.objects.get(pk=new_operation['result'])
|
||||
self.assertEqual(schema.alias, data['item_data']['alias'])
|
||||
self.assertEqual(schema.title, data['item_data']['title'])
|
||||
self.assertEqual(schema.description, data['item_data']['description'])
|
||||
self.assertEqual(schema.visible, False)
|
||||
self.assertEqual(schema.access_policy, self.owned.model.access_policy)
|
||||
self.assertEqual(schema.location, self.owned.model.location)
|
||||
self.assertIn(self.user2, schema.getQ_editors())
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_operation(self):
|
||||
self.executeNotFound(item=self.invalid_id)
|
||||
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
layout = response.data['layout']
|
||||
items = [item for item in layout['operations'] if item['id'] == data['target']]
|
||||
self.assertEqual(len(response.data['items']), 2)
|
||||
self.assertEqual(len(items), 0)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-input', method='patch')
|
||||
def test_create_input(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
self.executeBadData(data=data, item=self.owned_id)
|
||||
|
||||
self.operation1.result = None
|
||||
self.operation1.description = 'TestComment'
|
||||
self.operation1.title = 'TestTitle'
|
||||
self.operation1.save()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
|
||||
new_schema = response.data['new_schema']
|
||||
self.assertEqual(new_schema['id'], self.operation1.result.pk)
|
||||
self.assertEqual(new_schema['alias'], self.operation1.alias)
|
||||
self.assertEqual(new_schema['title'], self.operation1.title)
|
||||
self.assertEqual(new_schema['description'], self.operation1.description)
|
||||
|
||||
data['target'] = self.operation3.pk
|
||||
self.executeBadData(data=data)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/set-input', method='patch')
|
||||
def test_set_input_null(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
data['input'] = None
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.result, None)
|
||||
|
||||
data['input'] = self.ks1.model.pk
|
||||
self.ks1.model.alias = 'Test42'
|
||||
self.ks1.model.title = 'Test421'
|
||||
self.ks1.model.description = 'TestComment42'
|
||||
self.ks1.save()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.result, self.ks1.model)
|
||||
self.assertEqual(self.operation1.alias, self.ks1.model.alias)
|
||||
self.assertEqual(self.operation1.title, self.ks1.model.title)
|
||||
self.assertEqual(self.operation1.description, self.ks1.model.description)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/set-input', method='patch')
|
||||
def test_set_input_change_schema(self):
|
||||
self.populateData()
|
||||
self.operation2.result = None
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation1.pk,
|
||||
'input': self.ks2.model.pk
|
||||
}
|
||||
self.executeBadData(data=data, item=self.owned_id)
|
||||
|
||||
self.ks2.model.visible = False
|
||||
self.ks2.model.save(update_fields=['visible'])
|
||||
data = {
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation2.pk,
|
||||
'input': None
|
||||
}
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
self.operation2.refresh_from_db()
|
||||
self.ks2.model.refresh_from_db()
|
||||
self.assertEqual(self.operation2.result, None)
|
||||
self.assertEqual(self.ks2.model.visible, True)
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data,
|
||||
'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):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
ks3 = RSForm.create(alias='KS3', title='Test3', owner=self.user)
|
||||
ks3x1 = ks3.insert_new('X1', term_resolved='X1_1')
|
||||
|
||||
data = {
|
||||
'target': self.operation3.pk,
|
||||
'item_data': {
|
||||
'alias': 'Test3 mod',
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'layout': self.layout_data,
|
||||
'arguments': [self.operation2.pk, self.operation1.pk],
|
||||
'substitutions': [
|
||||
{
|
||||
'original': self.ks1X1.pk,
|
||||
'substitution': ks3x1.pk
|
||||
}
|
||||
]
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['substitutions'][0]['substitution'] = self.ks2X1.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation3.refresh_from_db()
|
||||
self.assertEqual(self.operation3.alias, data['item_data']['alias'])
|
||||
self.assertEqual(self.operation3.title, data['item_data']['title'])
|
||||
self.assertEqual(self.operation3.description, data['item_data']['description'])
|
||||
args = self.operation3.getQ_arguments().order_by('order')
|
||||
self.assertEqual(args[0].argument.pk, data['arguments'][0])
|
||||
self.assertEqual(args[0].order, 0)
|
||||
self.assertEqual(args[1].argument.pk, data['arguments'][1])
|
||||
self.assertEqual(args[1].order, 1)
|
||||
sub = self.operation3.getQ_substitutions()[0]
|
||||
self.assertEqual(sub.original.pk, data['substitutions'][0]['original'])
|
||||
self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution'])
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
|
||||
def test_update_operation_sync(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'target': self.operation1.pk,
|
||||
'item_data': {
|
||||
'alias': 'Test3 mod',
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'layout': self.layout_data
|
||||
}
|
||||
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.alias, data['item_data']['alias'])
|
||||
self.assertEqual(self.operation1.title, data['item_data']['title'])
|
||||
self.assertEqual(self.operation1.description, data['item_data']['description'])
|
||||
self.assertEqual(self.operation1.result.alias, data['item_data']['alias'])
|
||||
self.assertEqual(self.operation1.result.title, data['item_data']['title'])
|
||||
self.assertEqual(self.operation1.result.description, data['item_data']['description'])
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
|
||||
def test_update_operation_invalid_substitution(self):
|
||||
self.populateData()
|
||||
|
||||
self.ks1X2 = self.ks1.insert_new('X2')
|
||||
|
||||
data = {
|
||||
'target': self.operation3.pk,
|
||||
'item_data': {
|
||||
'alias': 'Test3 mod',
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'layout': self.layout_data,
|
||||
'arguments': [self.operation1.pk, self.operation2.pk],
|
||||
'substitutions': [
|
||||
{
|
||||
'original': self.ks1X1.pk,
|
||||
'substitution': self.ks2X1.pk
|
||||
},
|
||||
{
|
||||
'original': self.ks2X1.pk,
|
||||
'substitution': self.ks1X2.pk
|
||||
}
|
||||
]
|
||||
}
|
||||
self.executeBadData(data=data, item=self.owned_id)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/execute-operation', method='post')
|
||||
def test_execute_operation(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'layout': self.layout_data,
|
||||
'target': self.operation1.pk
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation3.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
self.executeOK(data=data)
|
||||
self.operation3.refresh_from_db()
|
||||
schema = self.operation3.result
|
||||
self.assertEqual(schema.alias, self.operation3.alias)
|
||||
self.assertEqual(schema.description, self.operation3.description)
|
||||
self.assertEqual(schema.title, self.operation3.title)
|
||||
self.assertEqual(schema.visible, False)
|
||||
items = list(RSForm(schema).constituents())
|
||||
self.assertEqual(len(items), 1)
|
||||
self.assertEqual(items[0].alias, 'X1')
|
||||
self.assertEqual(items[0].term_resolved, self.ks2X1.term_resolved)
|
|
@ -1,6 +1,6 @@
|
|||
''' Testing API: Operation Schema. '''
|
||||
from apps.library.models import AccessPolicy, Editor, LibraryItem, LibraryItemType
|
||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
||||
from apps.library.models import AccessPolicy, LibraryItemType
|
||||
from apps.oss.models import OperationSchema, OperationType
|
||||
from apps.rsform.models import Constituenta, RSForm
|
||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||
|
||||
|
@ -54,6 +54,14 @@ class TestOssViewset(EndpointTester):
|
|||
alias='3',
|
||||
operation_type=OperationType.SYNTHESIS
|
||||
)
|
||||
layout = self.owned.layout()
|
||||
layout.data = {'operations': [
|
||||
{'id': self.operation1.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation2.pk, 'x': 0, 'y': 0},
|
||||
{'id': self.operation3.pk, 'x': 0, 'y': 0},
|
||||
], 'blocks': []}
|
||||
layout.save()
|
||||
|
||||
self.owned.set_arguments(self.operation3.pk, [self.operation1, self.operation2])
|
||||
self.owned.set_substitutions(self.operation3.pk, [{
|
||||
'original': self.ks1X1,
|
||||
|
@ -95,6 +103,12 @@ class TestOssViewset(EndpointTester):
|
|||
self.assertEqual(arguments[1]['operation'], self.operation3.pk)
|
||||
self.assertEqual(arguments[1]['argument'], self.operation2.pk)
|
||||
|
||||
layout = response.data['layout']
|
||||
self.assertEqual(layout['blocks'], [])
|
||||
self.assertEqual(layout['operations'][0], {'id': self.operation1.pk, 'x': 0, 'y': 0})
|
||||
self.assertEqual(layout['operations'][1], {'id': self.operation2.pk, 'x': 0, 'y': 0})
|
||||
self.assertEqual(layout['operations'][2], {'id': self.operation3.pk, 'x': 0, 'y': 0})
|
||||
|
||||
self.executeOK(item=self.unowned_id)
|
||||
self.executeForbidden(item=self.private_id)
|
||||
|
||||
|
@ -103,401 +117,30 @@ class TestOssViewset(EndpointTester):
|
|||
self.executeOK(item=self.unowned_id)
|
||||
self.executeForbidden(item=self.private_id)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-positions', method='patch')
|
||||
def test_update_positions(self):
|
||||
@decl_endpoint('/api/oss/{item}/update-layout', method='patch')
|
||||
def test_update_layout(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {'positions': []}
|
||||
data = {'operations': [], 'blocks': []}
|
||||
self.executeOK(data=data)
|
||||
|
||||
data = {'positions': [
|
||||
{'id': self.operation1.pk, 'position_x': 42.1, 'position_y': 1337},
|
||||
{'id': self.operation2.pk, 'position_x': 36.1, 'position_y': 1437},
|
||||
{'id': self.invalid_id, 'position_x': 31, 'position_y': 12},
|
||||
]}
|
||||
data = {'operations': [
|
||||
{'id': self.operation1.pk, 'x': 42.1, 'y': 1337},
|
||||
{'id': self.operation2.pk, 'x': 36.1, 'y': 1437},
|
||||
{'id': self.operation3.pk, 'x': 36.1, 'y': 1435}
|
||||
], 'blocks': []}
|
||||
self.toggle_admin(True)
|
||||
self.executeOK(data=data, item=self.unowned_id)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertNotEqual(self.operation1.position_x, data['positions'][0]['position_x'])
|
||||
self.assertNotEqual(self.operation1.position_y, data['positions'][0]['position_y'])
|
||||
|
||||
self.toggle_admin(False)
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
self.operation1.refresh_from_db()
|
||||
self.operation2.refresh_from_db()
|
||||
self.assertEqual(self.operation1.position_x, data['positions'][0]['position_x'])
|
||||
self.assertEqual(self.operation1.position_y, data['positions'][0]['position_y'])
|
||||
self.assertEqual(self.operation2.position_x, data['positions'][1]['position_x'])
|
||||
self.assertEqual(self.operation2.position_y, data['positions'][1]['position_y'])
|
||||
self.owned.refresh_from_db()
|
||||
self.assertEqual(self.owned.layout().data, data)
|
||||
|
||||
self.executeForbidden(data=data, item=self.unowned_id)
|
||||
self.executeForbidden(data=data, item=self.private_id)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test3',
|
||||
'title': 'Test title',
|
||||
'description': 'Тест кириллицы',
|
||||
'position_x': 1,
|
||||
'position_y': 1,
|
||||
},
|
||||
'positions': [
|
||||
{'id': self.operation1.pk, 'position_x': 42.1, 'position_y': 1337}
|
||||
]
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['item_data']['operation_type'] = 'invalid'
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['item_data']['operation_type'] = OperationType.INPUT
|
||||
self.executeNotFound(data=data, item=self.invalid_id)
|
||||
|
||||
response = self.executeCreated(data=data, item=self.owned_id)
|
||||
self.assertEqual(len(response.data['oss']['items']), 4)
|
||||
new_operation = response.data['new_operation']
|
||||
self.assertEqual(new_operation['alias'], data['item_data']['alias'])
|
||||
self.assertEqual(new_operation['operation_type'], data['item_data']['operation_type'])
|
||||
self.assertEqual(new_operation['title'], data['item_data']['title'])
|
||||
self.assertEqual(new_operation['description'], data['item_data']['description'])
|
||||
self.assertEqual(new_operation['position_x'], data['item_data']['position_x'])
|
||||
self.assertEqual(new_operation['position_y'], data['item_data']['position_y'])
|
||||
self.assertEqual(new_operation['result'], None)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.position_x, data['positions'][0]['position_x'])
|
||||
self.assertEqual(self.operation1.position_y, data['positions'][0]['position_y'])
|
||||
|
||||
self.executeForbidden(data=data, item=self.unowned_id)
|
||||
self.toggle_admin(True)
|
||||
self.executeCreated(data=data, item=self.unowned_id)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_arguments(self):
|
||||
self.populateData()
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
'operation_type': OperationType.SYNTHESIS
|
||||
},
|
||||
'positions': [],
|
||||
'arguments': [self.operation1.pk, self.operation3.pk]
|
||||
}
|
||||
response = self.executeCreated(data=data, item=self.owned_id)
|
||||
self.owned.refresh_from_db()
|
||||
new_operation = response.data['new_operation']
|
||||
arguments = self.owned.arguments()
|
||||
self.assertTrue(arguments.filter(operation__id=new_operation['id'], argument=self.operation1))
|
||||
self.assertTrue(arguments.filter(operation__id=new_operation['id'], argument=self.operation3))
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_result(self):
|
||||
self.populateData()
|
||||
|
||||
self.operation1.result = None
|
||||
self.operation1.save()
|
||||
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
'operation_type': OperationType.INPUT,
|
||||
'result': self.ks1.model.pk
|
||||
},
|
||||
'positions': [],
|
||||
}
|
||||
response = self.executeCreated(data=data, item=self.owned_id)
|
||||
self.owned.refresh_from_db()
|
||||
new_operation = response.data['new_operation']
|
||||
self.assertEqual(new_operation['result'], self.ks1.model.pk)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_schema(self):
|
||||
self.populateData()
|
||||
Editor.add(self.owned.model.pk, self.user2.pk)
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
'title': 'Test title',
|
||||
'description': 'Comment',
|
||||
'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']
|
||||
schema = LibraryItem.objects.get(pk=new_operation['result'])
|
||||
self.assertEqual(schema.alias, data['item_data']['alias'])
|
||||
self.assertEqual(schema.title, data['item_data']['title'])
|
||||
self.assertEqual(schema.description, data['item_data']['description'])
|
||||
self.assertEqual(schema.visible, False)
|
||||
self.assertEqual(schema.access_policy, self.owned.model.access_policy)
|
||||
self.assertEqual(schema.location, self.owned.model.location)
|
||||
self.assertIn(self.user2, schema.getQ_editors())
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||
def test_delete_operation(self):
|
||||
self.executeNotFound(item=self.invalid_id)
|
||||
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'positions': []
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.assertEqual(len(response.data['items']), 2)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-input', method='patch')
|
||||
def test_create_input(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'positions': []
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
self.executeBadData(data=data, item=self.owned_id)
|
||||
|
||||
self.operation1.result = None
|
||||
self.operation1.description = 'TestComment'
|
||||
self.operation1.title = 'TestTitle'
|
||||
self.operation1.save()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
|
||||
new_schema = response.data['new_schema']
|
||||
self.assertEqual(new_schema['id'], self.operation1.result.pk)
|
||||
self.assertEqual(new_schema['alias'], self.operation1.alias)
|
||||
self.assertEqual(new_schema['title'], self.operation1.title)
|
||||
self.assertEqual(new_schema['description'], self.operation1.description)
|
||||
|
||||
data['target'] = self.operation3.pk
|
||||
self.executeBadData(data=data)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/set-input', method='patch')
|
||||
def test_set_input_null(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'positions': []
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation1.pk
|
||||
data['input'] = None
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.result, None)
|
||||
|
||||
data['input'] = self.ks1.model.pk
|
||||
self.ks1.model.alias = 'Test42'
|
||||
self.ks1.model.title = 'Test421'
|
||||
self.ks1.model.description = 'TestComment42'
|
||||
self.ks1.save()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.result, self.ks1.model)
|
||||
self.assertEqual(self.operation1.alias, self.ks1.model.alias)
|
||||
self.assertEqual(self.operation1.title, self.ks1.model.title)
|
||||
self.assertEqual(self.operation1.description, self.ks1.model.description)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/set-input', method='patch')
|
||||
def test_set_input_change_schema(self):
|
||||
self.populateData()
|
||||
self.operation2.result = None
|
||||
|
||||
data = {
|
||||
'positions': [],
|
||||
'target': self.operation1.pk,
|
||||
'input': self.ks2.model.pk
|
||||
}
|
||||
self.executeBadData(data=data, item=self.owned_id)
|
||||
|
||||
self.ks2.model.visible = False
|
||||
self.ks2.model.save(update_fields=['visible'])
|
||||
data = {
|
||||
'positions': [],
|
||||
'target': self.operation2.pk,
|
||||
'input': None
|
||||
}
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
self.operation2.refresh_from_db()
|
||||
self.ks2.model.refresh_from_db()
|
||||
self.assertEqual(self.operation2.result, None)
|
||||
self.assertEqual(self.ks2.model.visible, True)
|
||||
|
||||
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):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
ks3 = RSForm.create(alias='KS3', title='Test3', owner=self.user)
|
||||
ks3x1 = ks3.insert_new('X1', term_resolved='X1_1')
|
||||
|
||||
data = {
|
||||
'target': self.operation3.pk,
|
||||
'item_data': {
|
||||
'alias': 'Test3 mod',
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'positions': [],
|
||||
'arguments': [self.operation2.pk, self.operation1.pk],
|
||||
'substitutions': [
|
||||
{
|
||||
'original': self.ks1X1.pk,
|
||||
'substitution': ks3x1.pk
|
||||
}
|
||||
]
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['substitutions'][0]['substitution'] = self.ks2X1.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
response = self.executeOK(data=data)
|
||||
self.operation3.refresh_from_db()
|
||||
self.assertEqual(self.operation3.alias, data['item_data']['alias'])
|
||||
self.assertEqual(self.operation3.title, data['item_data']['title'])
|
||||
self.assertEqual(self.operation3.description, data['item_data']['description'])
|
||||
args = self.operation3.getQ_arguments().order_by('order')
|
||||
self.assertEqual(args[0].argument.pk, data['arguments'][0])
|
||||
self.assertEqual(args[0].order, 0)
|
||||
self.assertEqual(args[1].argument.pk, data['arguments'][1])
|
||||
self.assertEqual(args[1].order, 1)
|
||||
sub = self.operation3.getQ_substitutions()[0]
|
||||
self.assertEqual(sub.original.pk, data['substitutions'][0]['original'])
|
||||
self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution'])
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
|
||||
def test_update_operation_sync(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'target': self.operation1.pk,
|
||||
'item_data': {
|
||||
'alias': 'Test3 mod',
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'positions': [],
|
||||
}
|
||||
|
||||
response = self.executeOK(data=data)
|
||||
self.operation1.refresh_from_db()
|
||||
self.assertEqual(self.operation1.alias, data['item_data']['alias'])
|
||||
self.assertEqual(self.operation1.title, data['item_data']['title'])
|
||||
self.assertEqual(self.operation1.description, data['item_data']['description'])
|
||||
self.assertEqual(self.operation1.result.alias, data['item_data']['alias'])
|
||||
self.assertEqual(self.operation1.result.title, data['item_data']['title'])
|
||||
self.assertEqual(self.operation1.result.description, data['item_data']['description'])
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
|
||||
def test_update_operation_invalid_substitution(self):
|
||||
self.populateData()
|
||||
|
||||
self.ks1X2 = self.ks1.insert_new('X2')
|
||||
|
||||
data = {
|
||||
'target': self.operation3.pk,
|
||||
'item_data': {
|
||||
'alias': 'Test3 mod',
|
||||
'title': 'Test title mod',
|
||||
'description': 'Comment mod'
|
||||
},
|
||||
'positions': [],
|
||||
'arguments': [self.operation1.pk, self.operation2.pk],
|
||||
'substitutions': [
|
||||
{
|
||||
'original': self.ks1X1.pk,
|
||||
'substitution': self.ks2X1.pk
|
||||
},
|
||||
{
|
||||
'original': self.ks2X1.pk,
|
||||
'substitution': self.ks1X2.pk
|
||||
}
|
||||
]
|
||||
}
|
||||
self.executeBadData(data=data, item=self.owned_id)
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/execute-operation', method='post')
|
||||
def test_execute_operation(self):
|
||||
self.populateData()
|
||||
self.executeBadData(item=self.owned_id)
|
||||
|
||||
data = {
|
||||
'positions': [],
|
||||
'target': self.operation1.pk
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data['target'] = self.operation3.pk
|
||||
self.toggle_admin(True)
|
||||
self.executeBadData(data=data, item=self.unowned_id)
|
||||
self.logout()
|
||||
self.executeForbidden(data=data, item=self.owned_id)
|
||||
|
||||
self.login()
|
||||
self.executeOK(data=data)
|
||||
self.operation3.refresh_from_db()
|
||||
schema = self.operation3.result
|
||||
self.assertEqual(schema.alias, self.operation3.alias)
|
||||
self.assertEqual(schema.description, self.operation3.description)
|
||||
self.assertEqual(schema.title, self.operation3.title)
|
||||
self.assertEqual(schema.visible, False)
|
||||
items = list(RSForm(schema).constituents())
|
||||
self.assertEqual(len(items), 1)
|
||||
self.assertEqual(items[0].alias, 'X1')
|
||||
self.assertEqual(items[0].term_resolved, self.ks2X1.term_resolved)
|
||||
|
||||
@decl_endpoint('/api/oss/get-predecessor', method='post')
|
||||
def test_get_predecessor(self):
|
||||
self.populateData()
|
||||
|
|
|
@ -36,9 +36,9 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
def get_permissions(self):
|
||||
''' Determine permission class. '''
|
||||
if self.action in [
|
||||
'update_layout',
|
||||
'create_operation',
|
||||
'delete_operation',
|
||||
'update_positions',
|
||||
'create_input',
|
||||
'set_input',
|
||||
'update_operation',
|
||||
|
@ -73,21 +73,21 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='update positions',
|
||||
summary='update layout',
|
||||
tags=['OSS'],
|
||||
request=s.PositionsSerializer,
|
||||
request=s.LayoutSerializer,
|
||||
responses={
|
||||
c.HTTP_200_OK: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='update-positions')
|
||||
def update_positions(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Update operations positions. '''
|
||||
serializer = s.PositionsSerializer(data=request.data)
|
||||
@action(detail=True, methods=['patch'], url_path='update-layout')
|
||||
def update_layout(self, request: Request, pk) -> HttpResponse:
|
||||
''' Endpoint: Update schema layout. '''
|
||||
serializer = s.LayoutSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
m.OperationSchema(self.get_object()).update_positions(serializer.validated_data['positions'])
|
||||
m.OperationSchema(self.get_object()).update_layout(serializer.validated_data)
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
@extend_schema(
|
||||
|
@ -108,9 +108,16 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
layout = serializer.validated_data['layout']
|
||||
with transaction.atomic():
|
||||
oss.update_positions(serializer.validated_data['positions'])
|
||||
new_operation = oss.create_operation(**serializer.validated_data['item_data'])
|
||||
layout['operations'].append({
|
||||
'id': new_operation.pk,
|
||||
'x': serializer.validated_data['position_x'],
|
||||
'y': serializer.validated_data['position_y']
|
||||
})
|
||||
oss.update_layout(layout)
|
||||
|
||||
schema = new_operation.result
|
||||
if schema is not None:
|
||||
connected_operations = \
|
||||
|
@ -164,9 +171,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
oss = m.OperationSchema(self.get_object())
|
||||
operation = cast(m.Operation, serializer.validated_data['target'])
|
||||
old_schema = operation.result
|
||||
layout = serializer.validated_data['layout']
|
||||
layout['operations'] = [x for x in layout['operations'] if x['id'] != operation.pk]
|
||||
with transaction.atomic():
|
||||
oss.update_positions(serializer.validated_data['positions'])
|
||||
oss.delete_operation(operation.pk, serializer.validated_data['keep_constituents'])
|
||||
oss.update_layout(layout)
|
||||
if old_schema is not None:
|
||||
if serializer.validated_data['delete_schema']:
|
||||
m.PropagationFacade.before_delete_schema(old_schema)
|
||||
|
@ -211,7 +220,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
with transaction.atomic():
|
||||
oss.update_positions(serializer.validated_data['positions'])
|
||||
oss.update_layout(serializer.validated_data['layout'])
|
||||
schema = oss.create_input(operation)
|
||||
|
||||
return Response(
|
||||
|
@ -262,7 +271,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
if old_schema.is_synced(oss.model):
|
||||
old_schema.visible = True
|
||||
old_schema.save(update_fields=['visible'])
|
||||
oss.update_positions(serializer.validated_data['positions'])
|
||||
oss.update_layout(serializer.validated_data['layout'])
|
||||
oss.set_input(target_operation.pk, schema)
|
||||
return Response(
|
||||
status=c.HTTP_200_OK,
|
||||
|
@ -292,7 +301,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
with transaction.atomic():
|
||||
oss.update_positions(serializer.validated_data['positions'])
|
||||
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']
|
||||
|
@ -346,7 +355,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
|
||||
oss = m.OperationSchema(self.get_object())
|
||||
with transaction.atomic():
|
||||
oss.update_positions(serializer.validated_data['positions'])
|
||||
oss.update_layout(serializer.validated_data['layout'])
|
||||
oss.execute_operation(operation)
|
||||
|
||||
return Response(
|
||||
|
|
|
@ -39,7 +39,7 @@ export const ossApi = {
|
|||
});
|
||||
},
|
||||
|
||||
updatePositions: ({
|
||||
updateLayout: ({
|
||||
itemID,
|
||||
positions,
|
||||
isSilent
|
||||
|
@ -49,7 +49,7 @@ export const ossApi = {
|
|||
isSilent?: boolean;
|
||||
}) =>
|
||||
axiosPatch({
|
||||
endpoint: `/api/oss/${itemID}/update-positions`,
|
||||
endpoint: `/api/oss/${itemID}/update-layout`,
|
||||
request: {
|
||||
data: { positions: positions },
|
||||
successMessage: isSilent ? undefined : infoMsg.changesSaved
|
||||
|
|
|
@ -7,17 +7,17 @@ import { KEYS } from '@/backend/configuration';
|
|||
import { ossApi } from './api';
|
||||
import { type IOperationPosition } from './types';
|
||||
|
||||
export const useUpdatePositions = () => {
|
||||
export const useUpdateLayout = () => {
|
||||
const client = useQueryClient();
|
||||
const { updateTimestamp } = useUpdateTimestamp();
|
||||
const mutation = useMutation({
|
||||
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'update-positions'],
|
||||
mutationFn: ossApi.updatePositions,
|
||||
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'update-layout'],
|
||||
mutationFn: ossApi.updateLayout,
|
||||
onSuccess: (_, variables) => updateTimestamp(variables.itemID),
|
||||
onError: () => client.invalidateQueries()
|
||||
});
|
||||
return {
|
||||
updatePositions: (data: {
|
||||
updateLayout: (data: {
|
||||
itemID: number; //
|
||||
positions: IOperationPosition[];
|
||||
isSilent?: boolean;
|
|
@ -18,7 +18,7 @@ import { useDialogsStore } from '@/stores/dialogs';
|
|||
|
||||
import { type ICstRelocateDTO, type IOperationPosition, schemaCstRelocate } from '../backend/types';
|
||||
import { useRelocateConstituents } from '../backend/use-relocate-constituents';
|
||||
import { useUpdatePositions } from '../backend/use-update-positions';
|
||||
import { useUpdateLayout } from '../backend/use-update-layout';
|
||||
import { IconRelocationUp } from '../components/icon-relocation-up';
|
||||
import { type IOperation, type IOperationSchema } from '../models/oss';
|
||||
import { getRelocateCandidates } from '../models/oss-api';
|
||||
|
@ -32,7 +32,7 @@ export interface DlgRelocateConstituentsProps {
|
|||
export function DlgRelocateConstituents() {
|
||||
const { oss, initialTarget, positions } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
|
||||
const { items: libraryItems } = useLibrary();
|
||||
const { updatePositions } = useUpdatePositions();
|
||||
const { updateLayout: updatePositions } = useUpdateLayout();
|
||||
const { relocateConstituents } = useRelocateConstituents();
|
||||
|
||||
const {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useDialogsStore } from '@/stores/dialogs';
|
|||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||
import { useUpdatePositions } from '../../../backend/use-update-positions';
|
||||
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
||||
import { GRID_SIZE } from '../../../models/oss-api';
|
||||
import { type OssNode } from '../../../models/oss-layout';
|
||||
import { useOperationTooltipStore } from '../../../stores/operation-tooltip';
|
||||
|
@ -53,7 +53,7 @@ export function OssFlow() {
|
|||
const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
|
||||
|
||||
const getPositions = useGetPositions();
|
||||
const { updatePositions } = useUpdatePositions();
|
||||
const { updateLayout: updatePositions } = useUpdateLayout();
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
|
|
|
@ -6,7 +6,7 @@ import clsx from 'clsx';
|
|||
import { HelpTopic } from '@/features/help';
|
||||
import { BadgeHelp } from '@/features/help/components';
|
||||
import { useOperationExecute } from '@/features/oss/backend/use-operation-execute';
|
||||
import { useUpdatePositions } from '@/features/oss/backend/use-update-positions';
|
||||
import { useUpdateLayout } from '@/features/oss/backend/use-update-layout';
|
||||
|
||||
import { MiniButton } from '@/components/control';
|
||||
import {
|
||||
|
@ -62,7 +62,7 @@ export function ToolbarOssGraph({
|
|||
const toggleEdgeAnimate = useOSSGraphStore(state => state.toggleEdgeAnimate);
|
||||
const toggleEdgeStraight = useOSSGraphStore(state => state.toggleEdgeStraight);
|
||||
|
||||
const { updatePositions } = useUpdatePositions();
|
||||
const { updateLayout: updatePositions } = useUpdateLayout();
|
||||
const { operationExecute } = useOperationExecute();
|
||||
|
||||
const showEditOperation = useDialogsStore(state => state.showEditOperation);
|
||||
|
|
Loading…
Reference in New Issue
Block a user