From d3b1ce176ae552cf36a87a1b875723c4358e5331 Mon Sep 17 00:00:00 2001 From: ayesha waris <73840786+ayesha-waris@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:38:46 +0500 Subject: [PATCH] feat: adds waffle flag for show notifications tray (#32451) * feat: adds waffle flag for show notifications tray * refactor: refactored notifications count api code --- .../djangoapps/notifications/config/waffle.py | 10 +++++ .../notifications/tests/test_views.py | 43 +++++++++++++++---- .../core/djangoapps/notifications/views.py | 24 +++++++---- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/openedx/core/djangoapps/notifications/config/waffle.py b/openedx/core/djangoapps/notifications/config/waffle.py index cb53dc0e20..fdfd74571c 100644 --- a/openedx/core/djangoapps/notifications/config/waffle.py +++ b/openedx/core/djangoapps/notifications/config/waffle.py @@ -17,3 +17,13 @@ WAFFLE_NAMESPACE = 'notifications' # .. toggle_warning: When the flag is ON, Notifications feature is enabled. # .. toggle_tickets: INF-866 ENABLE_NOTIFICATIONS = CourseWaffleFlag(f'{WAFFLE_NAMESPACE}.enable_notifications', __name__) + +# .. toggle_name: notifications.show_notifications_tray +# .. toggle_implementation: CourseWaffleFlag +# .. toggle_default: False +# .. toggle_description: Waffle flag to show notifications tray +# .. toggle_use_cases: temporary, open_edx +# .. toggle_creation_date: 2023-06-07 +# .. toggle_target_removal_date: 2023-12-07 +# .. toggle_tickets: INF-902 +SHOW_NOTIFICATIONS_TRAY = CourseWaffleFlag(f"{WAFFLE_NAMESPACE}.show_notifications_tray", __name__) diff --git a/openedx/core/djangoapps/notifications/tests/test_views.py b/openedx/core/djangoapps/notifications/tests/test_views.py index 19cb96eb23..e27aeabb97 100644 --- a/openedx/core/djangoapps/notifications/tests/test_views.py +++ b/openedx/core/djangoapps/notifications/tests/test_views.py @@ -16,7 +16,7 @@ from rest_framework.test import APIClient, APITestCase from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import UserFactory from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory -from openedx.core.djangoapps.notifications.config.waffle import ENABLE_NOTIFICATIONS +from openedx.core.djangoapps.notifications.config.waffle import ENABLE_NOTIFICATIONS, SHOW_NOTIFICATIONS_TRAY from openedx.core.djangoapps.notifications.models import ( Notification, CourseNotificationPreference, @@ -397,31 +397,58 @@ class NotificationListAPIViewTest(APITestCase): self.assertEqual([data[0]['id'], data[1]['id']], [notification2.id, notification1.id]) -class NotificationCountViewSetTestCase(APITestCase): +@ddt.ddt +class NotificationCountViewSetTestCase(ModuleStoreTestCase): """ Tests for the NotificationCountViewSet. """ def setUp(self): # Create a user. + super().setUp() self.user = UserFactory() + self.client = APIClient() + + course = CourseFactory.create( + org='testorg', + number='testcourse', + run='testrun' + ) + + course_overview = CourseOverviewFactory.create(id=course.id, org='AwesomeOrg') + self.enrollment = CourseEnrollment.objects.create( + user=self.user, + course=course_overview, + is_active=True, + mode='audit' + ) + self.url = reverse('notifications-count') + # Create some notifications for the user. Notification.objects.create(user=self.user, app_name='App Name 1', notification_type='Type A') Notification.objects.create(user=self.user, app_name='App Name 1', notification_type='Type B') Notification.objects.create(user=self.user, app_name='App Name 2', notification_type='Type A') Notification.objects.create(user=self.user, app_name='App Name 3', notification_type='Type C') - def test_get_unseen_notifications_count(self): + @ddt.data((False,), (True,)) + @ddt.unpack + def test_get_unseen_notifications_count_with_show_notifications_tray(self, show_notifications_tray_enabled): """ - Test that the endpoint returns the correct count of unseen notifications. + Test that the endpoint returns the correct count of unseen notifications and show_notifications_tray value. """ self.client.login(username=self.user.username, password='test') - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['count'], 4) - self.assertEqual(response.data['count_by_app_name'], {'App Name 1': 2, 'App Name 2': 1, 'App Name 3': 1}) + # Enable or disable the waffle flag based on the test case data + with override_waffle_flag(SHOW_NOTIFICATIONS_TRAY, active=show_notifications_tray_enabled): + + # Make a request to the view + response = self.client.get(self.url) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data['count'], 4) + self.assertEqual(response.data['count_by_app_name'], {'App Name 1': 2, 'App Name 2': 1, 'App Name 3': 1}) + self.assertEqual(response.data['show_notifications_tray'], show_notifications_tray_enabled) def test_get_unseen_notifications_count_for_unauthenticated_user(self): """ diff --git a/openedx/core/djangoapps/notifications/views.py b/openedx/core/djangoapps/notifications/views.py index ac2363180b..ba664fbd59 100644 --- a/openedx/core/djangoapps/notifications/views.py +++ b/openedx/core/djangoapps/notifications/views.py @@ -4,7 +4,6 @@ Views for the notifications API. from datetime import datetime, timedelta from django.conf import settings -from django.contrib.auth import get_user_model from django.db.models import Count from opaque_keys.edx.keys import CourseKey from pytz import UTC @@ -19,7 +18,7 @@ from openedx.core.djangoapps.notifications.models import ( get_course_notification_preference_config_version ) -from .config.waffle import ENABLE_NOTIFICATIONS +from .config.waffle import ENABLE_NOTIFICATIONS, SHOW_NOTIFICATIONS_TRAY from .models import Notification from .serializers import ( NotificationCourseEnrollmentSerializer, @@ -28,8 +27,6 @@ from .serializers import ( UserNotificationPreferenceUpdateSerializer ) -User = get_user_model() - class CourseEnrollmentListView(generics.ListAPIView): """ @@ -247,19 +244,20 @@ class NotificationListAPIView(generics.ListAPIView): class NotificationCountView(APIView): """ - API view for getting the unseen notifications count for a user. + API view for getting the unseen notifications count and show_notification_tray flag for a user. """ permission_classes = (permissions.IsAuthenticated,) def get(self, request): """ - Get the unseen notifications count for a user. + Get the unseen notifications count and show_notification_tray flag for a user. **Permissions**: User must be authenticated. **Response Format**: ```json { + "show_notifications_tray": (bool) show_notifications_tray, "count": (int) total_number_of_unseen_notifications, "count_by_app_name": { (str) app_name: (int) number_of_unseen_notifications, @@ -279,16 +277,26 @@ class NotificationCountView(APIView): ) count_total = 0 count_by_app_name_dict = {} + show_notifications_tray_enabled = False for item in count_by_app_name: app_name = item['app_name'] count = item['count'] - count_total += count count_by_app_name_dict[app_name] = count - # Return the unseen notifications count for the user and the unseen notifications count for each app name. + + learner_enrollments_course_ids = CourseEnrollment.objects.filter( + user=request.user, + is_active=True + ).values_list('course_id', flat=True) + + for course_id in learner_enrollments_course_ids: + if SHOW_NOTIFICATIONS_TRAY.is_enabled(course_id): + show_notifications_tray_enabled = True + break return Response({ + "show_notifications_tray": show_notifications_tray_enabled, "count": count_total, "count_by_app_name": count_by_app_name_dict, })