mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Implement editors change for OSS -> RSForm
This commit is contained in:
parent
50760d7d13
commit
be76908788
|
@ -0,0 +1,21 @@
|
|||
# Generated by Django 5.0.7 on 2024-08-06 19:31
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('library', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='editor',
|
||||
name='editor',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Редактор'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 5.0.7 on 2024-08-06 19:35
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('library', '0002_alter_editor_editor'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='librarytemplate',
|
||||
name='lib_source',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.libraryitem', verbose_name='Источник'),
|
||||
),
|
||||
]
|
|
@ -1,14 +1,11 @@
|
|||
''' Models: Editor. '''
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Iterable
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import CASCADE, DateTimeField, ForeignKey, Model
|
||||
|
||||
from apps.users.models import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .LibraryItem import LibraryItem
|
||||
|
||||
|
||||
class Editor(Model):
|
||||
''' Editor list. '''
|
||||
|
@ -20,8 +17,7 @@ class Editor(Model):
|
|||
editor: ForeignKey = ForeignKey(
|
||||
verbose_name='Редактор',
|
||||
to=User,
|
||||
on_delete=CASCADE,
|
||||
null=True
|
||||
on_delete=CASCADE
|
||||
)
|
||||
time_create: DateTimeField = DateTimeField(
|
||||
verbose_name='Дата добавления',
|
||||
|
@ -38,17 +34,17 @@ class Editor(Model):
|
|||
return f'{self.item}: {self.editor}'
|
||||
|
||||
@staticmethod
|
||||
def add(item: 'LibraryItem', user: User) -> bool:
|
||||
def add(item: int, user: int) -> bool:
|
||||
''' Add Editor for item. '''
|
||||
if Editor.objects.filter(item=item, editor=user).exists():
|
||||
if Editor.objects.filter(item_id=item, editor_id=user).exists():
|
||||
return False
|
||||
Editor.objects.create(item=item, editor=user)
|
||||
Editor.objects.create(item_id=item, editor_id=user)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def remove(item: 'LibraryItem', user: User) -> bool:
|
||||
def remove(item: int, user: int) -> bool:
|
||||
''' Remove Editor. '''
|
||||
editor = Editor.objects.filter(item=item, editor=user)
|
||||
editor = Editor.objects.filter(item_id=item, editor_id=user).only('pk')
|
||||
if not editor.exists():
|
||||
return False
|
||||
editor.delete()
|
||||
|
@ -56,16 +52,40 @@ class Editor(Model):
|
|||
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def set(item: 'LibraryItem', users: list[User]):
|
||||
def set(item: int, users: Iterable[int]):
|
||||
''' Set editors for item. '''
|
||||
processed: list[User] = []
|
||||
for editor_item in Editor.objects.filter(item=item):
|
||||
if editor_item.editor not in users:
|
||||
processed: set[int] = set()
|
||||
for editor_item in Editor.objects.filter(item_id=item).only('pk', 'editor_id'):
|
||||
editor_id = editor_item.editor_id
|
||||
if editor_id not in users:
|
||||
editor_item.delete()
|
||||
else:
|
||||
processed.append(editor_item.editor)
|
||||
processed.add(editor_id)
|
||||
|
||||
for user in users:
|
||||
if user not in processed:
|
||||
processed.add(user)
|
||||
Editor.objects.create(item_id=item, editor_id=user)
|
||||
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def set_and_return_diff(item: int, users: Iterable[int]) -> tuple[list[int], list[int]]:
|
||||
''' Set editors for item and return diff. '''
|
||||
processed: list[int] = []
|
||||
deleted: list[int] = []
|
||||
added: list[int] = []
|
||||
for editor_item in Editor.objects.filter(item_id=item).only('pk', 'editor_id'):
|
||||
editor_id = editor_item.editor_id
|
||||
if editor_id not in users:
|
||||
deleted.append(editor_id)
|
||||
editor_item.delete()
|
||||
else:
|
||||
processed.append(editor_id)
|
||||
|
||||
for user in users:
|
||||
if user not in processed:
|
||||
processed.append(user)
|
||||
Editor.objects.create(item=item, editor=user)
|
||||
added.append(user)
|
||||
Editor.objects.create(item_id=item, editor_id=user)
|
||||
|
||||
return (added, deleted)
|
||||
|
|
|
@ -16,7 +16,6 @@ from django.db.models import (
|
|||
|
||||
from apps.users.models import User
|
||||
|
||||
from .Editor import Editor
|
||||
from .Subscription import Subscription
|
||||
from .Version import Version
|
||||
|
||||
|
@ -119,9 +118,9 @@ class LibraryItem(Model):
|
|||
''' Get all subscribers for this item. '''
|
||||
return [subscription.user for subscription in Subscription.objects.filter(item=self.pk).only('user')]
|
||||
|
||||
def editors(self) -> list[User]:
|
||||
def editors(self) -> QuerySet[User]:
|
||||
''' Get all Editors of this item. '''
|
||||
return [item.editor for item in Editor.objects.filter(item=self.pk).only('editor')]
|
||||
return User.objects.filter(editor__item=self.pk)
|
||||
|
||||
def versions(self) -> QuerySet[Version]:
|
||||
''' Get all Versions of this item. '''
|
||||
|
|
|
@ -7,8 +7,7 @@ class LibraryTemplate(Model):
|
|||
lib_source: ForeignKey = ForeignKey(
|
||||
verbose_name='Источник',
|
||||
to='library.LibraryItem',
|
||||
on_delete=CASCADE,
|
||||
null=True
|
||||
on_delete=CASCADE
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -86,7 +86,7 @@ class LibraryItemDetailsSerializer(serializers.ModelSerializer):
|
|||
return [item.pk for item in instance.subscribers()]
|
||||
|
||||
def get_editors(self, instance: LibraryItem) -> list[int]:
|
||||
return [item.pk for item in instance.editors()]
|
||||
return list(instance.editors().values_list('pk', flat=True))
|
||||
|
||||
def get_versions(self, instance: LibraryItem) -> list:
|
||||
return [VersionInnerSerializer(item).data for item in instance.versions()]
|
||||
|
|
|
@ -34,44 +34,65 @@ class TestEditor(TestCase):
|
|||
|
||||
|
||||
def test_add_editor(self):
|
||||
self.assertTrue(Editor.add(self.item, self.user1))
|
||||
self.assertEqual(len(self.item.editors()), 1)
|
||||
self.assertTrue(self.user1 in self.item.editors())
|
||||
self.assertTrue(Editor.add(self.item.pk, self.user1.pk))
|
||||
self.assertEqual(self.item.editors().count(), 1)
|
||||
self.assertTrue(self.user1 in list(self.item.editors()))
|
||||
|
||||
self.assertFalse(Editor.add(self.item, self.user1))
|
||||
self.assertEqual(len(self.item.editors()), 1)
|
||||
self.assertFalse(Editor.add(self.item.pk, self.user1.pk))
|
||||
self.assertEqual(self.item.editors().count(), 1)
|
||||
|
||||
self.assertTrue(Editor.add(self.item, self.user2))
|
||||
self.assertEqual(len(self.item.editors()), 2)
|
||||
self.assertTrue(Editor.add(self.item.pk, self.user2.pk))
|
||||
self.assertEqual(self.item.editors().count(), 2)
|
||||
self.assertTrue(self.user1 in self.item.editors())
|
||||
self.assertTrue(self.user2 in self.item.editors())
|
||||
|
||||
self.user1.delete()
|
||||
self.assertEqual(len(self.item.editors()), 1)
|
||||
self.assertEqual(self.item.editors().count(), 1)
|
||||
|
||||
|
||||
def test_remove_editor(self):
|
||||
self.assertFalse(Editor.remove(self.item, self.user1))
|
||||
Editor.add(self.item, self.user1)
|
||||
Editor.add(self.item, self.user2)
|
||||
self.assertEqual(len(self.item.editors()), 2)
|
||||
self.assertFalse(Editor.remove(self.item.pk, self.user1.pk))
|
||||
Editor.add(self.item.pk, self.user1.pk)
|
||||
Editor.add(self.item.pk, self.user2.pk)
|
||||
self.assertEqual(self.item.editors().count(), 2)
|
||||
|
||||
self.assertTrue(Editor.remove(self.item, self.user1))
|
||||
self.assertEqual(len(self.item.editors()), 1)
|
||||
self.assertTrue(Editor.remove(self.item.pk, self.user1.pk))
|
||||
self.assertEqual(self.item.editors().count(), 1)
|
||||
self.assertTrue(self.user2 in self.item.editors())
|
||||
|
||||
self.assertFalse(Editor.remove(self.item, self.user1))
|
||||
self.assertFalse(Editor.remove(self.item.pk, self.user1.pk))
|
||||
|
||||
|
||||
def test_set_editors(self):
|
||||
Editor.set(self.item, [self.user1])
|
||||
self.assertEqual(self.item.editors(), [self.user1])
|
||||
Editor.set(self.item.pk, [self.user1.pk])
|
||||
self.assertEqual(list(self.item.editors()), [self.user1])
|
||||
|
||||
Editor.set(self.item, [self.user1, self.user1])
|
||||
self.assertEqual(self.item.editors(), [self.user1])
|
||||
Editor.set(self.item.pk, [self.user1.pk, self.user1.pk])
|
||||
self.assertEqual(list(self.item.editors()), [self.user1])
|
||||
|
||||
Editor.set(self.item, [])
|
||||
self.assertEqual(self.item.editors(), [])
|
||||
Editor.set(self.item.pk, [])
|
||||
self.assertEqual(list(self.item.editors()), [])
|
||||
|
||||
Editor.set(self.item, [self.user1, self.user2])
|
||||
Editor.set(self.item.pk, [self.user1.pk, self.user2.pk])
|
||||
self.assertEqual(set(self.item.editors()), set([self.user1, self.user2]))
|
||||
|
||||
def test_set_editors_return_diff(self):
|
||||
added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk])
|
||||
self.assertEqual(added, [self.user1.pk])
|
||||
self.assertEqual(deleted, [])
|
||||
self.assertEqual(list(self.item.editors()), [self.user1])
|
||||
|
||||
added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk, self.user1.pk])
|
||||
self.assertEqual(added, [])
|
||||
self.assertEqual(deleted, [])
|
||||
self.assertEqual(list(self.item.editors()), [self.user1])
|
||||
|
||||
added, deleted = Editor.set_and_return_diff(self.item.pk, [])
|
||||
self.assertEqual(added, [])
|
||||
self.assertEqual(deleted, [self.user1.pk])
|
||||
self.assertEqual(list(self.item.editors()), [])
|
||||
|
||||
added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk, self.user2.pk])
|
||||
self.assertEqual(added, [self.user1.pk, self.user2.pk])
|
||||
self.assertEqual(deleted, [])
|
||||
self.assertEqual(set(self.item.editors()), set([self.user1, self.user2]))
|
||||
|
|
|
@ -197,18 +197,18 @@ class TestLibraryViewset(EndpointTester):
|
|||
self.executeOK(data=data, item=self.owned.pk)
|
||||
self.owned.refresh_from_db()
|
||||
self.assertEqual(self.owned.time_update, time_update)
|
||||
self.assertEqual(self.owned.editors(), [self.user])
|
||||
self.assertEqual(list(self.owned.editors()), [self.user])
|
||||
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(self.owned.editors(), [self.user])
|
||||
self.assertEqual(list(self.owned.editors()), [self.user])
|
||||
|
||||
data = {'users': [self.user2.pk]}
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(self.owned.editors(), [self.user2])
|
||||
self.assertEqual(list(self.owned.editors()), [self.user2])
|
||||
|
||||
data = {'users': []}
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(self.owned.editors(), [])
|
||||
self.assertEqual(list(self.owned.editors()), [])
|
||||
|
||||
data = {'users': [self.user2.pk, self.user.pk]}
|
||||
self.executeOK(data=data)
|
||||
|
|
|
@ -261,8 +261,32 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
|||
item = self._get_item()
|
||||
serializer = s.UsersListSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
editors = serializer.validated_data['users']
|
||||
m.Editor.set(item=item, users=editors)
|
||||
editors: list[int] = request.data['users']
|
||||
|
||||
with transaction.atomic():
|
||||
added, deleted = m.Editor.set_and_return_diff(item.pk, editors)
|
||||
if len(added) >= 0 or len(deleted) >= 0:
|
||||
owned_schemas = OperationSchema(item).owned_schemas().only('pk')
|
||||
if owned_schemas.exists():
|
||||
m.Editor.objects.filter(
|
||||
item__in=owned_schemas,
|
||||
editor_id__in=deleted
|
||||
).delete()
|
||||
|
||||
existing_editors = m.Editor.objects.filter(
|
||||
item__in=owned_schemas,
|
||||
editor__in=added
|
||||
).values_list('item_id', 'editor_id')
|
||||
existing_editor_set = set(existing_editors)
|
||||
|
||||
new_editors = [
|
||||
m.Editor(item=schema, editor_id=user)
|
||||
for schema in owned_schemas
|
||||
for user in added
|
||||
if (item.id, user) not in existing_editor_set
|
||||
]
|
||||
m.Editor.objects.bulk_create(new_editors)
|
||||
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ class OperationSchema:
|
|||
access_policy=self.model.access_policy,
|
||||
location=self.model.location
|
||||
)
|
||||
Editor.set(schema.model, self.model.editors())
|
||||
Editor.set(schema.model.pk, self.model.editors().values_list('pk', flat=True))
|
||||
operation.result = schema.model
|
||||
operation.save()
|
||||
self.save()
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from rest_framework import status
|
||||
|
||||
from apps.library.models import AccessPolicy, LocationHead
|
||||
from apps.library.models import AccessPolicy, Editor, LocationHead
|
||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
||||
from apps.rsform.models import RSForm
|
||||
from apps.users.models import User
|
||||
|
@ -105,3 +105,21 @@ class TestChangeAttributes(EndpointTester):
|
|||
self.assertNotEqual(self.ks1.model.access_policy, data['access_policy'])
|
||||
self.assertNotEqual(self.ks2.model.access_policy, data['access_policy'])
|
||||
self.assertEqual(self.ks3.access_policy, data['access_policy'])
|
||||
|
||||
@decl_endpoint('/api/library/{item}/set-editors', method='patch')
|
||||
def test_set_editors(self):
|
||||
Editor.set(self.owned.model.pk, [self.user2.pk])
|
||||
Editor.set(self.ks1.model.pk, [self.user2.pk, self.user.pk])
|
||||
Editor.set(self.ks3.pk, [self.user2.pk, self.user.pk])
|
||||
data = {'users': [self.user3.pk]}
|
||||
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
|
||||
self.owned.refresh_from_db()
|
||||
self.ks1.refresh_from_db()
|
||||
self.ks2.refresh_from_db()
|
||||
self.ks3.refresh_from_db()
|
||||
self.assertEqual(list(self.owned.model.editors()), [self.user3])
|
||||
self.assertEqual(list(self.ks1.model.editors()), [self.user, self.user2])
|
||||
self.assertEqual(list(self.ks2.model.editors()), [])
|
||||
self.assertEqual(set(self.ks3.editors()), set([self.user, self.user3]))
|
||||
|
|
|
@ -220,7 +220,7 @@ class TestOssViewset(EndpointTester):
|
|||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation_schema(self):
|
||||
self.populateData()
|
||||
Editor.add(self.owned.model, self.user2)
|
||||
Editor.add(self.owned.model.pk, self.user2.pk)
|
||||
data = {
|
||||
'item_data': {
|
||||
'alias': 'Test4',
|
||||
|
|
|
@ -67,9 +67,9 @@ class EndpointTester(APITestCase):
|
|||
|
||||
def toggle_editor(self, item: LibraryItem, value: bool = True):
|
||||
if value:
|
||||
Editor.add(item, self.user)
|
||||
Editor.add(item.pk, self.user.pk)
|
||||
else:
|
||||
Editor.remove(item, self.user)
|
||||
Editor.remove(item.pk, self.user.pk)
|
||||
|
||||
def login(self):
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
|
Loading…
Reference in New Issue
Block a user