Fix Editor filter and view permissions

This commit is contained in:
IRBorisov 2024-06-03 01:17:27 +03:00
parent f4c2731b72
commit 93d56ef4fa
9 changed files with 30 additions and 11 deletions

View File

@ -1,5 +1,5 @@
''' Custom Permission classes.
Hierarchy: Anonymous -> User -> Editor -> Owner -> Admin
Hierarchy: Anyone -> User -> Editor -> Owner -> Admin
'''
from typing import Any, cast
@ -66,6 +66,16 @@ class ItemEditor(ItemOwner):
return super().has_object_permission(request, view, obj)
class ItemAnyone(ItemEditor):
''' Item permission: Anyone if public. '''
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
item = _extract_item(obj)
if item.access_policy == m.AccessPolicy.PUBLIC:
return True
return super().has_object_permission(request, view, obj)
class EditorMixin(APIView):
''' Editor permissions mixin for API views. '''

View File

@ -36,7 +36,9 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
'load_trs', 'cst_create', 'cst_delete_multiple',
'reset_aliases', 'cst_rename', 'cst_substitute'
]:
permission_list = [permissions.ItemOwner]
permission_list = [permissions.ItemEditor]
elif self.action in ['contents', 'details', 'export_trs', 'resolve', 'check']:
permission_list = [permissions.ItemAnyone]
else:
permission_list = [permissions.Anyone]
return [permission() for permission in permission_list]

View File

@ -3,7 +3,7 @@ from django.contrib.auth import authenticate
from django.contrib.auth.password_validation import validate_password
from rest_framework import serializers
from apps.rsform.models import Subscription
from apps.rsform.models import Editor, Subscription
from . import messages as msg
from . import models
@ -69,14 +69,16 @@ class AuthSerializer(serializers.Serializer):
'id': None,
'username': '',
'is_staff': False,
'subscriptions': []
'subscriptions': [],
'editor': []
}
else:
return {
'id': instance.pk,
'username': instance.username,
'is_staff': instance.is_staff,
'subscriptions': [sub.item.pk for sub in Subscription.objects.filter(user=instance)]
'subscriptions': [sub.item.pk for sub in Subscription.objects.filter(user=instance)],
'editor': [edit.item.pk for edit in Editor.objects.filter(editor=instance)]
}

View File

@ -44,6 +44,7 @@ class TestUserAPIViews(EndpointTester):
self.assertEqual(response.data['username'], self.user.username)
self.assertEqual(response.data['is_staff'], self.user.is_staff)
self.assertEqual(response.data['subscriptions'], [])
self.assertEqual(response.data['editor'], [])
self.logout()
response = self.executeOK()
@ -51,6 +52,7 @@ class TestUserAPIViews(EndpointTester):
self.assertEqual(response.data['username'], '')
self.assertEqual(response.data['is_staff'], False)
self.assertEqual(response.data['subscriptions'], [])
self.assertEqual(response.data['editor'], [])
class TestUserUserProfileAPIView(EndpointTester):

View File

@ -112,8 +112,10 @@ class UpdatePassword(views.APIView):
if serializer.is_valid():
old_password = serializer.data.get("old_password")
if not self.object.check_password(old_password):
return Response({"old_password": ["Wrong password."]},
status=c.HTTP_400_BAD_REQUEST)
return Response(
{"old_password": ["Wrong password."]},
status=c.HTTP_400_BAD_REQUEST
)
# Note: set_password also hashes the password that the user will get
self.object.set_password(serializer.data.get("new_password"))
self.object.save()

View File

@ -172,7 +172,7 @@ DATABASES = {
SPECTACULAR_SETTINGS = {
'TITLE': 'ConceptPortal API',
'DESCRIPTION': 'Портал для работы с экспликациями концептуальных схем',
'VERSION': '0.1.1',
'VERSION': '0.1.2',
'SERVE_INCLUDE_SCHEMA': False,
'COMPONENT_SPLIT_PATCH': True,

View File

@ -81,7 +81,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
result = result.filter(item => filter.isSubscribed == user?.subscriptions.includes(item.id));
}
if (filter.isEditor !== undefined) {
// TODO: load editors from backend
result = result.filter(item => filter.isEditor == user?.editor.includes(item.id));
}
if (filter.query) {
result = result.filter(item => matchLibraryItem(item, filter.query!));

View File

@ -27,6 +27,7 @@ export interface IUser {
*/
export interface ICurrentUser extends Pick<IUser, 'id' | 'username' | 'is_staff'> {
subscriptions: LibraryItemID[];
editor: LibraryItemID[];
}
/**

View File

@ -262,7 +262,7 @@ export function labelLocationHead(head: LocationHead): string {
switch (head) {
case LocationHead.USER: return 'личные (/U)';
case LocationHead.COMMON: return 'общие (/S)';
case LocationHead.LIBRARY: return 'неизменные (/L)';
case LocationHead.LIBRARY: return 'примеры (/L)';
case LocationHead.PROJECTS: return 'проекты (/P)';
}
}
@ -275,7 +275,7 @@ export function describeLocationHead(head: LocationHead): string {
switch (head) {
case LocationHead.USER: return 'Личные схемы пользователя';
case LocationHead.COMMON: return 'Рабочий каталог публичных схем';
case LocationHead.LIBRARY: return 'Каталог неизменных схем';
case LocationHead.LIBRARY: return 'Каталог неизменных схем-примеров';
case LocationHead.PROJECTS: return 'Рабочий каталог проектных схем';
}
}