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:
parent
e98d07227f
commit
2a9f996853
3 changed files with 84 additions and 31 deletions
|
@ -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",
|
||||||
|
)
|
||||||
|
|
|
@ -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 = [
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue