Skip to content
Merged
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
50 changes: 37 additions & 13 deletions lms/djangoapps/learner_home/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
random_url,
)
from lms.djangoapps.learner_home.views import (
EnterpriseCustomerData,
get_course_overviews_for_pseudo_sessions,
get_course_programs,
get_email_settings_info,
Expand Down Expand Up @@ -427,26 +428,49 @@ def test_no_suggested_courses(self):
self.assertDictEqual(return_data, self.EMPTY_SUGGESTED_COURSES)


FAKE_ENTERPRISE_CUSTOMER_DATA: EnterpriseCustomerData = {
"name": "Fake Enterprise",
"uuid": str(uuid4()),
"slug": "fake-enterprise",
"auth_org_id": None,
"enable_learner_portal": True,
}


def _fake_enterprise_customer_override(prev_fn, user, request, is_masquerading):
"""Test double target for OVERRIDE_LEARNER_HOME_GET_ENTERPRISE_CUSTOMER"""
_fake_enterprise_customer_override.last_call = (prev_fn, user, request, is_masquerading)
return FAKE_ENTERPRISE_CUSTOMER_DATA

Comment thread
marlonkeating marked this conversation as resolved.

@ddt.ddt
class TestGetEnterpriseCustomer(TestCase):
"""Test for get_enterprise_customer"""

@ddt.data(True, False)
@patch("lms.djangoapps.learner_home.views.get_enterprise_learner_data_from_db")
@patch(
"lms.djangoapps.learner_home.views.enterprise_customer_from_session_or_learner_data"
)
def test_get_enterprise_customer(
self, is_masquerading, mock_get_from_session, mock_get_from_db
):
"""Don't load the user from session if we're masquerading, load directly from db"""
def test_get_enterprise_customer_default(self, is_masquerading):
"""With no plugin override configured, the base implementation returns None"""
user, request = Mock(), Mock()
result = get_enterprise_customer(user, request, is_masquerading)
if is_masquerading:
assert not mock_get_from_session.called
assert result is mock_get_from_db.return_value[0]["enterprise_customer"]
else:
assert result is mock_get_from_session.return_value
assert result is None

@override_settings(
OVERRIDE_LEARNER_HOME_GET_ENTERPRISE_CUSTOMER=(
f"{__name__}._fake_enterprise_customer_override"
)
)
def test_get_enterprise_customer_uses_plugin_override(self):
"""When OVERRIDE_LEARNER_HOME_GET_ENTERPRISE_CUSTOMER is configured, it is used instead"""
user, request = Mock(), Mock()
result = get_enterprise_customer(user, request, is_masquerading=True)
assert result == FAKE_ENTERPRISE_CUSTOMER_DATA

_, received_user, received_request, received_is_masquerading = (
_fake_enterprise_customer_override.last_call
)
assert received_user is user
assert received_request is request
assert received_is_masquerading is True


class TestGetSocialShareSettings(TestCase):
Expand Down
40 changes: 28 additions & 12 deletions lms/djangoapps/learner_home/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@
Views for Learner Home
"""

from __future__ import annotations

import logging
from collections import OrderedDict
from typing import TYPE_CHECKING, Optional, TypedDict

from completion.exceptions import UnavailableCompletionData
from completion.utilities import get_key_to_last_completed_block
from django.conf import settings
from django.urls import reverse
from edx_django_utils import monitoring as monitoring_utils
from edx_django_utils.monitoring import function_trace
from edx_django_utils.plugins import pluggable_override
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import (
SessionAuthenticationAllowInactiveUser,
)
from edx_rest_framework_extensions.permissions import NotJwtRestrictedApplication
from opaque_keys.edx.keys import CourseKey
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

Expand Down Expand Up @@ -60,10 +65,9 @@
from openedx.features.course_duration_limits.access import (
get_user_course_expiration_date,
)
from openedx.features.enterprise_support.api import (
enterprise_customer_from_session_or_learner_data,
get_enterprise_learner_data_from_db,
)

if TYPE_CHECKING:
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -208,17 +212,29 @@ def get_email_settings_info(user, course_enrollments):
return show_email_settings_for, course_optouts


class EnterpriseCustomerData(TypedDict):
"""Contract for the OVERRIDE_LEARNER_HOME_GET_ENTERPRISE_CUSTOMER return value."""
name: str
uuid: str
slug: str
auth_org_id: Optional[str]
enable_learner_portal: bool
Comment on lines +218 to +221


@function_trace("get_enterprise_customer")
def get_enterprise_customer(user, request, is_masquerading):
@pluggable_override('OVERRIDE_LEARNER_HOME_GET_ENTERPRISE_CUSTOMER')
def get_enterprise_customer(
user: User,
request: Request,
is_masquerading: bool,
) -> Optional[EnterpriseCustomerData]:
"""
If we are not masquerading, try to load the enterprise learner from session data, falling back to the db.
If we are masquerading, don't read or write to/from session data, go directly to db.
Return the enterprise customer dict for the given user, or None.

This function can be overridden by an installed plugin via the
OVERRIDE_LEARNER_HOME_GET_ENTERPRISE_CUSTOMER setting.
"""
Comment on lines +232 to 236
if is_masquerading:
learner_data = get_enterprise_learner_data_from_db(user)
return learner_data[0]["enterprise_customer"] if learner_data else None
else:
return enterprise_customer_from_session_or_learner_data(request)
return None


@function_trace("get_ecommerce_payment_page")
Expand Down
Loading