EDUCATOR-2753 | Add calls to retire secondary user data to the /accounts/retire endpoint.
This commit is contained in:
committed by
Alex Dusenbery
parent
137b9da22b
commit
95d5b13714
21
lms/djangoapps/survey/tests/factories.py
Normal file
21
lms/djangoapps/survey/tests/factories.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# pylint:disable=missing-docstring
|
||||
import factory
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from survey.models import SurveyAnswer, SurveyForm
|
||||
|
||||
|
||||
class SurveyFormFactory(factory.DjangoModelFactory):
|
||||
class Meta(object):
|
||||
model = SurveyForm
|
||||
|
||||
name = 'Test Survey Form'
|
||||
form = '<form>First name:<input type="text" name="firstname"/></form>'
|
||||
|
||||
|
||||
class SurveyAnswerFactory(factory.DjangoModelFactory):
|
||||
class Meta(object):
|
||||
model = SurveyAnswer
|
||||
|
||||
user = factory.SubFactory(UserFactory)
|
||||
form = factory.SubFactory(SurveyFormFactory)
|
||||
@@ -8,7 +8,14 @@ import factory
|
||||
from factory.fuzzy import FuzzyText
|
||||
import pytz
|
||||
|
||||
from openedx.core.djangoapps.credit.models import CreditProvider, CreditEligibility, CreditCourse, CreditRequest
|
||||
from openedx.core.djangoapps.credit.models import (
|
||||
CreditProvider,
|
||||
CreditEligibility,
|
||||
CreditCourse,
|
||||
CreditRequest,
|
||||
CreditRequirement,
|
||||
CreditRequirementStatus,
|
||||
)
|
||||
from util.date_utils import to_timestamp
|
||||
|
||||
|
||||
@@ -20,6 +27,21 @@ class CreditCourseFactory(factory.DjangoModelFactory):
|
||||
enabled = True
|
||||
|
||||
|
||||
class CreditRequirementFactory(factory.DjangoModelFactory):
|
||||
class Meta(object):
|
||||
model = CreditRequirement
|
||||
|
||||
course = factory.SubFactory(CreditCourseFactory)
|
||||
|
||||
|
||||
class CreditRequirementStatusFactory(factory.DjangoModelFactory):
|
||||
class Meta(object):
|
||||
model = CreditRequirementStatus
|
||||
|
||||
requirement = factory.SubFactory(CreditRequirementFactory)
|
||||
status = CreditRequirementStatus.REQUIREMENT_STATUS_CHOICES[0][0]
|
||||
|
||||
|
||||
class CreditProviderFactory(factory.DjangoModelFactory):
|
||||
class Meta(object):
|
||||
model = CreditProvider
|
||||
|
||||
@@ -28,6 +28,7 @@ from integrated_channels.sap_success_factors.models import (
|
||||
)
|
||||
import mock
|
||||
from nose.plugins.attrib import attr
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
import pytest
|
||||
import pytz
|
||||
from rest_framework import status
|
||||
@@ -37,6 +38,8 @@ from social_django.models import UserSocialAuth
|
||||
|
||||
from entitlements.models import CourseEntitlementSupportDetail
|
||||
from entitlements.tests.factories import CourseEntitlementFactory
|
||||
from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory
|
||||
from openedx.core.djangoapps.course_groups.models import CourseUserGroup, UnregisteredLearnerCohortAssignments
|
||||
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
|
||||
from openedx.core.djangoapps.user_api.accounts import ACCOUNT_VISIBILITY_PREF_KEY
|
||||
from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_MAILINGS
|
||||
@@ -45,6 +48,7 @@ from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms
|
||||
from openedx.core.lib.token_utils import JwtBuilder
|
||||
from student.models import (
|
||||
CourseEnrollmentAllowed,
|
||||
PendingEmailChange,
|
||||
SocialLink,
|
||||
UserProfile,
|
||||
@@ -54,12 +58,16 @@ from student.models import (
|
||||
from student.tests.factories import (
|
||||
TEST_PASSWORD,
|
||||
ContentTypeFactory,
|
||||
CourseEnrollmentAllowedFactory,
|
||||
PendingEmailChangeFactory,
|
||||
PermissionFactory,
|
||||
SuperuserFactory,
|
||||
UserFactory
|
||||
)
|
||||
|
||||
from .. import ALL_USERS_VISIBILITY, PRIVATE_VISIBILITY
|
||||
from ..views import AccountRetirementView, USER_PROFILE_PII
|
||||
from ...tests.factories import UserOrgTagFactory
|
||||
|
||||
TEST_PROFILE_IMAGE_UPLOADED_AT = datetime.datetime(2002, 1, 9, 15, 43, 1, tzinfo=pytz.UTC)
|
||||
|
||||
@@ -1677,6 +1685,26 @@ class TestAccountRetirementPost(RetirementTestCase):
|
||||
comments='A comment containing potential PII.'
|
||||
)
|
||||
|
||||
# Misc. setup
|
||||
self.photo_verification = SoftwareSecurePhotoVerificationFactory.create(user=self.test_user)
|
||||
PendingEmailChangeFactory.create(user=self.test_user)
|
||||
UserOrgTagFactory.create(user=self.test_user, key='foo', value='bar')
|
||||
UserOrgTagFactory.create(user=self.test_user, key='cat', value='dog')
|
||||
|
||||
CourseEnrollmentAllowedFactory.create(email=self.original_email)
|
||||
|
||||
self.course_key = CourseKey.from_string('course-v1:edX+DemoX+Demo_Course')
|
||||
self.cohort = CourseUserGroup.objects.create(
|
||||
name="TestCohort",
|
||||
course_id=self.course_key,
|
||||
group_type=CourseUserGroup.COHORT
|
||||
)
|
||||
self.cohort_assignment = UnregisteredLearnerCohortAssignments.objects.create(
|
||||
course_user_group=self.cohort,
|
||||
course_id=self.course_key,
|
||||
email=self.original_email
|
||||
)
|
||||
|
||||
# setup for doing POST from test client
|
||||
self.headers = self.build_jwt_headers(self.test_superuser)
|
||||
self.headers['content_type'] = "application/json"
|
||||
@@ -1771,6 +1799,13 @@ class TestAccountRetirementPost(RetirementTestCase):
|
||||
self._pending_enterprise_customer_user_assertions()
|
||||
self._entitlement_support_detail_assertions()
|
||||
|
||||
self._photo_verification_assertions()
|
||||
self.assertFalse(PendingEmailChange.objects.filter(user=self.test_user).exists())
|
||||
self.assertFalse(UserOrgTag.objects.filter(user=self.test_user).exists())
|
||||
|
||||
self.assertFalse(CourseEnrollmentAllowed.objects.filter(email=self.original_email).exists())
|
||||
self.assertFalse(UnregisteredLearnerCohortAssignments.objects.filter(email=self.original_email).exists())
|
||||
|
||||
def test_deletes_pii_from_user_profile(self):
|
||||
for model_field, value_to_assign in USER_PROFILE_PII.iteritems():
|
||||
if value_to_assign == '':
|
||||
@@ -1866,3 +1901,12 @@ class TestAccountRetirementPost(RetirementTestCase):
|
||||
"""
|
||||
self.entitlement_support_detail.refresh_from_db()
|
||||
self.assertEqual('', self.entitlement_support_detail.comments)
|
||||
|
||||
def _photo_verification_assertions(self):
|
||||
"""
|
||||
Helper method for asserting that ``SoftwareSecurePhotoVerification`` objects are retired.
|
||||
"""
|
||||
self.photo_verification.refresh_from_db()
|
||||
self.assertEqual(self.test_user, self.photo_verification.user)
|
||||
for field in ('name', 'face_image_url', 'photo_id_image_url', 'photo_id_key'):
|
||||
self.assertEqual('', getattr(self.photo_verification, field))
|
||||
|
||||
@@ -27,6 +27,8 @@ from six import text_type
|
||||
from social_django.models import UserSocialAuth
|
||||
|
||||
from entitlements.models import CourseEntitlement
|
||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
|
||||
from openedx.core.djangoapps.course_groups.models import UnregisteredLearnerCohortAssignments
|
||||
from openedx.core.djangoapps.profile_images.images import remove_profile_images
|
||||
from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_image_names, set_has_profile_image
|
||||
from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in
|
||||
@@ -36,6 +38,8 @@ from openedx.core.lib.api.authentication import (
|
||||
)
|
||||
from openedx.core.lib.api.parsers import MergePatchParser
|
||||
from student.models import (
|
||||
CourseEnrollmentAllowed,
|
||||
PendingEmailChange,
|
||||
User,
|
||||
UserProfile,
|
||||
get_potentially_retired_user_by_username,
|
||||
@@ -594,16 +598,31 @@ class AccountRetirementView(ViewSet):
|
||||
user = retirement_status.user
|
||||
retired_username = retirement_status.retired_username or get_retired_username_by_username(username)
|
||||
retired_email = retirement_status.retired_email or get_retired_email_by_email(user.email)
|
||||
original_email = retirement_status.original_email
|
||||
|
||||
# Retire core user/profile information
|
||||
self.clear_pii_from_userprofile(user)
|
||||
self.delete_users_profile_images(user)
|
||||
self.delete_users_country_cache(user)
|
||||
|
||||
# Retire data from Enterprise models
|
||||
self.retire_users_data_sharing_consent(username, retired_username)
|
||||
self.retire_sapsf_data_transmission(user)
|
||||
self.retire_user_from_pending_enterprise_customer_user(user, retired_email)
|
||||
self.retire_entitlement_support_detail(user)
|
||||
|
||||
# Retire misc. models that may contain PII of this user
|
||||
SoftwareSecurePhotoVerification.retire_user(user.id)
|
||||
PendingEmailChange.delete_by_user_value(user, field='user')
|
||||
UserOrgTag.delete_by_user_value(user, field='user')
|
||||
|
||||
# Retire any objects linked to the user via their original email
|
||||
CourseEnrollmentAllowed.delete_by_user_value(original_email, field='email')
|
||||
UnregisteredLearnerCohortAssignments.delete_by_user_value(original_email, field='email')
|
||||
|
||||
# TODO: Password Reset links - https://openedx.atlassian.net/browse/PLAT-2104
|
||||
# TODO: Delete OAuth2 records - https://openedx.atlassian.net/browse/EDUCATOR-2703
|
||||
|
||||
user.first_name = ''
|
||||
user.last_name = ''
|
||||
user.is_active = False
|
||||
|
||||
Reference in New Issue
Block a user