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

Add user listing route

This commit is contained in:
Steffo 2021-09-19 15:50:23 +02:00
parent e98d07227f
commit 2a9f996853
3 changed files with 84 additions and 31 deletions

View file

@ -1,4 +1,5 @@
from rest_framework.serializers import Serializer from django.contrib.auth.models import User
from rest_framework.serializers import Serializer, ModelSerializer
class NoneSerializer(Serializer): class NoneSerializer(Serializer):
@ -7,3 +8,24 @@ class NoneSerializer(Serializer):
def create(self, validated_data): def create(self, validated_data):
return None return None
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = (
"id",
"username",
"first_name",
"last_name",
"email",
)
read_only_fields = (
"id",
"username",
"first_name",
"last_name",
"email",
)

View file

@ -6,6 +6,7 @@ from . import views
router = rest_framework.routers.DefaultRouter() router = rest_framework.routers.DefaultRouter()
router.register("groups", views.ResearchGroupViewSet, basename="research-group") router.register("groups", views.ResearchGroupViewSet, basename="research-group")
router.register("users", views.UserViewSet, basename="user")
urlpatterns = [ urlpatterns = [

View file

@ -3,12 +3,13 @@ import typing as t
import deprecation import deprecation
import pkg_resources import pkg_resources
from django.contrib.auth.models import User
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
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.decorators import action from rest_framework.decorators import action
from rest_framework import status from rest_framework import status as s
from . import models from . import models
from . import permissions from . import permissions
@ -26,9 +27,9 @@ class HTTPException(Exception):
return Response(status=self.status) return Response(status=self.status)
class SophonViewSet(ModelViewSet, metaclass=abc.ABCMeta): class ReadSophonViewSet(ReadOnlyModelViewSet, metaclass=abc.ABCMeta):
""" """
An extension to :class:`~rest_framework.viewsets.ModelViewSet` including some essential (but missing) methods. An extension to :class:`~rest_framework.viewsets.ReadOnlyModelViewSet` including some essential (but missing) methods.
""" """
# A QuerySet should be specified, probably # A QuerySet should be specified, probably
@ -50,6 +51,29 @@ class SophonViewSet(ModelViewSet, metaclass=abc.ABCMeta):
""" """
return permissions.AllowAny, return permissions.AllowAny,
def get_serializer_class(self):
if self.action in ["list"]:
return self.get_queryset().model.get_view_serializer()
elif self.action in ["create", "metadata"]:
return self.get_queryset().model.get_creation_serializer()
elif self.action in ["retrieve", "update", "partial_update", "destroy"]:
return self.get_object().get_access_serializer(self.request.user)
else:
return self.get_custom_serializer_classes()
# noinspection PyMethodMayBeStatic
def get_custom_serializer_classes(self):
"""
.. todo:: Define this.
"""
return serializers.NoneSerializer
class WriteSophonViewSet(ModelViewSet, ReadSophonViewSet, metaclass=abc.ABCMeta):
"""
An extension to :class:`ReadSophonViewSet` that adds object-modifying methods.
"""
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def hook_create(self, serializer) -> dict[str, t.Any]: def hook_create(self, serializer) -> dict[str, t.Any]:
""" """
@ -79,7 +103,7 @@ class SophonViewSet(ModelViewSet, metaclass=abc.ABCMeta):
serializer.save(**hook) serializer.save(**hook)
headers = self.get_success_headers(serializer.data) headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) return Response(serializer.data, status=s.HTTP_201_CREATED, headers=headers)
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def hook_update(self, serializer) -> dict[str, t.Any]: def hook_update(self, serializer) -> dict[str, t.Any]:
@ -144,26 +168,32 @@ class SophonViewSet(ModelViewSet, metaclass=abc.ABCMeta):
return e.as_response() return e.as_response()
instance.delete() instance.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=s.HTTP_204_NO_CONTENT)
class UserViewSet(ReadSophonViewSet):
"""
A viewset to list registered users.
"""
def get_queryset(self):
return User.objects.all()
def get_serializer_class(self): def get_serializer_class(self):
if self.action in ["list"]: return serializers.UserSerializer
return self.get_queryset().model.get_view_serializer()
elif self.action in ["create", "metadata"]: # Small hack to make users listable by username
return self.get_queryset().model.get_creation_serializer() # Might break if someone's username is all-numbers, but I'm not sure Django allows that
elif self.action in ["retrieve", "update", "partial_update", "destroy"]: def get_object(self):
return self.get_object().get_access_serializer(self.request.user) pk = self.kwargs["pk"]
try:
pk = int(pk)
except ValueError:
return User.objects.filter(username=pk).get()
else: else:
return self.get_custom_serializer_classes() return User.objects.filter(id=pk).get()
def get_custom_serializer_classes(self):
"""
.. todo:: Define this.
"""
return serializers.NoneSerializer
class ResearchGroupViewSet(SophonViewSet): class ResearchGroupViewSet(WriteSophonViewSet):
""" """
The viewset for :class:`~.models.ResearchGroup`\\ s. The viewset for :class:`~.models.ResearchGroup`\\ s.
""" """
@ -184,16 +214,16 @@ class ResearchGroupViewSet(SophonViewSet):
# Raise an error if the user is already in the group # Raise an error if the user is already in the group
if self.request.user in group.members.all(): if self.request.user in group.members.all():
return Response(status=status.HTTP_409_CONFLICT) return Response(status=s.HTTP_409_CONFLICT)
# Raise an error if the group doesn't allow member joins # Raise an error if the group doesn't allow member joins
if group.access != "OPEN": if group.access != "OPEN":
return Response(status=status.HTTP_403_FORBIDDEN) return Response(status=s.HTTP_403_FORBIDDEN)
# Add the user to the group # Add the user to the group
group.members.add(self.request.user) group.members.add(self.request.user)
return Response(status=status.HTTP_200_OK) return Response(status=s.HTTP_200_OK)
@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):
@ -201,19 +231,19 @@ class ResearchGroupViewSet(SophonViewSet):
# Raise an error if the user is not in the group # Raise an error if the user is not in the group
if self.request.user not in group.members.all(): if self.request.user not in group.members.all():
raise HTTPException(status.HTTP_409_CONFLICT) raise HTTPException(s.HTTP_409_CONFLICT)
# Raise an error if the user is the owner of the group # Raise an error if the user is the owner of the group
if self.request.user == group.owner: if self.request.user == group.owner:
raise HTTPException(status.HTTP_403_FORBIDDEN) raise HTTPException(s.HTTP_403_FORBIDDEN)
# Add the user to the group # Add the user to the group
group.members.remove(self.request.user) group.members.remove(self.request.user)
return Response(status=status.HTTP_200_OK) return Response(status=s.HTTP_200_OK)
class SophonGroupViewSet(SophonViewSet, metaclass=abc.ABCMeta): class SophonGroupViewSet(WriteSophonViewSet, metaclass=abc.ABCMeta):
""" """
A :class:`ModelViewSet` for objects belonging to a :class:`~.models.ResearchGroup`. A :class:`ModelViewSet` for objects belonging to a :class:`~.models.ResearchGroup`.
""" """
@ -230,7 +260,7 @@ class SophonGroupViewSet(SophonViewSet, metaclass=abc.ABCMeta):
# Allow creation of objects only on groups the user has Edit access on # Allow creation of objects only on groups the user has Edit access on
group = self.get_group_from_serializer(serializer) group = self.get_group_from_serializer(serializer)
if not group.can_edit(self.request.user): if not group.can_edit(self.request.user):
raise HTTPException(status.HTTP_403_FORBIDDEN) raise HTTPException(s.HTTP_403_FORBIDDEN)
return {} return {}
@ -238,7 +268,7 @@ class SophonGroupViewSet(SophonViewSet, metaclass=abc.ABCMeta):
# Allow group transfers only to groups the user has Edit access on # Allow group transfers only to groups the user has Edit access on
group: models.ResearchGroup = self.get_group_from_serializer(serializer) group: models.ResearchGroup = self.get_group_from_serializer(serializer)
if not group.can_edit(self.request.user): if not group.can_edit(self.request.user):
raise HTTPException(status.HTTP_403_FORBIDDEN) raise HTTPException(s.HTTP_403_FORBIDDEN)
return {} return {}
@ -257,4 +287,4 @@ class VersionView(APIView):
# noinspection PyMethodMayBeStatic,PyUnusedLocal # noinspection PyMethodMayBeStatic,PyUnusedLocal
def get(self, request, format=None): def get(self, request, format=None):
version = pkg_resources.get_distribution("sophon").version version = pkg_resources.get_distribution("sophon").version
return Response(version, status=status.HTTP_200_OK) return Response(version, status=s.HTTP_200_OK)