Fix: Prevent double-deleted email suffix breaking user reactivation #776
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
When a user is deleted, we append
.deleted.<user_id>
to their email address to work around the uniqueness constraint in thecms_users
table. However, if someone attempts to delete an already-deleted user (due to race condition, UI bug, or direct API call), the suffix gets appended again:When reactivating, the code only removes ONE suffix, leaving
user@domain.com.deleted.123
, which is invalid. Auth0 rejects this email, making the user impossible to reactivate.Real-world example from bug report:
Root Cause
Files:
include/cms_users_handle_ajax_operations.php
,library/ajax/deleteprofile.php
The deletion code always appends the suffix without checking if it already exists:
While
listDelete()
prevents updating thedeleted
timestamp for already-deleted users, the email CONCAT still executes unconditionally.Solution
1. Prevention (Primary Fix)
Added regex check to prevent appending suffix if it already exists:
The pattern
@.*\.deleted\.[0-9]+$
:.deleted.<digits>
only after the@
symbol at end of emailjohn.deleted.smith@example.com
2. Cleanup (For Existing Issues)
Created cron job
/cron/fix-double-deleted-emails.php
:%.deleted.%.deleted.%
.deleted.<id>
suffixes and adds back a single one3. Testing
Added comprehensive Cypress tests (
2_9_DoubleDeletedEmailFix.js
):Changes
4 commits:
Files modified:
include/cms_users_handle_ajax_operations.php
- Prevention fixlibrary/ajax/deleteprofile.php
- Prevention fixcron/fix-double-deleted-emails.php
- New cleanup cron jobgcloud-entry.php
- Routing for cron jobcypress/e2e/2_auth_tests/2_9_DoubleDeletedEmailFix.js
- New testsTesting Done
✅ All Cypress tests pass (including new tests)
✅ PHP CS Fixer passes
✅ Logic verified: multiple delete/reactivate cycles work correctly
✅ Regex pattern tested with various email formats
Reviewer Checklist
Please verify:
@.*\.deleted\.[0-9]+$
correctly identifies already-deleted emailsjohn.deleted.smith@example.com
are not blocked from deletion.deleted.
in username (handled ✅)Deployment Notes
After merge:
/cron/fix-double-deleted-emails.php