From cdc8ddf190a62a71a25574ec237e48bddaed0ec8 Mon Sep 17 00:00:00 2001 From: Hammad Ahmad Waqas <hammadahmadwaqas1@gmail.com> Date: Mon, 13 May 2019 20:30:27 +0500 Subject: [PATCH] clearing all relevant cache if enterprise customer change DSC enable flag. --- lms/envs/common.py | 2 +- .../features/enterprise_support/signals.py | 31 ++++++++- openedx/features/enterprise_support/tasks.py | 38 +++++++++++ .../enterprise_support/tests/factories.py | 22 ++++++- .../enterprise_support/tests/test_signals.py | 66 ++++++++++++++++++- 5 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 openedx/features/enterprise_support/tasks.py diff --git a/lms/envs/common.py b/lms/envs/common.py index 5195b9a7efe..a0ac3829e31 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -3354,7 +3354,7 @@ SYSTEM_TO_FEATURE_ROLE_MAPPING = { ], } -DATA_CONSENT_SHARE_CACHE_TIMEOUT = None # Never expire +DATA_CONSENT_SHARE_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS = {} diff --git a/openedx/features/enterprise_support/signals.py b/openedx/features/enterprise_support/signals.py index 89a211cb322..682b4b88454 100644 --- a/openedx/features/enterprise_support/signals.py +++ b/openedx/features/enterprise_support/signals.py @@ -4,13 +4,19 @@ This module contains signals related to enterprise. from __future__ import absolute_import +import logging + from django.contrib.auth.models import User -from django.db.models.signals import post_save +from django.db.models.signals import post_save, pre_save from django.dispatch import receiver from email_marketing.tasks import update_user -from enterprise.models import EnterpriseCourseEnrollment, EnterpriseCustomerUser + +from enterprise.models import EnterpriseCourseEnrollment, EnterpriseCustomer, EnterpriseCustomerUser +from openedx.features.enterprise_support.tasks import clear_enterprise_customer_data_consent_share_cache from openedx.features.enterprise_support.utils import clear_data_consent_share_cache +log = logging.getLogger(__name__) + @receiver(post_save, sender=EnterpriseCustomerUser) def update_email_marketing_user_with_enterprise_vars(sender, instance, **kwargs): # pylint: disable=unused-argument, invalid-name @@ -30,7 +36,7 @@ def update_email_marketing_user_with_enterprise_vars(sender, instance, **kwargs) @receiver(post_save, sender=EnterpriseCourseEnrollment) -def update_data_consent_share_cache(sender, instance, **kwargs): # pylint: disable=unused-argument +def update_dsc_cache_on_course_enrollment(sender, instance, **kwargs): # pylint: disable=unused-argument """ clears data_sharing_consent_needed cache after Enterprise Course Enrollment """ @@ -38,3 +44,22 @@ def update_data_consent_share_cache(sender, instance, **kwargs): # pylint: disa instance.enterprise_customer_user.user_id, instance.course_id ) + + +@receiver(pre_save, sender=EnterpriseCustomer) +def update_dsc_cache_on_enterprise_customer_update(sender, instance, **kwargs): + """ + clears data_sharing_consent_needed cache after enable_data_sharing_consent flag is changed. + """ + old_instance = sender.objects.filter(pk=instance.uuid).first() + if old_instance: # instance already exists, so it's updating. + new_value = instance.enable_data_sharing_consent + old_value = old_instance.enable_data_sharing_consent + if new_value != old_value: + kwargs = {'enterprise_customer_uuid': instance.uuid} + result = clear_enterprise_customer_data_consent_share_cache.apply_async(kwargs=kwargs) + log.info(u"DSC: Created {task_name}[{task_id}] with arguments {kwargs}".format( + task_name=clear_enterprise_customer_data_consent_share_cache.name, + task_id=result.task_id, + kwargs=kwargs, + )) diff --git a/openedx/features/enterprise_support/tasks.py b/openedx/features/enterprise_support/tasks.py new file mode 100644 index 00000000000..7261d6df795 --- /dev/null +++ b/openedx/features/enterprise_support/tasks.py @@ -0,0 +1,38 @@ +""" +Tasks for Enterprise. +""" +from __future__ import absolute_import + +import logging + +from celery import task + +from enterprise.models import EnterpriseCourseEnrollment +from openedx.features.enterprise_support.utils import clear_data_consent_share_cache + +log = logging.getLogger('edx.celery.task') + + +@task(name=u'openedx.features.enterprise_support.tasks.clear_enterprise_customer_data_consent_share_cache') +def clear_enterprise_customer_data_consent_share_cache(enterprise_customer_uuid): + """ + clears data_sharing_consent_needed cache for whole enterprise + """ + enterprise_course_enrollments = EnterpriseCourseEnrollment.objects.filter( + enterprise_customer_user__enterprise_customer__uuid=enterprise_customer_uuid + ) + count = enterprise_course_enrollments.count() + log.info( + u'Stated Clearing {count} data_sharing_consent_needed cache for enterprise customer {uuid}'.format( + count=count, + uuid=enterprise_customer_uuid, + ) + ) + for enrollment in enterprise_course_enrollments: + clear_data_consent_share_cache( + enrollment.enterprise_customer_user.user_id, + enrollment.course_id + ) + log.info(u'Ended Clearing data_sharing_consent_needed cache for enterprise customer {uuid}'.format( + uuid=enterprise_customer_uuid, + )) diff --git a/openedx/features/enterprise_support/tests/factories.py b/openedx/features/enterprise_support/tests/factories.py index 59ea4331cd1..e8d4ffd4b58 100644 --- a/openedx/features/enterprise_support/tests/factories.py +++ b/openedx/features/enterprise_support/tests/factories.py @@ -6,8 +6,9 @@ from __future__ import absolute_import, unicode_literals from uuid import UUID import factory -from enterprise.models import EnterpriseCustomer, EnterpriseCustomerUser from faker import Factory as FakerFactory + +from enterprise.models import EnterpriseCourseEnrollment, EnterpriseCustomer, EnterpriseCustomerUser from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory FAKER = FakerFactory.create() @@ -54,3 +55,22 @@ class EnterpriseCustomerUserFactory(factory.django.DjangoModelFactory): enterprise_customer = factory.SubFactory(EnterpriseCustomerFactory) user_id = factory.LazyAttribute(lambda x: FAKER.pyint()) # pylint: disable=no-member + + +class EnterpriseCourseEnrollmentFactory(factory.django.DjangoModelFactory): + """ + EnterpriseCourseEnrollment factory. + + Creates an instance of EnterpriseCourseEnrollment with minimal boilerplate. + """ + + class Meta(object): + """ + Meta for EnterpriseCourseEnrollmentFactory. + """ + + model = EnterpriseCourseEnrollment + + id = factory.LazyAttribute(lambda x: FAKER.random_int(min=1)) # pylint: disable=no-member + course_id = factory.LazyAttribute(lambda x: FAKER.slug()) # pylint: disable=no-member + enterprise_customer_user = factory.SubFactory(EnterpriseCustomerUserFactory) diff --git a/openedx/features/enterprise_support/tests/test_signals.py b/openedx/features/enterprise_support/tests/test_signals.py index 4332632715c..e5fc14dd45f 100644 --- a/openedx/features/enterprise_support/tests/test_signals.py +++ b/openedx/features/enterprise_support/tests/test_signals.py @@ -3,12 +3,17 @@ from __future__ import absolute_import import logging -from mock import patch - import ddt from django.test import TestCase -from openedx.features.enterprise_support.tests.factories import EnterpriseCustomerFactory, EnterpriseCustomerUserFactory +from mock import patch from student.tests.factories import UserFactory +from edx_django_utils.cache import TieredCache +from openedx.features.enterprise_support.tests.factories import ( + EnterpriseCourseEnrollmentFactory, + EnterpriseCustomerFactory, + EnterpriseCustomerUserFactory +) +from openedx.features.enterprise_support.utils import get_data_consent_share_cache_key log = logging.getLogger(__name__) @@ -25,8 +30,20 @@ class EnterpriseSupportSignals(TestCase): def setUp(self): self.user = UserFactory.create(username='test', email=TEST_EMAIL) + self.course_id = 'course-v1:edX+DemoX+Demo_Course' super(EnterpriseSupportSignals, self).setUp() + @staticmethod + def _create_dsc_cache(user_id, course_id): + consent_cache_key = get_data_consent_share_cache_key(user_id, course_id) + TieredCache.set_all_tiers(consent_cache_key, 0) + + @staticmethod + def _is_dsc_cache_found(user_id, course_id): + consent_cache_key = get_data_consent_share_cache_key(user_id, course_id) + data_sharing_consent_needed_cache = TieredCache.get_cached_response(consent_cache_key) + return data_sharing_consent_needed_cache.is_found + @patch('openedx.features.enterprise_support.signals.update_user.delay') def test_register_user(self, mock_update_user): """ @@ -44,3 +61,46 @@ class EnterpriseSupportSignals(TestCase): }, email=self.user.email ) + + def test_signal_update_dsc_cache_on_course_enrollment(self): + """ + make sure update_dsc_cache_on_course_enrollment signal clears cache when Enterprise Course Enrollment + takes place + """ + + self._create_dsc_cache(self.user.id, self.course_id) + self.assertTrue(self._is_dsc_cache_found(self.user.id, self.course_id)) + + # Enrolling user to Course + enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=self.user.id) + EnterpriseCourseEnrollmentFactory( + course_id=self.course_id, + enterprise_customer_user=enterprise_customer_user, + ) + self.assertFalse(self._is_dsc_cache_found(self.user.id, self.course_id)) + + def test_signal_update_dsc_cache_on_enterprise_customer_update(self): + """ + make sure update_dsc_cache_on_enterprise_customer_update signal clears data_sharing_consent_needed cache after + enable_data_sharing_consent flag is changed. + """ + + # Enrolling user to Course + enterprise_customer = EnterpriseCustomerFactory() + enterprise_customer_user = EnterpriseCustomerUserFactory( + user_id=self.user.id, + enterprise_customer=enterprise_customer + ) + EnterpriseCourseEnrollmentFactory( + course_id=self.course_id, + enterprise_customer_user=enterprise_customer_user, + ) + + self._create_dsc_cache(self.user.id, self.course_id) + self.assertTrue(self._is_dsc_cache_found(self.user.id, self.course_id)) + + # updating enable_data_sharing_consent flag + enterprise_customer.enable_data_sharing_consent = False + enterprise_customer.save() + + self.assertFalse(self._is_dsc_cache_found(self.user.id, self.course_id)) -- GitLab