diff --git a/edx_name_affirmation/models.py b/edx_name_affirmation/models.py index 08e109b..8006fd3 100644 --- a/edx_name_affirmation/models.py +++ b/edx_name_affirmation/models.py @@ -46,6 +46,15 @@ class VerifiedName(TimeStampedModel): ) history = HistoricalRecords() + @classmethod + def retire_user(cls, user_id): + """ + Retire user as part of GDPR pipeline + :param user_id: int + """ + verified_names = cls.objects.filter(user_id=user_id) + verified_names.delete() + class Meta: """ Meta class for this Django model """ db_table = 'nameaffirmation_verifiedname' diff --git a/edx_name_affirmation/signals.py b/edx_name_affirmation/signals.py index 8b2bb38..aca5f73 100644 --- a/edx_name_affirmation/signals.py +++ b/edx_name_affirmation/signals.py @@ -3,5 +3,21 @@ """ from django.dispatch import Signal +from django.dispatch.dispatcher import receiver + +try: + from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_LMS_MISC +except ImportError: + # An ImportError should only be raised in tests, where the code is not running as an installation of + # edx-platform. In this case, the import should default to a generic Signal. + USER_RETIRE_LMS_MISC = Signal() + +from .models import VerifiedName VERIFIED_NAME_APPROVED = Signal() + + +@receiver(USER_RETIRE_LMS_MISC) +def _listen_for_lms_retire_verified_names(sender, **kwargs): # pylint: disable=unused-argument + user = kwargs.get('user') + VerifiedName.retire_user(user.id) diff --git a/edx_name_affirmation/tests/test_signals.py b/edx_name_affirmation/tests/test_signals.py new file mode 100644 index 0000000..e742023 --- /dev/null +++ b/edx_name_affirmation/tests/test_signals.py @@ -0,0 +1,66 @@ +""" +Tests for Name Affirmation signals +""" + +import ddt + +from django.contrib.auth import get_user_model +from django.test import TestCase + +from edx_name_affirmation.models import VerifiedName +from edx_name_affirmation.signals import _listen_for_lms_retire_verified_names + +User = get_user_model() + + +@ddt.ddt +class RetirementSignalVerifiedNamesTest(TestCase): + """ + Tests for the LMS User Retirement signal for Verified Names + """ + + def setUp(self): + self.user = User(username='tester', email='tester@test.com') + self.user.save() + self.name = 'Jonathan Smith' + self.profile_name = 'Jon Smith' + self.idv_attempt_id = 1111111 + self.verified_name_obj = VerifiedName.objects.create( + user=self.user, + verified_name=self.name, + profile_name=self.profile_name, + verification_attempt_id=self.idv_attempt_id + ) + + self.other_user = User(username='other_tester', email='other_tester@test.com') + self.other_user.save() + self.other_name = 'Jonathan Other' + self.other_profile_name = 'Jon Other' + self.other_idv_attempt_id = 1111112 + self.verified_name_obj = VerifiedName.objects.create( + user=self.other_user, + verified_name=self.other_name, + profile_name=self.other_profile_name, + verification_attempt_id=self.other_idv_attempt_id + ) + + def test_retirement_signal(self): + _listen_for_lms_retire_verified_names(sender=self.__class__, user=self.user) + self.assertEqual(len(VerifiedName.objects.filter(user=self.user)), 0) + self.assertEqual(len(VerifiedName.objects.filter(user=self.other_user)), 1) + + def test_retirement_signal_no_verified_names(self): + no_verified_user = User(username='no_verified', email='no_verified@test.com') + _listen_for_lms_retire_verified_names(sender=self.__class__, user=no_verified_user) + self.assertEqual(len(VerifiedName.objects.all()), 2) + + def test_retirement_signal_all_verified_names_for_user(self): + # create a second verified name for user to check that both names are deleted + VerifiedName.objects.create( + user=self.user, + verified_name='J Smith', + profile_name=self.profile_name, + verification_attempt_id=1111112 + ) + _listen_for_lms_retire_verified_names(sender=self.__class__, user=self.user) + self.assertEqual(len(VerifiedName.objects.filter(user=self.user)), 0)