From 2d71697823982b582bfe3c190596a6aca61ac794 Mon Sep 17 00:00:00 2001 From: bmedx <bmesick@edx.org> Date: Fri, 10 Aug 2018 16:48:53 -0400 Subject: [PATCH] Stop acct creation from using usernames still in the retirement queue --- common/djangoapps/student/models.py | 31 +++++++++++++++++-- .../djangoapps/user_api/accounts/views.py | 6 +--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index 5b325b75147..41e73105595 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -212,7 +212,14 @@ def is_username_retired(username): settings.RETIRED_USERNAME_FMT ) - return User.objects.filter(username__in=list(locally_hashed_usernames)).exists() + # TODO: Revert to this after username capitalization issues detailed in + # PLAT-2276, PLAT-2277, PLAT-2278 are sorted out: + # return User.objects.filter(username__in=list(locally_hashed_usernames)).exists() + + # Avoid circular import issues + from openedx.core.djangoapps.user_api.models import UserRetirementStatus + return User.objects.filter(username__in=list(locally_hashed_usernames)).exists() or \ + UserRetirementStatus.objects.filter(original_username=username).exists() def is_email_retired(email): @@ -293,7 +300,27 @@ def get_potentially_retired_user_by_username(username): """ locally_hashed_usernames = list(get_all_retired_usernames_by_username(username)) locally_hashed_usernames.append(username) - return User.objects.get(username__in=locally_hashed_usernames) + potential_users = User.objects.filter(username__in=locally_hashed_usernames) + + # Have to disambiguate between several Users here as we could have retirees with + # the same username, but for case. + # If there's only 1 we're done, this should be the common case + if len(potential_users) == 1: + return potential_users[0] + + # No user found, throw the usual error + if not potential_users: + raise User.DoesNotExist() + + # If there are 2, one of two things should be true: + # - The user we want is un-retired and has the same case-match username + # - Or retired one was the case-match + if len(potential_users) == 2: + return potential_users[0] if potential_users[0].username == username else potential_users[1] + + # We should have, at most, a retired username and an active one with a username + # differing only by case. If there are more we need to disambiguate them by hand. + raise Exception('Expected 1 or 2 Users, received {}'.format(text_type(potential_users))) def get_potentially_retired_user_by_username_and_hash(username, hashed_username): diff --git a/openedx/core/djangoapps/user_api/accounts/views.py b/openedx/core/djangoapps/user_api/accounts/views.py index 6980a737b04..81ace7529dd 100644 --- a/openedx/core/djangoapps/user_api/accounts/views.py +++ b/openedx/core/djangoapps/user_api/accounts/views.py @@ -788,7 +788,7 @@ class AccountRetirementStatusView(ViewSet): retirement = None if len(retirements) < 1: raise UserRetirementStatus.DoesNotExist() - elif len(retirements) > 1: + elif len(retirements) >= 1: for r in retirements: if r.original_username == username: retirement = r @@ -796,10 +796,6 @@ class AccountRetirementStatusView(ViewSet): # UserRetirementStatus was found, but it was the wrong case. if retirement is None: raise UserRetirementStatus.DoesNotExist() - else: - if username != retirements[0].original_username: - raise UserRetirementStatus.DoesNotExist() - retirement = retirements[0] retirement.update_state(request.data) return Response(status=status.HTTP_204_NO_CONTENT) -- GitLab