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