From 25d5d084e0bae76126d98b33415c1b9eceb7c2ff Mon Sep 17 00:00:00 2001 From: Muhammad Adeel Tajamul <77053848+muhammadadeeltajamul@users.noreply.github.com> Date: Mon, 12 Aug 2024 06:18:33 +0500 Subject: [PATCH] feat: fetched notifications based on time not date (#35250) --- .../djangoapps/notifications/email/tasks.py | 8 ++- .../notifications/email/tests/test_tasks.py | 55 +++++++++++++++---- .../djangoapps/notifications/email/utils.py | 9 +-- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/openedx/core/djangoapps/notifications/email/tasks.py b/openedx/core/djangoapps/notifications/email/tasks.py index 75af99aa86..0d450fe9a9 100644 --- a/openedx/core/djangoapps/notifications/email/tasks.py +++ b/openedx/core/djangoapps/notifications/email/tasks.py @@ -70,10 +70,12 @@ def get_user_preferences_for_courses(course_ids, user): return new_preferences -def send_digest_email_to_user(user, cadence_type, course_language='en', courses_data=None): +def send_digest_email_to_user(user, cadence_type, start_date, end_date, course_language='en', courses_data=None): """ Send [cadence_type] email to user. Cadence Type can be EmailCadence.DAILY or EmailCadence.WEEKLY + start_date: Datetime object + end_date: Datetime object """ if cadence_type not in [EmailCadence.DAILY, EmailCadence.WEEKLY]: raise ValueError('Invalid cadence_type') @@ -81,7 +83,6 @@ def send_digest_email_to_user(user, cadence_type, course_language='en', courses_ if not is_email_notification_flag_enabled(user): logger.info(f' Flag disabled for {user.username} ==Temp Log==') return - start_date, end_date = get_start_end_date(cadence_type) notifications = Notification.objects.filter(user=user, email=True, created__gte=start_date, created__lte=end_date) if not notifications: @@ -115,6 +116,7 @@ def send_digest_email_to_all_users(cadence_type): logger.info(f' Sending cadence email of type {cadence_type}') users = get_audience_for_cadence_email(cadence_type) courses_data = {} + start_date, end_date = get_start_end_date(cadence_type) logger.info(f' Email Cadence Audience {len(users)}') for user in users: - send_digest_email_to_user(user, cadence_type, courses_data=courses_data) + send_digest_email_to_user(user, cadence_type, start_date, end_date, courses_data=courses_data) diff --git a/openedx/core/djangoapps/notifications/email/tests/test_tasks.py b/openedx/core/djangoapps/notifications/email/tests/test_tasks.py index 5c88ef3edb..785dcf2a1b 100644 --- a/openedx/core/djangoapps/notifications/email/tests/test_tasks.py +++ b/openedx/core/djangoapps/notifications/email/tests/test_tasks.py @@ -16,6 +16,7 @@ from openedx.core.djangoapps.notifications.email.tasks import ( send_digest_email_to_all_users, send_digest_email_to_user ) +from openedx.core.djangoapps.notifications.email.utils import get_start_end_date from openedx.core.djangoapps.notifications.models import CourseNotificationPreference from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -42,8 +43,9 @@ class TestEmailDigestForUser(ModuleStoreTestCase): """ Tests email is sent iff waffle flag is enabled """ + start_date, end_date = get_start_end_date(EmailCadence.DAILY) with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert not mock_func.called @ddt.data(True, False) @@ -54,8 +56,9 @@ class TestEmailDigestForUser(ModuleStoreTestCase): """ created_date = datetime.datetime.now() - datetime.timedelta(days=1) create_notification(self.user, self.course.id, created=created_date) + start_date, end_date = get_start_end_date(EmailCadence.DAILY) with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, flag_value): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert mock_func.called is flag_value @patch('edx_ace.ace.send') @@ -63,9 +66,10 @@ class TestEmailDigestForUser(ModuleStoreTestCase): """ Tests email is not sent if notification is created on next day """ - create_notification(self.user, self.course.id) + start_date, end_date = get_start_end_date(EmailCadence.DAILY) + create_notification(self.user, self.course.id, created=end_date + datetime.timedelta(minutes=2)) with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert not mock_func.called @patch('edx_ace.ace.send') @@ -73,12 +77,35 @@ class TestEmailDigestForUser(ModuleStoreTestCase): """ Tests email is not sent if notification is created day before yesterday """ - created_date = datetime.datetime.now() - datetime.timedelta(days=2) + start_date, end_date = get_start_end_date(EmailCadence.DAILY) + created_date = datetime.datetime.now() - datetime.timedelta(days=1, minutes=18) create_notification(self.user, self.course.id, created=created_date) with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert not mock_func.called + @ddt.data( + (EmailCadence.DAILY, datetime.datetime.now() - datetime.timedelta(days=1, minutes=30), False), + (EmailCadence.DAILY, datetime.datetime.now() - datetime.timedelta(minutes=10), True), + (EmailCadence.DAILY, datetime.datetime.now() - datetime.timedelta(days=1), True), + (EmailCadence.DAILY, datetime.datetime.now() + datetime.timedelta(minutes=20), False), + (EmailCadence.WEEKLY, datetime.datetime.now() - datetime.timedelta(days=7, minutes=30), False), + (EmailCadence.WEEKLY, datetime.datetime.now() - datetime.timedelta(days=7), True), + (EmailCadence.WEEKLY, datetime.datetime.now() - datetime.timedelta(minutes=20), True), + (EmailCadence.WEEKLY, datetime.datetime.now() + datetime.timedelta(minutes=20), False), + ) + @ddt.unpack + @patch('edx_ace.ace.send') + def test_notification_content(self, cadence_type, created_time, notification_created, mock_func): + """ + Tests email only contains notification created within date + """ + start_date, end_date = get_start_end_date(cadence_type) + create_notification(self.user, self.course.id, created=created_time) + with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) + assert mock_func.called is notification_created + @ddt.ddt class TestEmailDigestAudience(ModuleStoreTestCase): @@ -146,10 +173,11 @@ class TestEmailDigestAudience(ModuleStoreTestCase): """ Tests email is sent only when notifications with email=True exists """ - created_date = datetime.datetime.now() - datetime.timedelta(days=1) + start_date, end_date = get_start_end_date(EmailCadence.DAILY) + created_date = datetime.datetime.now() - datetime.timedelta(hours=23, minutes=59) create_notification(self.user, self.course.id, created=created_date, email=email_value) with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert mock_func.called is email_value @@ -166,7 +194,7 @@ class TestPreferences(ModuleStoreTestCase): self.user = UserFactory() self.course = CourseFactory.create(display_name='test course', run="Testing_course") self.preference = CourseNotificationPreference.objects.create(user=self.user, course_id=self.course.id) - created_date = datetime.datetime.now() - datetime.timedelta(days=1) + created_date = datetime.datetime.now() - datetime.timedelta(hours=23) create_notification(self.user, self.course.id, notification_type='new_discussion_post', created=created_date) @patch('edx_ace.ace.send') @@ -174,13 +202,14 @@ class TestPreferences(ModuleStoreTestCase): """ Tests email is send for digest notification preference """ + start_date, end_date = get_start_end_date(EmailCadence.DAILY) config = self.preference.notification_preference_config types = config['discussion']['notification_types'] types['new_discussion_post']['email_cadence'] = EmailCadence.DAILY types['new_discussion_post']['email'] = True self.preference.save() with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert mock_func.called @ddt.data(True, False) @@ -189,13 +218,14 @@ class TestPreferences(ModuleStoreTestCase): """ Tests email is sent iff preference value is True """ + start_date, end_date = get_start_end_date(EmailCadence.DAILY) config = self.preference.notification_preference_config types = config['discussion']['notification_types'] types['new_discussion_post']['email_cadence'] = EmailCadence.DAILY types['new_discussion_post']['email'] = pref_value self.preference.save() with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert mock_func.called is pref_value @patch('edx_ace.ace.send') @@ -203,10 +233,11 @@ class TestPreferences(ModuleStoreTestCase): """ Tests email is not send if digest notification preference doesnot match """ + start_date, end_date = get_start_end_date(EmailCadence.DAILY) config = self.preference.notification_preference_config types = config['discussion']['notification_types'] types['new_discussion_post']['email_cadence'] = EmailCadence.WEEKLY self.preference.save() with override_waffle_flag(ENABLE_EMAIL_NOTIFICATIONS, True): - send_digest_email_to_user(self.user, EmailCadence.DAILY) + send_digest_email_to_user(self.user, EmailCadence.DAILY, start_date, end_date) assert not mock_func.called diff --git a/openedx/core/djangoapps/notifications/email/utils.py b/openedx/core/djangoapps/notifications/email/utils.py index 3ce2306435..1e0f4c81c7 100644 --- a/openedx/core/djangoapps/notifications/email/utils.py +++ b/openedx/core/djangoapps/notifications/email/utils.py @@ -171,13 +171,10 @@ def get_start_end_date(cadence_type): """ if cadence_type not in [EmailCadence.DAILY, EmailCadence.WEEKLY]: raise ValueError('Invalid cadence_type') - date_today = datetime.datetime.now() - yesterday = date_today - datetime.timedelta(days=1) - end_date = datetime.datetime.combine(yesterday, datetime.time.max) - start_date = end_date + end_date = datetime.datetime.now() + start_date = end_date - datetime.timedelta(days=1, minutes=15) if cadence_type == EmailCadence.WEEKLY: - start_date = end_date - datetime.timedelta(days=6) - start_date = datetime.datetime.combine(start_date, datetime.time.min) + start_date = start_date - datetime.timedelta(days=6) return utc.localize(start_date), utc.localize(end_date)