mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
Refactor RSForm backend and tests
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
This commit is contained in:
parent
6f3d3c830e
commit
1928972feb
|
@ -116,6 +116,7 @@ This readme file is used mostly to document project dependencies
|
||||||
- Pylint
|
- Pylint
|
||||||
- Django
|
- Django
|
||||||
- autopep8
|
- autopep8
|
||||||
|
- SQLite
|
||||||
</pre>
|
</pre>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ from .Version import Version
|
||||||
class LibraryItemType(TextChoices):
|
class LibraryItemType(TextChoices):
|
||||||
''' Type of library items '''
|
''' Type of library items '''
|
||||||
RSFORM = 'rsform'
|
RSFORM = 'rsform'
|
||||||
OPERATIONS_SCHEMA = 'oss'
|
OPERATION_SCHEMA = 'oss'
|
||||||
|
|
||||||
|
|
||||||
class AccessPolicy(TextChoices):
|
class AccessPolicy(TextChoices):
|
||||||
|
@ -115,7 +115,7 @@ class LibraryItem(Model):
|
||||||
|
|
||||||
def subscribers(self) -> list[Subscription]:
|
def subscribers(self) -> list[Subscription]:
|
||||||
''' Get all subscribers for this item. '''
|
''' Get all subscribers for this item. '''
|
||||||
return [subscription.user for subscription in Subscription.objects.filter(item=self.pk)]
|
return [subscription.user for subscription in Subscription.objects.filter(item=self.pk).only('user')]
|
||||||
|
|
||||||
def versions(self) -> list[Version]:
|
def versions(self) -> list[Version]:
|
||||||
''' Get all Versions of this item. '''
|
''' Get all Versions of this item. '''
|
||||||
|
@ -123,7 +123,7 @@ class LibraryItem(Model):
|
||||||
|
|
||||||
def editors(self) -> list[Editor]:
|
def editors(self) -> list[Editor]:
|
||||||
''' Get all Editors of this item. '''
|
''' Get all Editors of this item. '''
|
||||||
return [item.editor for item in Editor.objects.filter(item=self.pk)]
|
return [item.editor for item in Editor.objects.filter(item=self.pk).only('editor')]
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
''' Models: RSForm API. '''
|
''' Models: RSForm API. '''
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from typing import Optional, Union, cast
|
from typing import Optional, cast
|
||||||
|
|
||||||
from cctext import Entity, Resolver, TermForm, extract_entities, split_grams
|
from cctext import Entity, Resolver, TermForm, extract_entities, split_grams
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
@ -39,7 +39,7 @@ class RSForm:
|
||||||
def create(**kwargs) -> 'RSForm':
|
def create(**kwargs) -> 'RSForm':
|
||||||
return RSForm(LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, **kwargs))
|
return RSForm(LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, **kwargs))
|
||||||
|
|
||||||
def constituents(self) -> QuerySet['Constituenta']:
|
def constituents(self) -> QuerySet[Constituenta]:
|
||||||
''' Get QuerySet containing all constituents of current RSForm. '''
|
''' Get QuerySet containing all constituents of current RSForm. '''
|
||||||
return Constituenta.objects.filter(schema=self.item)
|
return Constituenta.objects.filter(schema=self.item)
|
||||||
|
|
||||||
|
@ -104,11 +104,39 @@ class RSForm:
|
||||||
result = max(result, int(alias[1:]))
|
result = max(result, int(alias[1:]))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create_cst(self, data: dict, insert_after: Optional[Constituenta] = None) -> Constituenta:
|
||||||
|
''' Create new cst from data. '''
|
||||||
|
if insert_after is None:
|
||||||
|
position = _INSERT_LAST
|
||||||
|
else:
|
||||||
|
position = insert_after.order + 1
|
||||||
|
result = self.insert_new(data['alias'], data['cst_type'], position)
|
||||||
|
result.convention = data.get('convention', '')
|
||||||
|
result.definition_formal = data.get('definition_formal', '')
|
||||||
|
result.term_forms = data.get('term_forms', [])
|
||||||
|
result.term_raw = data.get('term_raw', '')
|
||||||
|
result.definition_raw = data.get('definition_raw', '')
|
||||||
|
|
||||||
|
if result.term_raw != '' or result.definition_raw != '':
|
||||||
|
resolver = self.resolver()
|
||||||
|
if result.term_raw != '':
|
||||||
|
resolved = resolver.resolve(result.term_raw)
|
||||||
|
result.term_resolved = resolved
|
||||||
|
resolver.context[result.alias] = Entity(result.alias, resolved)
|
||||||
|
if result.definition_raw != '':
|
||||||
|
result.definition_resolved = resolver.resolve(result.definition_raw)
|
||||||
|
|
||||||
|
result.save()
|
||||||
|
self.on_term_change([result.id])
|
||||||
|
result.refresh_from_db()
|
||||||
|
return result
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def insert_new(
|
def insert_new(
|
||||||
self,
|
self,
|
||||||
alias: str,
|
alias: str,
|
||||||
cst_type: Union[CstType, None] = None,
|
cst_type: Optional[CstType] = None,
|
||||||
position: int = _INSERT_LAST,
|
position: int = _INSERT_LAST,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> Constituenta:
|
) -> Constituenta:
|
||||||
|
@ -195,27 +223,6 @@ class RSForm:
|
||||||
self.resolve_all_text()
|
self.resolve_all_text()
|
||||||
self.item.save()
|
self.item.save()
|
||||||
|
|
||||||
@transaction.atomic
|
|
||||||
def create_cst(self, data: dict, insert_after: Optional[str] = None) -> Constituenta:
|
|
||||||
''' Create new cst from data. '''
|
|
||||||
resolver = self.resolver()
|
|
||||||
cst = self._insert_new(data, insert_after)
|
|
||||||
cst.convention = data.get('convention', '')
|
|
||||||
cst.definition_formal = data.get('definition_formal', '')
|
|
||||||
cst.term_forms = data.get('term_forms', [])
|
|
||||||
cst.term_raw = data.get('term_raw', '')
|
|
||||||
if cst.term_raw != '':
|
|
||||||
resolved = resolver.resolve(cst.term_raw)
|
|
||||||
cst.term_resolved = resolved
|
|
||||||
resolver.context[cst.alias] = Entity(cst.alias, resolved)
|
|
||||||
cst.definition_raw = data.get('definition_raw', '')
|
|
||||||
if cst.definition_raw != '':
|
|
||||||
cst.definition_resolved = resolver.resolve(cst.definition_raw)
|
|
||||||
cst.save()
|
|
||||||
self.on_term_change([cst.id])
|
|
||||||
cst.refresh_from_db()
|
|
||||||
return cst
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def substitute(
|
def substitute(
|
||||||
self,
|
self,
|
||||||
|
@ -363,13 +370,6 @@ class RSForm:
|
||||||
cst.save()
|
cst.save()
|
||||||
order += 1
|
order += 1
|
||||||
|
|
||||||
def _insert_new(self, data: dict, insert_after: Optional[str] = None) -> Constituenta:
|
|
||||||
if insert_after is not None:
|
|
||||||
cst_after = Constituenta.objects.get(pk=insert_after)
|
|
||||||
return self.insert_new(data['alias'], data['cst_type'], cst_after.order + 1)
|
|
||||||
else:
|
|
||||||
return self.insert_new(data['alias'], data['cst_type'])
|
|
||||||
|
|
||||||
def _graph_formal(self) -> Graph[int]:
|
def _graph_formal(self) -> Graph[int]:
|
||||||
''' Graph based on formal definitions. '''
|
''' Graph based on formal definitions. '''
|
||||||
result: Graph[int] = Graph()
|
result: Graph[int] = Graph()
|
||||||
|
|
|
@ -26,6 +26,21 @@ class EndpointTester(APITestCase):
|
||||||
''' Abstract base class for Testing endpoints. '''
|
''' Abstract base class for Testing endpoints. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self.factory = APIRequestFactory()
|
||||||
|
self.user = User.objects.create(
|
||||||
|
username='UserTest',
|
||||||
|
email='blank@test.com',
|
||||||
|
password='password'
|
||||||
|
)
|
||||||
|
self.user2 = User.objects.create(
|
||||||
|
username='UserTest2',
|
||||||
|
email='another@test.com',
|
||||||
|
password='password'
|
||||||
|
)
|
||||||
|
self.client = APIClient()
|
||||||
|
self.client.force_authenticate(user=self.user)
|
||||||
|
|
||||||
|
def setUpFullUsers(self):
|
||||||
self.factory = APIRequestFactory()
|
self.factory = APIRequestFactory()
|
||||||
self.user = User.objects.create_user(
|
self.user = User.objects.create_user(
|
||||||
username='UserTest',
|
username='UserTest',
|
||||||
|
|
|
@ -101,6 +101,26 @@ class TestRSForm(TestCase):
|
||||||
self.assertEqual(x2.schema, self.schema.item)
|
self.assertEqual(x2.schema, self.schema.item)
|
||||||
self.assertEqual(x1.order, 1)
|
self.assertEqual(x1.order, 1)
|
||||||
|
|
||||||
|
def test_create_cst(self):
|
||||||
|
data = {
|
||||||
|
'alias': 'X3',
|
||||||
|
'cst_type': CstType.BASE,
|
||||||
|
'term_raw': 'слон',
|
||||||
|
'definition_raw': 'test',
|
||||||
|
'convention': 'convention'
|
||||||
|
}
|
||||||
|
|
||||||
|
x1 = self.schema.insert_new('X1')
|
||||||
|
x2 = self.schema.insert_new('X2')
|
||||||
|
x3 = self.schema.create_cst(data=data, insert_after=x1)
|
||||||
|
x2.refresh_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(x3.alias, data['alias'])
|
||||||
|
self.assertEqual(x3.term_raw, data['term_raw'])
|
||||||
|
self.assertEqual(x3.definition_raw, data['definition_raw'])
|
||||||
|
self.assertEqual(x2.order, 3)
|
||||||
|
self.assertEqual(x3.order, 2)
|
||||||
|
|
||||||
|
|
||||||
def test_create_cst_resolve(self):
|
def test_create_cst_resolve(self):
|
||||||
x1 = self.schema.insert_new(
|
x1 = self.schema.insert_new(
|
||||||
|
|
|
@ -52,7 +52,7 @@ class TestLibraryViewset(EndpointTester):
|
||||||
self.executeBadData(data)
|
self.executeBadData(data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'item_type': LibraryItemType.OPERATIONS_SCHEMA,
|
'item_type': LibraryItemType.OPERATION_SCHEMA,
|
||||||
'title': 'Title',
|
'title': 'Title',
|
||||||
'alias': 'alias',
|
'alias': 'alias',
|
||||||
'access_policy': AccessPolicy.PROTECTED,
|
'access_policy': AccessPolicy.PROTECTED,
|
||||||
|
@ -294,7 +294,7 @@ class TestLibraryViewset(EndpointTester):
|
||||||
@decl_endpoint('/api/library', method='get')
|
@decl_endpoint('/api/library', method='get')
|
||||||
def test_library_get(self):
|
def test_library_get(self):
|
||||||
non_schema = LibraryItem.objects.create(
|
non_schema = LibraryItem.objects.create(
|
||||||
item_type=LibraryItemType.OPERATIONS_SCHEMA,
|
item_type=LibraryItemType.OPERATION_SCHEMA,
|
||||||
title='Test4'
|
title='Test4'
|
||||||
)
|
)
|
||||||
response = self.executeOK()
|
response = self.executeOK()
|
||||||
|
|
|
@ -59,7 +59,7 @@ class TestRSFormViewset(EndpointTester):
|
||||||
@decl_endpoint('/api/rsforms', method='get')
|
@decl_endpoint('/api/rsforms', method='get')
|
||||||
def test_list_rsforms(self):
|
def test_list_rsforms(self):
|
||||||
non_schema = LibraryItem.objects.create(
|
non_schema = LibraryItem.objects.create(
|
||||||
item_type=LibraryItemType.OPERATIONS_SCHEMA,
|
item_type=LibraryItemType.OPERATION_SCHEMA,
|
||||||
title='Test3'
|
title='Test3'
|
||||||
)
|
)
|
||||||
response = self.executeOK()
|
response = self.executeOK()
|
||||||
|
|
|
@ -60,10 +60,15 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
serializer = s.CstCreateSerializer(data=request.data)
|
serializer = s.CstCreateSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
data = serializer.validated_data
|
data = serializer.validated_data
|
||||||
new_cst = schema.create_cst(
|
if 'insert_after' in data:
|
||||||
data=data,
|
try:
|
||||||
insert_after=data['insert_after'] if 'insert_after' in data else None
|
insert_after = m.Constituenta.objects.get(pk=data['insert_after'])
|
||||||
)
|
except m.LibraryItem.DoesNotExist:
|
||||||
|
return Response(status=c.HTTP_404_NOT_FOUND)
|
||||||
|
else:
|
||||||
|
insert_after = None
|
||||||
|
new_cst = schema.create_cst(data, insert_after)
|
||||||
|
|
||||||
schema.item.refresh_from_db()
|
schema.item.refresh_from_db()
|
||||||
response = Response(
|
response = Response(
|
||||||
status=c.HTTP_201_CREATED,
|
status=c.HTTP_201_CREATED,
|
||||||
|
@ -313,7 +318,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'], url_path='contents')
|
||||||
def contents(self, request: Request, pk):
|
def contents(self, request: Request, pk):
|
||||||
''' Endpoint: View schema db contents (including constituents). '''
|
''' Endpoint: View schema db contents (including constituents). '''
|
||||||
schema = s.RSFormSerializer(self.get_object())
|
schema = s.RSFormSerializer(self.get_object())
|
||||||
|
@ -331,7 +336,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'], url_path='details')
|
||||||
def details(self, request: Request, pk):
|
def details(self, request: Request, pk):
|
||||||
''' Endpoint: Detailed schema view including statuses and parse. '''
|
''' Endpoint: Detailed schema view including statuses and parse. '''
|
||||||
serializer = s.RSFormParseSerializer(cast(m.LibraryItem, self.get_object()))
|
serializer = s.RSFormParseSerializer(cast(m.LibraryItem, self.get_object()))
|
||||||
|
@ -349,7 +354,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'], url_path='check')
|
||||||
def check(self, request: Request, pk):
|
def check(self, request: Request, pk):
|
||||||
''' Endpoint: Check RSLang expression against schema context. '''
|
''' Endpoint: Check RSLang expression against schema context. '''
|
||||||
serializer = s.ExpressionSerializer(data=request.data)
|
serializer = s.ExpressionSerializer(data=request.data)
|
||||||
|
@ -371,7 +376,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'], url_path='resolve')
|
||||||
def resolve(self, request: Request, pk):
|
def resolve(self, request: Request, pk):
|
||||||
''' Endpoint: Resolve references in text against schema terms context. '''
|
''' Endpoint: Resolve references in text against schema terms context. '''
|
||||||
serializer = s.TextSerializer(data=request.data)
|
serializer = s.TextSerializer(data=request.data)
|
||||||
|
|
|
@ -9,7 +9,7 @@ class TestUserAPIViews(EndpointTester):
|
||||||
''' Testing Authentication views. '''
|
''' Testing Authentication views. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUpFullUsers()
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/users/api/login', method='post')
|
@decl_endpoint('/users/api/login', method='post')
|
||||||
|
@ -59,7 +59,7 @@ class TestUserUserProfileAPIView(EndpointTester):
|
||||||
''' Testing User profile views. '''
|
''' Testing User profile views. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUpFullUsers()
|
||||||
self.user.first_name = 'John'
|
self.user.first_name = 'John'
|
||||||
self.user.second_name = 'Smith'
|
self.user.second_name = 'Smith'
|
||||||
self.user.save()
|
self.user.save()
|
||||||
|
|
|
@ -1,4 +1,22 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"model": "auth.user",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"password": "pbkdf2_sha256$720000$gFZkaBswurtL0naQKiUnW7$3b6SUN3fY2Xl1H7erAszVpQl2LpoKusan+yJP7Bp3JA=",
|
||||||
|
"last_login": "2024-06-03T20:57:02.522Z",
|
||||||
|
"is_superuser": true,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "Администратор",
|
||||||
|
"last_name": "",
|
||||||
|
"email": "admin@mail.ru",
|
||||||
|
"is_staff": true,
|
||||||
|
"is_active": true,
|
||||||
|
"date_joined": "2024-05-27T18:31:48.913Z",
|
||||||
|
"groups": [],
|
||||||
|
"user_permissions": []
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"model": "auth.user",
|
"model": "auth.user",
|
||||||
"pk": 3,
|
"pk": 3,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user