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