Projet

Général

Profil

0001-api-add-a-full_known_users-option-to-synchronization.patch

Paul Marillonnet, 25 octobre 2021 15:01

Télécharger (7,4 ko)

Voir les différences:

Subject: [PATCH] api: add a full_known_users option to /synchronization/
 endpoint (#57567)

 src/authentic2/api_views.py | 34 ++++++++++++--
 src/authentic2/settings.py  |  2 +
 tests/test_api.py           | 93 +++++++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+), 3 deletions(-)
src/authentic2/api_views.py
795 795

  
796 796
    class SynchronizationSerializer(serializers.Serializer):
797 797
        known_uuids = serializers.ListField(child=serializers.CharField())
798
        full_known_users = serializers.BooleanField(required=False)
799
        page_size = serializers.IntegerField(
800
            min_value=settings.REST_FRAMEWORK.get('MIN_PAGE_SIZE', 0) or 10,
801
            max_value=settings.REST_FRAMEWORK.get('MAX_PAGE_SIZE', 0) or 1000,
802
            required=False,
803
        )
804
        page = serializers.IntegerField(min_value=1, required=False)
798 805

  
799 806
    def check_uuids(self, uuids):
800 807
        User = get_user_model()
801 808
        known_uuids = User.objects.filter(uuid__in=uuids).values_list('uuid', flat=True)
802
        return set(uuids) - set(known_uuids)
809
        return (known_uuids, set(uuids) - set(known_uuids))
810

  
811
    def get_users_from_uuids(self, known_uuids):
812
        User = get_user_model()
813
        known_users = User.objects.filter(uuid__in=known_uuids)
814
        return [BaseUserSerializer(user).data for user in known_users]
803 815

  
804 816
    @action(detail=False, methods=['post'], permission_classes=(DjangoPermission('custom_user.search_user'),))
805 817
    def synchronization(self, request):
......
808 820
            response = {'result': 0, 'errors': serializer.errors}
809 821
            return Response(response, status.HTTP_400_BAD_REQUEST)
810 822
        hooks.call_hooks('api_modify_serializer_after_validation', self, serializer)
811
        unknown_uuids = self.check_uuids(serializer.validated_data.get('known_uuids', []))
823
        known_uuids, unknown_uuids = self.check_uuids(serializer.validated_data.get('known_uuids', []))
824
        full_known_users = serializer.validated_data.get('full_known_users', None)
812 825
        data = {
813 826
            'result': 1,
814
            'unknown_uuids': unknown_uuids,
815 827
        }
828
        if full_known_users:
829
            page_size = serializer.validated_data.get('page_size', None)
830
            page = serializer.validated_data.get('page', None)
831
            if page:
832
                page_size = page_size or settings.REST_FRAMEWORK.get('PAGE_SIZE', 0) or 100
833
                if len(known_uuids) <= (page - 1) * page_size:
834
                    known_uuids = []
835
                else:
836
                    upper_bound = min(len(known_uuids), page * page_size)
837
                    known_uuids = known_uuids[(page - 1) * page_size : upper_bound]
838
            if known_uuids:
839
                data['known_users'] = self.get_users_from_uuids(known_uuids)
840
            else:
841
                data['known_users'] = []
842
        else:
843
            data['unknown_uuids'] = unknown_uuids
816 844
        hooks.call_hooks('api_modify_response', self, 'synchronization', data)
817 845
        return Response(data)
818 846

  
src/authentic2/settings.py
322 322
    ),
323 323
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
324 324
    'PAGE_SIZE': 100,
325
    'MAX_PAGE_SIZE': 1000,
326
    'MIN_PAGE_SIZE': 10,
325 327
}
326 328

  
327 329

  
tests/test_api.py
1150 1150
    assert set(response.json['unknown_uuids']) == set(unknown_uuids)
1151 1151

  
1152 1152

  
1153
def test_user_synchronization_full(app, admin):
1154
    headers = basic_authorization_header(admin)
1155
    uuids = []
1156
    for _ in range(100):
1157
        user = User.objects.create(first_name='jim', last_name='jam')
1158
        uuids.append(user.uuid)
1159
    unknown_uuids = [uuid.uuid4().hex for i in range(100)]
1160
    url = reverse('a2-api-users-synchronization')
1161
    content = {
1162
        'known_uuids': uuids + unknown_uuids,
1163
        'full_known_users': 1,
1164
    }
1165
    random.shuffle(content['known_uuids'])
1166
    response = app.post_json(url, params=content, headers=headers)
1167
    assert response.json['result'] == 1
1168

  
1169
    # known users returned as part of api's full mode:
1170
    assert len(response.json['known_users']) == 100
1171
    for user_dict in response.json['known_users']:
1172
        assert user_dict['first_name'] == 'jim'
1173
        assert user_dict['last_name'] == 'jam'
1174
        assert {
1175
            'uuid',
1176
            'email',
1177
            'is_staff',
1178
            'is_superuser',
1179
            'email_verified',
1180
            'ou',
1181
            'is_active',
1182
            'deactivation',
1183
            'modified',
1184
        }.issubset(set(user_dict.keys()))
1185

  
1186

  
1187
def test_user_synchronization_full_paginated(app, admin):
1188
    headers = basic_authorization_header(admin)
1189
    uuids = []
1190
    for _ in range(100):
1191
        user = User.objects.create(first_name='jim', last_name='jam')
1192
        uuids.append(user.uuid)
1193
    unknown_uuids = [uuid.uuid4().hex for i in range(100)]
1194
    url = reverse('a2-api-users-synchronization')
1195

  
1196
    # only page-size parameter declared, no effect
1197
    content = {
1198
        'known_uuids': uuids + unknown_uuids,
1199
        'full_known_users': 1,
1200
        'page_size': 30,
1201
    }
1202
    random.shuffle(content['known_uuids'])
1203
    response = app.post_json(url, params=content, headers=headers)
1204
    assert len(response.json['known_users']) == 100
1205

  
1206
    # page and page-size parameters
1207
    content = {
1208
        'known_uuids': uuids + unknown_uuids,
1209
        'full_known_users': 1,
1210
        'page_size': 30,
1211
    }
1212
    for i in range(3):
1213
        content['page'] = i + 1
1214
        random.shuffle(content['known_uuids'])
1215
        response = app.post_json(url, params=content, headers=headers)
1216
        assert len(response.json['known_users']) == 30
1217

  
1218
    # last page
1219
    content['page'] = 4
1220
    random.shuffle(content['known_uuids'])
1221
    response = app.post_json(url, params=content, headers=headers)
1222
    assert len(response.json['known_users']) == 10
1223

  
1224
    for i in range(5, 8):
1225
        content['page'] = i
1226
        random.shuffle(content['known_uuids'])
1227
        response = app.post_json(url, params=content, headers=headers)
1228
        assert len(response.json['known_users']) == 0
1229

  
1230
    # page size larger than result size:
1231
    content = {
1232
        'known_uuids': uuids + unknown_uuids,
1233
        'full_known_users': 1,
1234
        'page_size': 120,
1235
        'page': 1,
1236
    }
1237
    random.shuffle(content['known_uuids'])
1238
    response = app.post_json(url, params=content, headers=headers)
1239
    assert len(response.json['known_users']) == 100
1240

  
1241
    content['page'] = 2
1242
    response = app.post_json(url, params=content, headers=headers)
1243
    assert len(response.json['known_users']) == 0
1244

  
1245

  
1153 1246
def test_api_drf_authentication_class(app, admin, user_ou1, oidc_client):
1154 1247
    url = '/api/users/%s/' % user_ou1.uuid
1155 1248
    # test invalid client
1156
-