Skip to content

fix: free retired learner's email on retirement completion - #458

Merged
santhosh-apphelix-2u merged 5 commits into
release-ulmofrom
free-retired-learner-email
Sep 4, 2026
Merged

fix: free retired learner's email on retirement completion#458
santhosh-apphelix-2u merged 5 commits into
release-ulmofrom
free-retired-learner-email

Conversation

@rahulkanneri-2u

Copy link
Copy Markdown

Description

Retirement rewrites auth_user.email to a deterministic hash and keeps that row forever for compliance, but is_email_retired() matches that hash permanently, so a retired learner could never register again with their own former email.

This adds free_retired_learner_email(user) (accounts/utils.py), which appends .freed.<user_id> to the retired-hash email once retirement is COMPLETE. That's enough to stop it matching is_email_retired(), without deleting the row or nulling the email (both break compliance/uniqueness constraints). It's a no-op if the email's already been freed.

The handler behind PATCH /api/user/v1/accounts/update_retirement_status/ that tubular calls on every state transition so the email is freed automatically the moment retirement reaches COMPLETE.

A free_retired_user_email management command (--username/--user_id) is also added, for backfilling learners retired before this existed.

Impact: Learners can re-register with a previously-retired email once retirement completes.
Operators get a command to backfill older retirements. No UI changes, no migration.

Testing instructions

  • pytest openedx/core/djangoapps/user_api/accounts/tests/test_utils.py -k FreeRetiredLearnerEmail
  • pytest openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py -k TestAccountRetirementUpdate
  • pytest openedx/core/djangoapps/user_api/management/tests/test_free_retired_user_email.py

Other information

  • No database migration; only mutates the email column on already-retired rows the UserRetirementStatus audit row is untouched.

@santhosh-apphelix-2u
santhosh-apphelix-2u merged commit d249fc8 into release-ulmo Sep 4, 2026
64 checks passed
@santhosh-apphelix-2u
santhosh-apphelix-2u deleted the free-retired-learner-email branch September 4, 2026 11:21
Comment on lines +23 to +24
parser.add_argument('--username', type=str, help='Username of the retired learner to free.')
parser.add_argument('--user_id', type=int, help='User ID of the retired learner to free.')

@vgulati-apphelix vgulati-apphelix Sep 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
parser.add_argument('--username', type=str, help='Username of the retired learner to free.')
parser.add_argument('--user_id', type=int, help='User ID of the retired learner to free.')
user_group = parser.add_mutually_exclusive_group(required=True)
user_group.add_argument('--username', type=str, help='Username of the retired learner to allow email reuse.',)
user_group.add_argument('--user-id', type=int, help='User ID of the retired learner to allow email reuse.',)

old_email = user.email
user.email = old_email + freed_suffix
user.save(update_fields=['email'])
LOGGER.info(f"Freed retired email for user {user.id}: '{old_email}' -> '{user.email}'.")

@vgulati-apphelix vgulati-apphelix Sep 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger to be sanitized - remove email & username.

Comment on lines +43 to +44
logger.info(f'Successfully freed email for user {user.id}.')
print(f'Successfully freed email for user {user.id}.')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
logger.info(f'Successfully freed email for user {user.id}.')
print(f'Successfully freed email for user {user.id}.')
logger.info(f'Successfully freed email for user {user.id}.')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants