Implementing oss backend pt2
Some checks are pending
Backend CI / build (3.12) (push) Waiting to run
Some checks are pending
Backend CI / build (3.12) (push) Waiting to run
This commit is contained in:
parent
86033ccd46
commit
a256582a65
|
@ -4,5 +4,5 @@ from apps.rsform.models import LibraryItem, LibraryItemType
|
||||||
|
|
||||||
from .api_OSS import OperationSchema
|
from .api_OSS import OperationSchema
|
||||||
from .Argument import Argument
|
from .Argument import Argument
|
||||||
from .Operation import Operation
|
from .Operation import Operation, OperationType
|
||||||
from .SynthesisSubstitution import SynthesisSubstitution
|
from .SynthesisSubstitution import SynthesisSubstitution
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
''' Models: OSS API. '''
|
''' Models: OSS API. '''
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
|
@ -7,7 +9,7 @@ from apps.rsform.models import LibraryItem, LibraryItemType
|
||||||
from shared import messages as msg
|
from shared import messages as msg
|
||||||
|
|
||||||
from .Argument import Argument
|
from .Argument import Argument
|
||||||
from .Operation import Operation, OperationType
|
from .Operation import Operation
|
||||||
from .SynthesisSubstitution import SynthesisSubstitution
|
from .SynthesisSubstitution import SynthesisSubstitution
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,18 +35,26 @@ class OperationSchema:
|
||||||
return Argument.objects.filter(operation__oss=self.item)
|
return Argument.objects.filter(operation__oss=self.item)
|
||||||
|
|
||||||
def substitutions(self) -> QuerySet[SynthesisSubstitution]:
|
def substitutions(self) -> QuerySet[SynthesisSubstitution]:
|
||||||
''' Operation arguments. '''
|
''' Operation substitutions. '''
|
||||||
return SynthesisSubstitution.objects.filter(operation__oss=self.item)
|
return SynthesisSubstitution.objects.filter(operation__oss=self.item)
|
||||||
|
|
||||||
|
def update_positions(self, data: list[dict]):
|
||||||
|
''' 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'])
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def create_operation(self, operation_type: OperationType, alias: str, **kwargs) -> Operation:
|
def create_operation(self, **kwargs) -> Operation:
|
||||||
''' Insert new operation. '''
|
''' Insert new operation. '''
|
||||||
if self.operations().filter(alias=alias).exists():
|
if kwargs['alias'] != '' and self.operations().filter(alias=kwargs['alias']).exists():
|
||||||
raise ValidationError(msg.aliasTaken(alias))
|
raise ValidationError(msg.aliasTaken(kwargs['alias']))
|
||||||
result = Operation.objects.create(
|
result = Operation.objects.create(
|
||||||
oss=self.item,
|
oss=self.item,
|
||||||
alias=alias,
|
|
||||||
operation_type=operation_type,
|
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
self.item.save()
|
self.item.save()
|
||||||
|
@ -55,4 +65,64 @@ class OperationSchema:
|
||||||
def delete_operation(self, operation: Operation):
|
def delete_operation(self, operation: Operation):
|
||||||
''' Delete operation. '''
|
''' Delete operation. '''
|
||||||
operation.delete()
|
operation.delete()
|
||||||
|
|
||||||
|
# deal with attached schema
|
||||||
|
# trigger on_change effects
|
||||||
|
|
||||||
|
self.item.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def set_input(self, target: Operation, schema: Optional[LibraryItem]):
|
||||||
|
''' Set input schema for operation. '''
|
||||||
|
if schema == target.result:
|
||||||
|
return
|
||||||
|
if schema:
|
||||||
|
target.result = schema
|
||||||
|
target.alias = schema.alias
|
||||||
|
target.title = schema.title
|
||||||
|
target.comment = schema.comment
|
||||||
|
else:
|
||||||
|
target.result = None
|
||||||
|
target.save()
|
||||||
|
|
||||||
|
# trigger on_change effects
|
||||||
|
|
||||||
|
self.item.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def add_argument(self, operation: Operation, argument: Operation) -> Optional[Argument]:
|
||||||
|
''' Add Argument to operation. '''
|
||||||
|
if Argument.objects.filter(operation=operation, argument=argument).exists():
|
||||||
|
return None
|
||||||
|
result = Argument.objects.create(operation=operation, argument=argument)
|
||||||
|
self.item.save()
|
||||||
|
return result
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def clear_arguments(self, target: Operation):
|
||||||
|
''' Clear all arguments for operation. '''
|
||||||
|
if not Argument.objects.filter(operation=target).exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
Argument.objects.filter(operation=target).delete()
|
||||||
|
SynthesisSubstitution.objects.filter(operation=target).delete()
|
||||||
|
|
||||||
|
# trigger on_change effects
|
||||||
|
|
||||||
|
self.item.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def set_substitutions(self, target: Operation, substitutes: list[dict]):
|
||||||
|
''' Clear all arguments for operation. '''
|
||||||
|
SynthesisSubstitution.objects.filter(operation=target).delete()
|
||||||
|
for sub in substitutes:
|
||||||
|
SynthesisSubstitution.objects.create(
|
||||||
|
operation=target,
|
||||||
|
original=sub['original'],
|
||||||
|
substitution=sub['substitution'],
|
||||||
|
transfer_term=sub['transfer_term']
|
||||||
|
)
|
||||||
|
|
||||||
|
# trigger on_change effects
|
||||||
|
|
||||||
self.item.save()
|
self.item.save()
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
from apps.rsform.serializers import LibraryItemSerializer
|
from apps.rsform.serializers import LibraryItemSerializer
|
||||||
|
|
||||||
|
from .basics import OperationPositionSerializer, PositionsSerializer
|
||||||
from .data_access import (
|
from .data_access import (
|
||||||
ArgumentSerializer,
|
ArgumentSerializer,
|
||||||
OperationCreateSerializer,
|
OperationCreateSerializer,
|
||||||
|
OperationDeleteSerializer,
|
||||||
OperationSchemaSerializer,
|
OperationSchemaSerializer,
|
||||||
OperationSerializer
|
OperationSerializer
|
||||||
)
|
)
|
||||||
|
|
16
rsconcept/backend/apps/oss/serializers/basics.py
Normal file
16
rsconcept/backend/apps/oss/serializers/basics.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
''' Basic serializers that do not interact with database. '''
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class OperationPositionSerializer(serializers.Serializer):
|
||||||
|
''' Operation position. '''
|
||||||
|
id = serializers.IntegerField()
|
||||||
|
position_x = serializers.FloatField()
|
||||||
|
position_y = serializers.FloatField()
|
||||||
|
|
||||||
|
|
||||||
|
class PositionsSerializer(serializers.Serializer):
|
||||||
|
''' Operations position for OperationSchema. '''
|
||||||
|
positions = serializers.ListField(
|
||||||
|
child=OperationPositionSerializer()
|
||||||
|
)
|
|
@ -1,13 +1,16 @@
|
||||||
''' Serializers for persistent data manipulation. '''
|
''' Serializers for persistent data manipulation. '''
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
|
from django.db.models import F
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from rest_framework.serializers import PrimaryKeyRelatedField as PKField
|
||||||
|
|
||||||
from apps.rsform.models import LibraryItem
|
from apps.rsform.models import LibraryItem
|
||||||
from apps.rsform.serializers import LibraryItemDetailsSerializer
|
from apps.rsform.serializers import LibraryItemDetailsSerializer
|
||||||
from shared import messages as msg
|
from shared import messages as msg
|
||||||
|
|
||||||
from ..models import Argument, Operation, OperationSchema
|
from ..models import Argument, Operation, OperationSchema, OperationType
|
||||||
|
from .basics import OperationPositionSerializer
|
||||||
|
|
||||||
|
|
||||||
class OperationSerializer(serializers.ModelSerializer):
|
class OperationSerializer(serializers.ModelSerializer):
|
||||||
|
@ -27,30 +30,12 @@ class ArgumentSerializer(serializers.ModelSerializer):
|
||||||
fields = ('operation', 'argument')
|
fields = ('operation', 'argument')
|
||||||
|
|
||||||
|
|
||||||
|
class OperationCreateSerializer(serializers.Serializer):
|
||||||
class OperationPositionSerializer(serializers.ModelSerializer):
|
''' Serializer: Operation creation. '''
|
||||||
''' Serializer: Positions of a single operations in OSS. '''
|
class OperationData(serializers.ModelSerializer):
|
||||||
class Meta:
|
''' Serializer: Operation creation data. '''
|
||||||
''' serializer metadata. '''
|
alias = serializers.CharField()
|
||||||
model = Operation
|
operation_type = serializers.ChoiceField(OperationType.choices)
|
||||||
fields = 'id', 'position_x', 'position_y'
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
oss = cast(LibraryItem, self.context['oss'])
|
|
||||||
operation = cast(Operation, self.instance)
|
|
||||||
if operation.oss != oss:
|
|
||||||
raise serializers.ValidationError({
|
|
||||||
'id': msg.operationNotOwned(oss.title)
|
|
||||||
})
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class OperationCreateSerializer(serializers.ModelSerializer):
|
|
||||||
''' Serializer: Constituenta creation. '''
|
|
||||||
positions = serializers.ListField(
|
|
||||||
child=OperationPositionSerializer(),
|
|
||||||
default=[]
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
''' serializer metadata. '''
|
''' serializer metadata. '''
|
||||||
|
@ -59,6 +44,31 @@ class OperationCreateSerializer(serializers.ModelSerializer):
|
||||||
'alias', 'operation_type', 'title', \
|
'alias', 'operation_type', 'title', \
|
||||||
'comment', 'position_x', 'position_y'
|
'comment', 'position_x', 'position_y'
|
||||||
|
|
||||||
|
item_data = OperationData()
|
||||||
|
positions = serializers.ListField(
|
||||||
|
child=OperationPositionSerializer(),
|
||||||
|
default=[]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OperationDeleteSerializer(serializers.Serializer):
|
||||||
|
''' Serializer: Delete operation. '''
|
||||||
|
target = PKField(many=False, queryset=Operation.objects.all())
|
||||||
|
positions = serializers.ListField(
|
||||||
|
child=OperationPositionSerializer(),
|
||||||
|
default=[]
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
oss = cast(LibraryItem, self.context['oss'])
|
||||||
|
operation = cast(Operation, attrs['target'])
|
||||||
|
if oss and operation.oss != oss:
|
||||||
|
raise serializers.ValidationError({
|
||||||
|
f'{operation.id}': msg.operationNotOwned(oss.title)
|
||||||
|
})
|
||||||
|
self.instance = operation
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class OperationSchemaSerializer(serializers.ModelSerializer):
|
class OperationSchemaSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: Detailed data for OSS. '''
|
''' Serializer: Detailed data for OSS. '''
|
||||||
|
@ -85,13 +95,14 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
|
||||||
result['graph'].append(ArgumentSerializer(argument).data)
|
result['graph'].append(ArgumentSerializer(argument).data)
|
||||||
result['substitutions'] = []
|
result['substitutions'] = []
|
||||||
for substitution in oss.substitutions().values(
|
for substitution in oss.substitutions().values(
|
||||||
|
'operation',
|
||||||
'original',
|
'original',
|
||||||
'original__alias',
|
'transfer_term',
|
||||||
'original__term_resolved',
|
|
||||||
'substitution',
|
'substitution',
|
||||||
'substitution__alias',
|
original_alias=F('original__alias'),
|
||||||
'substitution__term_resolved',
|
original_term=F('original__term_resolved'),
|
||||||
'transfer_term'
|
substitution_alias=F('substitution__alias'),
|
||||||
|
substitution_term=F('substitution__term_resolved'),
|
||||||
):
|
):
|
||||||
result['substitutions'].append(substitution)
|
result['substitutions'].append(substitution)
|
||||||
return result
|
return result
|
||||||
|
|
3
rsconcept/backend/apps/oss/tests/__init__.py
Normal file
3
rsconcept/backend/apps/oss/tests/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
''' Tests. '''
|
||||||
|
from .s_models import *
|
||||||
|
from .s_views import *
|
1
rsconcept/backend/apps/oss/tests/s_models/__init__.py
Normal file
1
rsconcept/backend/apps/oss/tests/s_models/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
''' Tests for Django Models. '''
|
2
rsconcept/backend/apps/oss/tests/s_views/__init__.py
Normal file
2
rsconcept/backend/apps/oss/tests/s_views/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
''' Tests for REST API. '''
|
||||||
|
from .t_oss import *
|
189
rsconcept/backend/apps/oss/tests/s_views/t_oss.py
Normal file
189
rsconcept/backend/apps/oss/tests/s_views/t_oss.py
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
''' Testing API: Operation Schema. '''
|
||||||
|
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
from apps.oss.models import Operation, OperationSchema, OperationType
|
||||||
|
from apps.rsform.models import AccessPolicy, LibraryItem, LibraryItemType, LocationHead, RSForm
|
||||||
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
||||||
|
class TestOssViewset(EndpointTester):
|
||||||
|
''' Testing OSS view. '''
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
||||||
|
self.owned_id = self.owned.item.pk
|
||||||
|
self.unowned = OperationSchema.create(title='Test2', alias='T2')
|
||||||
|
self.unowned_id = self.unowned.item.pk
|
||||||
|
self.private = OperationSchema.create(title='Test2', alias='T2', access_policy=AccessPolicy.PRIVATE)
|
||||||
|
self.private_id = self.private.item.pk
|
||||||
|
self.invalid_id = self.private.item.pk + 1337
|
||||||
|
|
||||||
|
|
||||||
|
def populateData(self):
|
||||||
|
self.ks1 = RSForm.create(alias='KS1', title='Test1')
|
||||||
|
self.ks1x1 = self.ks1.insert_new('X1', term_resolved='X1_1')
|
||||||
|
self.ks2 = RSForm.create(alias='KS2', title='Test2')
|
||||||
|
self.ks2x1 = self.ks2.insert_new('X2', term_resolved='X1_2')
|
||||||
|
self.operation1 = self.owned.create_operation(
|
||||||
|
alias='1',
|
||||||
|
operation_type=OperationType.INPUT,
|
||||||
|
result=self.ks1.item
|
||||||
|
)
|
||||||
|
self.operation2 = self.owned.create_operation(
|
||||||
|
alias='2',
|
||||||
|
operation_type=OperationType.INPUT,
|
||||||
|
result=self.ks2.item
|
||||||
|
)
|
||||||
|
self.operation3 = self.owned.create_operation(
|
||||||
|
alias='3',
|
||||||
|
operation_type=OperationType.SYNTHESIS
|
||||||
|
)
|
||||||
|
self.owned.add_argument(self.operation3, self.operation1)
|
||||||
|
self.owned.add_argument(self.operation3, self.operation2)
|
||||||
|
self.owned.set_substitutions(self.operation3, [{
|
||||||
|
'original': self.ks1x1,
|
||||||
|
'substitution': self.ks2x1,
|
||||||
|
'transfer_term': False
|
||||||
|
}])
|
||||||
|
|
||||||
|
@decl_endpoint('/api/oss/{item}/details', method='get')
|
||||||
|
def test_details(self):
|
||||||
|
self.populateData()
|
||||||
|
|
||||||
|
response = self.executeOK(item=self.owned_id)
|
||||||
|
self.assertEqual(response.data['owner'], self.owned.item.owner.pk)
|
||||||
|
self.assertEqual(response.data['title'], self.owned.item.title)
|
||||||
|
self.assertEqual(response.data['alias'], self.owned.item.alias)
|
||||||
|
self.assertEqual(response.data['location'], self.owned.item.location)
|
||||||
|
self.assertEqual(response.data['access_policy'], self.owned.item.access_policy)
|
||||||
|
self.assertEqual(response.data['visible'], self.owned.item.visible)
|
||||||
|
|
||||||
|
self.assertEqual(response.data['item_type'], LibraryItemType.OPERATION_SCHEMA)
|
||||||
|
|
||||||
|
self.assertEqual(len(response.data['items']), 3)
|
||||||
|
self.assertEqual(response.data['items'][0]['id'], self.operation1.pk)
|
||||||
|
self.assertEqual(response.data['items'][0]['operation_type'], self.operation1.operation_type)
|
||||||
|
|
||||||
|
self.assertEqual(len(response.data['substitutions']), 1)
|
||||||
|
sub = response.data['substitutions'][0]
|
||||||
|
self.assertEqual(sub['operation'], self.operation3.pk)
|
||||||
|
self.assertEqual(sub['original'], self.ks1x1.pk)
|
||||||
|
self.assertEqual(sub['substitution'], self.ks2x1.pk)
|
||||||
|
self.assertEqual(sub['transfer_term'], False)
|
||||||
|
self.assertEqual(sub['original_alias'], self.ks1x1.alias)
|
||||||
|
self.assertEqual(sub['original_term'], self.ks1x1.term_resolved)
|
||||||
|
self.assertEqual(sub['substitution_alias'], self.ks2x1.alias)
|
||||||
|
self.assertEqual(sub['substitution_term'], self.ks2x1.term_resolved)
|
||||||
|
|
||||||
|
graph = response.data['graph']
|
||||||
|
self.assertEqual(len(graph), 2)
|
||||||
|
self.assertEqual(graph[0]['operation'], self.operation3.pk)
|
||||||
|
self.assertEqual(graph[0]['argument'], self.operation1.pk)
|
||||||
|
self.assertEqual(graph[1]['operation'], self.operation3.pk)
|
||||||
|
self.assertEqual(graph[1]['argument'], self.operation2.pk)
|
||||||
|
|
||||||
|
self.executeOK(item=self.unowned_id)
|
||||||
|
self.executeForbidden(item=self.private_id)
|
||||||
|
|
||||||
|
self.logout()
|
||||||
|
self.executeOK(item=self.owned_id)
|
||||||
|
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):
|
||||||
|
self.populateData()
|
||||||
|
self.executeBadData(item=self.owned_id)
|
||||||
|
|
||||||
|
data = {'positions': []}
|
||||||
|
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},
|
||||||
|
]}
|
||||||
|
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.executeForbidden(data=data, item=self.unowned_id)
|
||||||
|
self.executeForbidden(item=self.private_id)
|
||||||
|
|
||||||
|
|
||||||
|
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||||
|
def test_create_operation(self):
|
||||||
|
self.executeNotFound(item=self.invalid_id)
|
||||||
|
|
||||||
|
self.populateData()
|
||||||
|
self.executeBadData(item=self.owned_id)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'item_data': {
|
||||||
|
'alias': 'Test3',
|
||||||
|
'title': 'Test title',
|
||||||
|
'comment': 'Тест кириллицы',
|
||||||
|
'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
|
||||||
|
response = self.executeCreated(data=data)
|
||||||
|
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['comment'], data['item_data']['comment'])
|
||||||
|
self.assertEqual(new_operation['position_x'], data['item_data']['position_x'])
|
||||||
|
self.assertEqual(new_operation['position_y'], data['item_data']['position_y'])
|
||||||
|
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}/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)
|
|
@ -5,7 +5,7 @@ from rest_framework import routers
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
library_router = routers.SimpleRouter(trailing_slash=False)
|
library_router = routers.SimpleRouter(trailing_slash=False)
|
||||||
library_router.register('rsforms', views.OssViewSet, 'RSForm')
|
library_router.register('oss', views.OssViewSet, 'OSS')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include(library_router.urls)),
|
path('', include(library_router.urls)),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
''' Endpoints for OSS. '''
|
''' Endpoints for OSS. '''
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
|
from django.db import transaction
|
||||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework import status as c
|
from rest_framework import status as c
|
||||||
|
@ -28,8 +29,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 [
|
||||||
'operation_create',
|
'create_operation',
|
||||||
'operation_delete'
|
'delete_operation',
|
||||||
|
'update_positions'
|
||||||
]:
|
]:
|
||||||
permission_list = [permissions.ItemEditor]
|
permission_list = [permissions.ItemEditor]
|
||||||
elif self.action in ['details']:
|
elif self.action in ['details']:
|
||||||
|
@ -56,55 +58,84 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
data=serializer.data
|
data=serializer.data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
summary='update positions',
|
||||||
|
tags=['OSS'],
|
||||||
|
request=s.PositionsSerializer,
|
||||||
|
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):
|
||||||
|
''' Endpoint: Update operations positions. '''
|
||||||
|
schema = self._get_schema()
|
||||||
|
serializer = s.PositionsSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
schema.update_positions(serializer.validated_data['positions'])
|
||||||
|
return Response(status=c.HTTP_200_OK)
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
summary='create operation',
|
summary='create operation',
|
||||||
tags=['OSS'],
|
tags=['OSS'],
|
||||||
request=s.OperationCreateSerializer(),
|
request=s.OperationCreateSerializer(),
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_201_CREATED: s.NewOperationResponse,
|
c.HTTP_201_CREATED: s.NewOperationResponse,
|
||||||
c.HTTP_403_FORBIDDEN: None
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'], url_path='operation-create')
|
@action(detail=True, methods=['post'], url_path='create-operation')
|
||||||
def operation_create(self, request: Request, pk):
|
def create_operation(self, request: Request, pk):
|
||||||
''' Create new operation. '''
|
''' Create new operation. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
serializer = s.OperationCreateSerializer(data=request.data)
|
serializer = s.OperationCreateSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
data = serializer.validated_data
|
|
||||||
new_operation = schema.create_operation(*data)
|
with transaction.atomic():
|
||||||
|
schema.update_positions(serializer.validated_data['positions'])
|
||||||
|
new_operation = schema.create_operation(**serializer.validated_data['item_data'])
|
||||||
schema.item.refresh_from_db()
|
schema.item.refresh_from_db()
|
||||||
|
|
||||||
response = Response(
|
response = Response(
|
||||||
status=c.HTTP_201_CREATED,
|
status=c.HTTP_201_CREATED,
|
||||||
data={
|
data={
|
||||||
'new_operation': s.OperationSerializer(new_operation).data,
|
'new_operation': s.OperationSerializer(new_operation).data,
|
||||||
'schema': s.OperationSchemaSerializer(schema.item).data
|
'oss': s.OperationSchemaSerializer(schema.item).data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# @extend_schema(
|
@extend_schema(
|
||||||
# summary='delete operation',
|
summary='delete operation',
|
||||||
# tags=['RSForm'],
|
tags=['OSS'],
|
||||||
# request=s.CstListSerializer,
|
request=s.OperationDeleteSerializer,
|
||||||
# responses={
|
responses={
|
||||||
# c.HTTP_200_OK: s.RSFormParseSerializer,
|
c.HTTP_200_OK: s.OperationSchemaSerializer,
|
||||||
# c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
# c.HTTP_404_NOT_FOUND: None
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
# }
|
c.HTTP_404_NOT_FOUND: None
|
||||||
# )
|
}
|
||||||
# @action(detail=True, methods=['patch'], url_path='operation-delete')
|
)
|
||||||
# def operation_delete(self, request: Request, pk):
|
@action(detail=True, methods=['patch'], url_path='delete-operation')
|
||||||
# ''' Endpoint: Delete operation. '''
|
def delete_operation(self, request: Request, pk):
|
||||||
# schema = self._get_schema()
|
''' Endpoint: Delete operation. '''
|
||||||
# serializer = s.CstListSerializer(
|
schema = self._get_schema()
|
||||||
# data=request.data,
|
serializer = s.OperationDeleteSerializer(
|
||||||
# context={'schema': schema.item}
|
data=request.data,
|
||||||
# )
|
context={'oss': schema.item}
|
||||||
# serializer.is_valid(raise_exception=True)
|
)
|
||||||
# schema.delete_cst(serializer.validated_data['items'])
|
serializer.is_valid(raise_exception=True)
|
||||||
# schema.item.refresh_from_db()
|
|
||||||
# return Response(
|
with transaction.atomic():
|
||||||
# status=c.HTTP_200_OK,
|
schema.update_positions(serializer.validated_data['positions'])
|
||||||
# data=s.RSFormParseSerializer(schema.item).data
|
schema.delete_operation(serializer.validated_data['target'])
|
||||||
# )
|
schema.item.refresh_from_db()
|
||||||
|
|
||||||
|
return Response(
|
||||||
|
status=c.HTTP_200_OK,
|
||||||
|
data=s.OperationSchemaSerializer(schema.item).data
|
||||||
|
)
|
||||||
|
|
|
@ -35,7 +35,7 @@ class LocationSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class AccessPolicySerializer(serializers.Serializer):
|
class AccessPolicySerializer(serializers.Serializer):
|
||||||
''' Serializer: Constituenta renaming. '''
|
''' Serializer: Constituenta renaming. '''
|
||||||
access_policy = serializers.CharField(max_length=500)
|
access_policy = serializers.CharField()
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
attrs = super().validate(attrs)
|
attrs = super().validate(attrs)
|
||||||
|
|
|
@ -141,6 +141,8 @@ class CstDetailsSerializer(serializers.ModelSerializer):
|
||||||
class CstCreateSerializer(serializers.ModelSerializer):
|
class CstCreateSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: Constituenta creation. '''
|
''' Serializer: Constituenta creation. '''
|
||||||
insert_after = serializers.IntegerField(required=False, allow_null=True)
|
insert_after = serializers.IntegerField(required=False, allow_null=True)
|
||||||
|
alias = serializers.CharField(max_length=8)
|
||||||
|
cst_type = serializers.ChoiceField(CstType.choices)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
''' serializer metadata. '''
|
''' serializer metadata. '''
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
''' Tests. '''
|
''' Tests. '''
|
||||||
from .s_models.t_RSForm import *
|
from .s_models import *
|
||||||
from .s_views import *
|
from .s_views import *
|
||||||
from .t_graph import *
|
from .t_graph import *
|
||||||
from .t_imports import *
|
from .t_imports import *
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
''' Tests for REST API. '''
|
''' Tests for Django Models. '''
|
||||||
from .t_Constituenta import *
|
from .t_Constituenta import *
|
||||||
from .t_Editor import *
|
from .t_Editor import *
|
||||||
from .t_LibraryItem import *
|
from .t_LibraryItem import *
|
||||||
|
|
|
@ -14,20 +14,20 @@ class TestNaturalLanguageViews(EndpointTester):
|
||||||
@decl_endpoint(endpoint='/api/cctext/parse', method='post')
|
@decl_endpoint(endpoint='/api/cctext/parse', method='post')
|
||||||
def test_parse_text(self):
|
def test_parse_text(self):
|
||||||
data = {'text': 'синим слонам'}
|
data = {'text': 'синим слонам'}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc')
|
self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc')
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint(endpoint='/api/cctext/inflect', method='post')
|
@decl_endpoint(endpoint='/api/cctext/inflect', method='post')
|
||||||
def test_inflect(self):
|
def test_inflect(self):
|
||||||
data = {'text': 'синий слон', 'grams': 'plur,datv'}
|
data = {'text': 'синий слон', 'grams': 'plur,datv'}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self.assertEqual(response.data['result'], 'синим слонам')
|
self.assertEqual(response.data['result'], 'синим слонам')
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint(endpoint='/api/cctext/generate-lexeme', method='post')
|
@decl_endpoint(endpoint='/api/cctext/generate-lexeme', method='post')
|
||||||
def test_generate_lexeme(self):
|
def test_generate_lexeme(self):
|
||||||
data = {'text': 'синий слон'}
|
data = {'text': 'синий слон'}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self.assertEqual(len(response.data['items']), 12)
|
self.assertEqual(len(response.data['items']), 12)
|
||||||
self.assertEqual(response.data['items'][0]['text'], 'синий слон')
|
self.assertEqual(response.data['items'][0]['text'], 'синий слон')
|
||||||
|
|
|
@ -51,18 +51,18 @@ class TestConstituentaAPI(EndpointTester):
|
||||||
@decl_endpoint('/api/constituents/{item}', method='patch')
|
@decl_endpoint('/api/constituents/{item}', method='patch')
|
||||||
def test_partial_update(self):
|
def test_partial_update(self):
|
||||||
data = {'convention': 'tt'}
|
data = {'convention': 'tt'}
|
||||||
self.executeForbidden(data, item=self.cst2.pk)
|
self.executeForbidden(data=data, item=self.cst2.pk)
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
self.executeForbidden(data, item=self.cst1.pk)
|
self.executeForbidden(data=data, item=self.cst1.pk)
|
||||||
|
|
||||||
self.login()
|
self.login()
|
||||||
response = self.executeOK(data, item=self.cst1.pk)
|
response = self.executeOK(data=data, item=self.cst1.pk)
|
||||||
self.cst1.refresh_from_db()
|
self.cst1.refresh_from_db()
|
||||||
self.assertEqual(response.data['convention'], 'tt')
|
self.assertEqual(response.data['convention'], 'tt')
|
||||||
self.assertEqual(self.cst1.convention, 'tt')
|
self.assertEqual(self.cst1.convention, 'tt')
|
||||||
|
|
||||||
self.executeOK(data, item=self.cst1.pk)
|
self.executeOK(data=data, item=self.cst1.pk)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/constituents/{item}', method='patch')
|
@decl_endpoint('/api/constituents/{item}', method='patch')
|
||||||
|
@ -71,7 +71,7 @@ class TestConstituentaAPI(EndpointTester):
|
||||||
'term_raw': 'New term',
|
'term_raw': 'New term',
|
||||||
'definition_raw': 'New def'
|
'definition_raw': 'New def'
|
||||||
}
|
}
|
||||||
response = self.executeOK(data, item=self.cst3.pk)
|
response = self.executeOK(data=data, item=self.cst3.pk)
|
||||||
self.cst3.refresh_from_db()
|
self.cst3.refresh_from_db()
|
||||||
self.assertEqual(response.data['term_resolved'], 'New term')
|
self.assertEqual(response.data['term_resolved'], 'New term')
|
||||||
self.assertEqual(self.cst3.term_resolved, 'New term')
|
self.assertEqual(self.cst3.term_resolved, 'New term')
|
||||||
|
@ -85,7 +85,7 @@ class TestConstituentaAPI(EndpointTester):
|
||||||
'term_raw': '@{X1|nomn,sing}',
|
'term_raw': '@{X1|nomn,sing}',
|
||||||
'definition_raw': '@{X1|nomn,sing} @{X1|sing,datv}'
|
'definition_raw': '@{X1|nomn,sing} @{X1|sing,datv}'
|
||||||
}
|
}
|
||||||
response = self.executeOK(data, item=self.cst3.pk)
|
response = self.executeOK(data=data, item=self.cst3.pk)
|
||||||
self.cst3.refresh_from_db()
|
self.cst3.refresh_from_db()
|
||||||
self.assertEqual(self.cst3.term_resolved, self.cst1.term_resolved)
|
self.assertEqual(self.cst3.term_resolved, self.cst1.term_resolved)
|
||||||
self.assertEqual(response.data['term_resolved'], self.cst1.term_resolved)
|
self.assertEqual(response.data['term_resolved'], self.cst1.term_resolved)
|
||||||
|
@ -96,7 +96,7 @@ class TestConstituentaAPI(EndpointTester):
|
||||||
@decl_endpoint('/api/constituents/{item}', method='patch')
|
@decl_endpoint('/api/constituents/{item}', method='patch')
|
||||||
def test_readonly_cst_fields(self):
|
def test_readonly_cst_fields(self):
|
||||||
data = {'alias': 'X33', 'order': 10}
|
data = {'alias': 'X33', 'order': 10}
|
||||||
response = self.executeOK(data, item=self.cst1.pk)
|
response = self.executeOK(data=data, item=self.cst1.pk)
|
||||||
self.assertEqual(response.data['alias'], 'X1')
|
self.assertEqual(response.data['alias'], 'X1')
|
||||||
self.assertEqual(response.data['alias'], self.cst1.alias)
|
self.assertEqual(response.data['alias'], self.cst1.alias)
|
||||||
self.assertEqual(response.data['order'], self.cst1.order)
|
self.assertEqual(response.data['order'], self.cst1.order)
|
||||||
|
|
|
@ -48,7 +48,7 @@ class TestLibraryViewset(EndpointTester):
|
||||||
'title': 'Title',
|
'title': 'Title',
|
||||||
'alias': 'alias',
|
'alias': 'alias',
|
||||||
}
|
}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'item_type': LibraryItemType.OPERATION_SCHEMA,
|
'item_type': LibraryItemType.OPERATION_SCHEMA,
|
||||||
|
@ -58,7 +58,7 @@ class TestLibraryViewset(EndpointTester):
|
||||||
'visible': False,
|
'visible': False,
|
||||||
'read_only': True
|
'read_only': True
|
||||||
}
|
}
|
||||||
response = self.executeCreated(data)
|
response = self.executeCreated(data=data)
|
||||||
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'])
|
||||||
|
@ -69,25 +69,25 @@ class TestLibraryViewset(EndpointTester):
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
data = {'title': 'Title2'}
|
data = {'title': 'Title2'}
|
||||||
self.executeForbidden(data)
|
self.executeForbidden(data=data)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/library/{item}', method='patch')
|
@decl_endpoint('/api/library/{item}', method='patch')
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
data = {'id': self.unowned.pk, 'title': 'New Title'}
|
data = {'id': self.unowned.pk, 'title': 'New Title'}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
self.toggle_editor(self.unowned, True)
|
self.toggle_editor(self.unowned, True)
|
||||||
response = self.executeOK(data, item=self.unowned.pk)
|
response = self.executeOK(data=data, item=self.unowned.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
|
|
||||||
self.unowned.access_policy = AccessPolicy.PRIVATE
|
self.unowned.access_policy = AccessPolicy.PRIVATE
|
||||||
self.unowned.save()
|
self.unowned.save()
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
data = {'id': self.owned.pk, 'title': 'New Title'}
|
data = {'id': self.owned.pk, 'title': 'New Title'}
|
||||||
response = self.executeOK(data, item=self.owned.pk)
|
response = self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
self.assertEqual(response.data['alias'], self.owned.alias)
|
self.assertEqual(response.data['alias'], self.owned.alias)
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class TestLibraryViewset(EndpointTester):
|
||||||
'access_policy': AccessPolicy.PROTECTED,
|
'access_policy': AccessPolicy.PROTECTED,
|
||||||
'location': LocationHead.LIBRARY
|
'location': LocationHead.LIBRARY
|
||||||
}
|
}
|
||||||
response = self.executeOK(data, item=self.owned.pk)
|
response = self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
self.assertEqual(response.data['owner'], self.owned.owner.pk)
|
self.assertEqual(response.data['owner'], self.owned.owner.pk)
|
||||||
self.assertEqual(response.data['access_policy'], self.owned.access_policy)
|
self.assertEqual(response.data['access_policy'], self.owned.access_policy)
|
||||||
|
@ -111,22 +111,22 @@ class TestLibraryViewset(EndpointTester):
|
||||||
time_update = self.owned.time_update
|
time_update = self.owned.time_update
|
||||||
|
|
||||||
data = {'user': self.user.pk}
|
data = {'user': self.user.pk}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.owner, self.user)
|
self.assertEqual(self.owned.owner, self.user)
|
||||||
|
|
||||||
data = {'user': self.user2.pk}
|
data = {'user': self.user2.pk}
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.owner, self.user2)
|
self.assertEqual(self.owned.owner, self.user2)
|
||||||
self.assertEqual(self.owned.time_update, time_update)
|
self.assertEqual(self.owned.time_update, time_update)
|
||||||
self.executeForbidden(data, item=self.owned.pk)
|
self.executeForbidden(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
self.toggle_admin(True)
|
self.toggle_admin(True)
|
||||||
data = {'user': self.user.pk}
|
data = {'user': self.user.pk}
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.owner, self.user)
|
self.assertEqual(self.owned.owner, self.user)
|
||||||
|
|
||||||
|
@ -135,20 +135,20 @@ class TestLibraryViewset(EndpointTester):
|
||||||
time_update = self.owned.time_update
|
time_update = self.owned.time_update
|
||||||
|
|
||||||
data = {'access_policy': 'invalid'}
|
data = {'access_policy': 'invalid'}
|
||||||
self.executeBadData(data, item=self.owned.pk)
|
self.executeBadData(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
data = {'access_policy': AccessPolicy.PRIVATE}
|
data = {'access_policy': AccessPolicy.PRIVATE}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.access_policy, data['access_policy'])
|
self.assertEqual(self.owned.access_policy, data['access_policy'])
|
||||||
|
|
||||||
self.toggle_editor(self.unowned, True)
|
self.toggle_editor(self.unowned, True)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
self.toggle_admin(True)
|
self.toggle_admin(True)
|
||||||
self.executeOK(data, item=self.unowned.pk)
|
self.executeOK(data=data, item=self.unowned.pk)
|
||||||
self.unowned.refresh_from_db()
|
self.unowned.refresh_from_db()
|
||||||
self.assertEqual(self.unowned.access_policy, data['access_policy'])
|
self.assertEqual(self.unowned.access_policy, data['access_policy'])
|
||||||
|
|
||||||
|
@ -157,29 +157,29 @@ class TestLibraryViewset(EndpointTester):
|
||||||
time_update = self.owned.time_update
|
time_update = self.owned.time_update
|
||||||
|
|
||||||
data = {'location': 'invalid'}
|
data = {'location': 'invalid'}
|
||||||
self.executeBadData(data, item=self.owned.pk)
|
self.executeBadData(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
data = {'location': '/U/temp'}
|
data = {'location': '/U/temp'}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.location, data['location'])
|
self.assertEqual(self.owned.location, data['location'])
|
||||||
|
|
||||||
data = {'location': LocationHead.LIBRARY}
|
data = {'location': LocationHead.LIBRARY}
|
||||||
self.executeForbidden(data, item=self.owned.pk)
|
self.executeForbidden(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
data = {'location': '/U/temp'}
|
data = {'location': '/U/temp'}
|
||||||
self.toggle_editor(self.unowned, True)
|
self.toggle_editor(self.unowned, True)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
self.toggle_admin(True)
|
self.toggle_admin(True)
|
||||||
data = {'location': LocationHead.LIBRARY}
|
data = {'location': LocationHead.LIBRARY}
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.location, data['location'])
|
self.assertEqual(self.owned.location, data['location'])
|
||||||
|
|
||||||
self.executeOK(data, item=self.unowned.pk)
|
self.executeOK(data=data, item=self.unowned.pk)
|
||||||
self.unowned.refresh_from_db()
|
self.unowned.refresh_from_db()
|
||||||
self.assertEqual(self.unowned.location, data['location'])
|
self.assertEqual(self.unowned.location, data['location'])
|
||||||
|
|
||||||
|
@ -188,22 +188,22 @@ class TestLibraryViewset(EndpointTester):
|
||||||
time_update = self.owned.time_update
|
time_update = self.owned.time_update
|
||||||
|
|
||||||
data = {'user': self.invalid_user}
|
data = {'user': self.invalid_user}
|
||||||
self.executeBadData(data, item=self.owned.pk)
|
self.executeBadData(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
data = {'user': self.user.pk}
|
data = {'user': self.user.pk}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.time_update, time_update)
|
self.assertEqual(self.owned.time_update, time_update)
|
||||||
self.assertEqual(self.owned.editors(), [self.user])
|
self.assertEqual(self.owned.editors(), [self.user])
|
||||||
|
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(self.owned.editors(), [self.user])
|
self.assertEqual(self.owned.editors(), [self.user])
|
||||||
|
|
||||||
data = {'user': self.user2.pk}
|
data = {'user': self.user2.pk}
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(set(self.owned.editors()), set([self.user, self.user2]))
|
self.assertEqual(set(self.owned.editors()), set([self.user, self.user2]))
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,25 +212,25 @@ class TestLibraryViewset(EndpointTester):
|
||||||
time_update = self.owned.time_update
|
time_update = self.owned.time_update
|
||||||
|
|
||||||
data = {'user': self.invalid_user}
|
data = {'user': self.invalid_user}
|
||||||
self.executeBadData(data, item=self.owned.pk)
|
self.executeBadData(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
data = {'user': self.user.pk}
|
data = {'user': self.user.pk}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.time_update, time_update)
|
self.assertEqual(self.owned.time_update, time_update)
|
||||||
self.assertEqual(self.owned.editors(), [])
|
self.assertEqual(self.owned.editors(), [])
|
||||||
|
|
||||||
Editor.add(item=self.owned, user=self.user)
|
Editor.add(item=self.owned, user=self.user)
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(self.owned.editors(), [])
|
self.assertEqual(self.owned.editors(), [])
|
||||||
|
|
||||||
Editor.add(item=self.owned, user=self.user)
|
Editor.add(item=self.owned, user=self.user)
|
||||||
Editor.add(item=self.owned, user=self.user2)
|
Editor.add(item=self.owned, user=self.user2)
|
||||||
data = {'user': self.user2.pk}
|
data = {'user': self.user2.pk}
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(self.owned.editors(), [self.user])
|
self.assertEqual(self.owned.editors(), [self.user])
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,30 +239,30 @@ class TestLibraryViewset(EndpointTester):
|
||||||
time_update = self.owned.time_update
|
time_update = self.owned.time_update
|
||||||
|
|
||||||
data = {'users': [self.invalid_user]}
|
data = {'users': [self.invalid_user]}
|
||||||
self.executeBadData(data, item=self.owned.pk)
|
self.executeBadData(data=data, item=self.owned.pk)
|
||||||
|
|
||||||
data = {'users': [self.user.pk]}
|
data = {'users': [self.user.pk]}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeForbidden(data, item=self.unowned.pk)
|
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
self.executeOK(data, item=self.owned.pk)
|
self.executeOK(data=data, item=self.owned.pk)
|
||||||
self.owned.refresh_from_db()
|
self.owned.refresh_from_db()
|
||||||
self.assertEqual(self.owned.time_update, time_update)
|
self.assertEqual(self.owned.time_update, time_update)
|
||||||
self.assertEqual(self.owned.editors(), [self.user])
|
self.assertEqual(self.owned.editors(), [self.user])
|
||||||
|
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(self.owned.editors(), [self.user])
|
self.assertEqual(self.owned.editors(), [self.user])
|
||||||
|
|
||||||
data = {'users': [self.user2.pk]}
|
data = {'users': [self.user2.pk]}
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(self.owned.editors(), [self.user2])
|
self.assertEqual(self.owned.editors(), [self.user2])
|
||||||
|
|
||||||
data = {'users': []}
|
data = {'users': []}
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(self.owned.editors(), [])
|
self.assertEqual(self.owned.editors(), [])
|
||||||
|
|
||||||
data = {'users': [self.user2.pk, self.user.pk]}
|
data = {'users': [self.user2.pk, self.user.pk]}
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
self.assertEqual(set(self.owned.editors()), set([self.user2, self.user]))
|
self.assertEqual(set(self.owned.editors()), set([self.user2, self.user]))
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,11 +375,11 @@ class TestLibraryViewset(EndpointTester):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {'title': 'Title1337'}
|
data = {'title': 'Title1337'}
|
||||||
self.executeNotFound(data, item=self.invalid_item)
|
self.executeNotFound(data=data, item=self.invalid_item)
|
||||||
self.executeCreated(data, item=self.unowned.pk)
|
self.executeCreated(data=data, item=self.unowned.pk)
|
||||||
|
|
||||||
data = {'title': 'Title1338'}
|
data = {'title': 'Title1338'}
|
||||||
response = self.executeCreated(data, item=self.owned.pk)
|
response = self.executeCreated(data=data, item=self.owned.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
self.assertEqual(len(response.data['items']), 2)
|
self.assertEqual(len(response.data['items']), 2)
|
||||||
self.assertEqual(response.data['items'][0]['alias'], x12.alias)
|
self.assertEqual(response.data['items'][0]['alias'], x12.alias)
|
||||||
|
@ -389,12 +389,12 @@ class TestLibraryViewset(EndpointTester):
|
||||||
self.assertEqual(response.data['items'][1]['term_resolved'], d2.term_resolved)
|
self.assertEqual(response.data['items'][1]['term_resolved'], d2.term_resolved)
|
||||||
|
|
||||||
data = {'title': 'Title1340', 'items': []}
|
data = {'title': 'Title1340', 'items': []}
|
||||||
response = self.executeCreated(data, item=self.owned.pk)
|
response = self.executeCreated(data=data, item=self.owned.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
self.assertEqual(len(response.data['items']), 0)
|
self.assertEqual(len(response.data['items']), 0)
|
||||||
|
|
||||||
data = {'title': 'Title1341', 'items': [x12.pk]}
|
data = {'title': 'Title1341', 'items': [x12.pk]}
|
||||||
response = self.executeCreated(data, item=self.owned.pk)
|
response = self.executeCreated(data=data, item=self.owned.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
self.assertEqual(len(response.data['items']), 1)
|
self.assertEqual(len(response.data['items']), 1)
|
||||||
self.assertEqual(response.data['items'][0]['alias'], x12.alias)
|
self.assertEqual(response.data['items'][0]['alias'], x12.alias)
|
||||||
|
|
|
@ -23,20 +23,20 @@ class TestInlineSynthesis(EndpointTester):
|
||||||
'items': [],
|
'items': [],
|
||||||
'substitutions': []
|
'substitutions': []
|
||||||
}
|
}
|
||||||
self.executeForbidden(data)
|
self.executeForbidden(data=data)
|
||||||
|
|
||||||
data['receiver'] = invalid_id
|
data['receiver'] = invalid_id
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data['receiver'] = self.schema1.item.pk
|
data['receiver'] = self.schema1.item.pk
|
||||||
data['source'] = invalid_id
|
data['source'] = invalid_id
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data['source'] = self.schema1.item.pk
|
data['source'] = self.schema1.item.pk
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
|
|
||||||
data['items'] = [invalid_id]
|
data['items'] = [invalid_id]
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
|
|
||||||
def test_inline_synthesis(self):
|
def test_inline_synthesis(self):
|
||||||
|
@ -67,7 +67,7 @@ class TestInlineSynthesis(EndpointTester):
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
result = {item['alias']: item for item in response.data['items']}
|
result = {item['alias']: item for item in response.data['items']}
|
||||||
self.assertEqual(len(result), 6)
|
self.assertEqual(len(result), 6)
|
||||||
self.assertEqual(result['X2']['term_raw'], ks1_x2.term_raw)
|
self.assertEqual(result['X2']['term_raw'], ks1_x2.term_raw)
|
||||||
|
|
|
@ -43,7 +43,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'access_policy': AccessPolicy.PROTECTED,
|
'access_policy': AccessPolicy.PROTECTED,
|
||||||
'visible': False
|
'visible': False
|
||||||
}
|
}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
|
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
|
||||||
data['file'] = file
|
data['file'] = file
|
||||||
|
@ -123,14 +123,14 @@ class TestRSFormViewset(EndpointTester):
|
||||||
def test_check(self):
|
def test_check(self):
|
||||||
self.owned.insert_new('X1')
|
self.owned.insert_new('X1')
|
||||||
data = {'expression': 'X1=X1'}
|
data = {'expression': 'X1=X1'}
|
||||||
response = self.executeOK(data, item=self.owned_id)
|
response = self.executeOK(data=data, item=self.owned_id)
|
||||||
self.assertEqual(response.data['parseResult'], True)
|
self.assertEqual(response.data['parseResult'], True)
|
||||||
self.assertEqual(response.data['syntax'], 'math')
|
self.assertEqual(response.data['syntax'], 'math')
|
||||||
self.assertEqual(response.data['astText'], '[=[X1][X1]]')
|
self.assertEqual(response.data['astText'], '[=[X1][X1]]')
|
||||||
self.assertEqual(response.data['typification'], 'LOGIC')
|
self.assertEqual(response.data['typification'], 'LOGIC')
|
||||||
self.assertEqual(response.data['valueClass'], 'value')
|
self.assertEqual(response.data['valueClass'], 'value')
|
||||||
|
|
||||||
self.executeOK(data, item=self.unowned_id)
|
self.executeOK(data=data, item=self.unowned_id)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/resolve', method='post')
|
@decl_endpoint('/api/rsforms/{item}/resolve', method='post')
|
||||||
|
@ -141,7 +141,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {'text': '@{1|редкий} @{X1|plur,datv}'}
|
data = {'text': '@{1|редкий} @{X1|plur,datv}'}
|
||||||
response = self.executeOK(data, item=self.owned_id)
|
response = self.executeOK(data=data, item=self.owned_id)
|
||||||
self.assertEqual(response.data['input'], '@{1|редкий} @{X1|plur,datv}')
|
self.assertEqual(response.data['input'], '@{1|редкий} @{X1|plur,datv}')
|
||||||
self.assertEqual(response.data['output'], 'редким синим слонам')
|
self.assertEqual(response.data['output'], 'редким синим слонам')
|
||||||
self.assertEqual(len(response.data['refs']), 2)
|
self.assertEqual(len(response.data['refs']), 2)
|
||||||
|
@ -188,13 +188,19 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-create', method='post')
|
@decl_endpoint('/api/rsforms/{item}/cst-create', method='post')
|
||||||
def test_create_constituenta(self):
|
def test_create_constituenta(self):
|
||||||
data = {'alias': 'X3', 'cst_type': CstType.BASE}
|
data = {'alias': 'X3'}
|
||||||
self.executeForbidden(data, item=self.unowned_id)
|
self.executeForbidden(data=data, item=self.unowned_id)
|
||||||
|
|
||||||
self.owned.insert_new('X1')
|
self.owned.insert_new('X1')
|
||||||
x2 = self.owned.insert_new('X2')
|
x2 = self.owned.insert_new('X2')
|
||||||
|
self.executeBadData(item=self.owned_id)
|
||||||
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
response = self.executeCreated(data, item=self.owned_id)
|
data['cst_type'] = 'invalid'
|
||||||
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
|
data['cst_type'] = CstType.BASE
|
||||||
|
response = self.executeCreated(data=data, item=self.owned_id)
|
||||||
self.assertEqual(response.data['new_cst']['alias'], 'X3')
|
self.assertEqual(response.data['new_cst']['alias'], 'X3')
|
||||||
x3 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
|
x3 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
|
||||||
self.assertEqual(x3.order, 3)
|
self.assertEqual(x3.order, 3)
|
||||||
|
@ -206,7 +212,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'term_raw': 'test',
|
'term_raw': 'test',
|
||||||
'term_forms': [{'text': 'form1', 'tags': 'sing,datv'}]
|
'term_forms': [{'text': 'form1', 'tags': 'sing,datv'}]
|
||||||
}
|
}
|
||||||
response = self.executeCreated(data, item=self.owned_id)
|
response = self.executeCreated(data=data, item=self.owned_id)
|
||||||
self.assertEqual(response.data['new_cst']['alias'], data['alias'])
|
self.assertEqual(response.data['new_cst']['alias'], data['alias'])
|
||||||
x4 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
|
x4 = Constituenta.objects.get(alias=response.data['new_cst']['alias'])
|
||||||
self.assertEqual(x4.order, 3)
|
self.assertEqual(x4.order, 3)
|
||||||
|
@ -233,14 +239,14 @@ class TestRSFormViewset(EndpointTester):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {'target': x2_2.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
|
data = {'target': x2_2.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
|
||||||
self.executeForbidden(data, item=self.unowned_id)
|
self.executeForbidden(data=data, item=self.unowned_id)
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
data = {'target': x1.pk, 'alias': x1.alias, 'cst_type': CstType.TERM}
|
data = {'target': x1.pk, 'alias': x1.alias, 'cst_type': CstType.TERM}
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
data = {'target': x1.pk, 'alias': x3.alias}
|
data = {'target': x1.pk, 'alias': x3.alias}
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
d1 = self.owned.insert_new(
|
d1 = self.owned.insert_new(
|
||||||
alias='D1',
|
alias='D1',
|
||||||
|
@ -252,7 +258,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
self.assertEqual(x1.cst_type, CstType.BASE)
|
self.assertEqual(x1.cst_type, CstType.BASE)
|
||||||
|
|
||||||
data = {'target': x1.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
|
data = {'target': x1.pk, 'alias': 'D2', 'cst_type': CstType.TERM}
|
||||||
response = self.executeOK(data, item=self.owned_id)
|
response = self.executeOK(data=data, item=self.owned_id)
|
||||||
self.assertEqual(response.data['new_cst']['alias'], 'D2')
|
self.assertEqual(response.data['new_cst']['alias'], 'D2')
|
||||||
self.assertEqual(response.data['new_cst']['cst_type'], CstType.TERM)
|
self.assertEqual(response.data['new_cst']['cst_type'], CstType.TERM)
|
||||||
d1.refresh_from_db()
|
d1.refresh_from_db()
|
||||||
|
@ -279,14 +285,14 @@ class TestRSFormViewset(EndpointTester):
|
||||||
unowned = self.unowned.insert_new('X2')
|
unowned = self.unowned.insert_new('X2')
|
||||||
|
|
||||||
data = {'substitutions': [{'original': x1.pk, 'substitution': unowned.pk, 'transfer_term': True}]}
|
data = {'substitutions': [{'original': x1.pk, 'substitution': unowned.pk, 'transfer_term': True}]}
|
||||||
self.executeForbidden(data, item=self.unowned_id)
|
self.executeForbidden(data=data, item=self.unowned_id)
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
data = {'substitutions': [{'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True}]}
|
data = {'substitutions': [{'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True}]}
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
data = {'substitutions': [{'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True}]}
|
data = {'substitutions': [{'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True}]}
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
d1 = self.owned.insert_new(
|
d1 = self.owned.insert_new(
|
||||||
alias='D1',
|
alias='D1',
|
||||||
|
@ -294,7 +300,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
definition_formal='X1'
|
definition_formal='X1'
|
||||||
)
|
)
|
||||||
data = {'substitutions': [{'original': x1.pk, 'substitution': x2.pk, 'transfer_term': True}]}
|
data = {'substitutions': [{'original': x1.pk, 'substitution': x2.pk, 'transfer_term': True}]}
|
||||||
response = self.executeOK(data, item=self.owned_id)
|
response = self.executeOK(data=data, item=self.owned_id)
|
||||||
d1.refresh_from_db()
|
d1.refresh_from_db()
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
self.assertEqual(x2.term_raw, 'Test1')
|
self.assertEqual(x2.term_raw, 'Test1')
|
||||||
|
@ -314,7 +320,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {'substitutions': []}
|
data = {'substitutions': []}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {'substitutions': [
|
data = {'substitutions': [
|
||||||
{
|
{
|
||||||
|
@ -328,7 +334,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'transfer_term': True
|
'transfer_term': True
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {'substitutions': [
|
data = {'substitutions': [
|
||||||
{
|
{
|
||||||
|
@ -342,7 +348,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'transfer_term': True
|
'transfer_term': True
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
response = self.executeOK(data, item=self.owned_id)
|
response = self.executeOK(data=data, item=self.owned_id)
|
||||||
d3.refresh_from_db()
|
d3.refresh_from_db()
|
||||||
self.assertEqual(d3.definition_formal, r'D1 \ D2')
|
self.assertEqual(d3.definition_formal, r'D1 \ D2')
|
||||||
|
|
||||||
|
@ -357,7 +363,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'definition_formal': '3',
|
'definition_formal': '3',
|
||||||
'definition_raw': '4'
|
'definition_raw': '4'
|
||||||
}
|
}
|
||||||
response = self.executeCreated(data, item=self.owned_id)
|
response = self.executeCreated(data=data, item=self.owned_id)
|
||||||
self.assertEqual(response.data['new_cst']['alias'], 'X3')
|
self.assertEqual(response.data['new_cst']['alias'], 'X3')
|
||||||
self.assertEqual(response.data['new_cst']['cst_type'], CstType.BASE)
|
self.assertEqual(response.data['new_cst']['cst_type'], CstType.BASE)
|
||||||
self.assertEqual(response.data['new_cst']['convention'], '1')
|
self.assertEqual(response.data['new_cst']['convention'], '1')
|
||||||
|
@ -373,13 +379,13 @@ class TestRSFormViewset(EndpointTester):
|
||||||
self.set_params(item=self.owned_id)
|
self.set_params(item=self.owned_id)
|
||||||
|
|
||||||
data = {'items': [1337]}
|
data = {'items': [1337]}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
x1 = self.owned.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
x2 = self.owned.insert_new('X2')
|
x2 = self.owned.insert_new('X2')
|
||||||
|
|
||||||
data = {'items': [x1.pk]}
|
data = {'items': [x1.pk]}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
self.owned.item.refresh_from_db()
|
self.owned.item.refresh_from_db()
|
||||||
self.assertEqual(len(response.data['items']), 1)
|
self.assertEqual(len(response.data['items']), 1)
|
||||||
|
@ -389,7 +395,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
x3 = self.unowned.insert_new('X1')
|
x3 = self.unowned.insert_new('X1')
|
||||||
data = {'items': [x3.pk]}
|
data = {'items': [x3.pk]}
|
||||||
self.executeBadData(data, item=self.owned_id)
|
self.executeBadData(data=data, item=self.owned_id)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-moveto', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-moveto', method='patch')
|
||||||
|
@ -397,13 +403,13 @@ class TestRSFormViewset(EndpointTester):
|
||||||
self.set_params(item=self.owned_id)
|
self.set_params(item=self.owned_id)
|
||||||
|
|
||||||
data = {'items': [1337], 'move_to': 1}
|
data = {'items': [1337], 'move_to': 1}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
x1 = self.owned.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
x2 = self.owned.insert_new('X2')
|
x2 = self.owned.insert_new('X2')
|
||||||
|
|
||||||
data = {'items': [x2.pk], 'move_to': 1}
|
data = {'items': [x2.pk], 'move_to': 1}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
x1.refresh_from_db()
|
x1.refresh_from_db()
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
self.assertEqual(response.data['id'], self.owned_id)
|
self.assertEqual(response.data['id'], self.owned_id)
|
||||||
|
@ -412,7 +418,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
x3 = self.unowned.insert_new('X1')
|
x3 = self.unowned.insert_new('X1')
|
||||||
data = {'items': [x3.pk], 'move_to': 1}
|
data = {'items': [x3.pk], 'move_to': 1}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/reset-aliases', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/reset-aliases', method='patch')
|
||||||
|
|
|
@ -8,30 +8,30 @@ class TestRSLanguageViews(EndpointTester):
|
||||||
@decl_endpoint('/api/rslang/to-ascii', method='post')
|
@decl_endpoint('/api/rslang/to-ascii', method='post')
|
||||||
def test_convert_to_ascii(self):
|
def test_convert_to_ascii(self):
|
||||||
data = {'data': '1=1'}
|
data = {'data': '1=1'}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {'expression': '1=1'}
|
data = {'expression': '1=1'}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self.assertEqual(response.data['result'], r'1 \eq 1')
|
self.assertEqual(response.data['result'], r'1 \eq 1')
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rslang/to-math', method='post')
|
@decl_endpoint('/api/rslang/to-math', method='post')
|
||||||
def test_convert_to_math(self):
|
def test_convert_to_math(self):
|
||||||
data = {'data': r'1 \eq 1'}
|
data = {'data': r'1 \eq 1'}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {'expression': r'1 \eq 1'}
|
data = {'expression': r'1 \eq 1'}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self.assertEqual(response.data['result'], r'1=1')
|
self.assertEqual(response.data['result'], r'1=1')
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rslang/parse-expression', method='post')
|
@decl_endpoint('/api/rslang/parse-expression', method='post')
|
||||||
def test_parse_expression(self):
|
def test_parse_expression(self):
|
||||||
data = {'data': r'1=1'}
|
data = {'data': r'1=1'}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {'expression': r'1=1'}
|
data = {'expression': r'1=1'}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self.assertEqual(response.data['parseResult'], True)
|
self.assertEqual(response.data['parseResult'], True)
|
||||||
self.assertEqual(response.data['syntax'], 'math')
|
self.assertEqual(response.data['syntax'], 'math')
|
||||||
self.assertEqual(response.data['astText'], '[=[1][1]]')
|
self.assertEqual(response.data['astText'], '[=[1][1]]')
|
||||||
|
|
|
@ -30,11 +30,11 @@ class TestVersionViews(EndpointTester):
|
||||||
invalid_id = 1338
|
invalid_id = 1338
|
||||||
data = {'version': '1.0.0', 'description': 'test'}
|
data = {'version': '1.0.0', 'description': 'test'}
|
||||||
|
|
||||||
self.executeNotFound(data, schema=invalid_id)
|
self.executeNotFound(data=data, schema=invalid_id)
|
||||||
self.executeForbidden(data, schema=self.unowned.pk)
|
self.executeForbidden(data=data, schema=self.unowned.pk)
|
||||||
self.executeBadData(invalid_data, schema=self.owned.pk)
|
self.executeBadData(data=invalid_data, schema=self.owned.pk)
|
||||||
|
|
||||||
response = self.executeCreated(data, schema=self.owned.pk)
|
response = self.executeCreated(data=data, schema=self.owned.pk)
|
||||||
self.assertTrue('version' in response.data)
|
self.assertTrue('version' in response.data)
|
||||||
self.assertTrue('schema' in response.data)
|
self.assertTrue('schema' in response.data)
|
||||||
self.assertTrue(response.data['version'] in [v['id'] for v in response.data['schema']['versions']])
|
self.assertTrue(response.data['version'] in [v['id'] for v in response.data['schema']['versions']])
|
||||||
|
@ -64,7 +64,7 @@ class TestVersionViews(EndpointTester):
|
||||||
@decl_endpoint('/api/versions/{version}', method='get')
|
@decl_endpoint('/api/versions/{version}', method='get')
|
||||||
def test_access_version(self):
|
def test_access_version(self):
|
||||||
data = {'version': '1.0.0', 'description': 'test'}
|
data = {'version': '1.0.0', 'description': 'test'}
|
||||||
version_id = self._create_version(data)
|
version_id = self._create_version(data=data)
|
||||||
invalid_id = version_id + 1337
|
invalid_id = version_id + 1337
|
||||||
|
|
||||||
self.executeNotFound(version=invalid_id)
|
self.executeNotFound(version=invalid_id)
|
||||||
|
@ -78,14 +78,14 @@ class TestVersionViews(EndpointTester):
|
||||||
|
|
||||||
data = {'version': '1.2.0', 'description': 'test1'}
|
data = {'version': '1.2.0', 'description': 'test1'}
|
||||||
self.method = 'patch'
|
self.method = 'patch'
|
||||||
self.executeForbidden(data)
|
self.executeForbidden(data=data)
|
||||||
|
|
||||||
self.method = 'delete'
|
self.method = 'delete'
|
||||||
self.executeForbidden()
|
self.executeForbidden()
|
||||||
|
|
||||||
self.client.force_authenticate(user=self.user)
|
self.client.force_authenticate(user=self.user)
|
||||||
self.method = 'patch'
|
self.method = 'patch'
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
response = self.get()
|
response = self.get()
|
||||||
self.assertEqual(response.data['version'], data['version'])
|
self.assertEqual(response.data['version'], data['version'])
|
||||||
self.assertEqual(response.data['description'], data['description'])
|
self.assertEqual(response.data['description'], data['description'])
|
||||||
|
@ -138,7 +138,7 @@ class TestVersionViews(EndpointTester):
|
||||||
x2 = self.schema.insert_new('X2')
|
x2 = self.schema.insert_new('X2')
|
||||||
d1 = self.schema.insert_new('D1', term_raw='TestTerm')
|
d1 = self.schema.insert_new('D1', term_raw='TestTerm')
|
||||||
data = {'version': '1.0.0', 'description': 'test'}
|
data = {'version': '1.0.0', 'description': 'test'}
|
||||||
version_id = self._create_version(data)
|
version_id = self._create_version(data=data)
|
||||||
invalid_id = version_id + 1337
|
invalid_id = version_id + 1337
|
||||||
|
|
||||||
d1.delete()
|
d1.delete()
|
||||||
|
|
|
@ -43,17 +43,27 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
if self.action in ['update', 'partial_update']:
|
if self.action in ['update', 'partial_update']:
|
||||||
permission_list = [permissions.ItemEditor]
|
access_level = permissions.ItemEditor
|
||||||
elif self.action in [
|
elif self.action in [
|
||||||
'destroy', 'set_owner', 'set_access_policy', 'set_location',
|
'destroy',
|
||||||
'editors_add', 'editors_remove', 'editors_set'
|
'set_owner',
|
||||||
|
'set_access_policy',
|
||||||
|
'set_location',
|
||||||
|
'editors_add',
|
||||||
|
'editors_remove',
|
||||||
|
'editors_set'
|
||||||
]:
|
]:
|
||||||
permission_list = [permissions.ItemOwner]
|
access_level = permissions.ItemOwner
|
||||||
elif self.action in ['create', 'clone', 'subscribe', 'unsubscribe']:
|
elif self.action in [
|
||||||
permission_list = [permissions.GlobalUser]
|
'create',
|
||||||
|
'clone',
|
||||||
|
'subscribe',
|
||||||
|
'unsubscribe'
|
||||||
|
]:
|
||||||
|
access_level = permissions.GlobalUser
|
||||||
else:
|
else:
|
||||||
permission_list = [permissions.ItemAnyone]
|
access_level = permissions.ItemAnyone
|
||||||
return [permission() for permission in permission_list]
|
return [access_level()]
|
||||||
|
|
||||||
def _get_item(self) -> m.LibraryItem:
|
def _get_item(self) -> m.LibraryItem:
|
||||||
return cast(m.LibraryItem, self.get_object())
|
return cast(m.LibraryItem, self.get_object())
|
||||||
|
@ -69,7 +79,6 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
|
||||||
@action(detail=True, methods=['post'], url_path='clone')
|
@action(detail=True, methods=['post'], url_path='clone')
|
||||||
def clone(self, request: Request, pk):
|
def clone(self, request: Request, pk):
|
||||||
''' Endpoint: Create deep copy of library item. '''
|
''' Endpoint: Create deep copy of library item. '''
|
||||||
|
@ -86,8 +95,9 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
clone.read_only = False
|
clone.read_only = False
|
||||||
clone.access_policy = serializer.validated_data.get('access_policy', m.AccessPolicy.PUBLIC)
|
clone.access_policy = serializer.validated_data.get('access_policy', m.AccessPolicy.PUBLIC)
|
||||||
clone.location = serializer.validated_data.get('location', m.LocationHead.USER)
|
clone.location = serializer.validated_data.get('location', m.LocationHead.USER)
|
||||||
clone.save()
|
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
clone.save()
|
||||||
if clone.item_type == m.LibraryItemType.RSFORM:
|
if clone.item_type == m.LibraryItemType.RSFORM:
|
||||||
need_filter = 'items' in request.data
|
need_filter = 'items' in request.data
|
||||||
for cst in m.RSForm(item).constituents():
|
for cst in m.RSForm(item).constituents():
|
||||||
|
@ -267,24 +277,17 @@ class LibraryActiveView(generics.ListAPIView):
|
||||||
serializer_class = s.LibraryItemSerializer
|
serializer_class = s.LibraryItemSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
common_location = Q(location__startswith=m.LocationHead.COMMON) | Q(location__startswith=m.LocationHead.LIBRARY)
|
||||||
|
is_public = Q(access_policy=m.AccessPolicy.PUBLIC)
|
||||||
if self.request.user.is_anonymous:
|
if self.request.user.is_anonymous:
|
||||||
return m.LibraryItem.objects.filter(
|
return m.LibraryItem.objects \
|
||||||
Q(access_policy=m.AccessPolicy.PUBLIC),
|
.filter(is_public) \
|
||||||
).filter(
|
.filter(common_location).order_by('-time_update')
|
||||||
Q(location__startswith=m.LocationHead.COMMON) |
|
|
||||||
Q(location__startswith=m.LocationHead.LIBRARY)
|
|
||||||
).order_by('-time_update')
|
|
||||||
else:
|
else:
|
||||||
user = cast(m.User, self.request.user)
|
user = cast(m.User, self.request.user)
|
||||||
# pylint: disable=unsupported-binary-operation
|
# pylint: disable=unsupported-binary-operation
|
||||||
return m.LibraryItem.objects.filter(
|
return m.LibraryItem.objects.filter(
|
||||||
(
|
(is_public & common_location) |
|
||||||
Q(access_policy=m.AccessPolicy.PUBLIC) &
|
|
||||||
(
|
|
||||||
Q(location__startswith=m.LocationHead.COMMON) |
|
|
||||||
Q(location__startswith=m.LocationHead.LIBRARY)
|
|
||||||
)
|
|
||||||
) |
|
|
||||||
Q(owner=user) |
|
Q(owner=user) |
|
||||||
Q(editor__editor=user) |
|
Q(editor__editor=user) |
|
||||||
Q(subscription__user=user)
|
Q(subscription__user=user)
|
||||||
|
|
|
@ -18,7 +18,6 @@ from .. import serializers as s
|
||||||
request=s.InlineSynthesisSerializer,
|
request=s.InlineSynthesisSerializer,
|
||||||
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
|
||||||
@api_view(['PATCH'])
|
@api_view(['PATCH'])
|
||||||
def inline_synthesis(request: Request):
|
def inline_synthesis(request: Request):
|
||||||
''' Endpoint: Inline synthesis. '''
|
''' Endpoint: Inline synthesis. '''
|
||||||
|
@ -30,8 +29,9 @@ def inline_synthesis(request: Request):
|
||||||
|
|
||||||
schema = m.RSForm(serializer.validated_data['receiver'])
|
schema = m.RSForm(serializer.validated_data['receiver'])
|
||||||
items = cast(list[m.Constituenta], serializer.validated_data['items'])
|
items = cast(list[m.Constituenta], serializer.validated_data['items'])
|
||||||
new_items = schema.insert_copy(items)
|
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
new_items = schema.insert_copy(items)
|
||||||
for substitution in serializer.validated_data['substitutions']:
|
for substitution in serializer.validated_data['substitutions']:
|
||||||
original = cast(m.Constituenta, substitution['original'])
|
original = cast(m.Constituenta, substitution['original'])
|
||||||
replacement = cast(m.Constituenta, substitution['substitution'])
|
replacement = cast(m.Constituenta, substitution['substitution'])
|
||||||
|
@ -42,8 +42,8 @@ def inline_synthesis(request: Request):
|
||||||
index = next(i for (i, cst) in enumerate(items) if cst == replacement)
|
index = next(i for (i, cst) in enumerate(items) if cst == replacement)
|
||||||
replacement = new_items[index]
|
replacement = new_items[index]
|
||||||
schema.substitute(original, replacement, substitution['transfer_term'])
|
schema.substitute(original, replacement, substitution['transfer_term'])
|
||||||
|
|
||||||
schema.restore_order()
|
schema.restore_order()
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data=s.RSFormParseSerializer(schema.item).data
|
data=s.RSFormParseSerializer(schema.item).data
|
||||||
|
|
|
@ -34,11 +34,21 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
''' Determine permission class. '''
|
''' Determine permission class. '''
|
||||||
if self.action in [
|
if self.action in [
|
||||||
'load_trs', 'cst_create', 'cst_delete_multiple',
|
'load_trs',
|
||||||
'reset_aliases', 'cst_rename', 'cst_substitute'
|
'reset_aliases',
|
||||||
|
'cst_create',
|
||||||
|
'cst_delete_multiple',
|
||||||
|
'cst_rename',
|
||||||
|
'cst_substitute'
|
||||||
]:
|
]:
|
||||||
permission_list = [permissions.ItemEditor]
|
permission_list = [permissions.ItemEditor]
|
||||||
elif self.action in ['contents', 'details', 'export_trs', 'resolve', 'check']:
|
elif self.action in [
|
||||||
|
'contents',
|
||||||
|
'details',
|
||||||
|
'export_trs',
|
||||||
|
'resolve',
|
||||||
|
'check'
|
||||||
|
]:
|
||||||
permission_list = [permissions.ItemAnyone]
|
permission_list = [permissions.ItemAnyone]
|
||||||
else:
|
else:
|
||||||
permission_list = [permissions.Anyone]
|
permission_list = [permissions.Anyone]
|
||||||
|
@ -50,6 +60,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.CstCreateSerializer,
|
request=s.CstCreateSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_201_CREATED: s.NewCstResponse,
|
c.HTTP_201_CREATED: s.NewCstResponse,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
|
@ -87,6 +98,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.CstTargetSerializer,
|
request=s.CstTargetSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_200_OK: s.NewMultiCstResponse,
|
c.HTTP_200_OK: s.NewMultiCstResponse,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
|
@ -123,11 +135,11 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.CstRenameSerializer,
|
request=s.CstRenameSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_200_OK: s.NewCstResponse,
|
c.HTTP_200_OK: s.NewCstResponse,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
|
||||||
@action(detail=True, methods=['patch'], url_path='cst-rename')
|
@action(detail=True, methods=['patch'], url_path='cst-rename')
|
||||||
def cst_rename(self, request: Request, pk):
|
def cst_rename(self, request: Request, pk):
|
||||||
''' Rename constituenta possibly changing type. '''
|
''' Rename constituenta possibly changing type. '''
|
||||||
|
@ -140,10 +152,10 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
|
|
||||||
cst.alias = serializer.validated_data['alias']
|
cst.alias = serializer.validated_data['alias']
|
||||||
cst.cst_type = serializer.validated_data['cst_type']
|
cst.cst_type = serializer.validated_data['cst_type']
|
||||||
cst.save()
|
|
||||||
|
|
||||||
mapping = {old_alias: cst.alias}
|
with transaction.atomic():
|
||||||
schema.apply_mapping(mapping, change_aliases=False)
|
cst.save()
|
||||||
|
schema.apply_mapping(mapping={old_alias: cst.alias}, change_aliases=False)
|
||||||
schema.item.refresh_from_db()
|
schema.item.refresh_from_db()
|
||||||
cst.refresh_from_db()
|
cst.refresh_from_db()
|
||||||
|
|
||||||
|
@ -161,11 +173,11 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.CstSubstituteSerializer,
|
request=s.CstSubstituteSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_200_OK: s.RSFormParseSerializer,
|
c.HTTP_200_OK: s.RSFormParseSerializer,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
|
||||||
@action(detail=True, methods=['patch'], url_path='cst-substitute')
|
@action(detail=True, methods=['patch'], url_path='cst-substitute')
|
||||||
def cst_substitute(self, request: Request, pk):
|
def cst_substitute(self, request: Request, pk):
|
||||||
''' Substitute occurrences of constituenta with another one. '''
|
''' Substitute occurrences of constituenta with another one. '''
|
||||||
|
@ -175,6 +187,8 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
context={'schema': schema.item}
|
context={'schema': schema.item}
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
for substitution in serializer.validated_data['substitutions']:
|
for substitution in serializer.validated_data['substitutions']:
|
||||||
original = cast(m.Constituenta, substitution['original'])
|
original = cast(m.Constituenta, substitution['original'])
|
||||||
replacement = cast(m.Constituenta, substitution['substitution'])
|
replacement = cast(m.Constituenta, substitution['substitution'])
|
||||||
|
@ -191,6 +205,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.CstListSerializer,
|
request=s.CstListSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_200_OK: s.RSFormParseSerializer,
|
c.HTTP_200_OK: s.RSFormParseSerializer,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
|
@ -217,6 +232,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.CstMoveSerializer,
|
request=s.CstMoveSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_200_OK: s.RSFormParseSerializer,
|
c.HTTP_200_OK: s.RSFormParseSerializer,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
|
@ -285,6 +301,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
request=s.RSFormUploadSerializer,
|
request=s.RSFormUploadSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_200_OK: s.RSFormParseSerializer,
|
c.HTTP_200_OK: s.RSFormParseSerializer,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ class VersionViewset(
|
||||||
request=s.VersionCreateSerializer,
|
request=s.VersionCreateSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_201_CREATED: s.NewVersionResponse,
|
c.HTTP_201_CREATED: s.NewVersionResponse,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None,
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,15 @@ class TestUserAPIViews(EndpointTester):
|
||||||
def test_login(self):
|
def test_login(self):
|
||||||
self.logout()
|
self.logout()
|
||||||
data = {'username': self.user.username, 'password': 'invalid'}
|
data = {'username': self.user.username, 'password': 'invalid'}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {'username': self.user.username, 'password': 'password'}
|
data = {'username': self.user.username, 'password': 'password'}
|
||||||
self.executeAccepted(data)
|
self.executeAccepted(data=data)
|
||||||
self.executeAccepted(data)
|
self.executeAccepted(data=data)
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
data = {'username': self.user.email, 'password': 'password'}
|
data = {'username': self.user.email, 'password': 'password'}
|
||||||
self.executeAccepted(data)
|
self.executeAccepted(data=data)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/users/api/logout', method='post')
|
@decl_endpoint('/users/api/logout', method='post')
|
||||||
|
@ -84,7 +84,7 @@ class TestUserUserProfileAPIView(EndpointTester):
|
||||||
'first_name': 'firstName',
|
'first_name': 'firstName',
|
||||||
'last_name': 'lastName',
|
'last_name': 'lastName',
|
||||||
}
|
}
|
||||||
response = self.executeOK(data)
|
response = self.executeOK(data=data)
|
||||||
self.user.refresh_from_db()
|
self.user.refresh_from_db()
|
||||||
self.assertEqual(response.data['email'], '123@mail.ru')
|
self.assertEqual(response.data['email'], '123@mail.ru')
|
||||||
self.assertEqual(self.user.email, '123@mail.ru')
|
self.assertEqual(self.user.email, '123@mail.ru')
|
||||||
|
@ -98,10 +98,10 @@ class TestUserUserProfileAPIView(EndpointTester):
|
||||||
'first_name': 'new',
|
'first_name': 'new',
|
||||||
'last_name': 'new2',
|
'last_name': 'new2',
|
||||||
}
|
}
|
||||||
self.executeOK(data)
|
self.executeOK(data=data)
|
||||||
|
|
||||||
data = {'email': self.user2.email}
|
data = {'email': self.user2.email}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
self.executeForbidden()
|
self.executeForbidden()
|
||||||
|
@ -113,14 +113,14 @@ class TestUserUserProfileAPIView(EndpointTester):
|
||||||
'old_password': 'invalid',
|
'old_password': 'invalid',
|
||||||
'new_password': 'password2'
|
'new_password': 'password2'
|
||||||
}
|
}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'old_password': 'password',
|
'old_password': 'password',
|
||||||
'new_password': 'password2'
|
'new_password': 'password2'
|
||||||
}
|
}
|
||||||
oldHash = self.user.password
|
oldHash = self.user.password
|
||||||
response = self.executeNoContent(data)
|
response = self.executeNoContent(data=data)
|
||||||
self.user.refresh_from_db()
|
self.user.refresh_from_db()
|
||||||
self.assertNotEqual(self.user.password, oldHash)
|
self.assertNotEqual(self.user.password, oldHash)
|
||||||
self.assertTrue(self.client.login(username=self.user.username, password='password2'))
|
self.assertTrue(self.client.login(username=self.user.username, password='password2'))
|
||||||
|
@ -154,7 +154,7 @@ class TestSignupAPIView(EndpointTester):
|
||||||
'first_name': 'firstName',
|
'first_name': 'firstName',
|
||||||
'last_name': 'lastName'
|
'last_name': 'lastName'
|
||||||
}
|
}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'username': 'NewUser',
|
'username': 'NewUser',
|
||||||
|
@ -164,7 +164,7 @@ class TestSignupAPIView(EndpointTester):
|
||||||
'first_name': 'firstName',
|
'first_name': 'firstName',
|
||||||
'last_name': 'lastName'
|
'last_name': 'lastName'
|
||||||
}
|
}
|
||||||
response = self.executeCreated(data)
|
response = self.executeCreated(data=data)
|
||||||
self.assertTrue('id' in response.data)
|
self.assertTrue('id' in response.data)
|
||||||
self.assertEqual(response.data['username'], data['username'])
|
self.assertEqual(response.data['username'], data['username'])
|
||||||
self.assertEqual(response.data['email'], data['email'])
|
self.assertEqual(response.data['email'], data['email'])
|
||||||
|
@ -179,7 +179,7 @@ class TestSignupAPIView(EndpointTester):
|
||||||
'first_name': 'firstName',
|
'first_name': 'firstName',
|
||||||
'last_name': 'lastName'
|
'last_name': 'lastName'
|
||||||
}
|
}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'username': 'NewUser2',
|
'username': 'NewUser2',
|
||||||
|
@ -189,4 +189,4 @@ class TestSignupAPIView(EndpointTester):
|
||||||
'first_name': 'firstName',
|
'first_name': 'firstName',
|
||||||
'last_name': 'lastName'
|
'last_name': 'lastName'
|
||||||
}
|
}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data=data)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, Spec
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin', admin.site.urls),
|
path('admin', admin.site.urls),
|
||||||
path('api/', include('apps.rsform.urls')),
|
path('api/', include('apps.rsform.urls')),
|
||||||
|
path('api/', include('apps.oss.urls')),
|
||||||
path('users/', include('apps.users.urls')),
|
path('users/', include('apps.users.urls')),
|
||||||
path('schema', SpectacularAPIView.as_view(), name='schema'),
|
path('schema', SpectacularAPIView.as_view(), name='schema'),
|
||||||
path('redoc', SpectacularRedocView.as_view()),
|
path('redoc', SpectacularRedocView.as_view()),
|
||||||
|
|
|
@ -11,6 +11,7 @@ from rest_framework.permissions import \
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from apps.oss.models import Operation
|
||||||
from apps.rsform.models import (
|
from apps.rsform.models import (
|
||||||
AccessPolicy,
|
AccessPolicy,
|
||||||
Constituenta,
|
Constituenta,
|
||||||
|
@ -27,6 +28,8 @@ def _extract_item(obj: Any) -> LibraryItem:
|
||||||
return obj
|
return obj
|
||||||
elif isinstance(obj, Constituenta):
|
elif isinstance(obj, Constituenta):
|
||||||
return cast(LibraryItem, obj.schema)
|
return cast(LibraryItem, obj.schema)
|
||||||
|
elif isinstance(obj, Operation):
|
||||||
|
return cast(LibraryItem, obj.oss)
|
||||||
elif isinstance(obj, (Version, Subscription, Editor)):
|
elif isinstance(obj, (Version, Subscription, Editor)):
|
||||||
return cast(LibraryItem, obj.item)
|
return cast(LibraryItem, obj.item)
|
||||||
raise PermissionDenied({
|
raise PermissionDenied({
|
||||||
|
|
Loading…
Reference in New Issue
Block a user