api: refactor user synchronization API endpoint (#67901)
This commit is contained in:
parent
ff581d6617
commit
0cb14c0138
|
@ -52,6 +52,7 @@ from rest_framework.validators import UniqueTogetherValidator
|
|||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ModelViewSet, ViewSet
|
||||
|
||||
from authentic2.apps.journal.models import reference_integer
|
||||
from authentic2.compat.drf import action
|
||||
|
||||
from . import api_mixins, app_settings, decorators
|
||||
|
@ -797,31 +798,27 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
|
|||
full_known_users = serializers.BooleanField(required=False)
|
||||
timestamp = serializers.DateTimeField(required=False)
|
||||
|
||||
def check_uuids(self, uuids, timestamp=None):
|
||||
User = get_user_model()
|
||||
known_uuids = User.objects.filter(uuid__in=uuids).values_list('uuid', flat=True)
|
||||
unknown_uuids = set(uuids) - set(known_uuids)
|
||||
modified_users_uuids = []
|
||||
if timestamp:
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
user_events = Event.objects.filter(
|
||||
reference_ct_ids__contains=[user_ct.id], timestamp__gt=timestamp
|
||||
)
|
||||
for user_event in user_events:
|
||||
for reference in user_event.references:
|
||||
if (
|
||||
reference is not None # xxx None references in journal?!
|
||||
and ContentType.objects.get_for_model(reference) == user_ct
|
||||
and reference.uuid not in modified_users_uuids
|
||||
and reference.uuid not in unknown_uuids
|
||||
):
|
||||
modified_users_uuids.append(reference.uuid)
|
||||
return (known_uuids, unknown_uuids, modified_users_uuids)
|
||||
def check_unknown_uuids(self, remote_uuids, users):
|
||||
return set(remote_uuids) - {user.uuid for user in users}
|
||||
|
||||
def get_users_from_uuids(self, known_uuids):
|
||||
User = get_user_model()
|
||||
known_users = User.objects.filter(uuid__in=known_uuids)
|
||||
return [BaseUserSerializer(user).data for user in known_users]
|
||||
def check_modified_uuids(self, timestamp, users, unknown_uuids):
|
||||
modified_users_uuids = set()
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
reference_ids = [reference_integer(user) for user in users]
|
||||
user_events = Event.objects.filter(
|
||||
models.Q(reference_ids__overlap=reference_ids) | models.Q(user__in=users),
|
||||
timestamp__gt=timestamp,
|
||||
)
|
||||
users_pks = {user.pk: user for user in users}
|
||||
for user_event in user_events:
|
||||
for ct_id, instance_pk in user_event.get_reference_ids():
|
||||
if (
|
||||
ct_id == user_ct.pk
|
||||
and instance_pk in users_pks
|
||||
and users_pks[instance_pk].uuid not in modified_users_uuids
|
||||
):
|
||||
modified_users_uuids.add(users_pks[instance_pk].uuid)
|
||||
return modified_users_uuids
|
||||
|
||||
@action(detail=False, methods=['post'], permission_classes=(DjangoPermission('custom_user.search_user'),))
|
||||
def synchronization(self, request):
|
||||
|
@ -830,19 +827,23 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
|
|||
response = {'result': 0, 'errors': serializer.errors}
|
||||
return Response(response, status.HTTP_400_BAD_REQUEST)
|
||||
hooks.call_hooks('api_modify_serializer_after_validation', self, serializer)
|
||||
known_uuids = serializer.validated_data.get('known_uuids', [])
|
||||
timestamp = serializer.validated_data.get('timestamp', None)
|
||||
known_uuids, unknown_uuids, modified_users_uuids = self.check_uuids(known_uuids, timestamp)
|
||||
remote_uuids = serializer.validated_data.get('known_uuids', [])
|
||||
users = User.objects.filter(uuid__in=remote_uuids).only('id', 'uuid')
|
||||
unknown_uuids = self.check_unknown_uuids(remote_uuids, users)
|
||||
data = {
|
||||
'result': 1,
|
||||
'unknown_uuids': unknown_uuids,
|
||||
'modified_users_uuids': modified_users_uuids,
|
||||
}
|
||||
|
||||
timestamp = serializer.validated_data.get('timestamp', None)
|
||||
if timestamp:
|
||||
data['modified_users_uuids'] = self.check_modified_uuids(timestamp, users, unknown_uuids)
|
||||
|
||||
full_known_users = serializer.validated_data.get('full_known_users', None)
|
||||
if full_known_users:
|
||||
if len(known_uuids) > 1000:
|
||||
known_uuids = known_uuids[:1000]
|
||||
data['known_users'] = self.get_users_from_uuids(known_uuids)
|
||||
# reload users to get all fields
|
||||
known_users = User.objects.filter(pk__in=[user.pk for user in users[:1000]])
|
||||
data['known_users'] = [BaseUserSerializer(user).data for user in known_users]
|
||||
hooks.call_hooks('api_modify_response', self, 'synchronization', data)
|
||||
return Response(data)
|
||||
|
||||
|
|
Loading…
Reference in New Issue