Merge pull request #19794 from edx/bessiesteinberg/ent-1512

ENT-1512: Make Recovery Email Retireable
This commit is contained in:
Bessie Steinberg
2019-02-15 16:57:21 -05:00
committed by GitHub
4 changed files with 71 additions and 4 deletions

View File

@@ -2735,6 +2735,10 @@ class AccountRecoveryManager(models.Manager):
class AccountRecovery(models.Model):
"""
Model for storing information for user's account recovery in case of access loss.
.. pii: the field named secondary_email contains pii, retired in the `DeactivateLogoutView`
.. pii_types: email_address
.. pii_retirement: local_api
"""
user = models.OneToOneField(User, related_name='account_recovery', on_delete=models.CASCADE)
secondary_email = models.EmailField(
@@ -2761,3 +2765,22 @@ class AccountRecovery(models.Model):
self.secondary_email = email
self.is_active = False
self.save()
@classmethod
def retire_recovery_email(cls, user_id):
"""
Retire user's recovery/secondary email as part of GDPR Phase I.
Returns 'True'
If an AccountRecovery record is found for this user it will be deleted,
if it is not found it is assumed this table has no PII for the given user.
:param user_id: int
:return: bool
"""
try:
cls.objects.get(user_id=user_id).delete()
except cls.DoesNotExist:
pass
return True

View File

@@ -10,7 +10,6 @@ from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.db.models import signals
from django.db.models.functions import Lower
from django.test import TestCase
from course_modes.models import CourseMode
from course_modes.tests.factories import CourseModeFactory
@@ -26,11 +25,13 @@ from student.models import (
PendingEmailChange,
ManualEnrollmentAudit,
ALLOWEDTOENROLL_TO_ENROLLED,
PendingNameChange
PendingNameChange,
AccountRecovery
)
from student.tests.factories import CourseEnrollmentFactory, UserFactory
from student.tests.factories import CourseEnrollmentFactory, UserFactory, AccountRecoveryFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from django.test import TestCase
@ddt.ddt
@@ -383,3 +384,24 @@ class TestManualEnrollmentAudit(SharedModuleStoreTestCase):
self.assertFalse(ManualEnrollmentAudit.objects.filter(enrollment=enrollment).exclude(
reason=""
))
class TestAccountRecovery(TestCase):
"""
Tests for the AccountRecovery Model
"""
def test_retire_recovery_email(self):
"""
Assert that Account Record for a given user is deleted when `retire_recovery_email` is called
"""
# Create user and associated recovery email record
user = UserFactory()
AccountRecoveryFactory(user=user)
assert len(AccountRecovery.objects.filter(user_id=user.id)) == 1
# Retire recovery email
AccountRecovery.retire_recovery_email(user_id=user.id)
# Assert that there is no longer an AccountRecovery record for this user
assert len(AccountRecovery.objects.filter(user_id=user.id)) == 0

View File

@@ -64,6 +64,7 @@ from student.models import (
UserProfile,
get_retired_username_by_username,
get_retired_email_by_email,
AccountRecovery,
)
from student.tests.factories import (
ContentTypeFactory,
@@ -71,7 +72,8 @@ from student.tests.factories import (
PendingEmailChangeFactory,
PermissionFactory,
SuperuserFactory,
UserFactory
UserFactory,
AccountRecoveryFactory,
)
from ..views import AccountRetirementView, USER_PROFILE_PII
@@ -221,6 +223,24 @@ class TestDeactivateLogout(RetirementTestCase):
# ensure that it's been sent to the correct email address
self.assertIn(self.test_user.email, mail.outbox[0].to)
def test_user_can_deactivate_secondary_email(self):
"""
Verify that if a user has a secondary/recovery email that record will be deleted
if the user requests a retirement
"""
# Create secondary/recovery email for test user
AccountRecoveryFactory(user=self.test_user)
# Assert that there is an secondary/recovery email for test user
self.assertEqual(len(AccountRecovery.objects.filter(user_id=self.test_user.id)), 1)
self.client.login(username=self.test_user.username, password=self.test_password)
headers = build_jwt_headers(self.test_user)
response = self.client.post(self.url, self.build_post(self.test_password), **headers)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
# Assert that there is no longer a secondary/recovery email for test user
self.assertEqual(len(AccountRecovery.objects.filter(user_id=self.test_user.id)), 0)
def test_password_mismatch(self):
"""
Verify that the user submitting a mismatched password results in

View File

@@ -47,6 +47,7 @@ from openedx.core.djangolib.oauth2_retirement_utils import retire_dot_oauth2_mod
from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser
from openedx.core.lib.api.parsers import MergePatchParser
from student.models import (
AccountRecovery,
CourseEnrollment,
ManualEnrollmentAudit,
PendingNameChange,
@@ -412,6 +413,7 @@ class DeactivateLogoutView(APIView):
# Delete OAuth tokens associated with the user.
retire_dop_oauth2_models(request.user)
retire_dot_oauth2_models(request.user)
AccountRecovery.retire_recovery_email(request.user.id)
try:
# Send notification email to user