mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Implementing versioning: backend createVersion
This commit is contained in:
parent
e0deefd0cb
commit
ca4882575e
|
@ -34,3 +34,4 @@ DB_PASSWORD=78ACF6C4F3
|
||||||
DEBUG=1
|
DEBUG=1
|
||||||
PYTHONDEVMODE=1
|
PYTHONDEVMODE=1
|
||||||
PYTHONTRACEMALLOC=1
|
PYTHONTRACEMALLOC=1
|
||||||
|
DJANGO_LOG_LEVEL=DEBUG
|
|
@ -34,3 +34,4 @@ DB_PORT=5432
|
||||||
DEBUG=0
|
DEBUG=0
|
||||||
PYTHONDEVMODE=0
|
PYTHONDEVMODE=0
|
||||||
PYTHONTRACEMALLOC=0
|
PYTHONTRACEMALLOC=0
|
||||||
|
DJANGO_LOG_LEVEL=DEBUG
|
|
@ -34,3 +34,4 @@ DB_PASSWORD=78ACF6C4F3
|
||||||
DEBUG=0
|
DEBUG=0
|
||||||
PYTHONDEVMODE=0
|
PYTHONDEVMODE=0
|
||||||
PYTHONTRACEMALLOC=0
|
PYTHONTRACEMALLOC=0
|
||||||
|
DJANGO_LOG_LEVEL=DEBUG
|
|
@ -44,7 +44,16 @@ class SubscriptionAdmin(admin.ModelAdmin):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class VersionAdmin(admin.ModelAdmin):
|
||||||
|
''' Admin model: Versions. '''
|
||||||
|
list_display = ['id', 'item', 'version', 'description', 'time_create']
|
||||||
|
search_fields = [
|
||||||
|
'item__title', 'item__alias'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(models.Constituenta, ConstituentaAdmin)
|
admin.site.register(models.Constituenta, ConstituentaAdmin)
|
||||||
admin.site.register(models.LibraryItem, LibraryItemAdmin)
|
admin.site.register(models.LibraryItem, LibraryItemAdmin)
|
||||||
admin.site.register(models.LibraryTemplate, LibraryTemplateAdmin)
|
admin.site.register(models.LibraryTemplate, LibraryTemplateAdmin)
|
||||||
admin.site.register(models.Subscription, SubscriptionAdmin)
|
admin.site.register(models.Subscription, SubscriptionAdmin)
|
||||||
|
admin.site.register(models.Version, VersionAdmin)
|
||||||
|
|
30
rsconcept/backend/apps/rsform/migrations/0004_version.py
Normal file
30
rsconcept/backend/apps/rsform/migrations/0004_version.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-03-03 10:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rsform', '0003_alter_constituenta_definition_raw_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Version',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('version', models.CharField(max_length=20, verbose_name='Версия')),
|
||||||
|
('description', models.TextField(blank=True, verbose_name='Описание')),
|
||||||
|
('data', models.JSONField(verbose_name='Содержание')),
|
||||||
|
('time_create', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rsform.libraryitem', verbose_name='Схема')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Версии',
|
||||||
|
'verbose_name_plural': 'Версия',
|
||||||
|
'unique_together': {('item', 'version')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -128,6 +128,10 @@ class LibraryItem(Model):
|
||||||
''' 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)]
|
||||||
|
|
||||||
|
def versions(self) -> list['Version']:
|
||||||
|
''' Get all Versions of this item. '''
|
||||||
|
return list(Version.objects.filter(item=self.pk))
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
subscribe = not self.pk and self.owner
|
subscribe = not self.pk and self.owner
|
||||||
|
@ -151,6 +155,40 @@ class LibraryTemplate(Model):
|
||||||
verbose_name_plural = 'Шаблоны'
|
verbose_name_plural = 'Шаблоны'
|
||||||
|
|
||||||
|
|
||||||
|
class Version(Model):
|
||||||
|
''' Library item version archive. '''
|
||||||
|
item: ForeignKey = ForeignKey(
|
||||||
|
verbose_name='Схема',
|
||||||
|
to=LibraryItem,
|
||||||
|
on_delete=CASCADE
|
||||||
|
)
|
||||||
|
version = CharField(
|
||||||
|
verbose_name='Версия',
|
||||||
|
max_length=20,
|
||||||
|
blank=False
|
||||||
|
)
|
||||||
|
description: TextField = TextField(
|
||||||
|
verbose_name='Описание',
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
data: JSONField = JSONField(
|
||||||
|
verbose_name='Содержание'
|
||||||
|
)
|
||||||
|
time_create: DateTimeField = DateTimeField(
|
||||||
|
verbose_name='Дата создания',
|
||||||
|
auto_now_add=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
''' Model metadata. '''
|
||||||
|
verbose_name = 'Версии'
|
||||||
|
verbose_name_plural = 'Версия'
|
||||||
|
unique_together = [['item', 'version']]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f'{self.item} v{self.version}'
|
||||||
|
|
||||||
|
|
||||||
class Subscription(Model):
|
class Subscription(Model):
|
||||||
''' User subscription to library item. '''
|
''' User subscription to library item. '''
|
||||||
user: ForeignKey = ForeignKey(
|
user: ForeignKey = ForeignKey(
|
||||||
|
@ -511,6 +549,16 @@ class RSForm:
|
||||||
cst.definition_resolved = resolved
|
cst.definition_resolved = resolved
|
||||||
cst.save()
|
cst.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create_version(self, version: str, description: str, data) -> Version:
|
||||||
|
''' Creates version for current state. '''
|
||||||
|
return Version.objects.create(
|
||||||
|
item=self.item,
|
||||||
|
version=version,
|
||||||
|
description=description,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def _reset_order(self):
|
def _reset_order(self):
|
||||||
order = 1
|
order = 1
|
||||||
|
|
|
@ -8,7 +8,7 @@ import pyconcept
|
||||||
from cctext import Resolver, Reference, ReferenceType, EntityReference, SyntacticReference
|
from cctext import Resolver, Reference, ReferenceType, EntityReference, SyntacticReference
|
||||||
|
|
||||||
from .utils import fix_old_references
|
from .utils import fix_old_references
|
||||||
from .models import Constituenta, LibraryItem, RSForm
|
from .models import Constituenta, LibraryItem, RSForm, Version
|
||||||
from . import messages as msg
|
from . import messages as msg
|
||||||
|
|
||||||
_CST_TYPE = 'constituenta'
|
_CST_TYPE = 'constituenta'
|
||||||
|
@ -128,9 +128,27 @@ class ExpressionParseSerializer(serializers.Serializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VersionSerializer(serializers.ModelSerializer):
|
||||||
|
''' Serializer: Version data. '''
|
||||||
|
class Meta:
|
||||||
|
''' serializer metadata. '''
|
||||||
|
model = Version
|
||||||
|
fields = 'id', 'version', 'description', 'time_create'
|
||||||
|
read_only_fields = ('item', 'id', 'time_create')
|
||||||
|
|
||||||
|
|
||||||
|
class VersionCreateSerializer(serializers.ModelSerializer):
|
||||||
|
''' Serializer: Version create data. '''
|
||||||
|
class Meta:
|
||||||
|
''' serializer metadata. '''
|
||||||
|
model = Version
|
||||||
|
fields = 'version', 'description'
|
||||||
|
|
||||||
|
|
||||||
class LibraryItemDetailsSerializer(serializers.ModelSerializer):
|
class LibraryItemDetailsSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: LibraryItem detailed data. '''
|
''' Serializer: LibraryItem detailed data. '''
|
||||||
subscribers = serializers.SerializerMethodField()
|
subscribers = serializers.SerializerMethodField()
|
||||||
|
versions = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
''' serializer metadata. '''
|
''' serializer metadata. '''
|
||||||
|
@ -141,6 +159,9 @@ class LibraryItemDetailsSerializer(serializers.ModelSerializer):
|
||||||
def get_subscribers(self, instance: LibraryItem) -> list[int]:
|
def get_subscribers(self, instance: LibraryItem) -> list[int]:
|
||||||
return [item.pk for item in instance.subscribers()]
|
return [item.pk for item in instance.subscribers()]
|
||||||
|
|
||||||
|
def get_versions(self, instance: LibraryItem) -> list:
|
||||||
|
return [VersionSerializer(item).data for item in instance.versions()]
|
||||||
|
|
||||||
|
|
||||||
class ConstituentaSerializer(serializers.ModelSerializer):
|
class ConstituentaSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: Constituenta data. '''
|
''' Serializer: Constituenta data. '''
|
||||||
|
@ -398,7 +419,7 @@ class RSFormSerializer(serializers.ModelSerializer):
|
||||||
model = LibraryItem
|
model = LibraryItem
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def to_representation(self, instance: LibraryItem):
|
def to_representation(self, instance: LibraryItem) -> dict:
|
||||||
result = LibraryItemDetailsSerializer(instance).data
|
result = LibraryItemDetailsSerializer(instance).data
|
||||||
schema = RSForm(instance)
|
schema = RSForm(instance)
|
||||||
result['items'] = []
|
result['items'] = []
|
||||||
|
@ -406,6 +427,25 @@ class RSFormSerializer(serializers.ModelSerializer):
|
||||||
result['items'].append(ConstituentaSerializer(cst).data)
|
result['items'].append(ConstituentaSerializer(cst).data)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def to_versioned_data(self) -> dict:
|
||||||
|
''' Create serializable version representation without redundant data. '''
|
||||||
|
result = self.to_representation(self.instance)
|
||||||
|
del result['versions']
|
||||||
|
del result['subscribers']
|
||||||
|
|
||||||
|
del result['owner']
|
||||||
|
del result['is_common']
|
||||||
|
del result['is_canonical']
|
||||||
|
del result['time_create']
|
||||||
|
del result['time_update']
|
||||||
|
return result
|
||||||
|
|
||||||
|
def from_versioned_data(self, version: int, data: dict) -> dict:
|
||||||
|
''' Load data from version. '''
|
||||||
|
result = self.to_representation(self.instance)
|
||||||
|
result['version'] = version
|
||||||
|
return result | data
|
||||||
|
|
||||||
|
|
||||||
class CstDetailsSerializer(serializers.ModelSerializer):
|
class CstDetailsSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: Constituenta data including parse. '''
|
''' Serializer: Constituenta data including parse. '''
|
||||||
|
|
|
@ -4,6 +4,7 @@ import io
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
|
from rest_framework.test import APITestCase, APIRequestFactory, APIClient
|
||||||
from rest_framework.exceptions import ErrorDetail
|
from rest_framework.exceptions import ErrorDetail
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
from cctext import ReferenceType, split_grams
|
from cctext import ReferenceType, split_grams
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ class TestConstituentaAPI(APITestCase):
|
||||||
|
|
||||||
def test_retrieve(self):
|
def test_retrieve(self):
|
||||||
response = self.client.get(f'/api/constituents/{self.cst1.id}')
|
response = self.client.get(f'/api/constituents/{self.cst1.id}')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['alias'], self.cst1.alias)
|
self.assertEqual(response.data['alias'], self.cst1.alias)
|
||||||
self.assertEqual(response.data['convention'], self.cst1.convention)
|
self.assertEqual(response.data['convention'], self.cst1.convention)
|
||||||
|
|
||||||
|
@ -73,21 +74,21 @@ class TestConstituentaAPI(APITestCase):
|
||||||
f'/api/constituents/{self.cst2.id}',
|
f'/api/constituents/{self.cst2.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/constituents/{self.cst1.id}',
|
f'/api/constituents/{self.cst1.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
self.client.force_authenticate(user=self.user)
|
self.client.force_authenticate(user=self.user)
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/constituents/{self.cst1.id}',
|
f'/api/constituents/{self.cst1.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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')
|
||||||
|
@ -97,7 +98,7 @@ class TestConstituentaAPI(APITestCase):
|
||||||
data=data,
|
data=data,
|
||||||
format='json'
|
format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_update_resolved_no_refs(self):
|
def test_update_resolved_no_refs(self):
|
||||||
data = {
|
data = {
|
||||||
|
@ -105,7 +106,7 @@ class TestConstituentaAPI(APITestCase):
|
||||||
'definition_raw': 'New def'
|
'definition_raw': 'New def'
|
||||||
}
|
}
|
||||||
response = self.client.patch(f'/api/constituents/{self.cst3.id}', data, format='json')
|
response = self.client.patch(f'/api/constituents/{self.cst3.id}', data, format='json')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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')
|
||||||
|
@ -121,7 +122,7 @@ class TestConstituentaAPI(APITestCase):
|
||||||
f'/api/constituents/{self.cst3.id}',
|
f'/api/constituents/{self.cst3.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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)
|
||||||
|
@ -134,7 +135,7 @@ class TestConstituentaAPI(APITestCase):
|
||||||
f'/api/constituents/{self.cst1.id}',
|
f'/api/constituents/{self.cst1.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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)
|
||||||
|
@ -169,12 +170,12 @@ class TestLibraryViewset(APITestCase):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
data = {'title': 'Title'}
|
data = {'title': 'Title'}
|
||||||
response = self.client.post('/api/library', data=data, format='json')
|
response = self.client.post('/api/library', data=data, format='json')
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
def test_create_populate_user(self):
|
def test_create_populate_user(self):
|
||||||
data = {'title': 'Title'}
|
data = {'title': 'Title'}
|
||||||
response = self.client.post('/api/library', data=data, format='json')
|
response = self.client.post('/api/library', data=data, format='json')
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
self.assertEqual(response.data['title'], 'Title')
|
self.assertEqual(response.data['title'], 'Title')
|
||||||
self.assertEqual(response.data['owner'], self.user.id)
|
self.assertEqual(response.data['owner'], self.user.id)
|
||||||
|
|
||||||
|
@ -184,7 +185,7 @@ class TestLibraryViewset(APITestCase):
|
||||||
f'/api/library/{self.owned.id}',
|
f'/api/library/{self.owned.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['title'], 'New title')
|
self.assertEqual(response.data['title'], 'New title')
|
||||||
self.assertEqual(response.data['alias'], self.owned.alias)
|
self.assertEqual(response.data['alias'], self.owned.alias)
|
||||||
|
|
||||||
|
@ -194,37 +195,37 @@ class TestLibraryViewset(APITestCase):
|
||||||
f'/api/library/{self.unowned.id}',
|
f'/api/library/{self.unowned.id}',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
def test_destroy(self):
|
def test_destroy(self):
|
||||||
response = self.client.delete(f'/api/library/{self.owned.id}')
|
response = self.client.delete(f'/api/library/{self.owned.id}')
|
||||||
self.assertTrue(response.status_code in [202, 204])
|
self.assertTrue(response.status_code in [status.HTTP_202_ACCEPTED, status.HTTP_204_NO_CONTENT])
|
||||||
|
|
||||||
def test_destroy_admin_override(self):
|
def test_destroy_admin_override(self):
|
||||||
response = self.client.delete(f'/api/library/{self.unowned.id}')
|
response = self.client.delete(f'/api/library/{self.unowned.id}')
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
self.user.is_staff = True
|
self.user.is_staff = True
|
||||||
self.user.save()
|
self.user.save()
|
||||||
response = self.client.delete(f'/api/library/{self.unowned.id}')
|
response = self.client.delete(f'/api/library/{self.unowned.id}')
|
||||||
self.assertTrue(response.status_code in [202, 204])
|
self.assertTrue(response.status_code in [status.HTTP_202_ACCEPTED, status.HTTP_204_NO_CONTENT])
|
||||||
|
|
||||||
def test_claim(self):
|
def test_claim(self):
|
||||||
response = self.client.post(f'/api/library/{self.owned.id}/claim')
|
response = self.client.post(f'/api/library/{self.owned.id}/claim')
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
self.owned.is_common = True
|
self.owned.is_common = True
|
||||||
self.owned.save()
|
self.owned.save()
|
||||||
response = self.client.post(f'/api/library/{self.owned.id}/claim')
|
response = self.client.post(f'/api/library/{self.owned.id}/claim')
|
||||||
self.assertEqual(response.status_code, 304)
|
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED)
|
||||||
|
|
||||||
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
|
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
self.assertFalse(self.user in self.unowned.subscribers())
|
self.assertFalse(self.user in self.unowned.subscribers())
|
||||||
self.unowned.is_common = True
|
self.unowned.is_common = True
|
||||||
self.unowned.save()
|
self.unowned.save()
|
||||||
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
|
response = self.client.post(f'/api/library/{self.unowned.id}/claim')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.unowned.refresh_from_db()
|
self.unowned.refresh_from_db()
|
||||||
self.assertEqual(self.unowned.owner, self.user)
|
self.assertEqual(self.unowned.owner, self.user)
|
||||||
self.assertEqual(self.unowned.owner, self.user)
|
self.assertEqual(self.unowned.owner, self.user)
|
||||||
|
@ -233,26 +234,26 @@ class TestLibraryViewset(APITestCase):
|
||||||
def test_claim_anonymous(self):
|
def test_claim_anonymous(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
response = self.client.post(f'/api/library/{self.owned.id}/claim')
|
response = self.client.post(f'/api/library/{self.owned.id}/claim')
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
def test_retrieve_common(self):
|
def test_retrieve_common(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
response = self.client.get('/api/library/active')
|
response = self.client.get('/api/library/active')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertTrue(_response_contains(response, self.common))
|
self.assertTrue(_response_contains(response, self.common))
|
||||||
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))
|
||||||
|
|
||||||
def test_retrieve_owned(self):
|
def test_retrieve_owned(self):
|
||||||
response = self.client.get('/api/library/active')
|
response = self.client.get('/api/library/active')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertTrue(_response_contains(response, self.common))
|
self.assertTrue(_response_contains(response, self.common))
|
||||||
self.assertFalse(_response_contains(response, self.unowned))
|
self.assertFalse(_response_contains(response, self.unowned))
|
||||||
self.assertTrue(_response_contains(response, self.owned))
|
self.assertTrue(_response_contains(response, self.owned))
|
||||||
|
|
||||||
def test_retrieve_subscribed(self):
|
def test_retrieve_subscribed(self):
|
||||||
response = self.client.get('/api/library/active')
|
response = self.client.get('/api/library/active')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertFalse(_response_contains(response, self.unowned))
|
self.assertFalse(_response_contains(response, self.unowned))
|
||||||
|
|
||||||
user2 = User.objects.create(username='UserTest2')
|
user2 = User.objects.create(username='UserTest2')
|
||||||
|
@ -260,37 +261,37 @@ class TestLibraryViewset(APITestCase):
|
||||||
Subscription.subscribe(user=user2, item=self.unowned)
|
Subscription.subscribe(user=user2, item=self.unowned)
|
||||||
Subscription.subscribe(user=user2, item=self.owned)
|
Subscription.subscribe(user=user2, item=self.owned)
|
||||||
response = self.client.get('/api/library/active')
|
response = self.client.get('/api/library/active')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertTrue(_response_contains(response, self.unowned))
|
self.assertTrue(_response_contains(response, self.unowned))
|
||||||
self.assertEqual(len(response.data), 3)
|
self.assertEqual(len(response.data), 3)
|
||||||
|
|
||||||
def test_subscriptions(self):
|
def test_subscriptions(self):
|
||||||
response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe')
|
response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
self.assertFalse(self.user in self.unowned.subscribers())
|
self.assertFalse(self.user in self.unowned.subscribers())
|
||||||
|
|
||||||
response = self.client.post(f'/api/library/{self.unowned.id}/subscribe')
|
response = self.client.post(f'/api/library/{self.unowned.id}/subscribe')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
self.assertTrue(self.user in self.unowned.subscribers())
|
self.assertTrue(self.user in self.unowned.subscribers())
|
||||||
|
|
||||||
response = self.client.post(f'/api/library/{self.unowned.id}/subscribe')
|
response = self.client.post(f'/api/library/{self.unowned.id}/subscribe')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
self.assertTrue(self.user in self.unowned.subscribers())
|
self.assertTrue(self.user in self.unowned.subscribers())
|
||||||
|
|
||||||
response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe')
|
response = self.client.delete(f'/api/library/{self.unowned.id}/unsubscribe')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
self.assertFalse(self.user in self.unowned.subscribers())
|
self.assertFalse(self.user in self.unowned.subscribers())
|
||||||
|
|
||||||
def test_retrieve_templates(self):
|
def test_retrieve_templates(self):
|
||||||
response = self.client.get('/api/library/templates')
|
response = self.client.get('/api/library/templates')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertFalse(_response_contains(response, self.common))
|
self.assertFalse(_response_contains(response, self.common))
|
||||||
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))
|
||||||
|
|
||||||
LibraryTemplate.objects.create(lib_source=self.unowned)
|
LibraryTemplate.objects.create(lib_source=self.unowned)
|
||||||
response = self.client.get('/api/library/templates')
|
response = self.client.get('/api/library/templates')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertFalse(_response_contains(response, self.common))
|
self.assertFalse(_response_contains(response, self.common))
|
||||||
self.assertTrue(_response_contains(response, self.unowned))
|
self.assertTrue(_response_contains(response, self.unowned))
|
||||||
self.assertFalse(_response_contains(response, self.owned))
|
self.assertFalse(_response_contains(response, self.owned))
|
||||||
|
@ -312,13 +313,13 @@ class TestRSFormViewset(APITestCase):
|
||||||
title='Test3'
|
title='Test3'
|
||||||
)
|
)
|
||||||
response = self.client.get('/api/rsforms')
|
response = self.client.get('/api/rsforms')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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.owned.item))
|
self.assertTrue(_response_contains(response, self.owned.item))
|
||||||
|
|
||||||
response = self.client.get('/api/library')
|
response = self.client.get('/api/library')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertTrue(_response_contains(response, non_schema))
|
self.assertTrue(_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.owned.item))
|
self.assertTrue(_response_contains(response, self.owned.item))
|
||||||
|
@ -327,7 +328,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
schema = RSForm.create(title='Title1')
|
schema = RSForm.create(title='Title1')
|
||||||
schema.insert_last(alias='X1', insert_type=CstType.BASE)
|
schema.insert_last(alias='X1', insert_type=CstType.BASE)
|
||||||
response = self.client.get(f'/api/rsforms/{schema.item.id}/contents')
|
response = self.client.get(f'/api/rsforms/{schema.item.id}/contents')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_details(self):
|
def test_details(self):
|
||||||
schema = RSForm.create(title='Test', owner=self.user)
|
schema = RSForm.create(title='Test', owner=self.user)
|
||||||
|
@ -342,7 +343,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
|
|
||||||
response = self.client.get(f'/api/rsforms/{schema.item.id}/details')
|
response = self.client.get(f'/api/rsforms/{schema.item.id}/details')
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['title'], 'Test')
|
self.assertEqual(response.data['title'], 'Test')
|
||||||
self.assertEqual(len(response.data['items']), 2)
|
self.assertEqual(len(response.data['items']), 2)
|
||||||
self.assertEqual(response.data['items'][0]['id'], x1.id)
|
self.assertEqual(response.data['items'][0]['id'], x1.id)
|
||||||
|
@ -362,7 +363,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{schema.item.id}/check',
|
f'/api/rsforms/{schema.item.id}/check',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['parseResult'], True)
|
self.assertEqual(response.data['parseResult'], True)
|
||||||
self.assertEqual(response.data['syntax'], Syntax.MATH)
|
self.assertEqual(response.data['syntax'], Syntax.MATH)
|
||||||
self.assertEqual(response.data['astText'], '[=[X1][X1]]')
|
self.assertEqual(response.data['astText'], '[=[X1][X1]]')
|
||||||
|
@ -373,7 +374,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{self.unowned.item.id}/check',
|
f'/api/rsforms/{self.unowned.item.id}/check',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_resolve(self):
|
def test_resolve(self):
|
||||||
schema = RSForm.create(title='Test')
|
schema = RSForm.create(title='Test')
|
||||||
|
@ -385,7 +386,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{schema.item.id}/resolve',
|
f'/api/rsforms/{schema.item.id}/resolve',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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)
|
||||||
|
@ -411,7 +412,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
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}
|
||||||
response = self.client.post('/api/rsforms/import-trs', data=data, format='multipart')
|
response = self.client.post('/api/rsforms/import-trs', data=data, format='multipart')
|
||||||
self.assertEqual(response.status_code, 201)
|
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.assertTrue(response.data['title'] != '')
|
self.assertTrue(response.data['title'] != '')
|
||||||
|
|
||||||
|
@ -419,7 +420,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
schema = RSForm.create(title='Test')
|
schema = RSForm.create(title='Test')
|
||||||
schema.insert_at(1, 'X1', CstType.BASE)
|
schema.insert_at(1, 'X1', CstType.BASE)
|
||||||
response = self.client.get(f'/api/rsforms/{schema.item.id}/export-trs')
|
response = self.client.get(f'/api/rsforms/{schema.item.id}/export-trs')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename=Schema.trs')
|
self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename=Schema.trs')
|
||||||
with io.BytesIO(response.content) as stream:
|
with io.BytesIO(response.content) as stream:
|
||||||
with ZipFile(stream, 'r') as zipped_file:
|
with ZipFile(stream, 'r') as zipped_file:
|
||||||
|
@ -432,7 +433,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{self.unowned.item.id}/cst-create',
|
f'/api/rsforms/{self.unowned.item.id}/cst-create',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
item = self.owned.item
|
item = self.owned.item
|
||||||
Constituenta.objects.create(
|
Constituenta.objects.create(
|
||||||
|
@ -451,7 +452,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{item.id}/cst-create',
|
f'/api/rsforms/{item.id}/cst-create',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
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)
|
||||||
|
@ -467,7 +468,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{item.id}/cst-create',
|
f'/api/rsforms/{item.id}/cst-create',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
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)
|
||||||
|
@ -503,27 +504,27 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{self.unowned.item.id}/cst-rename',
|
f'/api/rsforms/{self.unowned.item.id}/cst-rename',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-rename',
|
f'/api/rsforms/{self.owned.item.id}/cst-rename',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
data = {'id': cst1.pk, 'alias': cst1.alias, 'cst_type': 'term'}
|
data = {'id': cst1.pk, 'alias': cst1.alias, 'cst_type': 'term'}
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-rename',
|
f'/api/rsforms/{self.owned.item.id}/cst-rename',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
data = {'id': cst1.pk, 'alias': cst3.alias}
|
data = {'id': cst1.pk, 'alias': cst3.alias}
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-rename',
|
f'/api/rsforms/{self.owned.item.id}/cst-rename',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
data = {'alias': 'D2', 'cst_type': 'term', 'id': cst1.pk}
|
data = {'alias': 'D2', 'cst_type': 'term', 'id': cst1.pk}
|
||||||
item = self.owned.item
|
item = self.owned.item
|
||||||
|
@ -540,7 +541,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{item.id}/cst-rename',
|
f'/api/rsforms/{item.id}/cst-rename',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['new_cst']['alias'], 'D2')
|
self.assertEqual(response.data['new_cst']['alias'], 'D2')
|
||||||
self.assertEqual(response.data['new_cst']['cst_type'], 'term')
|
self.assertEqual(response.data['new_cst']['cst_type'], 'term')
|
||||||
d1.refresh_from_db()
|
d1.refresh_from_db()
|
||||||
|
@ -578,27 +579,27 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{self.unowned.item.id}/cst-substitute',
|
f'/api/rsforms/{self.unowned.item.id}/cst-substitute',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
data = {'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True}
|
data = {'original': unowned.pk, 'substitution': x1.pk, 'transfer_term': True}
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
data = {'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True}
|
data = {'original': x1.pk, 'substitution': x1.pk, 'transfer_term': True}
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
d1 = Constituenta.objects.create(
|
d1 = Constituenta.objects.create(
|
||||||
alias='D1',
|
alias='D1',
|
||||||
|
@ -612,7 +613,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
f'/api/rsforms/{self.owned.item.id}/cst-substitute',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
d1.refresh_from_db()
|
d1.refresh_from_db()
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
|
@ -634,7 +635,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{item.id}/cst-create',
|
f'/api/rsforms/{item.id}/cst-create',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
self.assertEqual(response.data['new_cst']['alias'], 'X3')
|
self.assertEqual(response.data['new_cst']['alias'], 'X3')
|
||||||
self.assertEqual(response.data['new_cst']['cst_type'], 'basic')
|
self.assertEqual(response.data['new_cst']['cst_type'], 'basic')
|
||||||
self.assertEqual(response.data['new_cst']['convention'], '1')
|
self.assertEqual(response.data['new_cst']['convention'], '1')
|
||||||
|
@ -651,7 +652,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
|
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
x1 = Constituenta.objects.create(schema=schema.item, alias='X1', cst_type='basic', order=1)
|
x1 = Constituenta.objects.create(schema=schema.item, alias='X1', cst_type='basic', order=1)
|
||||||
x2 = Constituenta.objects.create(schema=schema.item, alias='X2', cst_type='basic', order=2)
|
x2 = Constituenta.objects.create(schema=schema.item, alias='X2', cst_type='basic', order=2)
|
||||||
|
@ -662,7 +663,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
)
|
)
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
schema.item.refresh_from_db()
|
schema.item.refresh_from_db()
|
||||||
self.assertEqual(response.status_code, 202)
|
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||||
self.assertEqual(len(response.data['items']), 1)
|
self.assertEqual(len(response.data['items']), 1)
|
||||||
self.assertEqual(schema.constituents().count(), 1)
|
self.assertEqual(schema.constituents().count(), 1)
|
||||||
self.assertEqual(x2.alias, 'X2')
|
self.assertEqual(x2.alias, 'X2')
|
||||||
|
@ -674,7 +675,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
|
f'/api/rsforms/{schema.item.id}/cst-delete-multiple',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
def test_move_constituenta(self):
|
def test_move_constituenta(self):
|
||||||
item = self.owned.item
|
item = self.owned.item
|
||||||
|
@ -683,7 +684,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{item.id}/cst-moveto',
|
f'/api/rsforms/{item.id}/cst-moveto',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=1)
|
x1 = Constituenta.objects.create(schema=item, alias='X1', cst_type='basic', order=1)
|
||||||
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=2)
|
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=2)
|
||||||
|
@ -694,7 +695,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
)
|
)
|
||||||
x1.refresh_from_db()
|
x1.refresh_from_db()
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['id'], item.id)
|
self.assertEqual(response.data['id'], item.id)
|
||||||
self.assertEqual(x1.order, 2)
|
self.assertEqual(x1.order, 2)
|
||||||
self.assertEqual(x2.order, 1)
|
self.assertEqual(x2.order, 1)
|
||||||
|
@ -705,12 +706,12 @@ class TestRSFormViewset(APITestCase):
|
||||||
f'/api/rsforms/{item.id}/cst-moveto',
|
f'/api/rsforms/{item.id}/cst-moveto',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
def test_reset_aliases(self):
|
def test_reset_aliases(self):
|
||||||
item = self.owned.item
|
item = self.owned.item
|
||||||
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
|
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['id'], item.id)
|
self.assertEqual(response.data['id'], item.id)
|
||||||
|
|
||||||
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=1)
|
x2 = Constituenta.objects.create(schema=item, alias='X2', cst_type='basic', order=1)
|
||||||
|
@ -720,7 +721,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
x1.refresh_from_db()
|
x1.refresh_from_db()
|
||||||
x2.refresh_from_db()
|
x2.refresh_from_db()
|
||||||
d11.refresh_from_db()
|
d11.refresh_from_db()
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(x2.order, 1)
|
self.assertEqual(x2.order, 1)
|
||||||
self.assertEqual(x2.alias, 'X1')
|
self.assertEqual(x2.alias, 'X1')
|
||||||
self.assertEqual(x1.order, 2)
|
self.assertEqual(x1.order, 2)
|
||||||
|
@ -729,7 +730,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
self.assertEqual(d11.alias, 'D1')
|
self.assertEqual(d11.alias, 'D1')
|
||||||
|
|
||||||
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
|
response = self.client.patch(f'/api/rsforms/{item.id}/reset-aliases')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_load_trs(self):
|
def test_load_trs(self):
|
||||||
schema = self.owned
|
schema = self.owned
|
||||||
|
@ -744,7 +745,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
data=data, format='multipart'
|
data=data, format='multipart'
|
||||||
)
|
)
|
||||||
schema.item.refresh_from_db()
|
schema.item.refresh_from_db()
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(schema.item.title, 'Test11')
|
self.assertEqual(schema.item.title, 'Test11')
|
||||||
self.assertEqual(len(response.data['items']), 25)
|
self.assertEqual(len(response.data['items']), 25)
|
||||||
self.assertEqual(schema.constituents().count(), 25)
|
self.assertEqual(schema.constituents().count(), 25)
|
||||||
|
@ -769,7 +770,7 @@ class TestRSFormViewset(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
self.assertEqual(response.data['title'], 'Title')
|
self.assertEqual(response.data['title'], 'Title')
|
||||||
self.assertEqual(response.data['items'][0]['alias'], x1.alias)
|
self.assertEqual(response.data['items'][0]['alias'], x1.alias)
|
||||||
self.assertEqual(response.data['items'][0]['term_raw'], x1.term_raw)
|
self.assertEqual(response.data['items'][0]['term_raw'], x1.term_raw)
|
||||||
|
@ -778,6 +779,55 @@ class TestRSFormViewset(APITestCase):
|
||||||
self.assertEqual(response.data['items'][1]['term_resolved'], d1.term_resolved)
|
self.assertEqual(response.data['items'][1]['term_resolved'], d1.term_resolved)
|
||||||
|
|
||||||
|
|
||||||
|
class TestVersionViews(APITestCase):
|
||||||
|
''' Testing versioning endpoints. '''
|
||||||
|
def setUp(self):
|
||||||
|
self.factory = APIRequestFactory()
|
||||||
|
self.user = User.objects.create(username='UserTest')
|
||||||
|
self.client = APIClient()
|
||||||
|
self.client.force_authenticate(user=self.user)
|
||||||
|
self.owned = RSForm.create(title='Test', alias='T1', owner=self.user)
|
||||||
|
self.unowned = RSForm.create(title='Test2', alias='T2')
|
||||||
|
self.x1 = Constituenta.objects.create(
|
||||||
|
schema=self.owned.item,
|
||||||
|
alias='X1',
|
||||||
|
cst_type='basic',
|
||||||
|
convention='testStart',
|
||||||
|
order=1
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_create_version(self):
|
||||||
|
invalid_data = {'description': 'test'}
|
||||||
|
data = {'version': '1.0.0', 'description': 'test'}
|
||||||
|
invalid_id = 1338
|
||||||
|
response = self.client.post(
|
||||||
|
f'/api/rsforms/{invalid_id}/versions/create',
|
||||||
|
data=data, format='json'
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
f'/api/rsforms/{self.unowned.item.id}/versions/create',
|
||||||
|
data=data, format='json'
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
f'/api/rsforms/{self.owned.item.id}/versions/create',
|
||||||
|
data=invalid_data, format='json'
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
f'/api/rsforms/{self.owned.item.id}/versions/create',
|
||||||
|
data=data, format='json'
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
self.assertTrue('version' in response.data)
|
||||||
|
self.assertTrue('schema' in response.data)
|
||||||
|
self.assertTrue(response.data['version'] in [v['id'] for v in response.data['schema']['versions']])
|
||||||
|
|
||||||
|
|
||||||
class TestRSLanguageViews(APITestCase):
|
class TestRSLanguageViews(APITestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.factory = APIRequestFactory()
|
self.factory = APIRequestFactory()
|
||||||
|
@ -793,7 +843,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
'/api/rsforms/create-detailed',
|
'/api/rsforms/create-detailed',
|
||||||
data=data, format='multipart'
|
data=data, format='multipart'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 201)
|
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'], 'Test123')
|
self.assertEqual(response.data['title'], 'Test123')
|
||||||
self.assertEqual(response.data['alias'], 'ks1')
|
self.assertEqual(response.data['alias'], 'ks1')
|
||||||
|
@ -805,7 +855,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
'/api/rsforms/create-detailed',
|
'/api/rsforms/create-detailed',
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 201)
|
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'], 'Test123')
|
self.assertEqual(response.data['title'], 'Test123')
|
||||||
self.assertEqual(response.data['alias'], 'ks1')
|
self.assertEqual(response.data['alias'], 'ks1')
|
||||||
|
@ -818,7 +868,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = convert_to_ascii(request)
|
response = convert_to_ascii(request)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['result'], r'1 \eq 1')
|
self.assertEqual(response.data['result'], r'1 \eq 1')
|
||||||
|
|
||||||
def test_convert_to_ascii_missing_data(self):
|
def test_convert_to_ascii_missing_data(self):
|
||||||
|
@ -828,7 +878,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = convert_to_ascii(request)
|
response = convert_to_ascii(request)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
|
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
|
||||||
|
|
||||||
def test_convert_to_math(self):
|
def test_convert_to_math(self):
|
||||||
|
@ -838,7 +888,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = convert_to_math(request)
|
response = convert_to_math(request)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['result'], r'1=1')
|
self.assertEqual(response.data['result'], r'1=1')
|
||||||
|
|
||||||
def test_convert_to_math_missing_data(self):
|
def test_convert_to_math_missing_data(self):
|
||||||
|
@ -848,7 +898,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = convert_to_math(request)
|
response = convert_to_math(request)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
|
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
|
||||||
|
|
||||||
def test_parse_expression(self):
|
def test_parse_expression(self):
|
||||||
|
@ -858,7 +908,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = parse_expression(request)
|
response = parse_expression(request)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['parseResult'], True)
|
self.assertEqual(response.data['parseResult'], True)
|
||||||
self.assertEqual(response.data['syntax'], Syntax.MATH)
|
self.assertEqual(response.data['syntax'], Syntax.MATH)
|
||||||
self.assertEqual(response.data['astText'], '[=[1][1]]')
|
self.assertEqual(response.data['astText'], '[=[1][1]]')
|
||||||
|
@ -870,7 +920,7 @@ class TestRSLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = parse_expression(request)
|
response = parse_expression(request)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
|
self.assertIsInstance(response.data['expression'][0], ErrorDetail)
|
||||||
|
|
||||||
|
|
||||||
|
@ -889,7 +939,7 @@ class TestNaturalLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = parse_text(request)
|
response = parse_text(request)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc')
|
self._assert_tags(response.data['result'], 'datv,NOUN,plur,anim,masc')
|
||||||
|
|
||||||
def test_inflect(self):
|
def test_inflect(self):
|
||||||
|
@ -899,7 +949,7 @@ class TestNaturalLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = inflect(request)
|
response = inflect(request)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['result'], 'синим слонам')
|
self.assertEqual(response.data['result'], 'синим слонам')
|
||||||
|
|
||||||
def test_generate_lexeme(self):
|
def test_generate_lexeme(self):
|
||||||
|
@ -909,6 +959,6 @@ class TestNaturalLanguageViews(APITestCase):
|
||||||
data=data, format='json'
|
data=data, format='json'
|
||||||
)
|
)
|
||||||
response = generate_lexeme(request)
|
response = generate_lexeme(request)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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'], 'синий слон')
|
||||||
|
|
|
@ -13,6 +13,7 @@ urlpatterns = [
|
||||||
path('constituents/<int:pk>', views.ConstituentAPIView.as_view(), name='constituenta-detail'),
|
path('constituents/<int:pk>', views.ConstituentAPIView.as_view(), name='constituenta-detail'),
|
||||||
path('rsforms/import-trs', views.TrsImportView.as_view()),
|
path('rsforms/import-trs', views.TrsImportView.as_view()),
|
||||||
path('rsforms/create-detailed', views.create_rsform),
|
path('rsforms/create-detailed', views.create_rsform),
|
||||||
|
path('rsforms/<int:pk_item>/versions/create', views.create_version),
|
||||||
|
|
||||||
path('rslang/parse-expression', views.parse_expression),
|
path('rslang/parse-expression', views.parse_expression),
|
||||||
path('rslang/to-ascii', views.convert_to_ascii),
|
path('rslang/to-ascii', views.convert_to_ascii),
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
''' REST API: RSForms for conceptual schemas. '''
|
''' REST API: RSForms for conceptual schemas. '''
|
||||||
import json
|
import json
|
||||||
from typing import cast
|
from typing import cast, Union
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from rest_framework import views, viewsets, filters, generics, permissions
|
from rest_framework import views, viewsets, filters, generics, permissions
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action, api_view, permission_classes
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.decorators import api_view
|
from rest_framework.request import Request
|
||||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||||
from rest_framework import status as c
|
from rest_framework import status as c
|
||||||
|
|
||||||
|
@ -27,14 +27,14 @@ class LibraryActiveView(generics.ListAPIView):
|
||||||
serializer_class = s.LibraryItemSerializer
|
serializer_class = s.LibraryItemSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
if self.request.user.is_anonymous:
|
||||||
if not user.is_anonymous:
|
return m.LibraryItem.objects.filter(is_common=True).order_by('-time_update')
|
||||||
|
else:
|
||||||
|
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(
|
||||||
Q(is_common=True) | Q(owner=user) | Q(subscription__user=user)
|
Q(is_common=True) | Q(owner=user) | Q(subscription__user=user)
|
||||||
).distinct().order_by('-time_update')
|
).distinct().order_by('-time_update')
|
||||||
else:
|
|
||||||
return m.LibraryItem.objects.filter(is_common=True).order_by('-time_update')
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(tags=['Library'])
|
@extend_schema(tags=['Library'])
|
||||||
|
@ -86,14 +86,14 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
if self.action in ['update', 'destroy', 'partial_update']:
|
if self.action in ['update', 'destroy', 'partial_update']:
|
||||||
permission_classes = [utils.ObjectOwnerOrAdmin]
|
permission_list = [utils.ObjectOwnerOrAdmin]
|
||||||
elif self.action in ['create', 'clone', 'subscribe', 'unsubscribe']:
|
elif self.action in ['create', 'clone', 'subscribe', 'unsubscribe']:
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_list = [permissions.IsAuthenticated]
|
||||||
elif self.action in ['claim']:
|
elif self.action in ['claim']:
|
||||||
permission_classes = [utils.IsClaimable]
|
permission_list = [utils.IsClaimable]
|
||||||
else:
|
else:
|
||||||
permission_classes = [permissions.AllowAny]
|
permission_list = [permissions.AllowAny]
|
||||||
return [permission() for permission in permission_classes]
|
return [permission() for permission in permission_list]
|
||||||
|
|
||||||
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())
|
||||||
|
@ -109,7 +109,7 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@action(detail=True, methods=['post'], url_path='clone')
|
@action(detail=True, methods=['post'], url_path='clone')
|
||||||
def clone(self, request, pk):
|
def clone(self, request: Request, pk):
|
||||||
''' Endpoint: Create deep copy of library item. '''
|
''' Endpoint: Create deep copy of library item. '''
|
||||||
serializer = s.LibraryItemSerializer(data=request.data)
|
serializer = s.LibraryItemSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -141,13 +141,13 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'])
|
||||||
def claim(self, request, pk=None):
|
def claim(self, request: Request, pk=None):
|
||||||
''' Endpoint: Claim ownership of LibraryItem. '''
|
''' Endpoint: Claim ownership of LibraryItem. '''
|
||||||
item = self._get_item()
|
item = self._get_item()
|
||||||
if item.owner == self.request.user:
|
if item.owner == self.request.user:
|
||||||
return Response(status=304)
|
return Response(status=c.HTTP_304_NOT_MODIFIED)
|
||||||
else:
|
else:
|
||||||
item.owner = self.request.user
|
item.owner = cast(m.User, self.request.user)
|
||||||
item.save()
|
item.save()
|
||||||
m.Subscription.subscribe(user=item.owner, item=item)
|
m.Subscription.subscribe(user=item.owner, item=item)
|
||||||
return Response(
|
return Response(
|
||||||
|
@ -162,10 +162,10 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
responses={c.HTTP_204_NO_CONTENT: None}
|
responses={c.HTTP_204_NO_CONTENT: None}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'])
|
||||||
def subscribe(self, request, pk):
|
def subscribe(self, request: Request, pk):
|
||||||
''' Endpoint: Subscribe current user to item. '''
|
''' Endpoint: Subscribe current user to item. '''
|
||||||
item = self._get_item()
|
item = self._get_item()
|
||||||
m.Subscription.subscribe(user=self.request.user, item=item)
|
m.Subscription.subscribe(user=cast(m.User, self.request.user), item=item)
|
||||||
return Response(status=c.HTTP_204_NO_CONTENT)
|
return Response(status=c.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
|
@ -175,10 +175,10 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
responses={c.HTTP_204_NO_CONTENT: None},
|
responses={c.HTTP_204_NO_CONTENT: None},
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['delete'])
|
@action(detail=True, methods=['delete'])
|
||||||
def unsubscribe(self, request, pk):
|
def unsubscribe(self, request: Request, pk):
|
||||||
''' Endpoint: Unsubscribe current user from item. '''
|
''' Endpoint: Unsubscribe current user from item. '''
|
||||||
item = self._get_item()
|
item = self._get_item()
|
||||||
m.Subscription.unsubscribe(user=self.request.user, item=item)
|
m.Subscription.unsubscribe(user=cast(m.User, self.request.user), item=item)
|
||||||
return Response(status=c.HTTP_204_NO_CONTENT)
|
return Response(status=c.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
serializer_class = s.LibraryItemSerializer
|
serializer_class = s.LibraryItemSerializer
|
||||||
|
|
||||||
def _get_schema(self) -> m.RSForm:
|
def _get_schema(self) -> m.RSForm:
|
||||||
return m.RSForm(self.get_object()) # type: ignore
|
return m.RSForm(cast(m.LibraryItem, self.get_object()))
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
''' Determine permission class. '''
|
''' Determine permission class. '''
|
||||||
|
@ -208,7 +208,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_201_CREATED: s.NewCstResponse}
|
responses={c.HTTP_201_CREATED: s.NewCstResponse}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'], url_path='cst-create')
|
@action(detail=True, methods=['post'], url_path='cst-create')
|
||||||
def cst_create(self, request, pk):
|
def cst_create(self, request: Request, pk):
|
||||||
''' Create new constituenta. '''
|
''' Create new constituenta. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
serializer = s.CstCreateSerializer(data=request.data)
|
serializer = s.CstCreateSerializer(data=request.data)
|
||||||
|
@ -237,7 +237,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
@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, pk):
|
def cst_rename(self, request: Request, pk):
|
||||||
''' Rename constituenta possibly changing type. '''
|
''' Rename constituenta possibly changing type. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
serializer = s.CstRenameSerializer(data=request.data, context={'schema': schema})
|
serializer = s.CstRenameSerializer(data=request.data, context={'schema': schema})
|
||||||
|
@ -264,7 +264,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
)
|
)
|
||||||
@transaction.atomic
|
@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, pk):
|
def cst_substitute(self, request: Request, pk):
|
||||||
''' Substitute occurrences of constituenta with another one. '''
|
''' Substitute occurrences of constituenta with another one. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
serializer = s.CstSubstituteSerializer(data=request.data, context={'schema': schema})
|
serializer = s.CstSubstituteSerializer(data=request.data, context={'schema': schema})
|
||||||
|
@ -287,7 +287,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_202_ACCEPTED: s.RSFormParseSerializer}
|
responses={c.HTTP_202_ACCEPTED: s.RSFormParseSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['patch'], url_path='cst-delete-multiple')
|
@action(detail=True, methods=['patch'], url_path='cst-delete-multiple')
|
||||||
def cst_delete_multiple(self, request, pk):
|
def cst_delete_multiple(self, request: Request, pk):
|
||||||
''' Endpoint: Delete multiple constituents. '''
|
''' Endpoint: Delete multiple constituents. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
serializer = s.CstListSerializer(
|
serializer = s.CstListSerializer(
|
||||||
|
@ -309,7 +309,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['patch'], url_path='cst-moveto')
|
@action(detail=True, methods=['patch'], url_path='cst-moveto')
|
||||||
def cst_moveto(self, request, pk):
|
def cst_moveto(self, request: Request, pk):
|
||||||
''' Endpoint: Move multiple constituents. '''
|
''' Endpoint: Move multiple constituents. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
serializer = s.CstMoveSerializer(
|
serializer = s.CstMoveSerializer(
|
||||||
|
@ -334,7 +334,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['patch'], url_path='reset-aliases')
|
@action(detail=True, methods=['patch'], url_path='reset-aliases')
|
||||||
def reset_aliases(self, request, pk):
|
def reset_aliases(self, request: Request, pk):
|
||||||
''' Endpoint: Recreate all aliases based on order. '''
|
''' Endpoint: Recreate all aliases based on order. '''
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
schema.reset_aliases()
|
schema.reset_aliases()
|
||||||
|
@ -350,12 +350,12 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['patch'], url_path='load-trs')
|
@action(detail=True, methods=['patch'], url_path='load-trs')
|
||||||
def load_trs(self, request, pk):
|
def load_trs(self, request: Request, pk):
|
||||||
''' Endpoint: Load data from file and replace current schema. '''
|
''' Endpoint: Load data from file and replace current schema. '''
|
||||||
serializer = s.RSFormUploadSerializer(data=request.data)
|
input_serializer = s.RSFormUploadSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
input_serializer.is_valid(raise_exception=True)
|
||||||
schema = self._get_schema()
|
schema = self._get_schema()
|
||||||
load_metadata = serializer.validated_data['load_metadata']
|
load_metadata = input_serializer.validated_data['load_metadata']
|
||||||
data = utils.read_trs(request.FILES['file'].file)
|
data = utils.read_trs(request.FILES['file'].file)
|
||||||
data['id'] = schema.item.pk
|
data['id'] = schema.item.pk
|
||||||
|
|
||||||
|
@ -364,10 +364,10 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
context={'load_meta': load_metadata}
|
context={'load_meta': load_metadata}
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
schema = serializer.save()
|
result = serializer.save()
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data=s.RSFormParseSerializer(schema.item).data
|
data=s.RSFormParseSerializer(result.item).data
|
||||||
)
|
)
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
|
@ -377,7 +377,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.RSFormSerializer}
|
responses={c.HTTP_200_OK: s.RSFormSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'])
|
||||||
def contents(self, 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())
|
||||||
return Response(
|
return Response(
|
||||||
|
@ -392,10 +392,9 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
responses={c.HTTP_200_OK: s.RSFormParseSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'])
|
||||||
def details(self, request, pk):
|
def details(self, request: Request, pk):
|
||||||
''' Endpoint: Detailed schema view including statuses and parse. '''
|
''' Endpoint: Detailed schema view including statuses and parse. '''
|
||||||
schema = self._get_schema()
|
serializer = s.RSFormParseSerializer(cast(m.LibraryItem, self.get_object()))
|
||||||
serializer = s.RSFormParseSerializer(schema.item)
|
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data=serializer.data
|
data=serializer.data
|
||||||
|
@ -408,7 +407,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.ExpressionParseSerializer},
|
responses={c.HTTP_200_OK: s.ExpressionParseSerializer},
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'])
|
||||||
def check(self, 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)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -427,7 +426,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={c.HTTP_200_OK: s.ResolverSerializer}
|
responses={c.HTTP_200_OK: s.ResolverSerializer}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'])
|
||||||
def resolve(self, 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)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -446,7 +445,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
responses={(c.HTTP_200_OK, 'application/zip'): bytes}
|
responses={(c.HTTP_200_OK, 'application/zip'): bytes}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=['get'], url_path='export-trs')
|
@action(detail=True, methods=['get'], url_path='export-trs')
|
||||||
def export_trs(self, request, pk):
|
def export_trs(self, request: Request, pk):
|
||||||
''' Endpoint: Download Exteor compatible file. '''
|
''' Endpoint: Download Exteor compatible file. '''
|
||||||
schema = s.RSFormTRSSerializer(self._get_schema()).data
|
schema = s.RSFormTRSSerializer(self._get_schema()).data
|
||||||
trs = utils.write_trs(schema)
|
trs = utils.write_trs(schema)
|
||||||
|
@ -465,6 +464,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
class TrsImportView(views.APIView):
|
class TrsImportView(views.APIView):
|
||||||
''' Endpoint: Upload RS form in Exteor format. '''
|
''' Endpoint: Upload RS form in Exteor format. '''
|
||||||
serializer_class = s.FileSerializer
|
serializer_class = s.FileSerializer
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
summary='import TRS file into RSForm',
|
summary='import TRS file into RSForm',
|
||||||
|
@ -472,11 +472,9 @@ class TrsImportView(views.APIView):
|
||||||
request=s.FileSerializer,
|
request=s.FileSerializer,
|
||||||
responses={c.HTTP_201_CREATED: s.LibraryItemSerializer}
|
responses={c.HTTP_201_CREATED: s.LibraryItemSerializer}
|
||||||
)
|
)
|
||||||
def post(self, request):
|
def post(self, request: Request):
|
||||||
data = utils.read_trs(request.FILES['file'].file)
|
data = utils.read_trs(request.FILES['file'].file)
|
||||||
owner = self.request.user
|
owner = cast(m.User, self.request.user)
|
||||||
if owner.is_anonymous:
|
|
||||||
owner = None
|
|
||||||
_prepare_rsform_data(data, request, owner)
|
_prepare_rsform_data(data, request, owner)
|
||||||
serializer = s.RSFormTRSSerializer(
|
serializer = s.RSFormTRSSerializer(
|
||||||
data=data,
|
data=data,
|
||||||
|
@ -498,11 +496,9 @@ class TrsImportView(views.APIView):
|
||||||
responses={c.HTTP_201_CREATED: s.LibraryItemSerializer}
|
responses={c.HTTP_201_CREATED: s.LibraryItemSerializer}
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def create_rsform(request):
|
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 = request.user
|
owner = cast(m.User, request.user) if not request.user.is_anonymous else None
|
||||||
if owner.is_anonymous:
|
|
||||||
owner = None
|
|
||||||
if 'file' not in request.FILES:
|
if 'file' not in request.FILES:
|
||||||
serializer = s.LibraryItemSerializer(data=request.data)
|
serializer = s.LibraryItemSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -517,16 +513,17 @@ def create_rsform(request):
|
||||||
else:
|
else:
|
||||||
data = utils.read_trs(request.FILES['file'].file)
|
data = utils.read_trs(request.FILES['file'].file)
|
||||||
_prepare_rsform_data(data, request, owner)
|
_prepare_rsform_data(data, request, owner)
|
||||||
serializer = s.RSFormTRSSerializer(data=data, context={'load_meta': True})
|
serializer_rsform = s.RSFormTRSSerializer(data=data, context={'load_meta': True})
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer_rsform.is_valid(raise_exception=True)
|
||||||
schema = serializer.save()
|
schema = serializer_rsform.save()
|
||||||
result = s.LibraryItemSerializer(schema.item)
|
result = s.LibraryItemSerializer(schema.item)
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_201_CREATED,
|
status=c.HTTP_201_CREATED,
|
||||||
data=result.data
|
data=result.data
|
||||||
)
|
)
|
||||||
|
|
||||||
def _prepare_rsform_data(data: dict, request, owner: m.User):
|
|
||||||
|
def _prepare_rsform_data(data: dict, request: Request, owner: Union[m.User, None]):
|
||||||
data['owner'] = owner
|
data['owner'] = owner
|
||||||
if 'title' in request.data and request.data['title'] != '':
|
if 'title' in request.data and request.data['title'] != '':
|
||||||
data['title'] = request.data['title']
|
data['title'] = request.data['title']
|
||||||
|
@ -548,6 +545,45 @@ def _prepare_rsform_data(data: dict, request, owner: m.User):
|
||||||
data['is_canonical'] = is_canonical
|
data['is_canonical'] = is_canonical
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
summary='save version for RSForm copying current content',
|
||||||
|
tags=['Versions'],
|
||||||
|
request=s.VersionCreateSerializer,
|
||||||
|
responses={
|
||||||
|
c.HTTP_201_CREATED: s.RSFormParseSerializer,
|
||||||
|
c.HTTP_403_FORBIDDEN: None,
|
||||||
|
c.HTTP_404_NOT_FOUND: None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@api_view(['POST'])
|
||||||
|
@permission_classes([permissions.IsAuthenticated])
|
||||||
|
def create_version(request: Request, pk_item: int):
|
||||||
|
''' Endpoint: Create new version for RSForm copying current content. '''
|
||||||
|
try:
|
||||||
|
item = m.LibraryItem.objects.get(pk=pk_item)
|
||||||
|
except m.LibraryItem.DoesNotExist:
|
||||||
|
return Response(status=c.HTTP_404_NOT_FOUND)
|
||||||
|
creator = request.user
|
||||||
|
if not creator.is_staff and creator != item.owner:
|
||||||
|
return Response(status=c.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
|
version_input = s.VersionCreateSerializer(data=request.data)
|
||||||
|
version_input.is_valid(raise_exception=True)
|
||||||
|
data = s.RSFormSerializer(item).to_versioned_data()
|
||||||
|
result = m.RSForm(item).create_version(
|
||||||
|
version=version_input.validated_data['version'],
|
||||||
|
description=version_input.validated_data['description'],
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
return Response(
|
||||||
|
status=c.HTTP_201_CREATED,
|
||||||
|
data={
|
||||||
|
'version': result.pk,
|
||||||
|
'schema': s.RSFormParseSerializer(item).data
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
summary='RS expression into Syntax Tree',
|
summary='RS expression into Syntax Tree',
|
||||||
tags=['FormalLanguage'],
|
tags=['FormalLanguage'],
|
||||||
|
@ -556,7 +592,7 @@ def _prepare_rsform_data(data: dict, request, owner: m.User):
|
||||||
auth=None
|
auth=None
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def parse_expression(request):
|
def parse_expression(request: Request):
|
||||||
''' Endpoint: Parse RS expression. '''
|
''' Endpoint: Parse RS expression. '''
|
||||||
serializer = s.ExpressionSerializer(data=request.data)
|
serializer = s.ExpressionSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -576,7 +612,7 @@ def parse_expression(request):
|
||||||
auth=None
|
auth=None
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def convert_to_ascii(request):
|
def convert_to_ascii(request: Request):
|
||||||
''' Endpoint: Convert expression to ASCII syntax. '''
|
''' Endpoint: Convert expression to ASCII syntax. '''
|
||||||
serializer = s.ExpressionSerializer(data=request.data)
|
serializer = s.ExpressionSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -596,7 +632,7 @@ def convert_to_ascii(request):
|
||||||
auth=None
|
auth=None
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def convert_to_math(request):
|
def convert_to_math(request: Request):
|
||||||
''' Endpoint: Convert expression to MATH syntax. '''
|
''' Endpoint: Convert expression to MATH syntax. '''
|
||||||
serializer = s.ExpressionSerializer(data=request.data)
|
serializer = s.ExpressionSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -615,7 +651,7 @@ def convert_to_math(request):
|
||||||
auth=None
|
auth=None
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def inflect(request):
|
def inflect(request: Request):
|
||||||
''' Endpoint: Generate wordform with set grammemes. '''
|
''' Endpoint: Generate wordform with set grammemes. '''
|
||||||
serializer = s.WordFormSerializer(data=request.data)
|
serializer = s.WordFormSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -636,7 +672,7 @@ def inflect(request):
|
||||||
auth=None
|
auth=None
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def generate_lexeme(request):
|
def generate_lexeme(request: Request):
|
||||||
''' Endpoint: Generate complete set of wordforms for lexeme. '''
|
''' Endpoint: Generate complete set of wordforms for lexeme. '''
|
||||||
serializer = s.TextSerializer(data=request.data)
|
serializer = s.TextSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
@ -656,7 +692,7 @@ def generate_lexeme(request):
|
||||||
auth=None
|
auth=None
|
||||||
)
|
)
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def parse_text(request):
|
def parse_text(request: Request):
|
||||||
''' Endpoint: Get likely vocabulary parse. '''
|
''' Endpoint: Get likely vocabulary parse. '''
|
||||||
serializer = s.TextSerializer(data=request.data)
|
serializer = s.TextSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
|
@ -394,8 +394,7 @@ class PhraseParser:
|
||||||
def _filtered_parse(text: str):
|
def _filtered_parse(text: str):
|
||||||
capital = Capitalization.from_text(text)
|
capital = Capitalization.from_text(text)
|
||||||
score_filter = PhraseParser._filter_score(morpho.parse(text))
|
score_filter = PhraseParser._filter_score(morpho.parse(text))
|
||||||
for form in PhraseParser._filter_capital(score_filter, capital):
|
yield from PhraseParser._filter_capital(score_filter, capital)
|
||||||
yield form
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _filter_score(generator):
|
def _filter_score(generator):
|
||||||
|
@ -412,8 +411,7 @@ class PhraseParser:
|
||||||
continue
|
continue
|
||||||
yield form
|
yield form
|
||||||
else:
|
else:
|
||||||
for form in generator:
|
yield from generator
|
||||||
yield form
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_word(text: str, require_index: int = INDEX_NONE,
|
def _parse_word(text: str, require_index: int = INDEX_NONE,
|
||||||
|
|
|
@ -10,6 +10,8 @@ For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/4.1/ref/settings/
|
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
@ -229,6 +231,10 @@ LOGGING = {
|
||||||
},
|
},
|
||||||
'root': {
|
'root': {
|
||||||
'handlers': ['console'],
|
'handlers': ['console'],
|
||||||
'level': 'DEBUG',
|
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO')
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) > 1 and sys.argv[1] == 'test':
|
||||||
|
logging.disable(logging.CRITICAL)
|
||||||
|
|
|
@ -86,6 +86,16 @@ export enum LibraryItemType {
|
||||||
OPERATIONS_SCHEMA = 'oss'
|
OPERATIONS_SCHEMA = 'oss'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents library item version information.
|
||||||
|
*/
|
||||||
|
export interface IVersionInfo {
|
||||||
|
id: number;
|
||||||
|
version: string;
|
||||||
|
description: string;
|
||||||
|
time_create: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents library item common data typical for all item types.
|
* Represents library item common data typical for all item types.
|
||||||
*/
|
*/
|
||||||
|
@ -107,6 +117,8 @@ export interface ILibraryItem {
|
||||||
*/
|
*/
|
||||||
export interface ILibraryItemEx extends ILibraryItem {
|
export interface ILibraryItemEx extends ILibraryItem {
|
||||||
subscribers: number[];
|
subscribers: number[];
|
||||||
|
version?: number;
|
||||||
|
versions: IVersionInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user