From 4cdfe8ff981c50f67c8615919d6d89e79be7c217 Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Thu, 6 Jan 2022 17:30:06 +0100
Subject: [PATCH 3/3] api: provide a profile type management endpoint (#60082)

---
 src/authentic2/api_views.py |  36 ++++++++
 tests/test_api.py           | 177 ++++++++++++++++++++++++++++++++++++
 2 files changed, 213 insertions(+)

diff --git a/src/authentic2/api_views.py b/src/authentic2/api_views.py
index 0decf9d1..2d5f28f7 100644
--- a/src/authentic2/api_views.py
+++ b/src/authentic2/api_views.py
@@ -1051,6 +1051,41 @@ class UserProfilesAPI(ExceptionHandlerMixin, APIView):
 user_profiles = UserProfilesAPI.as_view()
 
 
+class ProfileTypeSerializer(serializers.ModelSerializer):
+    slug = serializers.SlugField(
+        required=False,
+        allow_blank=False,
+        max_length=256,
+        default=SlugFromNameDefault(),
+    )
+    allowed_services = serializers.SlugRelatedField(
+        required=False,
+        many=True,
+        default=SlugFromNameDefault(),
+        queryset=Service.objects.all(),
+        slug_field='slug',
+    )
+
+    class Meta:
+        model = ProfileType
+        fields = (
+            'slug',
+            'name',
+            'allowed_services',
+            'uuid',
+            'id',
+        )
+
+
+class ProfileTypesAPI(api_mixins.GetOrCreateMixinView, ExceptionHandlerMixin, ModelViewSet):
+    permission_classes = (DjangoPermission('custom_user.manage_profile_type'),)
+    serializer_class = ProfileTypeSerializer
+    lookup_field = 'uuid'
+
+    def get_queryset(self):
+        return ProfileType.objects.all()
+
+
 class RoleMembershipAPI(ExceptionHandlerMixin, APIView):
     permission_classes = (permissions.IsAuthenticated,)
 
@@ -1190,6 +1225,7 @@ router = SimpleRouter()
 router.register(r'users', UsersAPI, basename='a2-api-users')
 router.register(r'ous', OrganizationalUnitAPI, basename='a2-api-ous')
 router.register(r'roles', RolesAPI, basename='a2-api-roles')
+router.register(r'profile-types', ProfileTypesAPI, basename='a2-api-profile-types')
 
 
 class CheckPasswordSerializer(serializers.Serializer):
diff --git a/tests/test_api.py b/tests/test_api.py
index ec0610c3..47aede7f 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -2707,3 +2707,180 @@ def test_user_profile_delete(app, superuser):
     assert not Profile.objects.filter(user=user, profile_type=profile_type)
 
     app.delete('/api/users/%s/profiles/one-type/' % user.uuid, status=404)
+
+
+def test_profile_type_get(app, superuser):
+    app.authorization = ('Basic', (superuser.username, superuser.username))
+
+    resp = app.get('/api/profile-types/')
+    assert not resp.json['count']
+    assert not resp.json['results']
+
+    profile_type = ProfileType.objects.create(slug='one-type', name='One Type')
+    resp = app.get('/api/profile-types/')
+    assert resp.json['count'] == 1
+    assert len(resp.json['results']) == 1
+    assert resp.json['results'][0] == {
+        'id': profile_type.id,
+        'slug': 'one-type',
+        'uuid': profile_type.uuid,
+        'name': 'One Type',
+        'allowed_services': [],
+    }
+
+    service = Service.objects.create(name='My Service', slug='my-service')
+    profile_type2 = ProfileType.objects.create(slug='other-type', name='Other Type')
+    profile_type2.allowed_services.add(service)
+    profile_type2.save()
+
+    resp = app.get('/api/profile-types/')
+    assert resp.json['count'] == 2
+    assert len(resp.json['results']) == 2
+    assert resp.json['results'] == [
+        {
+            'id': profile_type.id,
+            'slug': 'one-type',
+            'uuid': profile_type.uuid,
+            'name': 'One Type',
+            'allowed_services': [],
+        },
+        {
+            'id': profile_type2.id,
+            'slug': 'other-type',
+            'uuid': profile_type2.uuid,
+            'name': 'Other Type',
+            'allowed_services': ['my-service'],
+        },
+    ]
+
+    resp = app.get('/api/profile-types/%s/' % profile_type.uuid)
+    assert resp.json == {
+        'id': profile_type.id,
+        'slug': 'one-type',
+        'uuid': profile_type.uuid,
+        'name': 'One Type',
+        'allowed_services': [],
+    }
+
+    service2 = Service.objects.create(name='My Service 2', slug='my-service-2')
+    profile_type2.allowed_services.add(service2)
+    profile_type2.save()
+
+    resp = app.get('/api/profile-types/%s/' % profile_type2.uuid)
+    assert resp.json == {
+        'id': profile_type2.id,
+        'slug': 'other-type',
+        'uuid': profile_type2.uuid,
+        'name': 'Other Type',
+        'allowed_services': ['my-service', 'my-service-2'],
+    }
+
+
+def test_profile_type_post(app, superuser):
+    app.authorization = ('Basic', (superuser.username, superuser.username))
+
+    payload = {
+        'slug': 'one-type',
+        'name': 'One Type',
+        'allowed_services': [],
+    }
+
+    assert not ProfileType.objects.filter(slug='one-type')
+
+    resp = app.post_json('/api/profile-types/', params=payload)
+    profile_type = ProfileType.objects.get(slug='one-type')
+
+    assert resp.json['slug'] == 'one-type'
+    assert resp.json['name'] == 'One Type'
+    assert resp.json['allowed_services'] == []
+    assert resp.json['uuid'] == profile_type.uuid
+    assert resp.json['id'] == profile_type.id
+
+    Service.objects.create(name='My Service', slug='my-service')
+    Service.objects.create(name='My Service 2', slug='my-service-2')
+
+    payload = {
+        'slug': 'other-type',
+        'name': 'Other Type',
+        'allowed_services': ['my-service', 'my-service-2'],
+    }
+
+    assert not ProfileType.objects.filter(slug='other-type')
+
+    resp = app.post_json('/api/profile-types/', params=payload)
+    profile_type = ProfileType.objects.get(slug='other-type')
+
+    assert resp.json['slug'] == 'other-type'
+    assert resp.json['name'] == 'Other Type'
+    assert resp.json['allowed_services'] == ['my-service', 'my-service-2']
+    assert resp.json['uuid'] == profile_type.uuid
+    assert resp.json['id'] == profile_type.id
+
+
+def test_profile_type_get_or_create(app, superuser):
+    app.authorization = ('Basic', (superuser.username, superuser.username))
+
+    payload = {
+        'slug': 'one-type',
+        'name': 'One Type',
+        'allowed_services': [],
+    }
+
+    assert not ProfileType.objects.filter(slug='one-type')
+
+    resp = app.post_json('/api/profile-types/?get_or_create=slug', params=payload)
+    profile_type = ProfileType.objects.get(slug='one-type')
+    number_of_profiles = len(ProfileType.objects.all())
+
+    assert resp.json['slug'] == 'one-type'
+    assert resp.json['name'] == 'One Type'
+    assert resp.json['allowed_services'] == []
+    assert resp.json['uuid'] == profile_type.uuid
+    assert resp.json['id'] == profile_type.id
+
+    app.post_json('/api/profile-types/?get_or_create=slug', params=payload)
+    ProfileType.objects.get(slug='one-type')
+    assert number_of_profiles == len(ProfileType.objects.all())
+
+
+def test_profile_type_update_or_create(app, superuser):
+    app.authorization = ('Basic', (superuser.username, superuser.username))
+
+    payload = {
+        'slug': 'one-type',
+        'name': 'One Type',
+        'allowed_services': [],
+    }
+
+    assert not ProfileType.objects.filter(slug='one-type')
+
+    resp = app.post_json('/api/profile-types/?update_or_create=slug', params=payload)
+    profile_type = ProfileType.objects.get(slug='one-type')
+    number_of_profiles = len(ProfileType.objects.all())
+
+    assert resp.json['slug'] == 'one-type'
+    assert resp.json['name'] == 'One Type'
+    assert resp.json['allowed_services'] == []
+    assert resp.json['uuid'] == profile_type.uuid
+    assert resp.json['id'] == profile_type.id
+
+    payload['name'] = 'Not the same type name'
+    app.post_json('/api/profile-types/?update_or_create=slug', params=payload)
+    profile_type = ProfileType.objects.get(slug='one-type')
+    assert number_of_profiles == len(ProfileType.objects.all())
+    assert profile_type.name == 'Not the same type name'
+
+
+def test_profile_type_delete(app, superuser):
+    app.authorization = ('Basic', (superuser.username, superuser.username))
+
+    profile_type = ProfileType.objects.create(slug='one-type', name='One Type')
+    profile_type2 = ProfileType.objects.create(slug='other-type', name='Other Type')
+
+    resp = app.delete('/api/profile-types/%s/' % profile_type.uuid)
+    assert resp.status_code == 204
+    assert not ProfileType.objects.filter(slug='one-type')
+
+    resp = app.delete('/api/profile-types/%s/' % profile_type2.uuid)
+    assert resp.status_code == 204
+    assert not ProfileType.objects.filter(slug='other-type')
-- 
2.34.1

