0001-api-add-a-full_known_users-option-to-synchronization.patch
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 |
- |