mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Add OSS creation and fix access policy implementation
This commit is contained in:
parent
93d56ef4fa
commit
9e02d809a0
|
@ -60,3 +60,7 @@ def invalidPosition():
|
||||||
|
|
||||||
def constituentaNoStructure():
|
def constituentaNoStructure():
|
||||||
return 'Указанная конституента не обладает теоретико-множественной типизацией'
|
return 'Указанная конституента не обладает теоретико-множественной типизацией'
|
||||||
|
|
||||||
|
|
||||||
|
def missingFile():
|
||||||
|
return 'Отсутствует прикрепленный файл'
|
||||||
|
|
|
@ -57,6 +57,8 @@ class ItemEditor(ItemOwner):
|
||||||
''' Item permission: Editor or higher. '''
|
''' Item permission: Editor or higher. '''
|
||||||
|
|
||||||
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
||||||
|
if request.user.is_anonymous:
|
||||||
|
return False
|
||||||
item = _extract_item(obj)
|
item = _extract_item(obj)
|
||||||
if m.Editor.objects.filter(
|
if m.Editor.objects.filter(
|
||||||
item=item,
|
item=item,
|
||||||
|
@ -69,6 +71,9 @@ class ItemEditor(ItemOwner):
|
||||||
class ItemAnyone(ItemEditor):
|
class ItemAnyone(ItemEditor):
|
||||||
''' Item permission: Anyone if public. '''
|
''' Item permission: Anyone if public. '''
|
||||||
|
|
||||||
|
def has_permission(self, request: Request, view: APIView) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
||||||
item = _extract_item(obj)
|
item = _extract_item(obj)
|
||||||
if item.access_policy == m.AccessPolicy.PUBLIC:
|
if item.access_policy == m.AccessPolicy.PUBLIC:
|
||||||
|
|
|
@ -20,7 +20,7 @@ from .data_access import (
|
||||||
CstSubstituteSerializer,
|
CstSubstituteSerializer,
|
||||||
CstTargetSerializer,
|
CstTargetSerializer,
|
||||||
InlineSynthesisSerializer,
|
InlineSynthesisSerializer,
|
||||||
LibraryItemBase,
|
LibraryItemBaseSerializer,
|
||||||
LibraryItemCloneSerializer,
|
LibraryItemCloneSerializer,
|
||||||
LibraryItemSerializer,
|
LibraryItemSerializer,
|
||||||
RSFormParseSerializer,
|
RSFormParseSerializer,
|
||||||
|
|
|
@ -13,13 +13,13 @@ from .basics import CstParseSerializer
|
||||||
from .io_pyconcept import PyConceptAdapter
|
from .io_pyconcept import PyConceptAdapter
|
||||||
|
|
||||||
|
|
||||||
class LibraryItemBase(serializers.ModelSerializer):
|
class LibraryItemBaseSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: LibraryItem entry full access. '''
|
''' Serializer: LibraryItem entry full access. '''
|
||||||
class Meta:
|
class Meta:
|
||||||
''' serializer metadata. '''
|
''' serializer metadata. '''
|
||||||
model = LibraryItem
|
model = LibraryItem
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
read_only_fields = ('id', 'item_type')
|
read_only_fields = ('id',)
|
||||||
|
|
||||||
|
|
||||||
class LibraryItemSerializer(serializers.ModelSerializer):
|
class LibraryItemSerializer(serializers.ModelSerializer):
|
||||||
|
@ -31,6 +31,16 @@ class LibraryItemSerializer(serializers.ModelSerializer):
|
||||||
read_only_fields = ('id', 'item_type', 'owner', 'location', 'access_policy')
|
read_only_fields = ('id', 'item_type', 'owner', 'location', 'access_policy')
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryItemCloneSerializer(serializers.ModelSerializer):
|
||||||
|
''' Serializer: LibraryItem cloning. '''
|
||||||
|
items = PKField(many=True, required=False, queryset=Constituenta.objects.all())
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
''' serializer metadata. '''
|
||||||
|
model = LibraryItem
|
||||||
|
exclude = ['id', 'item_type', 'owner']
|
||||||
|
|
||||||
|
|
||||||
class VersionSerializer(serializers.ModelSerializer):
|
class VersionSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: Version data. '''
|
''' Serializer: Version data. '''
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -220,7 +230,7 @@ class RSFormSerializer(serializers.ModelSerializer):
|
||||||
validated_data=new_cst.validated_data
|
validated_data=new_cst.validated_data
|
||||||
)
|
)
|
||||||
|
|
||||||
loaded_item = LibraryItemBase(data=data)
|
loaded_item = LibraryItemBaseSerializer(data=data)
|
||||||
loaded_item.is_valid(raise_exception=True)
|
loaded_item.is_valid(raise_exception=True)
|
||||||
loaded_item.update(
|
loaded_item.update(
|
||||||
instance=cast(LibraryItem, self.instance),
|
instance=cast(LibraryItem, self.instance),
|
||||||
|
@ -337,11 +347,6 @@ class CstListSerializer(serializers.Serializer):
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class LibraryItemCloneSerializer(LibraryItemBase):
|
|
||||||
''' Serializer: LibraryItem cloning. '''
|
|
||||||
items = PKField(many=True, required=False, queryset=Constituenta.objects.all())
|
|
||||||
|
|
||||||
|
|
||||||
class CstMoveSerializer(CstListSerializer):
|
class CstMoveSerializer(CstListSerializer):
|
||||||
''' Serializer: Change constituenta position. '''
|
''' Serializer: Change constituenta position. '''
|
||||||
move_to = serializers.IntegerField()
|
move_to = serializers.IntegerField()
|
||||||
|
|
|
@ -45,10 +45,28 @@ class TestLibraryViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/library', method='post')
|
@decl_endpoint('/api/library', method='post')
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
data = {'title': 'Title'}
|
data = {
|
||||||
|
'title': 'Title',
|
||||||
|
'alias': 'alias',
|
||||||
|
}
|
||||||
|
self.executeBadData(data)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'item_type': LibraryItemType.OPERATIONS_SCHEMA,
|
||||||
|
'title': 'Title',
|
||||||
|
'alias': 'alias',
|
||||||
|
'access_policy': AccessPolicy.PROTECTED,
|
||||||
|
'visible': False,
|
||||||
|
'read_only': True
|
||||||
|
}
|
||||||
response = self.executeCreated(data)
|
response = self.executeCreated(data)
|
||||||
self.assertEqual(response.data['title'], 'Title')
|
|
||||||
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['title'], data['title'])
|
||||||
|
self.assertEqual(response.data['alias'], data['alias'])
|
||||||
|
self.assertEqual(response.data['access_policy'], data['access_policy'])
|
||||||
|
self.assertEqual(response.data['visible'], data['visible'])
|
||||||
|
self.assertEqual(response.data['read_only'], data['read_only'])
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
data = {'title': 'Title2'}
|
data = {'title': 'Title2'}
|
||||||
|
@ -273,6 +291,16 @@ class TestLibraryViewset(EndpointTester):
|
||||||
self.assertFalse(response_contains(response, self.unowned))
|
self.assertFalse(response_contains(response, self.unowned))
|
||||||
self.assertFalse(response_contains(response, self.owned))
|
self.assertFalse(response_contains(response, self.owned))
|
||||||
|
|
||||||
|
@decl_endpoint('/api/library', method='get')
|
||||||
|
def test_library_get(self):
|
||||||
|
non_schema = LibraryItem.objects.create(
|
||||||
|
item_type=LibraryItemType.OPERATIONS_SCHEMA,
|
||||||
|
title='Test4'
|
||||||
|
)
|
||||||
|
response = self.executeOK()
|
||||||
|
self.assertTrue(response_contains(response, non_schema))
|
||||||
|
self.assertTrue(response_contains(response, self.unowned))
|
||||||
|
self.assertTrue(response_contains(response, self.owned))
|
||||||
|
|
||||||
@decl_endpoint('/api/library/all', method='get')
|
@decl_endpoint('/api/library/all', method='get')
|
||||||
def test_retrieve_all(self):
|
def test_retrieve_all(self):
|
||||||
|
|
|
@ -25,27 +25,17 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.schema = RSForm.create(title='Test', alias='T1', owner=self.user)
|
self.owned = RSForm.create(title='Test', alias='T1', owner=self.user)
|
||||||
self.schema_id = self.schema.item.pk
|
self.owned_id = self.owned.item.pk
|
||||||
self.unowned = RSForm.create(title='Test2', alias='T2')
|
self.unowned = RSForm.create(title='Test2', alias='T2')
|
||||||
self.unowned_id = self.unowned.item.pk
|
self.unowned_id = self.unowned.item.pk
|
||||||
|
self.private = RSForm.create(title='Test2', alias='T2', access_policy=AccessPolicy.PRIVATE)
|
||||||
|
self.private_id = self.private.item.pk
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/create-detailed', method='post')
|
@decl_endpoint('/api/rsforms/create-detailed', method='post')
|
||||||
def test_create_rsform_file(self):
|
def test_create_rsform_file(self):
|
||||||
work_dir = os.path.dirname(os.path.abspath(__file__))
|
work_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
|
|
||||||
data = {'file': file, 'title': 'Test123', 'comment': '123', 'alias': 'ks1'}
|
|
||||||
response = self.client.post(self.endpoint, data=data, format='multipart')
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
|
||||||
self.assertEqual(response.data['owner'], self.user.pk)
|
|
||||||
self.assertEqual(response.data['title'], 'Test123')
|
|
||||||
self.assertEqual(response.data['alias'], 'ks1')
|
|
||||||
self.assertEqual(response.data['comment'], '123')
|
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/create-detailed', method='post')
|
|
||||||
def test_create_rsform_json(self):
|
|
||||||
data = {
|
data = {
|
||||||
'title': 'Test123',
|
'title': 'Test123',
|
||||||
'comment': '123',
|
'comment': '123',
|
||||||
|
@ -54,17 +44,20 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'access_policy': AccessPolicy.PROTECTED,
|
'access_policy': AccessPolicy.PROTECTED,
|
||||||
'visible': False
|
'visible': False
|
||||||
}
|
}
|
||||||
response = self.executeCreated(data)
|
self.executeBadData(data)
|
||||||
|
|
||||||
|
with open(f'{work_dir}/data/sample-rsform.trs', 'rb') as file:
|
||||||
|
data['file'] = file
|
||||||
|
response = self.client.post(self.endpoint, data=data, format='multipart')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
self.assertEqual(response.data['owner'], self.user.pk)
|
self.assertEqual(response.data['owner'], self.user.pk)
|
||||||
self.assertEqual(response.data['title'], data['title'])
|
self.assertEqual(response.data['title'], data['title'])
|
||||||
self.assertEqual(response.data['alias'], data['alias'])
|
self.assertEqual(response.data['alias'], data['alias'])
|
||||||
self.assertEqual(response.data['location'], data['location'])
|
self.assertEqual(response.data['comment'], data['comment'])
|
||||||
self.assertEqual(response.data['access_policy'], data['access_policy'])
|
|
||||||
self.assertEqual(response.data['visible'], data['visible'])
|
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms', method='get')
|
@decl_endpoint('/api/rsforms', method='get')
|
||||||
def test_list(self):
|
def test_list_rsforms(self):
|
||||||
non_schema = LibraryItem.objects.create(
|
non_schema = LibraryItem.objects.create(
|
||||||
item_type=LibraryItemType.OPERATIONS_SCHEMA,
|
item_type=LibraryItemType.OPERATIONS_SCHEMA,
|
||||||
title='Test3'
|
title='Test3'
|
||||||
|
@ -72,38 +65,41 @@ class TestRSFormViewset(EndpointTester):
|
||||||
response = self.executeOK()
|
response = self.executeOK()
|
||||||
self.assertFalse(response_contains(response, non_schema))
|
self.assertFalse(response_contains(response, non_schema))
|
||||||
self.assertTrue(response_contains(response, self.unowned.item))
|
self.assertTrue(response_contains(response, self.unowned.item))
|
||||||
self.assertTrue(response_contains(response, self.schema.item))
|
self.assertTrue(response_contains(response, self.owned.item))
|
||||||
|
|
||||||
response = self.client.get('/api/library')
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
self.assertTrue(response_contains(response, non_schema))
|
|
||||||
self.assertTrue(response_contains(response, self.unowned.item))
|
|
||||||
self.assertTrue(response_contains(response, self.schema.item))
|
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/contents', method='get')
|
@decl_endpoint('/api/rsforms/{item}/contents', method='get')
|
||||||
def test_contents(self):
|
def test_contents(self):
|
||||||
schema = RSForm.create(title='Title1')
|
response = self.executeOK(item=self.owned_id)
|
||||||
schema.insert_new('X1')
|
self.assertEqual(response.data['owner'], self.owned.item.owner.pk)
|
||||||
self.executeOK(item=schema.item.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)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/details', method='get')
|
@decl_endpoint('/api/rsforms/{item}/details', method='get')
|
||||||
def test_details(self):
|
def test_details(self):
|
||||||
schema = RSForm.create(title='Test', owner=self.user)
|
x1 = self.owned.insert_new(
|
||||||
x1 = schema.insert_new(
|
|
||||||
alias='X1',
|
alias='X1',
|
||||||
term_raw='человек',
|
term_raw='человек',
|
||||||
term_resolved='человек'
|
term_resolved='человек'
|
||||||
)
|
)
|
||||||
x2 = schema.insert_new(
|
x2 = self.owned.insert_new(
|
||||||
alias='X2',
|
alias='X2',
|
||||||
term_raw='@{X1|plur}',
|
term_raw='@{X1|plur}',
|
||||||
term_resolved='люди'
|
term_resolved='люди'
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self.executeOK(item=schema.item.pk)
|
response = self.executeOK(item=self.owned_id)
|
||||||
self.assertEqual(response.data['title'], 'Test')
|
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(len(response.data['items']), 2)
|
self.assertEqual(len(response.data['items']), 2)
|
||||||
self.assertEqual(response.data['items'][0]['id'], x1.pk)
|
self.assertEqual(response.data['items'][0]['id'], x1.pk)
|
||||||
self.assertEqual(response.data['items'][0]['parse']['status'], 'verified')
|
self.assertEqual(response.data['items'][0]['parse']['status'], 'verified')
|
||||||
|
@ -115,13 +111,20 @@ class TestRSFormViewset(EndpointTester):
|
||||||
self.assertEqual(response.data['subscribers'], [self.user.pk])
|
self.assertEqual(response.data['subscribers'], [self.user.pk])
|
||||||
self.assertEqual(response.data['editors'], [])
|
self.assertEqual(response.data['editors'], [])
|
||||||
|
|
||||||
|
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/rsforms/{item}/check', method='post')
|
@decl_endpoint('/api/rsforms/{item}/check', method='post')
|
||||||
def test_check(self):
|
def test_check(self):
|
||||||
schema = RSForm.create(title='Test')
|
self.owned.insert_new('X1')
|
||||||
schema.insert_new('X1')
|
|
||||||
data = {'expression': 'X1=X1'}
|
data = {'expression': 'X1=X1'}
|
||||||
response = self.executeOK(data, item=schema.item.pk)
|
response = self.executeOK(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]]')
|
||||||
|
@ -133,14 +136,13 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/resolve', method='post')
|
@decl_endpoint('/api/rsforms/{item}/resolve', method='post')
|
||||||
def test_resolve(self):
|
def test_resolve(self):
|
||||||
schema = RSForm.create(title='Test')
|
x1 = self.owned.insert_new(
|
||||||
x1 = schema.insert_new(
|
|
||||||
alias='X1',
|
alias='X1',
|
||||||
term_resolved='синий слон'
|
term_resolved='синий слон'
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {'text': '@{1|редкий} @{X1|plur,datv}'}
|
data = {'text': '@{1|редкий} @{X1|plur,datv}'}
|
||||||
response = self.executeOK(data, item=schema.item.pk)
|
response = self.executeOK(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)
|
||||||
|
@ -190,10 +192,10 @@ class TestRSFormViewset(EndpointTester):
|
||||||
data = {'alias': 'X3', 'cst_type': CstType.BASE}
|
data = {'alias': 'X3', 'cst_type': CstType.BASE}
|
||||||
self.executeForbidden(data, item=self.unowned_id)
|
self.executeForbidden(data, item=self.unowned_id)
|
||||||
|
|
||||||
self.schema.insert_new('X1')
|
self.owned.insert_new('X1')
|
||||||
x2 = self.schema.insert_new('X2')
|
x2 = self.owned.insert_new('X2')
|
||||||
|
|
||||||
response = self.executeCreated(data, item=self.schema_id)
|
response = self.executeCreated(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)
|
||||||
|
@ -205,7 +207,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.schema_id)
|
response = self.executeCreated(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)
|
||||||
|
@ -215,7 +217,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-rename', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-rename', method='patch')
|
||||||
def test_rename_constituenta(self):
|
def test_rename_constituenta(self):
|
||||||
x1 = self.schema.insert_new(
|
x1 = self.owned.insert_new(
|
||||||
alias='X1',
|
alias='X1',
|
||||||
convention='Test',
|
convention='Test',
|
||||||
term_raw='Test1',
|
term_raw='Test1',
|
||||||
|
@ -223,7 +225,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
term_forms=[{'text': 'form1', 'tags': 'sing,datv'}]
|
term_forms=[{'text': 'form1', 'tags': 'sing,datv'}]
|
||||||
)
|
)
|
||||||
x2_2 = self.unowned.insert_new('X2')
|
x2_2 = self.unowned.insert_new('X2')
|
||||||
x3 = self.schema.insert_new(
|
x3 = self.owned.insert_new(
|
||||||
alias='X3',
|
alias='X3',
|
||||||
term_raw='Test3',
|
term_raw='Test3',
|
||||||
term_resolved='Test3',
|
term_resolved='Test3',
|
||||||
|
@ -233,15 +235,15 @@ 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, item=self.unowned_id)
|
||||||
self.executeBadData(data, item=self.schema_id)
|
self.executeBadData(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.schema_id)
|
self.executeBadData(data, item=self.owned_id)
|
||||||
|
|
||||||
data = {'target': x1.pk, 'alias': x3.alias}
|
data = {'target': x1.pk, 'alias': x3.alias}
|
||||||
self.executeBadData(data, item=self.schema_id)
|
self.executeBadData(data, item=self.owned_id)
|
||||||
|
|
||||||
d1 = self.schema.insert_new(
|
d1 = self.owned.insert_new(
|
||||||
alias='D1',
|
alias='D1',
|
||||||
term_raw='@{X1|plur}',
|
term_raw='@{X1|plur}',
|
||||||
definition_formal='X1'
|
definition_formal='X1'
|
||||||
|
@ -251,7 +253,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.schema_id)
|
response = self.executeOK(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()
|
||||||
|
@ -265,13 +267,13 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-substitute', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-substitute', method='patch')
|
||||||
def test_substitute_single(self):
|
def test_substitute_single(self):
|
||||||
x1 = self.schema.insert_new(
|
x1 = self.owned.insert_new(
|
||||||
alias='X1',
|
alias='X1',
|
||||||
term_raw='Test1',
|
term_raw='Test1',
|
||||||
term_resolved='Test1',
|
term_resolved='Test1',
|
||||||
term_forms=[{'text': 'form1', 'tags': 'sing,datv'}]
|
term_forms=[{'text': 'form1', 'tags': 'sing,datv'}]
|
||||||
)
|
)
|
||||||
x2 = self.schema.insert_new(
|
x2 = self.owned.insert_new(
|
||||||
alias='X2',
|
alias='X2',
|
||||||
term_raw='Test2'
|
term_raw='Test2'
|
||||||
)
|
)
|
||||||
|
@ -279,21 +281,21 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
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, item=self.unowned_id)
|
||||||
self.executeBadData(data, item=self.schema_id)
|
self.executeBadData(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.schema_id)
|
self.executeBadData(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.schema_id)
|
self.executeBadData(data, item=self.owned_id)
|
||||||
|
|
||||||
d1 = self.schema.insert_new(
|
d1 = self.owned.insert_new(
|
||||||
alias='D1',
|
alias='D1',
|
||||||
term_raw='@{X2|sing,datv}',
|
term_raw='@{X2|sing,datv}',
|
||||||
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.schema_id)
|
response = self.executeOK(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')
|
||||||
|
@ -302,12 +304,12 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-substitute', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-substitute', method='patch')
|
||||||
def test_substitute_multiple(self):
|
def test_substitute_multiple(self):
|
||||||
self.set_params(item=self.schema_id)
|
self.set_params(item=self.owned_id)
|
||||||
x1 = self.schema.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
x2 = self.schema.insert_new('X2')
|
x2 = self.owned.insert_new('X2')
|
||||||
d1 = self.schema.insert_new('D1')
|
d1 = self.owned.insert_new('D1')
|
||||||
d2 = self.schema.insert_new('D2')
|
d2 = self.owned.insert_new('D2')
|
||||||
d3 = self.schema.insert_new(
|
d3 = self.owned.insert_new(
|
||||||
alias='D3',
|
alias='D3',
|
||||||
definition_formal=r'X1 \ X2'
|
definition_formal=r'X1 \ X2'
|
||||||
)
|
)
|
||||||
|
@ -341,7 +343,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'transfer_term': True
|
'transfer_term': True
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
response = self.executeOK(data, item=self.schema_id)
|
response = self.executeOK(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')
|
||||||
|
|
||||||
|
@ -356,7 +358,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
'definition_formal': '3',
|
'definition_formal': '3',
|
||||||
'definition_raw': '4'
|
'definition_raw': '4'
|
||||||
}
|
}
|
||||||
response = self.executeCreated(data, item=self.schema_id)
|
response = self.executeCreated(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')
|
||||||
|
@ -369,43 +371,43 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-delete-multiple', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-delete-multiple', method='patch')
|
||||||
def test_delete_constituenta(self):
|
def test_delete_constituenta(self):
|
||||||
self.set_params(item=self.schema_id)
|
self.set_params(item=self.owned_id)
|
||||||
|
|
||||||
data = {'items': [1337]}
|
data = {'items': [1337]}
|
||||||
self.executeBadData(data)
|
self.executeBadData(data)
|
||||||
|
|
||||||
x1 = self.schema.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
x2 = self.schema.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)
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
self.schema.item.refresh_from_db()
|
self.owned.item.refresh_from_db()
|
||||||
self.assertEqual(len(response.data['items']), 1)
|
self.assertEqual(len(response.data['items']), 1)
|
||||||
self.assertEqual(self.schema.constituents().count(), 1)
|
self.assertEqual(self.owned.constituents().count(), 1)
|
||||||
self.assertEqual(x2.alias, 'X2')
|
self.assertEqual(x2.alias, 'X2')
|
||||||
self.assertEqual(x2.order, 1)
|
self.assertEqual(x2.order, 1)
|
||||||
|
|
||||||
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.schema_id)
|
self.executeBadData(data, item=self.owned_id)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-moveto', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-moveto', method='patch')
|
||||||
def test_move_constituenta(self):
|
def test_move_constituenta(self):
|
||||||
self.set_params(item=self.schema_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)
|
||||||
|
|
||||||
x1 = self.schema.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
x2 = self.schema.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)
|
||||||
x1.refresh_from_db()
|
x1.refresh_from_db()
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
self.assertEqual(response.data['id'], self.schema_id)
|
self.assertEqual(response.data['id'], self.owned_id)
|
||||||
self.assertEqual(x1.order, 2)
|
self.assertEqual(x1.order, 2)
|
||||||
self.assertEqual(x2.order, 1)
|
self.assertEqual(x2.order, 1)
|
||||||
|
|
||||||
|
@ -416,14 +418,14 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/reset-aliases', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/reset-aliases', method='patch')
|
||||||
def test_reset_aliases(self):
|
def test_reset_aliases(self):
|
||||||
self.set_params(item=self.schema_id)
|
self.set_params(item=self.owned_id)
|
||||||
|
|
||||||
response = self.executeOK()
|
response = self.executeOK()
|
||||||
self.assertEqual(response.data['id'], self.schema_id)
|
self.assertEqual(response.data['id'], self.owned_id)
|
||||||
|
|
||||||
x2 = self.schema.insert_new('X2')
|
x2 = self.owned.insert_new('X2')
|
||||||
x1 = self.schema.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
d11 = self.schema.insert_new('D11')
|
d11 = self.owned.insert_new('D11')
|
||||||
|
|
||||||
response = self.executeOK()
|
response = self.executeOK()
|
||||||
x1.refresh_from_db()
|
x1.refresh_from_db()
|
||||||
|
@ -441,43 +443,43 @@ class TestRSFormViewset(EndpointTester):
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/load-trs', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/load-trs', method='patch')
|
||||||
def test_load_trs(self):
|
def test_load_trs(self):
|
||||||
self.set_params(item=self.schema_id)
|
self.set_params(item=self.owned_id)
|
||||||
self.schema.item.title = 'Test11'
|
self.owned.item.title = 'Test11'
|
||||||
self.schema.item.save()
|
self.owned.item.save()
|
||||||
x1 = self.schema.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
work_dir = os.path.dirname(os.path.abspath(__file__))
|
work_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
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, 'load_metadata': False}
|
data = {'file': file, 'load_metadata': False}
|
||||||
response = self.client.patch(self.endpoint, data=data, format='multipart')
|
response = self.client.patch(self.endpoint, data=data, format='multipart')
|
||||||
self.schema.item.refresh_from_db()
|
self.owned.item.refresh_from_db()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(self.schema.item.title, 'Test11')
|
self.assertEqual(self.owned.item.title, 'Test11')
|
||||||
self.assertEqual(len(response.data['items']), 25)
|
self.assertEqual(len(response.data['items']), 25)
|
||||||
self.assertEqual(self.schema.constituents().count(), 25)
|
self.assertEqual(self.owned.constituents().count(), 25)
|
||||||
self.assertFalse(Constituenta.objects.filter(pk=x1.pk).exists())
|
self.assertFalse(Constituenta.objects.filter(pk=x1.pk).exists())
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/rsforms/{item}/cst-produce-structure', method='patch')
|
@decl_endpoint('/api/rsforms/{item}/cst-produce-structure', method='patch')
|
||||||
def test_produce_structure(self):
|
def test_produce_structure(self):
|
||||||
self.set_params(item=self.schema_id)
|
self.set_params(item=self.owned_id)
|
||||||
x1 = self.schema.insert_new('X1')
|
x1 = self.owned.insert_new('X1')
|
||||||
s1 = self.schema.insert_new(
|
s1 = self.owned.insert_new(
|
||||||
alias='S1',
|
alias='S1',
|
||||||
definition_formal='ℬ(X1×X1)'
|
definition_formal='ℬ(X1×X1)'
|
||||||
)
|
)
|
||||||
s2 = self.schema.insert_new(
|
s2 = self.owned.insert_new(
|
||||||
alias='S2',
|
alias='S2',
|
||||||
definition_formal='invalid'
|
definition_formal='invalid'
|
||||||
)
|
)
|
||||||
s3 = self.schema.insert_new(
|
s3 = self.owned.insert_new(
|
||||||
alias='S3',
|
alias='S3',
|
||||||
definition_formal='X1×(X1×ℬℬ(X1))×ℬ(X1×X1)'
|
definition_formal='X1×(X1×ℬℬ(X1))×ℬ(X1×X1)'
|
||||||
)
|
)
|
||||||
a1 = self.schema.insert_new(
|
a1 = self.owned.insert_new(
|
||||||
alias='A1',
|
alias='A1',
|
||||||
definition_formal='1=1'
|
definition_formal='1=1'
|
||||||
)
|
)
|
||||||
f1 = self.schema.insert_new(
|
f1 = self.owned.insert_new(
|
||||||
alias='F10',
|
alias='F10',
|
||||||
definition_formal='[α∈X1, β∈X1] Fi1[{α,β}](S1)'
|
definition_formal='[α∈X1, β∈X1] Fi1[{α,β}](S1)'
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,74 +18,22 @@ from .. import permissions
|
||||||
from .. import serializers as s
|
from .. import serializers as s
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(tags=['Library'])
|
|
||||||
@extend_schema_view()
|
|
||||||
class LibraryActiveView(generics.ListAPIView):
|
|
||||||
''' Endpoint: Get list of library items available for active user. '''
|
|
||||||
permission_classes = (permissions.Anyone,)
|
|
||||||
serializer_class = s.LibraryItemSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
if self.request.user.is_anonymous:
|
|
||||||
return m.LibraryItem.objects.filter(
|
|
||||||
Q(access_policy=m.AccessPolicy.PUBLIC),
|
|
||||||
).filter(
|
|
||||||
Q(location__startswith=m.LocationHead.COMMON) |
|
|
||||||
Q(location__startswith=m.LocationHead.LIBRARY)
|
|
||||||
).order_by('-time_update')
|
|
||||||
else:
|
|
||||||
user = cast(m.User, self.request.user)
|
|
||||||
# pylint: disable=unsupported-binary-operation
|
|
||||||
return m.LibraryItem.objects.filter(
|
|
||||||
(
|
|
||||||
Q(access_policy=m.AccessPolicy.PUBLIC) &
|
|
||||||
(
|
|
||||||
Q(location__startswith=m.LocationHead.COMMON) |
|
|
||||||
Q(location__startswith=m.LocationHead.LIBRARY)
|
|
||||||
)
|
|
||||||
) |
|
|
||||||
Q(owner=user) |
|
|
||||||
Q(editor__editor=user) |
|
|
||||||
Q(subscription__user=user)
|
|
||||||
).distinct().order_by('-time_update')
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(tags=['Library'])
|
|
||||||
@extend_schema_view()
|
|
||||||
class LibraryAdminView(generics.ListAPIView):
|
|
||||||
''' Endpoint: Get list of all library items. Admin only '''
|
|
||||||
permission_classes = (permissions.GlobalAdmin,)
|
|
||||||
serializer_class = s.LibraryItemSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return m.LibraryItem.objects.all().order_by('-time_update')
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(tags=['Library'])
|
|
||||||
@extend_schema_view()
|
|
||||||
class LibraryTemplatesView(generics.ListAPIView):
|
|
||||||
''' Endpoint: Get list of templates. '''
|
|
||||||
permission_classes = (permissions.Anyone,)
|
|
||||||
serializer_class = s.LibraryItemSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
template_ids = m.LibraryTemplate.objects.values_list('lib_source', flat=True)
|
|
||||||
return m.LibraryItem.objects.filter(pk__in=template_ids)
|
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-many-ancestors
|
|
||||||
@extend_schema(tags=['Library'])
|
@extend_schema(tags=['Library'])
|
||||||
@extend_schema_view()
|
@extend_schema_view()
|
||||||
class LibraryViewSet(viewsets.ModelViewSet):
|
class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
''' Endpoint: Library operations. '''
|
''' Endpoint: Library operations. '''
|
||||||
queryset = m.LibraryItem.objects.all()
|
queryset = m.LibraryItem.objects.all()
|
||||||
serializer_class = s.LibraryItemSerializer
|
|
||||||
|
|
||||||
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
|
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
|
||||||
filterset_fields = ['item_type', 'owner']
|
filterset_fields = ['item_type', 'owner']
|
||||||
ordering_fields = ('item_type', 'owner', 'alias', 'title', 'time_update')
|
ordering_fields = ('item_type', 'owner', 'alias', 'title', 'time_update')
|
||||||
ordering = '-time_update'
|
ordering = '-time_update'
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == 'create':
|
||||||
|
return s.LibraryItemBaseSerializer
|
||||||
|
return s.LibraryItemSerializer
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
if not self.request.user.is_anonymous and 'owner' not in self.request.POST:
|
if not self.request.user.is_anonymous and 'owner' not in self.request.POST:
|
||||||
return serializer.save(owner=self.request.user)
|
return serializer.save(owner=self.request.user)
|
||||||
|
@ -103,7 +51,7 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
elif self.action in ['create', 'clone', 'subscribe', 'unsubscribe']:
|
elif self.action in ['create', 'clone', 'subscribe', 'unsubscribe']:
|
||||||
permission_list = [permissions.GlobalUser]
|
permission_list = [permissions.GlobalUser]
|
||||||
else:
|
else:
|
||||||
permission_list = [permissions.Anyone]
|
permission_list = [permissions.ItemAnyone]
|
||||||
return [permission() for permission in permission_list]
|
return [permission() for permission in permission_list]
|
||||||
|
|
||||||
def _get_item(self) -> m.LibraryItem:
|
def _get_item(self) -> m.LibraryItem:
|
||||||
|
@ -308,3 +256,58 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
editors = serializer.validated_data['users']
|
editors = serializer.validated_data['users']
|
||||||
m.Editor.set(item=item, users=editors)
|
m.Editor.set(item=item, users=editors)
|
||||||
return Response(status=c.HTTP_200_OK)
|
return Response(status=c.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=['Library'])
|
||||||
|
@extend_schema_view()
|
||||||
|
class LibraryActiveView(generics.ListAPIView):
|
||||||
|
''' Endpoint: Get list of library items available for active user. '''
|
||||||
|
permission_classes = (permissions.Anyone,)
|
||||||
|
serializer_class = s.LibraryItemSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
if self.request.user.is_anonymous:
|
||||||
|
return m.LibraryItem.objects.filter(
|
||||||
|
Q(access_policy=m.AccessPolicy.PUBLIC),
|
||||||
|
).filter(
|
||||||
|
Q(location__startswith=m.LocationHead.COMMON) |
|
||||||
|
Q(location__startswith=m.LocationHead.LIBRARY)
|
||||||
|
).order_by('-time_update')
|
||||||
|
else:
|
||||||
|
user = cast(m.User, self.request.user)
|
||||||
|
# pylint: disable=unsupported-binary-operation
|
||||||
|
return m.LibraryItem.objects.filter(
|
||||||
|
(
|
||||||
|
Q(access_policy=m.AccessPolicy.PUBLIC) &
|
||||||
|
(
|
||||||
|
Q(location__startswith=m.LocationHead.COMMON) |
|
||||||
|
Q(location__startswith=m.LocationHead.LIBRARY)
|
||||||
|
)
|
||||||
|
) |
|
||||||
|
Q(owner=user) |
|
||||||
|
Q(editor__editor=user) |
|
||||||
|
Q(subscription__user=user)
|
||||||
|
).distinct().order_by('-time_update')
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=['Library'])
|
||||||
|
@extend_schema_view()
|
||||||
|
class LibraryAdminView(generics.ListAPIView):
|
||||||
|
''' Endpoint: Get list of all library items. Admin only '''
|
||||||
|
permission_classes = (permissions.GlobalAdmin,)
|
||||||
|
serializer_class = s.LibraryItemSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return m.LibraryItem.objects.all().order_by('-time_update')
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=['Library'])
|
||||||
|
@extend_schema_view()
|
||||||
|
class LibraryTemplatesView(generics.ListAPIView):
|
||||||
|
''' Endpoint: Get list of templates. '''
|
||||||
|
permission_classes = (permissions.Anyone,)
|
||||||
|
serializer_class = s.LibraryItemSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
template_ids = m.LibraryTemplate.objects.values_list('lib_source', flat=True)
|
||||||
|
return m.LibraryItem.objects.filter(pk__in=template_ids)
|
||||||
|
|
|
@ -441,6 +441,7 @@ class TrsImportView(views.APIView):
|
||||||
request=s.LibraryItemSerializer,
|
request=s.LibraryItemSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_201_CREATED: s.LibraryItemSerializer,
|
c.HTTP_201_CREATED: s.LibraryItemSerializer,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None
|
c.HTTP_403_FORBIDDEN: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -449,17 +450,9 @@ def create_rsform(request: Request):
|
||||||
''' Endpoint: Create RSForm from user input and/or trs file. '''
|
''' Endpoint: Create RSForm from user input and/or trs file. '''
|
||||||
owner = cast(m.User, request.user) if not request.user.is_anonymous else None
|
owner = cast(m.User, request.user) if not request.user.is_anonymous else None
|
||||||
if 'file' not in request.FILES:
|
if 'file' not in request.FILES:
|
||||||
serializer = s.LibraryItemBase(data=request.data)
|
return Response(
|
||||||
serializer.is_valid(raise_exception=True)
|
status=c.HTTP_400_BAD_REQUEST,
|
||||||
schema = m.RSForm.create(
|
data={f'file': msg.missingFile()}
|
||||||
title=serializer.validated_data['title'],
|
|
||||||
owner=owner,
|
|
||||||
alias=serializer.validated_data.get('alias', ''),
|
|
||||||
comment=serializer.validated_data.get('comment', ''),
|
|
||||||
visible=serializer.validated_data.get('visible', True),
|
|
||||||
read_only=serializer.validated_data.get('read_only', False),
|
|
||||||
access_policy=serializer.validated_data.get('access_policy', m.AccessPolicy.PUBLIC),
|
|
||||||
location=serializer.validated_data.get('location', m.LocationHead.USER),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
data = utils.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
|
data = utils.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createBrowserRouter } from 'react-router-dom';
|
import { createBrowserRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import CreateItemPage from '@/pages/CreateRSFormPage';
|
import CreateItemPage from '@/pages/CreateItemPage';
|
||||||
import HomePage from '@/pages/HomePage';
|
import HomePage from '@/pages/HomePage';
|
||||||
import LibraryPage from '@/pages/LibraryPage';
|
import LibraryPage from '@/pages/LibraryPage';
|
||||||
import LoginPage from '@/pages/LoginPage';
|
import LoginPage from '@/pages/LoginPage';
|
||||||
|
|
|
@ -198,7 +198,7 @@ export function getTemplates(request: FrontPull<ILibraryItem[]>) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postNewRSForm(request: FrontExchange<ILibraryCreateData, ILibraryItem>) {
|
export function postRSFormFromFile(request: FrontExchange<ILibraryCreateData, ILibraryItem>) {
|
||||||
AxiosPost({
|
AxiosPost({
|
||||||
endpoint: '/api/rsforms/create-detailed',
|
endpoint: '/api/rsforms/create-detailed',
|
||||||
request: request,
|
request: request,
|
||||||
|
@ -210,6 +210,13 @@ export function postNewRSForm(request: FrontExchange<ILibraryCreateData, ILibrar
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function postCreateLibraryItem(request: FrontExchange<ILibraryCreateData, ILibraryItem>) {
|
||||||
|
AxiosPost({
|
||||||
|
endpoint: '/api/library',
|
||||||
|
request: request
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function postCloneLibraryItem(target: string, request: FrontExchange<IRSFormCloneData, IRSFormData>) {
|
export function postCloneLibraryItem(target: string, request: FrontExchange<IRSFormCloneData, IRSFormData>) {
|
||||||
AxiosPost({
|
AxiosPost({
|
||||||
endpoint: `/api/library/${target}/clone`,
|
endpoint: `/api/library/${target}/clone`,
|
||||||
|
|
|
@ -44,6 +44,7 @@ export const urls = {
|
||||||
help_topic: (topic: string) => `/manuals?topic=${topic}`,
|
help_topic: (topic: string) => `/manuals?topic=${topic}`,
|
||||||
schema: (id: number | string, version?: number | string) =>
|
schema: (id: number | string, version?: number | string) =>
|
||||||
`/rsforms/${id}` + (version !== undefined ? `?v=${version}` : ''),
|
`/rsforms/${id}` + (version !== undefined ? `?v=${version}` : ''),
|
||||||
|
oss: (id: number | string) => `/oss/${id}`,
|
||||||
schema_props: ({ id, tab, version, active }: SchemaProps) => {
|
schema_props: ({ id, tab, version, active }: SchemaProps) => {
|
||||||
const versionStr = version !== undefined ? `v=${version}&` : '';
|
const versionStr = version !== undefined ? `v=${version}&` : '';
|
||||||
const activeStr = active !== undefined ? `&active=${active}` : '';
|
const activeStr = active !== undefined ? `&active=${active}` : '';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AccessPolicy, LocationHead } from '@/models/library';
|
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||||
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -13,10 +13,12 @@ import {
|
||||||
IconGraphInputs,
|
IconGraphInputs,
|
||||||
IconGraphOutputs,
|
IconGraphOutputs,
|
||||||
IconHide,
|
IconHide,
|
||||||
|
IconOSS,
|
||||||
IconPrivate,
|
IconPrivate,
|
||||||
IconProps,
|
IconProps,
|
||||||
IconProtected,
|
IconProtected,
|
||||||
IconPublic,
|
IconPublic,
|
||||||
|
IconRSForm,
|
||||||
IconSettings,
|
IconSettings,
|
||||||
IconShow,
|
IconShow,
|
||||||
IconTemplates,
|
IconTemplates,
|
||||||
|
@ -29,6 +31,15 @@ export interface DomIconProps<RequestData> extends IconProps {
|
||||||
value: RequestData;
|
value: RequestData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ItemTypeIcon({ value, size = '1.25rem', className }: DomIconProps<LibraryItemType>) {
|
||||||
|
switch (value) {
|
||||||
|
case LibraryItemType.RSFORM:
|
||||||
|
return <IconRSForm size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
|
case LibraryItemType.OSS:
|
||||||
|
return <IconOSS size={size} className={className ?? 'clr-text-green'} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function PolicyIcon({ value, size = '1.25rem', className }: DomIconProps<AccessPolicy>) {
|
export function PolicyIcon({ value, size = '1.25rem', className }: DomIconProps<AccessPolicy>) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case AccessPolicy.PRIVATE:
|
case AccessPolicy.PRIVATE:
|
||||||
|
|
|
@ -56,6 +56,8 @@ export { TbBriefcase as IconBusiness } from 'react-icons/tb';
|
||||||
export { VscLibrary as IconLibrary } from 'react-icons/vsc';
|
export { VscLibrary as IconLibrary } from 'react-icons/vsc';
|
||||||
export { IoLibrary as IconLibrary2 } from 'react-icons/io5';
|
export { IoLibrary as IconLibrary2 } from 'react-icons/io5';
|
||||||
export { BiDiamond as IconTemplates } from 'react-icons/bi';
|
export { BiDiamond as IconTemplates } from 'react-icons/bi';
|
||||||
|
export { FaRegObjectGroup as IconOSS } from 'react-icons/fa';
|
||||||
|
export { RiHexagonLine as IconRSForm } from 'react-icons/ri';
|
||||||
export { LuArchive as IconArchive } from 'react-icons/lu';
|
export { LuArchive as IconArchive } from 'react-icons/lu';
|
||||||
export { LuDatabase as IconDatabase } from 'react-icons/lu';
|
export { LuDatabase as IconDatabase } from 'react-icons/lu';
|
||||||
export { LuImage as IconImage } from 'react-icons/lu';
|
export { LuImage as IconImage } from 'react-icons/lu';
|
||||||
|
|
62
rsconcept/frontend/src/components/select/SelectItemType.tsx
Normal file
62
rsconcept/frontend/src/components/select/SelectItemType.tsx
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import Dropdown from '@/components/ui/Dropdown';
|
||||||
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
|
import { LibraryItemType } from '@/models/library';
|
||||||
|
import { prefixes } from '@/utils/constants';
|
||||||
|
import { describeLibraryItemType, labelLibraryItemType } from '@/utils/labels';
|
||||||
|
|
||||||
|
import { ItemTypeIcon } from '../DomainIcons';
|
||||||
|
import DropdownButton from '../ui/DropdownButton';
|
||||||
|
import SelectorButton from '../ui/SelectorButton';
|
||||||
|
|
||||||
|
interface SelectItemTypeProps {
|
||||||
|
value: LibraryItemType;
|
||||||
|
onChange: (value: LibraryItemType) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
stretchLeft?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectItemType({ value, disabled, stretchLeft, onChange }: SelectItemTypeProps) {
|
||||||
|
const menu = useDropdown();
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(newValue: LibraryItemType) => {
|
||||||
|
menu.hide();
|
||||||
|
if (newValue !== value) {
|
||||||
|
onChange(newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[menu, value, onChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={menu.ref}>
|
||||||
|
<SelectorButton
|
||||||
|
transparent
|
||||||
|
title={describeLibraryItemType(value)}
|
||||||
|
hideTitle={menu.isOpen}
|
||||||
|
className='h-full py-1 px-2 disabled:cursor-auto rounded-lg'
|
||||||
|
icon={<ItemTypeIcon value={value} size='1.25rem' />}
|
||||||
|
text={labelLibraryItemType(value)}
|
||||||
|
onClick={menu.toggle}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<Dropdown isOpen={menu.isOpen} stretchLeft={stretchLeft}>
|
||||||
|
{Object.values(LibraryItemType).map((item, index) => (
|
||||||
|
<DropdownButton
|
||||||
|
key={`${prefixes.policy_list}${index}`}
|
||||||
|
text={labelLibraryItemType(item)}
|
||||||
|
title={describeLibraryItemType(item)}
|
||||||
|
icon={<ItemTypeIcon value={item} size='1rem' />}
|
||||||
|
onClick={() => handleChange(item)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectItemType;
|
|
@ -34,7 +34,6 @@ function SelectMatchMode({ value, onChange }: SelectMatchModeProps) {
|
||||||
<div ref={menu.ref}>
|
<div ref={menu.ref}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
transparent
|
||||||
tabIndex={-1}
|
|
||||||
title='Настройка фильтрации по проверяемым атрибутам'
|
title='Настройка фильтрации по проверяемым атрибутам'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
|
|
|
@ -26,6 +26,7 @@ function SelectorButton({
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-1 flex flex-start items-center gap-1',
|
'px-1 flex flex-start items-center gap-1',
|
||||||
'text-sm font-controls select-none',
|
'text-sm font-controls select-none',
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {
|
||||||
getRSFormDetails,
|
getRSFormDetails,
|
||||||
getTemplates,
|
getTemplates,
|
||||||
postCloneLibraryItem,
|
postCloneLibraryItem,
|
||||||
postNewRSForm
|
postCreateLibraryItem,
|
||||||
|
postRSFormFromFile
|
||||||
} from '@/app/backendAPI';
|
} from '@/app/backendAPI';
|
||||||
import { ErrorData } from '@/components/info/InfoError';
|
import { ErrorData } from '@/components/info/InfoError';
|
||||||
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
||||||
|
@ -181,20 +182,31 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
|
|
||||||
const createItem = useCallback(
|
const createItem = useCallback(
|
||||||
(data: ILibraryCreateData, callback?: DataCallback<ILibraryItem>) => {
|
(data: ILibraryCreateData, callback?: DataCallback<ILibraryItem>) => {
|
||||||
setError(undefined);
|
const onSuccess = (newSchema: ILibraryItem) =>
|
||||||
postNewRSForm({
|
|
||||||
data: data,
|
|
||||||
showError: true,
|
|
||||||
setLoading: setProcessing,
|
|
||||||
onError: setError,
|
|
||||||
onSuccess: newSchema =>
|
|
||||||
reloadItems(() => {
|
reloadItems(() => {
|
||||||
if (user && !user.subscriptions.includes(newSchema.id)) {
|
if (user && !user.subscriptions.includes(newSchema.id)) {
|
||||||
user.subscriptions.push(newSchema.id);
|
user.subscriptions.push(newSchema.id);
|
||||||
}
|
}
|
||||||
if (callback) callback(newSchema);
|
if (callback) callback(newSchema);
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
setError(undefined);
|
||||||
|
if (data.file) {
|
||||||
|
postRSFormFromFile({
|
||||||
|
data: data,
|
||||||
|
showError: true,
|
||||||
|
setLoading: setProcessing,
|
||||||
|
onError: setError,
|
||||||
|
onSuccess: onSuccess
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
postCreateLibraryItem({
|
||||||
|
data: data,
|
||||||
|
showError: true,
|
||||||
|
setLoading: setProcessing,
|
||||||
|
onError: setError,
|
||||||
|
onSuccess: onSuccess
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[reloadItems, user]
|
[reloadItems, user]
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { UserID } from './user';
|
||||||
*/
|
*/
|
||||||
export enum LibraryItemType {
|
export enum LibraryItemType {
|
||||||
RSFORM = 'rsform',
|
RSFORM = 'rsform',
|
||||||
OPERATIONS_SCHEMA = 'oss'
|
OSS = 'oss'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { VisibilityIcon } from '@/components/DomainIcons';
|
||||||
import { IconDownload } from '@/components/Icons';
|
import { IconDownload } from '@/components/Icons';
|
||||||
import InfoError from '@/components/info/InfoError';
|
import InfoError from '@/components/info/InfoError';
|
||||||
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||||
|
import SelectItemType from '@/components/select/SelectItemType';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
|
@ -30,6 +31,7 @@ function FormCreateItem() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { createItem, error, setError, processing } = useLibrary();
|
const { createItem, error, setError, processing } = useLibrary();
|
||||||
|
|
||||||
|
const [itemType, setItemType] = useState(LibraryItemType.RSFORM);
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
const [alias, setAlias] = useState('');
|
const [alias, setAlias] = useState('');
|
||||||
const [comment, setComment] = useState('');
|
const [comment, setComment] = useState('');
|
||||||
|
@ -64,7 +66,7 @@ function FormCreateItem() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data: ILibraryCreateData = {
|
const data: ILibraryCreateData = {
|
||||||
item_type: LibraryItemType.RSFORM,
|
item_type: itemType,
|
||||||
title: title,
|
title: title,
|
||||||
alias: alias,
|
alias: alias,
|
||||||
comment: comment,
|
comment: comment,
|
||||||
|
@ -75,9 +77,13 @@ function FormCreateItem() {
|
||||||
file: file,
|
file: file,
|
||||||
fileName: file?.name
|
fileName: file?.name
|
||||||
};
|
};
|
||||||
createItem(data, newSchema => {
|
createItem(data, newItem => {
|
||||||
toast.success('Схема успешно создана');
|
toast.success('Схема успешно создана');
|
||||||
router.push(urls.schema(newSchema.id));
|
if (itemType == LibraryItemType.RSFORM) {
|
||||||
|
router.push(urls.schema(newItem.id));
|
||||||
|
} else {
|
||||||
|
router.push(urls.oss(newItem.id));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,8 +115,8 @@ function FormCreateItem() {
|
||||||
/>
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<form className={clsx('cc-column', 'min-w-[30rem]', 'px-6 py-3')} onSubmit={handleSubmit}>
|
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem]', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||||
<h1>Создание концептуальной схемы</h1>
|
<h1>Создание схемы</h1>
|
||||||
|
|
||||||
{fileName ? <Label text={`Загружен файл: ${fileName}`} /> : null}
|
{fileName ? <Label text={`Загружен файл: ${fileName}`} /> : null}
|
||||||
|
|
||||||
|
@ -135,11 +141,14 @@ function FormCreateItem() {
|
||||||
value={alias}
|
value={alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => setAlias(event.target.value)}
|
||||||
/>
|
/>
|
||||||
|
<div className='flex flex-col items-center gap-2'>
|
||||||
|
<Label text='Тип схемы' className='self-center select-none' />
|
||||||
|
<SelectItemType value={itemType} onChange={setItemType} />
|
||||||
|
</div>
|
||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
<Label text='Доступ' className='self-center select-none' />
|
<Label text='Доступ' className='self-center select-none' />
|
||||||
<div className='ml-auto cc-icons'>
|
<div className='ml-auto cc-icons'>
|
||||||
<SelectAccessPolicy value={policy} onChange={newPolicy => setPolicy(newPolicy)} />
|
<SelectAccessPolicy value={policy} onChange={setPolicy} />
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
className='disabled:cursor-auto'
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import Divider from '@/components/ui/Divider';
|
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
|
@ -52,9 +51,6 @@ function EditorRSForm({ isModified, onDestroy, setIsModified }: EditorRSFormProp
|
||||||
<AnimateFade onKeyDown={handleInput} className={clsx('sm:w-fit mx-auto', 'flex flex-col sm:flex-row')}>
|
<AnimateFade onKeyDown={handleInput} className={clsx('sm:w-fit mx-auto', 'flex flex-col sm:flex-row')}>
|
||||||
<FlexColumn className='px-3'>
|
<FlexColumn className='px-3'>
|
||||||
<FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />
|
<FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />
|
||||||
|
|
||||||
<Divider margins='my-1' />
|
|
||||||
|
|
||||||
<EditorLibraryItem item={schema} isModified={isModified} />
|
<EditorLibraryItem item={schema} isModified={isModified} />
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
import { GraphLayout } from '@/components/ui/GraphUI';
|
import { GraphLayout } from '@/components/ui/GraphUI';
|
||||||
import { GramData, Grammeme, ReferenceType } from '@/models/language';
|
import { GramData, Grammeme, ReferenceType } from '@/models/language';
|
||||||
import { AccessPolicy, LocationHead } from '@/models/library';
|
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||||
import { CstMatchMode, DependencyMode, GraphColoring, GraphSizing, HelpTopic } from '@/models/miscellaneous';
|
import { CstMatchMode, DependencyMode, GraphColoring, GraphSizing, HelpTopic } from '@/models/miscellaneous';
|
||||||
import { CstClass, CstType, ExpressionStatus, IConstituenta, IRSForm } from '@/models/rsform';
|
import { CstClass, CstType, ExpressionStatus, IConstituenta, IRSForm } from '@/models/rsform';
|
||||||
import {
|
import {
|
||||||
|
@ -821,6 +821,28 @@ export function describeAccessPolicy(policy: AccessPolicy): string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves label for {@link LibraryItemType}.
|
||||||
|
*/
|
||||||
|
export function labelLibraryItemType(itemType: LibraryItemType): string {
|
||||||
|
// prettier-ignore
|
||||||
|
switch (itemType) {
|
||||||
|
case LibraryItemType.RSFORM: return 'КС';
|
||||||
|
case LibraryItemType.OSS: return 'ОСС';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves description for {@link LibraryItemType}.
|
||||||
|
*/
|
||||||
|
export function describeLibraryItemType(itemType: LibraryItemType): string {
|
||||||
|
// prettier-ignore
|
||||||
|
switch (itemType) {
|
||||||
|
case LibraryItemType.RSFORM: return 'Концептуальная схема';
|
||||||
|
case LibraryItemType.OSS: return 'Операционная схема синтеза';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UI shared messages.
|
* UI shared messages.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user