1
Fork 0
mirror of https://github.com/Steffo99/sophon.git synced 2024-12-22 14:54:22 +00:00

💥 Improve documentation and optimize a bit

This commit is contained in:
Steffo 2021-10-28 05:58:52 +02:00
parent f5efbbcb9d
commit 970f9e93be

View file

@ -6,6 +6,7 @@ from django.contrib.auth.models import User
from django.db.models import QuerySet from django.db.models import QuerySet
from rest_framework import status as s from rest_framework import status as s
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import Serializer from rest_framework.serializers import Serializer
from rest_framework.views import APIView from rest_framework.views import APIView
@ -144,8 +145,6 @@ class WriteSophonViewSet(ModelViewSet, ReadSophonViewSet, metaclass=abc.ABCMeta)
serializer.save(**hook) serializer.save(**hook)
if getattr(instance, '_prefetched_objects_cache', None): if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {} instance._prefetched_objects_cache = {}
return Response(serializer.data) return Response(serializer.data)
@ -241,21 +240,26 @@ class ResearchGroupViewSet(WriteSophonViewSet):
raise errors.HTTPException(s.HTTP_403_FORBIDDEN) raise errors.HTTPException(s.HTTP_403_FORBIDDEN)
def get_permission_classes(self) -> t.Collection[t.Type[permissions.BasePermission]]: def get_permission_classes(self) -> t.Collection[t.Type[permissions.BasePermission]]:
# Only the owner can destroy a ResearchGroup
if self.action in ["destroy"]: if self.action in ["destroy"]:
return permissions.Admin, return permissions.Admin,
elif self.action in ["update", "partial_update"]: # Otherwise, ignore DRF permissions and delegate to the access serializer
return permissions.Edit,
else: else:
return permissions.AllowAny, return permissions.AllowAny,
def get_custom_serializer_classes(self): def get_custom_serializer_classes(self):
# Use access serializer for join and leave actions
if self.action in ["join", "leave"]: if self.action in ["join", "leave"]:
return self.get_object().get_access_serializer(self.request.user) return self.get_object().get_access_serializer(self.request.user)
# Default to NoneSerializer for not recognized actions to stop DRF from going crazy
else: else:
return serializers.NoneSerializer return serializers.NoneSerializer
@action(detail=True, methods=["post"], name="Join group") @action(detail=True, methods=["post"], name="Join group")
def join(self, request, pk) -> Response: def join(self, request: Request, pk: int) -> Response:
"""
An action that allows an user to join a group with ``"OPEN"`` access.
"""
group = models.ResearchGroup.objects.get(pk=pk) group = models.ResearchGroup.objects.get(pk=pk)
# Raise an error if the user is already in the group # Raise an error if the user is already in the group
@ -276,6 +280,11 @@ class ResearchGroupViewSet(WriteSophonViewSet):
@action(detail=True, methods=["delete"], name="Leave group") @action(detail=True, methods=["delete"], name="Leave group")
def leave(self, request, pk): def leave(self, request, pk):
"""
An action that allows an user to leave a group they're a part of.
Group owners aren't allowed to leave the group they created to prevent situations where a group has no owner.
"""
group = models.ResearchGroup.objects.get(pk=pk) group = models.ResearchGroup.objects.get(pk=pk)
# Raise an error if the user is not in the group # Raise an error if the user is not in the group
@ -286,7 +295,7 @@ class ResearchGroupViewSet(WriteSophonViewSet):
if self.request.user == group.owner: if self.request.user == group.owner:
return Response(status=s.HTTP_403_FORBIDDEN) return Response(status=s.HTTP_403_FORBIDDEN)
# Add the user to the group # Remove the user from the group
group.members.remove(self.request.user) group.members.remove(self.request.user)
serializer_class = group.get_access_serializer(self.request.user) serializer_class = group.get_access_serializer(self.request.user)
@ -297,14 +306,18 @@ class ResearchGroupViewSet(WriteSophonViewSet):
class SophonGroupViewSet(WriteSophonViewSet, metaclass=abc.ABCMeta): class SophonGroupViewSet(WriteSophonViewSet, metaclass=abc.ABCMeta):
""" """
A :class:`ModelViewSet` for objects belonging to a :class:`~.models.ResearchGroup`. An abstract ViewSet for resources belonging to a :class:`~.models.ResearchGroup`, like projects or notebooks.
""" """
@abc.abstractmethod @abc.abstractmethod
def get_group_from_serializer(self, serializer) -> models.ResearchGroup: def get_group_from_serializer(self, serializer) -> models.ResearchGroup:
""" """
:param serializer: The validated serializer containing the data of the object about to be created. A method to find the group that the serialized resource belongs to.
:return: The group the data in the serializer refers to.
Used in :meth:`.hook_create` and :meth:`.hook_update` to prevent the creation of resources on inaccessible groups.
:param serializer: The validated serializer containing the data of the resource about to be created.
:return: The group the serialized resource belongs to.
""" """
raise NotImplementedError() raise NotImplementedError()
@ -314,7 +327,7 @@ class SophonGroupViewSet(WriteSophonViewSet, metaclass=abc.ABCMeta):
if not group.can_edit(self.request.user): if not group.can_edit(self.request.user):
raise errors.HTTPException(s.HTTP_403_FORBIDDEN) raise errors.HTTPException(s.HTTP_403_FORBIDDEN)
return {} return super().hook_create(serializer)
def hook_update(self, serializer) -> dict[str, t.Any]: def hook_update(self, serializer) -> dict[str, t.Any]:
# Allow group transfers only to groups the user has Edit access on # Allow group transfers only to groups the user has Edit access on
@ -322,22 +335,24 @@ class SophonGroupViewSet(WriteSophonViewSet, metaclass=abc.ABCMeta):
if not group.can_edit(self.request.user): if not group.can_edit(self.request.user):
raise errors.HTTPException(s.HTTP_403_FORBIDDEN) raise errors.HTTPException(s.HTTP_403_FORBIDDEN)
return {} return super().hook_update(serializer)
def get_permission_classes(self) -> t.Collection[t.Type[permissions.BasePermission]]: def get_permission_classes(self) -> t.Collection[t.Type[permissions.BasePermission]]:
if self.action in ["destroy", "update", "partial_update"]: # Allow all group members to destroy resources that are not the group itself
if self.action == "destroy":
return permissions.Edit, return permissions.Edit,
# Ignore the DRF permissions and delegate to the access serializer
else: else:
return permissions.AllowAny, return permissions.AllowAny,
class SophonInstanceDetailsView(APIView): class SophonInstanceDetailsView(APIView):
""" """
Get the details of this Sophon instance. A `GET`\\ table APIView that returns details about the current Sophon instance.
""" """
# noinspection PyMethodMayBeStatic,PyUnusedLocal # noinspection PyMethodMayBeStatic,PyUnusedLocal,PyShadowingBuiltins
def get(self, request, format=None): def get(self, request: Request, format=None) -> Response:
details = models.SophonInstanceDetails.objects.get() details = models.SophonInstanceDetails.objects.get()
# noinspection PyPep8Naming # noinspection PyPep8Naming
ViewSerializer = details.get_view_serializer() ViewSerializer = details.get_view_serializer()