-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add auto generated username #34349
feat: Add auto generated username #34349
Conversation
ffbdf19
to
7df11ab
Compare
return username | ||
|
||
|
||
def generate_username_from_data(data): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def generate_username_from_data(data): | |
def generate_username_from_request_payload(data): |
7df11ab
to
86361e7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use case came to my mind that we might need to address:
Our code for auto-generating usernames currently assumes the presence of a learner's full name (first and last name combined or a single name field). However, are there scenarios where a learner or an external workflow could submit a registration form or call the registration API without providing a name?
If such cases exist, our current error handling might not be helpful. The way the code is currently written, it will return username error message (because the generate_username_from_request_payload
function returns None
). However, if the username field is hidden from the registration form, it would be beneficial to inform users directly that their name cannot be empty. This would guide them towards completing the registration process properly and then we can generate their username.
cms/envs/common.py
Outdated
### Random configurable username string length | ||
RANDOM_USERNAME_STRING_LENGTH = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
Can you move this to the section where other registration settings are present?
edx-platform/cms/envs/common.py
Lines 2770 to 2778 in 6e0bc66
######################## Registration ######################## # Social-core setting that allows inactive users to be able to # log in. The only case it's used is when user registering a new account through the LMS. INACTIVE_USER_LOGIN = True # Redirect URL for inactive user. If not set, user will be redirected to /login after the login itself (loop) INACTIVE_USER_URL = f'http://{CMS_BASE}' -
Update setting name
### Random configurable username string length | |
RANDOM_USERNAME_STRING_LENGTH = 4 | |
### String length for the configurable part of the auto-generated username | |
AUTO_GENERATED_USERNAME_RANDOM_STRING_LENGTH = 4 |
lms/envs/common.py
Outdated
@@ -4462,6 +4462,9 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring | |||
FINANCIAL_ASSISTANCE_MIN_LENGTH = 1250 | |||
FINANCIAL_ASSISTANCE_MAX_LENGTH = 2500 | |||
|
|||
### Random configurable username string length | |||
RANDOM_USERNAME_STRING_LENGTH = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
if is_auto_generated_username_enabled() and 'username' not in data: | ||
data['username'] = generate_username_from_request_payload(data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add empty line before and after
return username | ||
|
||
|
||
def generate_username_from_request_payload(data): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def generate_username_from_request_payload(data): | |
def get_auto_generated_username(data): |
|
||
def generate_username(username_initials): | ||
""" | ||
Generate a username based on initials and current date. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generate a username based on initials and current date. | |
Generate username based on learner's name initials, current date and configurable random string. | |
This function creates a username in the format <name_initials>_<YYMM>_<configurable_random_string> | |
The length of random string is determined by AUTO_GENERATED_USERNAME_RANDOM_STRING_LENGTH setting. |
Generate a username based on the provided data. | ||
|
||
Args: | ||
- data (dict): Dictionary containing user data, including 'first_name', 'last_name', or 'name'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- data (dict): Dictionary containing user data, including 'first_name', 'last_name', or 'name'. | |
- data (dict): Registration payload. |
Returns: | ||
- str: Generated username. | ||
""" | ||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if we can improve the flow of code.
- Get username_prefix i.e name initials (this should maybe be a separate util function)
- Add the logic of actually generating username in this function and get rid of
generate_username
|
||
username_initials = ''.join(initials) | ||
return generate_username(username_initials) | ||
except KeyError as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can avoid this by using data.get('first_name', '')
first_name = data['first_name'] | ||
last_name = data['last_name'] | ||
|
||
username_initials = f"{first_name[0]}{last_name[0]}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will raise IndexError
if first and last name is empty
ff99fae
to
86d6017
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add tests for the registration flow too? A few that come to my mind are:
- Test registration is successful when the auto-generated username flag is true
- Test some unsuccessful flows like missing name or invalid name
4448f3c
to
58dc1db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to test the failure case too where username returned by get_auto_generated_username
is already in use? Maybe by mocking the get_auto_generated_username
to return a username that is already taken.
openedx/core/djangoapps/user_authn/views/tests/test_register.py
Outdated
Show resolved
Hide resolved
2f57847
to
55ead87
Compare
# We generate the username regardless of whether the name is empty or invalid. We do this | ||
# because the name validations occur later, ensuring that users cannot create an account without a valid name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move this either in the docstring or above the return statement at the end?
55ead87
to
8c43530
Compare
Description
This PR enhances the user registration process by implementing auto-generated usernames when no username is provided and the
ENABLE_AUTO_GENERATED_USERNAME
feature flag is enabled.The generated username follows a specific pattern: it consists of name initials, the current year and month, and a random configurable string. Here's how it's structured:
<name initials>_<current year><current month>_<random configurable string>
Example: AI_2403_AK8L
Supporting information
VAN-1871
Testing instructions
Tested locally
Unit tests added.