|
12 | 12 | from django.contrib.sites.models import Site |
13 | 13 | from django.core import mail |
14 | 14 | from django.core.cache import cache |
| 15 | +from django.db.models.signals import pre_delete |
15 | 16 | from django.test import TestCase |
16 | 17 | from django.urls import reverse |
17 | 18 | from opaque_keys.edx.keys import CourseKey |
@@ -1365,10 +1366,8 @@ def test_retire_user_where_username_not_provided(self): |
1365 | 1366 |
|
1366 | 1367 | @mock.patch('openedx.core.djangoapps.user_api.accounts.views.get_profile_image_names') |
1367 | 1368 | @mock.patch('openedx.core.djangoapps.user_api.accounts.views.remove_profile_images') |
1368 | | - @mock.patch('openedx.core.djangoapps.user_api.accounts.views.PendingEmailChange.redact_pending_email_by_user_value') |
1369 | 1369 | def test_retire_user( |
1370 | 1370 | self, |
1371 | | - mock_redact_pending_email, |
1372 | 1371 | mock_remove_profile_images, |
1373 | 1372 | mock_get_profile_image_names, |
1374 | 1373 | ): |
@@ -1415,22 +1414,34 @@ def test_retire_user_twice_idempotent(self): |
1415 | 1414 | fake_completed_retirement(self.test_user) |
1416 | 1415 | self.post_and_assert_status(data) |
1417 | 1416 |
|
1418 | | - @mock.patch('openedx.core.djangoapps.user_api.accounts.views.PendingEmailChange.delete_by_user_value') |
1419 | | - def test_retire_user_redacts_pending_email_before_delete(self, mock_delete_pending_email): |
1420 | | - pending_email_record = PendingEmailChange.objects.get(user=self.test_user) |
1421 | | - pending_email_before_retirement = pending_email_record.new_email |
1422 | | - expected_retired_pending_email = get_retired_email_by_email(pending_email_before_retirement) |
1423 | | - |
1424 | | - def _assert_redacted_then_delete(value, field): |
1425 | | - pending_record = PendingEmailChange.objects.get(user=self.test_user) |
1426 | | - assert pending_record.new_email == expected_retired_pending_email |
1427 | | - pending_record.delete() |
1428 | | - return True |
1429 | | - |
1430 | | - mock_delete_pending_email.side_effect = _assert_redacted_then_delete |
1431 | | - data = {'username': self.original_username} |
1432 | | - self.post_and_assert_status(data) |
1433 | | - assert not PendingEmailChange.objects.filter(user=self.test_user).exists() |
| 1417 | + def test_retire_user_redacts_pending_email_before_delete(self): |
| 1418 | + """ |
| 1419 | + Verify that delete_by_user_value redacts new_email using bulk update before deletion. |
| 1420 | + """ |
| 1421 | + expected_redacted_email = '[email protected]' |
| 1422 | + captured_state = {} |
| 1423 | + |
| 1424 | + def capture_before_delete(sender, instance, **kwargs): |
| 1425 | + """Capture email value before it's deleted.""" |
| 1426 | + captured_state['new_email'] = instance.new_email |
| 1427 | + |
| 1428 | + # Connect signal to capture pre-delete state |
| 1429 | + pre_delete.connect(capture_before_delete, sender=PendingEmailChange) |
| 1430 | + try: |
| 1431 | + # Verify the record exists with original email before retirement |
| 1432 | + assert PendingEmailChange.objects.filter(user=self.test_user).exists() |
| 1433 | + |
| 1434 | + # Retire the user |
| 1435 | + data = {'username': self.original_username} |
| 1436 | + self.post_and_assert_status(data) |
| 1437 | + |
| 1438 | + # Verify the redaction happened before deletion |
| 1439 | + assert captured_state.get('new_email') == expected_redacted_email |
| 1440 | + |
| 1441 | + # Verify the record was deleted |
| 1442 | + assert not PendingEmailChange.objects.filter(user=self.test_user).exists() |
| 1443 | + finally: |
| 1444 | + pre_delete.disconnect(capture_before_delete, sender=PendingEmailChange) |
1434 | 1445 |
|
1435 | 1446 | @mock.patch('openedx.core.djangoapps.user_api.accounts.views.USER_RETIRE_LMS_CRITICAL') |
1436 | 1447 | def test_retirement_sends_critical_signal_with_retirement_data(self, mock_signal): |
|
0 commit comments