diff --git a/openedx/core/djangoapps/notifications/tests/test_utils.py b/openedx/core/djangoapps/notifications/tests/test_utils.py index e300c63c1d..066c7b7f59 100644 --- a/openedx/core/djangoapps/notifications/tests/test_utils.py +++ b/openedx/core/djangoapps/notifications/tests/test_utils.py @@ -1,9 +1,15 @@ """ Test cases for the notification utility functions. """ +import copy import unittest -from openedx.core.djangoapps.notifications.utils import aggregate_notification_configs +import pytest + +from common.djangoapps.student.tests.factories import UserFactory +from openedx.core.djangoapps.django_comment_common.models import assign_role, FORUM_ROLE_MODERATOR +from openedx.core.djangoapps.notifications.utils import aggregate_notification_configs, \ + filter_out_visible_preferences_by_course_ids class TestAggregateNotificationConfigs(unittest.TestCase): @@ -286,3 +292,55 @@ class TestAggregateNotificationConfigs(unittest.TestCase): result = aggregate_notification_configs(config_list) assert result["grading"]["notification_types"]["core"]["email_cadence"] == "Mixed" + + +@pytest.mark.django_db +class TestVisibilityFilter(unittest.TestCase): + """ + Test cases for the filter_out_visible_preferences_by_course_ids function. + """ + + def setUp(self): + self.user = UserFactory() + self.course_key = "course-v1:edX+DemoX+Demo_Course" + self.mock_preferences = { + 'discussion': { + 'enabled': True, + 'non_editable': {'core': ['web']}, + 'notification_types': { + 'core': {'web': True, 'push': True, 'email': True, 'email_cadence': 'Daily'}, + 'content_reported': {'web': True, 'push': True, 'email': True, 'email_cadence': 'Daily'}, + 'new_question_post': {'web': False, 'push': False, 'email': False, 'email_cadence': 'Daily'}, + 'new_discussion_post': {'web': False, 'push': False, 'email': False, 'email_cadence': 'Daily'} + }, + 'core_notification_types': [ + 'new_response', 'comment_on_followed_post', + 'response_endorsed_on_thread', 'new_comment_on_response', + 'new_comment', 'response_on_followed_post', 'response_endorsed' + ] + } + } + + def test_visibility_filter_with_no_role(self): + """ + Test that the preferences are filtered out correctly when the user has no role. + """ + updated_preferences = filter_out_visible_preferences_by_course_ids( + self.user, + copy.deepcopy(self.mock_preferences), + [self.course_key] + ) + assert updated_preferences != self.mock_preferences + assert not updated_preferences["discussion"]["notification_types"].get("content_reported", False) + + def test_visibility_filter_with_instructor_role(self): + """ + Instructors should see all preferences. + """ + updated_preferences = filter_out_visible_preferences_by_course_ids( + self.user, + self.mock_preferences, + [self.course_key] + ) + assign_role(self.course_key, self.user, FORUM_ROLE_MODERATOR) + assert updated_preferences == self.mock_preferences diff --git a/openedx/core/djangoapps/notifications/utils.py b/openedx/core/djangoapps/notifications/utils.py index 34f9d71cb0..014f7461b5 100644 --- a/openedx/core/djangoapps/notifications/utils.py +++ b/openedx/core/djangoapps/notifications/utils.py @@ -269,3 +269,21 @@ def aggregate_notification_configs(existing_user_configs: List[Dict]) -> Dict: result_config[app]["notification_types"][type_key]["email_cadence"] = ( result_config[app]["notification_types"][type_key]["email_cadence"].pop()) return result_config + + +def filter_out_visible_preferences_by_course_ids(user, preferences: Dict, course_ids: List) -> Dict: + """ + Filter out notifications visible to forum roles from user preferences. + """ + forum_roles = Role.objects.filter(users__id=user.id).values_list('name', flat=True) + course_roles = CourseAccessRole.objects.filter( + user=user, + course_id__in=course_ids + ).values_list('role', flat=True) + notification_types_with_visibility = get_notification_types_with_visibility_settings() + return filter_out_visible_notifications( + preferences, + notification_types_with_visibility, + forum_roles, + course_roles + ) diff --git a/openedx/core/djangoapps/notifications/views.py b/openedx/core/djangoapps/notifications/views.py index 8718b6818c..84e60b49b4 100644 --- a/openedx/core/djangoapps/notifications/views.py +++ b/openedx/core/djangoapps/notifications/views.py @@ -39,7 +39,8 @@ from .serializers import ( UserNotificationPreferenceUpdateAllSerializer, UserNotificationPreferenceUpdateSerializer ) -from .utils import get_is_new_notification_view_enabled, get_show_notifications_tray, aggregate_notification_configs +from .utils import get_is_new_notification_view_enabled, get_show_notifications_tray, aggregate_notification_configs, \ + filter_out_visible_preferences_by_course_ids @allow_any_authenticated_user() @@ -588,6 +589,11 @@ class AggregatedNotificationPreferences(APIView): notification_configs = aggregate_notification_configs( notification_configs ) + filter_out_visible_preferences_by_course_ids( + request.user, + notification_configs, + notification_preferences.values_list('course_id', flat=True), + ) notification_preferences_viewed_event(request) return Response({ 'status': 'success',