From 9449f7e665d5a605c62f299c41613e7c9bc437ff Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 22 Oct 2021 12:38:25 +0200 Subject: [PATCH] feat: Add user view set --- userausfall/rest_api/serializers.py | 12 ++++-- userausfall/rest_api/tests/__init__.py | 5 ++- userausfall/rest_api/tests/auth.py | 26 +----------- userausfall/rest_api/tests/trust_bridges.py | 9 ++++- userausfall/rest_api/tests/userausfall.py | 5 +++ userausfall/rest_api/tests/users.py | 44 +++++++++++++++++++++ userausfall/rest_api/urls.py | 5 ++- userausfall/rest_api/views.py | 9 ++++- 8 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 userausfall/rest_api/tests/users.py diff --git a/userausfall/rest_api/serializers.py b/userausfall/rest_api/serializers.py index 94225d1..5392b10 100644 --- a/userausfall/rest_api/serializers.py +++ b/userausfall/rest_api/serializers.py @@ -7,17 +7,23 @@ from userausfall.views import get_authenticated_user class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User - fields = ["username"] + fields = ["id", "trust_bridge", "url"] + + +class TrustBridgeUserSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = User + fields = ["id", "url", "username"] # the UniqueValidator for username prevents successful validation for existing users extra_kwargs = {"username": {"validators": []}} class TrustBridgeSerializer(serializers.HyperlinkedModelSerializer): - trust_giver = UserSerializer() + trust_giver = TrustBridgeUserSerializer() class Meta: model = TrustBridge - fields = ["is_trusted", "trust_giver"] + fields = ["id", "is_trusted", "trust_giver", "url"] read_only_fields = ["is_trusted"] def create(self, validated_data): diff --git a/userausfall/rest_api/tests/__init__.py b/userausfall/rest_api/tests/__init__.py index f7cf7fe..abbee82 100644 --- a/userausfall/rest_api/tests/__init__.py +++ b/userausfall/rest_api/tests/__init__.py @@ -1,2 +1,3 @@ -from .auth import * # noqa: F401, F403 -from .trust_bridges import * # noqa: F401, F403 +from .auth import AuthenticationTestCase # noqa: F401, F403 +from .trust_bridges import TrustBridgeTestCase # noqa: F401, F403 +from .users import UserTestCase # noqa: F401, F403 diff --git a/userausfall/rest_api/tests/auth.py b/userausfall/rest_api/tests/auth.py index 233f23e..b1ca2a6 100644 --- a/userausfall/rest_api/tests/auth.py +++ b/userausfall/rest_api/tests/auth.py @@ -2,32 +2,10 @@ from rest_framework import status from userausfall.models import User from userausfall.rest_api.tests.userausfall import UserausfallAPITestCase +from userausfall.rest_api.tests.users import UserMixin -class UserMixin: - user: User - password: str - username: str - - def create_user(self): - self.username = f"test{User.objects.count()}" - self.password = "test12345" - self.user = User.objects.create_user(self.username, self.password) - return self.user - - def ensure_user_exists(self): - if not hasattr(self, "user"): - self.create_user() - - def authenticate_user(self): - self.ensure_user_exists() - if hasattr(self.client, "force_authentication"): - self.client.force_authenticate(user=self.user) - else: - self.client.force_login(user=self.user) - - -class UserTestCase(UserMixin, UserausfallAPITestCase): +class AuthenticationTestCase(UserMixin, UserausfallAPITestCase): base_url = "/api/auth" def test_signup(self): diff --git a/userausfall/rest_api/tests/trust_bridges.py b/userausfall/rest_api/tests/trust_bridges.py index 8bb4678..0f78599 100644 --- a/userausfall/rest_api/tests/trust_bridges.py +++ b/userausfall/rest_api/tests/trust_bridges.py @@ -2,7 +2,8 @@ from django.core import mail from rest_framework import status from userausfall.models import TrustBridge -from userausfall.rest_api.tests import UserausfallAPITestCase, UserMixin +from userausfall.rest_api.tests.userausfall import get_url, UserausfallAPITestCase +from userausfall.rest_api.tests.users import UserMixin class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase): @@ -37,13 +38,17 @@ class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase): self.authenticate_user() response = self.client.get(self.get_api_url(url, pk=self.trust_bridge.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( + self.assertDictEqual( response.data, { + "id": self.trust_bridge.id, "is_trusted": False, "trust_giver": { + "id": self.trust_giver.id, "username": self.trust_giver.username, + "url": get_url(response, "user", self.trust_giver), }, + "url": get_url(response, "trustbridge", self.trust_bridge), }, ) diff --git a/userausfall/rest_api/tests/userausfall.py b/userausfall/rest_api/tests/userausfall.py index 30fd6ea..32e335c 100644 --- a/userausfall/rest_api/tests/userausfall.py +++ b/userausfall/rest_api/tests/userausfall.py @@ -1,6 +1,11 @@ +from rest_framework.reverse import reverse from rest_framework.test import APITestCase +def get_url(response, basename, instance): + return reverse(f"{basename}-detail", [instance.pk], request=response.wsgi_request) + + class UserausfallAPITestCase(APITestCase): base_url = "/api" diff --git a/userausfall/rest_api/tests/users.py b/userausfall/rest_api/tests/users.py new file mode 100644 index 0000000..6df5a5e --- /dev/null +++ b/userausfall/rest_api/tests/users.py @@ -0,0 +1,44 @@ +from rest_framework import status + +from userausfall.models import User +from userausfall.rest_api.tests.userausfall import get_url, UserausfallAPITestCase + + +class UserMixin: + user: User + password: str + username: str + + def create_user(self): + self.username = f"test{User.objects.count()}" + self.password = "test12345" + self.user = User.objects.create_user(self.username, self.password) + return self.user + + def ensure_user_exists(self): + if not hasattr(self, "user"): + self.create_user() + + def authenticate_user(self): + self.ensure_user_exists() + if hasattr(self.client, "force_authentication"): + self.client.force_authenticate(user=self.user) + else: + self.client.force_login(user=self.user) + + +class UserTestCase(UserMixin, UserausfallAPITestCase): + def test_retrieve_user(self): + """Retrieve the details of the current user.""" + url = "/users/{pk}/" + self.authenticate_user() + response = self.client.get(self.get_api_url(url, pk=self.user.pk)) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertDictEqual( + response.data, + { + "id": self.user.id, + "trust_bridge": None, + "url": get_url(response, "user", self.user), + }, + ) diff --git a/userausfall/rest_api/urls.py b/userausfall/rest_api/urls.py index 7545a24..5128234 100644 --- a/userausfall/rest_api/urls.py +++ b/userausfall/rest_api/urls.py @@ -2,10 +2,11 @@ from django.urls import include, path from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView from rest_framework import routers -from userausfall.rest_api.views import TrustBridgeViewSet +from userausfall.rest_api.views import TrustBridgeViewSet, UserViewSet router = routers.SimpleRouter() -router.register(r"trust-bridges", TrustBridgeViewSet, "trust-bridge") +router.register(r"trust-bridges", TrustBridgeViewSet, "trustbridge") +router.register(r"users", UserViewSet, "user") urlpatterns = [ path("", include(router.urls)), diff --git a/userausfall/rest_api/views.py b/userausfall/rest_api/views.py index f078fa6..7ddb5c4 100644 --- a/userausfall/rest_api/views.py +++ b/userausfall/rest_api/views.py @@ -4,7 +4,7 @@ from rest_framework.decorators import action from rest_framework.response import Response from userausfall.models import MissingUserAttribute, PasswordMismatch, TrustBridge, User -from userausfall.rest_api.serializers import TrustBridgeSerializer +from userausfall.rest_api.serializers import TrustBridgeSerializer, UserSerializer from userausfall.views import get_authenticated_user @@ -18,7 +18,12 @@ class TrustBridgeViewSet( return self.queryset.filter(trust_taker=get_authenticated_user(self.request)) -class UserViewSet(viewsets.GenericViewSet): +class UserViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): + serializer_class = UserSerializer + + def get_queryset(self): + return User.objects.filter(pk=get_authenticated_user(self.request).pk) + @action(detail=True, methods=["post"]) def activate(self, request, pk=None): """Create the corresponding LDAP account."""