Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions enterprise/overrides/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Pluggable override implementations for edx-enterprise.
"""
30 changes: 30 additions & 0 deletions enterprise/overrides/course_home_progress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Pluggable override for the course home progress view username obfuscation.
"""
import logging

log = logging.getLogger(__name__)


def enterprise_obfuscated_username(prev_fn, request, student): # pylint: disable=unused-argument
"""
Return an enterprise-specific generic name for the student, or None.

This function overrides the default ``obfuscated_username`` implementation in
``lms/djangoapps/course_home_api/progress/views.py`` via the pluggable override
mechanism. When an enterprise SSO learner has a configured generic name, that name
is returned so the learner's real username is not exposed in the progress tab.

Arguments:
prev_fn: the previous (default) implementation — returns None, not called.
request: the current HTTP request.
student: the Django User object for the student being viewed.

Returns:
str or None: the generic enterprise name, or None if the learner is not an
enterprise SSO user with a configured generic name.
"""
# Deferred import — will be replaced with internal path in epic 17.
from openedx.features.enterprise_support.utils import \
get_enterprise_learner_generic_name # pylint: disable=import-outside-toplevel
return get_enterprise_learner_generic_name(request) or None
87 changes: 87 additions & 0 deletions tests/test_enterprise/test_overrides_course_home_progress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""
Tests for enterprise.overrides.course_home_progress pluggable override.
"""
from unittest import TestCase
from unittest.mock import MagicMock, patch


ENTERPRISE_SUPPORT_UTILS_PATH = 'openedx.features.enterprise_support.utils'


class TestEnterpriseObfuscatedUsername(TestCase):
"""
Tests for enterprise_obfuscated_username override function.
"""

def _call(self, request=None, student=None):
"""Import and call the override function."""
# pylint: disable=import-outside-toplevel
from enterprise.overrides.course_home_progress import enterprise_obfuscated_username
prev_fn = MagicMock()
return enterprise_obfuscated_username(prev_fn, request, student)

def test_enterprise_learner_returns_generic_name(self):
"""
When get_enterprise_learner_generic_name returns a non-empty string,
should return that string.
"""
request = MagicMock()
student = MagicMock()
expected_name = 'Enterprise Learner'
mock_utils = MagicMock()
mock_utils.get_enterprise_learner_generic_name.return_value = expected_name

with patch.dict('sys.modules', {ENTERPRISE_SUPPORT_UTILS_PATH: mock_utils}):
result = self._call(request=request, student=student)

mock_utils.get_enterprise_learner_generic_name.assert_called_once_with(request)
self.assertEqual(result, expected_name)

def test_non_enterprise_learner_returns_none(self):
"""
When get_enterprise_learner_generic_name returns None (no enterprise generic name),
should return None.
"""
request = MagicMock()
student = MagicMock()
mock_utils = MagicMock()
mock_utils.get_enterprise_learner_generic_name.return_value = None

with patch.dict('sys.modules', {ENTERPRISE_SUPPORT_UTILS_PATH: mock_utils}):
result = self._call(request=request, student=student)

mock_utils.get_enterprise_learner_generic_name.assert_called_once_with(request)
self.assertIsNone(result)

def test_empty_string_generic_name_returns_none(self):
"""
When get_enterprise_learner_generic_name returns an empty string,
should return None (falsy value is converted to None via `or None`).
"""
request = MagicMock()
student = MagicMock()
mock_utils = MagicMock()
mock_utils.get_enterprise_learner_generic_name.return_value = ''

with patch.dict('sys.modules', {ENTERPRISE_SUPPORT_UTILS_PATH: mock_utils}):
result = self._call(request=request, student=student)

mock_utils.get_enterprise_learner_generic_name.assert_called_once_with(request)
self.assertIsNone(result)

def test_prev_fn_is_not_called(self):
"""
The override fully replaces the default implementation — prev_fn should not be called.
"""
request = MagicMock()
student = MagicMock()
prev_fn = MagicMock()
mock_utils = MagicMock()
mock_utils.get_enterprise_learner_generic_name.return_value = 'Some Name'

# pylint: disable=import-outside-toplevel
from enterprise.overrides.course_home_progress import enterprise_obfuscated_username
with patch.dict('sys.modules', {ENTERPRISE_SUPPORT_UTILS_PATH: mock_utils}):
enterprise_obfuscated_username(prev_fn, request, student)

prev_fn.assert_not_called()
Loading