From 1dfc8683452c8ac154757b15ed0094201cf7b36f Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 22 Oct 2021 11:43:33 +0200 Subject: [PATCH] refactor: Trust bridge API as a view set --- userausfall/models.py | 7 --- userausfall/rest_api/serializers.py | 9 ++-- userausfall/rest_api/tests/auth.py | 24 ++++++++- userausfall/rest_api/tests/trust_bridges.py | 59 +++++++++++---------- userausfall/rest_api/urls.py | 4 +- userausfall/rest_api/views.py | 14 +++-- userausfall/tests.py | 24 --------- 7 files changed, 71 insertions(+), 70 deletions(-) delete mode 100644 userausfall/tests.py diff --git a/userausfall/models.py b/userausfall/models.py index 003e675..42ebdd3 100644 --- a/userausfall/models.py +++ b/userausfall/models.py @@ -101,13 +101,6 @@ class User(PermissionsMixin, AbstractBaseUser): raise PasswordMismatch("The given password does not match the user's password.") return ldap.create_account(self.username, raw_password) - def get_or_create_trust_bridge(self): - """Returns a trust bridge instance. If it doesn't exist it is created.""" - try: - return self.trust_bridge - except TrustBridge.DoesNotExist: - return TrustBridge.objects.create(trust_taker=self) - def get_primary_email(self): """Returns the primary email address for this user.""" return f"{self.username}@{settings.USERAUSFALL['PRIMARY_EMAIL_DOMAIN']}" diff --git a/userausfall/rest_api/serializers.py b/userausfall/rest_api/serializers.py index 3680a0f..94225d1 100644 --- a/userausfall/rest_api/serializers.py +++ b/userausfall/rest_api/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers from userausfall.models import TrustBridge, User +from userausfall.views import get_authenticated_user class UserSerializer(serializers.HyperlinkedModelSerializer): @@ -19,7 +20,7 @@ class TrustBridgeSerializer(serializers.HyperlinkedModelSerializer): fields = ["is_trusted", "trust_giver"] read_only_fields = ["is_trusted"] - def update(self, instance: TrustBridge, validated_data): - instance.trust_giver, _ = User.objects.get_or_create(username=validated_data["trust_giver"]["username"]) - instance.save() - return instance + def create(self, validated_data): + user = get_authenticated_user(self.context["request"]) + trust_giver, _ = User.objects.get_or_create(username=validated_data["trust_giver"]["username"]) + return TrustBridge.objects.create(trust_taker=user, trust_giver=trust_giver) diff --git a/userausfall/rest_api/tests/auth.py b/userausfall/rest_api/tests/auth.py index 48fb079..233f23e 100644 --- a/userausfall/rest_api/tests/auth.py +++ b/userausfall/rest_api/tests/auth.py @@ -2,7 +2,29 @@ from rest_framework import status from userausfall.models import User from userausfall.rest_api.tests.userausfall import UserausfallAPITestCase -from userausfall.tests 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): diff --git a/userausfall/rest_api/tests/trust_bridges.py b/userausfall/rest_api/tests/trust_bridges.py index c6c8582..e9ec4e5 100644 --- a/userausfall/rest_api/tests/trust_bridges.py +++ b/userausfall/rest_api/tests/trust_bridges.py @@ -1,32 +1,24 @@ from django.core import mail from rest_framework import status -from userausfall.rest_api.tests import UserausfallAPITestCase -from userausfall.tests import UserMixin +from userausfall.models import TrustBridge +from userausfall.rest_api.tests import UserausfallAPITestCase, UserMixin class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase): - def test_retrieve_trust_bridge(self): - """Retrieve the trust bridge information of a user without an ldap account.""" - url = "/trust-bridge/" - self.authenticate_user() - response = self.client.get(self.get_api_url(url)) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - response.data, - { - "is_trusted": False, - "trust_giver": None, - }, - ) + def create_trust_bridge(self): + self.trust_giver = self.create_user() + self.create_user() + self.trust_bridge = TrustBridge.objects.create(trust_taker=self.user, trust_giver=self.trust_giver) + return self.trust_bridge - def test_update_trust_bridge(self): - """Update the trust giver of the user's trust bridge.""" - url = "/trust-bridge/" + def test_create_trust_bridge(self): + """Create a trust bridge for the current user.""" + url = "/trust-bridges/" trust_giver = self.create_user() self.create_user() self.authenticate_user() - response = self.client.put( + response = self.client.post( self.get_api_url(url), { "trust_giver": { @@ -34,16 +26,29 @@ class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase): }, }, ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(TrustBridge.objects.count(), 1) + self.assertEqual(TrustBridge.objects.get().trust_giver, trust_giver) + + def test_retrieve_trust_bridge(self): + """Retrieve the trust bridge information of a user without an ldap account.""" + url = "/trust-bridges/{pk}/" + self.create_trust_bridge() + 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.user.trust_bridge.trust_giver, trust_giver) + self.assertEqual( + response.data, + { + "is_trusted": False, + "trust_giver": { + "username": self.trust_giver.username, + }, + }, + ) - def test_set_trust_giver(self): + def test_send_confirmation_email_on_creation(self): """When setting a trust giver a confirmation email is sent.""" - self.trust_giver = self.create_user() - self.create_user() - trust_bridge = self.user.get_or_create_trust_bridge() - trust_bridge.trust_giver = self.trust_giver - trust_bridge.save() - + self.create_trust_bridge() self.assertEqual(len(mail.outbox), 1) self.assertIn(self.user.trust_bridge.get_confirmation_token(), mail.outbox[0].body) diff --git a/userausfall/rest_api/urls.py b/userausfall/rest_api/urls.py index 0d476a2..7545a24 100644 --- a/userausfall/rest_api/urls.py +++ b/userausfall/rest_api/urls.py @@ -2,9 +2,10 @@ 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 TrustBridgeView +from userausfall.rest_api.views import TrustBridgeViewSet router = routers.SimpleRouter() +router.register(r"trust-bridges", TrustBridgeViewSet, "trust-bridge") urlpatterns = [ path("", include(router.urls)), @@ -12,5 +13,4 @@ urlpatterns = [ path("schema/", SpectacularAPIView.as_view(), name="schema"), path("schema/swagger-ui/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"), path("schema/redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"), - path("trust-bridge/", TrustBridgeView.as_view()), ] diff --git a/userausfall/rest_api/views.py b/userausfall/rest_api/views.py index 1bed186..f078fa6 100644 --- a/userausfall/rest_api/views.py +++ b/userausfall/rest_api/views.py @@ -1,17 +1,21 @@ -from rest_framework import generics, status, viewsets +from djeveric.views import ConfirmModelMixin +from rest_framework import mixins, status, viewsets from rest_framework.decorators import action from rest_framework.response import Response -from userausfall.models import MissingUserAttribute, PasswordMismatch, User +from userausfall.models import MissingUserAttribute, PasswordMismatch, TrustBridge, User from userausfall.rest_api.serializers import TrustBridgeSerializer from userausfall.views import get_authenticated_user -class TrustBridgeView(generics.RetrieveUpdateAPIView): +class TrustBridgeViewSet( + ConfirmModelMixin, mixins.CreateModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet +): + queryset = TrustBridge.objects serializer_class = TrustBridgeSerializer - def get_object(self): - return get_authenticated_user(self.request).get_or_create_trust_bridge() + def get_basic_queryset(self): + return self.queryset.filter(trust_taker=get_authenticated_user(self.request)) class UserViewSet(viewsets.GenericViewSet): diff --git a/userausfall/tests.py b/userausfall/tests.py deleted file mode 100644 index d7d0276..0000000 --- a/userausfall/tests.py +++ /dev/null @@ -1,24 +0,0 @@ -from userausfall.models import User - - -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)