Projet

Général

Profil

0002-api-add-identifier-management-to-user-profile-endpoi.patch

Paul Marillonnet, 04 mars 2022 07:52

Télécharger (13 ko)

Voir les différences:

Subject: [PATCH 2/2] api: add identifier management to user profile endpoint
 (#58556)

 src/authentic2/api_urls.py  |  2 +-
 src/authentic2/api_views.py | 63 +++++++++++++++++++-------
 tests/test_api.py           | 90 ++++++++++++++++++++++++++++---------
 3 files changed, 117 insertions(+), 38 deletions(-)
src/authentic2/api_urls.py
33 33
        name='a2-api-role-member',
34 34
    ),
35 35
    url(
36
        r'^users/(?P<user_uuid>[\w+]*)/profiles/(?P<profile_type_slug>[^/]+)/default/$',
36
        r'^users/(?P<user_uuid>[\w+]*)/profiles/(?P<profile_type_slug>[^/]+)/$',
37 37
        api_views.user_profiles,
38 38
        name='a2-api-user-profiles',
39 39
    ),
src/authentic2/api_views.py
965 965

  
966 966
    class Meta:
967 967
        model = Profile
968
        fields = ('data',)
968
        fields = (
969
            'identifier',
970
            'data',
971
        )
972
        extra_kwargs = {
973
            'identifier': {
974
                'required': False,
975
                'allow_blank': True,
976
                'max_length': 256,
977
            }
978
        }
969 979

  
970 980

  
971 981
class UserProfilesAPI(ExceptionHandlerMixin, APIView):
......
977 987
        User = get_user_model()
978 988
        self.profile_type = get_object_or_404(ProfileType, slug=kwargs['profile_type_slug'])
979 989
        self.user = get_object_or_404(User, uuid=kwargs['user_uuid'])
990
        self.identifier = request.GET.get('identifier', '')
980 991

  
981 992
    def get(self, request, *args, **kwargs):
982
        profile = get_object_or_404(Profile, user=self.user, profile_type=self.profile_type)
983
        if not request.user.has_perm('custom_user.view_profile', obj=profile):
993
        if not request.user.has_perm('custom_user.view_profile'):
984 994
            raise PermissionDenied('User not allowed to view user profiles')
985
        return Response(self.serializer_class(profile).data)
995
        if 'identifier' in request.GET:
996
            # request on a single entity
997
            profile = get_object_or_404(
998
                Profile, user=self.user, profile_type=self.profile_type, identifier=self.identifier
999
            )
1000
            return Response(self.serializer_class(profile).data)
1001
        else:
1002
            # user's profiles of a given type
1003
            profiles = Profile.objects.filter(
1004
                user=self.user,
1005
                profile_type=self.profile_type,
1006
            )
1007
            return Response([self.serializer_class(profile).data for profile in profiles])
986 1008

  
987 1009
    def post(self, request, *args, **kwargs):
988 1010
        if not request.user.has_perm('custom_user.create_profile'):
989 1011
            raise PermissionDenied('User not allowed to create user profiles')
990
        serializer = self.serializer_class(data=request.data)
991
        if not serializer.is_valid():
992
            response = {'data': [], 'err': 1, 'err_desc': serializer.errors}
993
            return Response(response, status.HTTP_400_BAD_REQUEST)
994 1012
        try:
995
            profile = Profile.objects.get(user=self.user, profile_type=self.profile_type)
1013
            profile = Profile.objects.get(
1014
                user=self.user, profile_type=self.profile_type, identifier=self.identifier
1015
            )
996 1016
        except Profile.DoesNotExist:
1017
            data = request.data.copy()
1018
            data.update({'identifier': self.identifier})
1019
            serializer = self.serializer_class(data=data)
1020
            if not serializer.is_valid():
1021
                response = {'data': [], 'err': 1, 'err_desc': serializer.errors}
1022
                return Response(response, status.HTTP_400_BAD_REQUEST)
997 1023
            profile = serializer.save()
998 1024
            profile.profile_type = self.profile_type
999 1025
            profile.user = self.user
......
1006 1032
            return Response(
1007 1033
                {'result': 1, 'detail': _('Profile successfully assigned to user')}, status=status.HTTP_200_OK
1008 1034
            )
1035
        else:
1036
            response = {
1037
                'data': [],
1038
                'err': 1,
1039
                'err_desc': 'cannot overwrite already existing profile. use PUT verb instead',
1040
            }
1041
            return Response(response, status.HTTP_400_BAD_REQUEST)
1009 1042

  
1010 1043
    def patch(self, request, *args, **kwargs):
1011
        serializer = self.serializer_class(data=request.data)
1012
        if not serializer.is_valid():
1013
            response = {'data': [], 'err': 1, 'err_desc': serializer.errors}
1014
            return Response(response, status.HTTP_400_BAD_REQUEST)
1015
        profile = get_object_or_404(Profile, user=self.user, profile_type=self.profile_type)
1044
        profile = get_object_or_404(
1045
            Profile, user=self.user, profile_type=self.profile_type, identifier=self.identifier
1046
        )
1016 1047
        if not request.user.has_perm('custom_user.change_profile', obj=profile):
1017 1048
            raise PermissionDenied('User not allowed to change user profiles')
1018 1049
        profile.data = request.data.get('data', {})
......
1028 1059
        return self.patch(request, *args, **kwargs)
1029 1060

  
1030 1061
    def delete(self, request, *args, **kwargs):
1031
        profile = get_object_or_404(Profile, user=self.user, profile_type=self.profile_type)
1062
        profile = get_object_or_404(
1063
            Profile, user=self.user, profile_type=self.profile_type, identifier=self.identifier
1064
        )
1032 1065
        if not request.user.has_perm('custom_user.delete_profile', obj=profile):
1033 1066
            raise PermissionDenied('User not allowed to delete user profiles')
1034 1067
        request.journal.record(
tests/test_api.py
2626 2626
    user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
2627 2627

  
2628 2628
    # wrong type
2629
    resp = app.get('/api/users/%s/profiles/non-existant-slug/default/' % user.uuid, status=404)
2629
    app.get('/api/users/%s/profiles/non-existant-slug/' % user.uuid, status=404)
2630 2630

  
2631 2631
    profile_type = ProfileType.objects.create(slug='one-type', name='One Type')
2632 2632

  
2633 2633
    # wrong user
2634
    resp = app.get('/api/users/1234/profiles/one-type/default/', status=404)
2634
    app.get('/api/users/1234/profiles/one-type/', status=404)
2635 2635

  
2636
    Profile.objects.create(profile_type=profile_type, user=user, data={'foo': 'bar'})
2637
    resp = app.get('/api/users/%s/profiles/one-type/default/' % user.uuid)
2638
    assert resp.json == {'data': {'foo': 'bar'}}
2636
    profile = Profile.objects.create(profile_type=profile_type, user=user, data={'foo': 'bar'})
2637
    resp = app.get('/api/users/%s/profiles/one-type/' % user.uuid)
2638
    assert resp.json == [{'data': {'foo': 'bar'}, 'identifier': ''}]
2639

  
2640
    resp = app.get('/api/users/%s/profiles/one-type/?identifier=' % user.uuid)
2641
    assert resp.json == {'data': {'foo': 'bar'}, 'identifier': ''}
2642

  
2643
    profile.identifier = 'Company ABC'
2644
    profile.save()
2645

  
2646
    # specify identifier in qs
2647
    resp = app.get(
2648
        '/api/users/%s/profiles/one-type/?identifier=Company ABC' % user.uuid,
2649
    )
2650
    assert resp.json == {'data': {'foo': 'bar'}, 'identifier': 'Company ABC'}
2651

  
2652
    # not found on empty identifier
2653
    app.get(
2654
        '/api/users/%s/profiles/one-type/?identifier=' % user.uuid,
2655
        status=404,
2656
    )
2639 2657

  
2640 2658

  
2641 2659
def test_user_profile_put(app, superuser):
......
2644 2662
    user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
2645 2663

  
2646 2664
    # wrong type
2647
    resp = app.put('/api/users/%s/profiles/non-existant-slug/default/' % user.uuid, status=404)
2665
    resp = app.put('/api/users/%s/profiles/non-existant-slug/' % user.uuid, status=404)
2648 2666

  
2649 2667
    profile_type = ProfileType.objects.create(slug='one-type', name='One Type')
2650 2668

  
2651 2669
    # wrong user
2652
    resp = app.put('/api/users/1234/profiles/one-type/default/', status=404)
2670
    resp = app.put('/api/users/1234/profiles/one-type/', status=404)
2653 2671

  
2654 2672
    # missing profile
2655 2673
    resp = app.put_json(
2656
        '/api/users/%s/profiles/one-type/default/' % user.uuid, params={'data': {'foo': 'bar'}}, status=404
2674
        '/api/users/%s/profiles/one-type/' % user.uuid, params={'data': {'foo': 'bar'}}, status=404
2657 2675
    )
2658 2676

  
2659 2677
    Profile.objects.create(user=user, profile_type=profile_type, data={})
2660 2678

  
2661
    resp = app.put_json(
2662
        '/api/users/%s/profiles/one-type/default/' % user.uuid, params={'data': {'foo': 'bar'}}
2663
    )
2679
    resp = app.put_json('/api/users/%s/profiles/one-type/' % user.uuid, params={'data': {'foo': 'bar'}})
2664 2680
    assert resp.json == {'result': 1, 'detail': 'Profile successfully updated'}
2665 2681
    assert len(user.subprofiles.all()) == 1
2666 2682
    assert user.subprofiles.last().data == {'foo': 'bar'}
2667 2683

  
2668 2684
    # attempt at overwriting profile data
2669
    resp = app.put_json(
2670
        '/api/users/%s/profiles/one-type/default/' % user.uuid, params={'data': {'baz': 'bob'}}
2671
    )
2685
    resp = app.put_json('/api/users/%s/profiles/one-type/' % user.uuid, params={'data': {'baz': 'bob'}})
2672 2686

  
2673 2687
    # profile has been updated, no extra profile has been created
2674 2688
    assert resp.json == {'result': 1, 'detail': 'Profile successfully updated'}
2675 2689
    assert len(user.subprofiles.all()) == 1
2676 2690
    assert user.subprofiles.last().data == {'baz': 'bob'}
2677 2691

  
2692
    Profile.objects.create(
2693
        user=user,
2694
        profile_type=profile_type,
2695
        identifier='Company DEF',
2696
        data={},
2697
    )
2698

  
2699
    # overwrite profile data while specifying the identifier
2700
    resp = app.put_json(
2701
        '/api/users/%s/profiles/one-type/?identifier=Company DEF' % user.uuid,
2702
        params={'data': {'baz': 'bob'}},
2703
    )
2704
    assert resp.json == {'result': 1, 'detail': 'Profile successfully updated'}
2705
    assert user.subprofiles.get(identifier='Company DEF').data == {'baz': 'bob'}
2706

  
2678 2707

  
2679 2708
def test_user_profile_post(app, superuser):
2680 2709
    app.authorization = ('Basic', (superuser.username, superuser.username))
......
2682 2711
    user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
2683 2712

  
2684 2713
    # wrong type
2685
    resp = app.get('/api/users/%s/profiles/non-existant-slug/default/' % user.uuid, status=404)
2714
    resp = app.get('/api/users/%s/profiles/non-existant-slug/' % user.uuid, status=404)
2686 2715

  
2687 2716
    ProfileType.objects.create(slug='one-type', name='One Type')
2688 2717

  
2689 2718
    # wrong user
2690
    resp = app.get('/api/users/1234/profiles/one-type/default/', status=404)
2719
    resp = app.get('/api/users/1234/profiles/one-type/', status=404)
2691 2720

  
2692 2721
    assert len(user.subprofiles.all()) == 0
2693 2722

  
2694
    resp = app.post_json(
2695
        '/api/users/%s/profiles/one-type/default/' % user.uuid, params={'data': {'baz': 'bob'}}
2696
    )
2723
    resp = app.post_json('/api/users/%s/profiles/one-type/' % user.uuid, params={'data': {'baz': 'bob'}})
2697 2724
    assert resp.json == {'result': 1, 'detail': 'Profile successfully assigned to user'}
2698 2725
    assert len(user.subprofiles.all()) == 1
2699 2726
    assert user.subprofiles.last().data == {'baz': 'bob'}
2700 2727

  
2728
    app.post_json('/api/users/%s/profiles/one-type/' % user.uuid, status=400)
2729

  
2730
    resp = app.post_json(
2731
        '/api/users/%s/profiles/one-type/?identifier=FooBar' % user.uuid,
2732
        params={'data': {'foo': 'bar'}},
2733
    )
2734
    assert resp.json == {'result': 1, 'detail': 'Profile successfully assigned to user'}
2735
    assert len(user.subprofiles.all()) == 2
2736
    assert user.subprofiles.get(identifier='FooBar').data == {'foo': 'bar'}
2737

  
2738
    app.post_json('/api/users/%s/profiles/one-type/?identifier=FooBar' % user.uuid, status=400)
2739

  
2701 2740

  
2702 2741
def test_user_profile_delete(app, superuser):
2703 2742

  
......
2707 2746
    profile_type = ProfileType.objects.create(slug='one-type', name='One Type')
2708 2747
    Profile.objects.create(user=user, profile_type=profile_type)
2709 2748

  
2710
    app.delete('/api/users/%s/profiles/non-existant-slug/default/' % user.uuid, status=404)
2711
    app.delete('/api/users/%s/profiles/one-type/default/' % user.uuid)
2749
    app.delete('/api/users/%s/profiles/non-existant-slug/' % user.uuid, status=404)
2750
    app.delete('/api/users/%s/profiles/one-type/' % user.uuid)
2712 2751

  
2713 2752
    assert not Profile.objects.filter(user=user, profile_type=profile_type)
2714 2753

  
2715
    app.delete('/api/users/%s/profiles/one-type/default/' % user.uuid, status=404)
2754
    app.delete('/api/users/%s/profiles/one-type/' % user.uuid, status=404)
2755

  
2756
    Profile.objects.create(user=user, profile_type=profile_type, identifier='FooBar')
2757
    app.delete('/api/users/%s/profiles/one-type/?identifier=FooBar' % user.uuid)
2758
    app.delete(
2759
        '/api/users/%s/profiles/one-type/?identifier=FooBar' % user.uuid,
2760
        status=404,
2761
    )
2716
-