Make username generation hackable

This commit is contained in:
Martin Pépin 2020-05-12 20:53:08 +02:00
parent add3b56690
commit 111bdfef7b

View file

@ -30,21 +30,6 @@ def get_entrance_year(attributes):
return 2000 + year
def find_available_username(clipper_uid):
"""Find an available username 'close' to a clipper uid."""
taken = UserModel.objects.filter(username__startswith=clipper_uid).values_list(
"username", flat=True
)
if clipper_uid not in taken:
return clipper_uid
else:
i = 2
while clipper_uid + str(i) in taken:
i += 1
return clipper_uid + str(i)
class ENSCASBackend:
"""ENSAuth authentication backend.
@ -72,6 +57,31 @@ class ENSCASBackend:
year = get_entrance_year(attributes)
return self._get_or_create(uid, year)
def find_available_username(self, clipper_uid):
"""Find an available username for the new user.
If you override this method, make sure it returns a username that is not taken
by any existing user.
This method will be called from within an atomic database transation (don't
worry about data races).
"""
taken = UserModel.objects.values_list("username", flat=True)
# This should handle most cases and produce a nice username.
prefered = [clipper_uid, "cas_" + clipper_uid]
pref_taken = taken.filter(username__in=prefered)
for name in prefered:
if name not in pref_taken:
return name
# Worst case: generate a username of the form clipper_uid + int
taken = taken.filter(username__startswith=clipper_uid)
i = 2
while clipper_uid + str(i) in taken:
i += 1
return clipper_uid + str(i)
def _get_or_create(self, uid, entrance_year):
with transaction.atomic():
try:
@ -83,7 +93,7 @@ class ENSCASBackend:
user = None
if user is None:
username = find_available_username(uid)
username = self.find_available_username(uid)
user = UserModel.objects.create_user(username=username)
Clipper.objects.create(user=user, entrance_year=entrance_year, uid=uid)
return user