Merge pull request #30958 from openedx/jhynes/APER-1922_route-to-lr-mfe-from-program-dash

feat: Add configuration option to route `View Records` button to the Learner Record MFE
This commit is contained in:
Justin Hynes
2022-09-07 14:08:18 -04:00
committed by GitHub
5 changed files with 124 additions and 12 deletions

View File

@@ -4887,14 +4887,21 @@ LEARNING_MICROFRONTEND_URL = None
# waffle flag.
ORA_GRADING_MICROFRONTEND_URL = None
# .. setting_name: DISCUSSIONS_MICROFRONTEND_URL
# .. setting_description: Base URL of the micro-frontend-based discussions page.
# .. setting_default: None
# .. setting_description: Base URL of the micro-frontend-based discussions page.
# .. setting_warning: Also set site's courseware.discussions_mfe waffle flag.
DISCUSSIONS_MICROFRONTEND_URL = None
# .. setting_name: DISCUSSIONS_MFE_FEEDBACK_URL = None
# .. setting_name: DISCUSSIONS_MFE_FEEDBACK_URL
# .. setting_default: None
# .. setting_description: Base URL of the discussions micro-frontend google form based feedback.
DISCUSSIONS_MFE_FEEDBACK_URL = None
# .. setting_name: LEARNER_RECORD_MFE_URL
# .. setting_default: None
# .. setting_description: Base URL of the micro-frontend responsible for displaying Learner Record and Program record
# pages. This MFE replaces the legacy frontend originally offered in the Credentials IDA.
# .. setting_warning: In order to route requests to the MFE correctly you must also create and enable the credentials
# app's `USE_LEARNER_RECORD_MFE` waffle flag. See openedx/core/djangoapps/credentials/config.py.
LEARNER_RECORD_MICROFRONTEND_URL = None
# .. toggle_name: ENABLE_AUTHN_RESET_PASSWORD_HIBP_POLICY
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False

View File

@@ -362,6 +362,7 @@ ACCOUNT_MICROFRONTEND_URL = 'http://localhost:1997'
COMMUNICATIONS_MICROFRONTEND_URL = 'http://localhost:1984'
AUTHN_MICROFRONTEND_URL = 'http://localhost:1999'
AUTHN_MICROFRONTEND_DOMAIN = 'localhost:1999'
LEARNER_RECORD_MICROFRONTEND_URL = 'http://localhost:1990'
################### FRONTEND APPLICATION DISCUSSIONS ###################
DISCUSSIONS_MICROFRONTEND_URL = 'http://localhost:2002'

View File

@@ -0,0 +1,17 @@
"""
This module contains various configuration settings via waffle switches for the Credentials app.
"""
from edx_toggles.toggles import WaffleSwitch
# Namespace
WAFFLE_NAMESPACE = 'credentials'
# .. toggle_name: credentials.use_learner_record_mfe
# .. toggle_implementation: WaffleSwitch
# .. toggle_default: False
# .. toggle_description: This toggle will inform the Program Dashboard to route to the Learner Record MFE over the
# legacy frontend of the Credentials IDA.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2022-09-07
USE_LEARNER_RECORD_MFE = WaffleSwitch(f"{WAFFLE_NAMESPACE}.use_learner_record_mfe", __name__)

View File

@@ -1,14 +1,15 @@
"""Tests covering Credentials utilities."""
import uuid
from unittest import mock
from django.test import override_settings
from edx_toggles.toggles.testutils import override_waffle_switch
from openedx.core.djangoapps.credentials.config import USE_LEARNER_RECORD_MFE
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
from openedx.core.djangoapps.credentials.tests import factories
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin
from openedx.core.djangoapps.credentials.utils import get_credentials
from openedx.core.djangoapps.credentials.utils import get_credentials, get_credentials_records_url
from openedx.core.djangoapps.oauth_dispatch.tests.factories import ApplicationFactory
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms
from common.djangoapps.student.tests.factories import UserFactory
@@ -17,7 +18,6 @@ UTILS_MODULE = 'openedx.core.djangoapps.credentials.utils'
@skip_unless_lms
@mock.patch(UTILS_MODULE + '.get_api_data')
class TestGetCredentials(CredentialsApiConfigMixin, CacheIsolationTestCase):
""" Tests for credentials utility functions. """
@@ -31,6 +31,7 @@ class TestGetCredentials(CredentialsApiConfigMixin, CacheIsolationTestCase):
self.credentials_config = self.create_credentials_config(cache_ttl=1)
self.user = UserFactory()
@mock.patch(UTILS_MODULE + '.get_api_data')
def test_get_many(self, mock_get_edx_api_data):
expected = factories.UserCredential.create_batch(3)
mock_get_edx_api_data.return_value = expected
@@ -52,6 +53,7 @@ class TestGetCredentials(CredentialsApiConfigMixin, CacheIsolationTestCase):
assert actual == expected
@mock.patch(UTILS_MODULE + '.get_api_data')
def test_get_one(self, mock_get_edx_api_data):
expected = factories.UserCredential()
mock_get_edx_api_data.return_value = expected
@@ -75,6 +77,7 @@ class TestGetCredentials(CredentialsApiConfigMixin, CacheIsolationTestCase):
assert actual == expected
@mock.patch(UTILS_MODULE + '.get_api_data')
def test_type_filter(self, mock_get_edx_api_data):
get_credentials(self.user, credential_type='program')
@@ -89,3 +92,70 @@ class TestGetCredentials(CredentialsApiConfigMixin, CacheIsolationTestCase):
'type': 'program',
}
assert kwargs['querystring'] == querystring
@override_settings(LEARNER_RECORD_MICROFRONTEND_URL=None)
@override_settings(CREDENTIALS_PUBLIC_SERVICE_URL="http://foo")
def test_get_credentials_records_url(self):
"""
A test that verifies the functionality of the `get_credentials_records_url`. 
"""
result = get_credentials_records_url()
assert result == "http://foo/records/"
result = get_credentials_records_url("abcdefgh-ijkl-mnop-qrst-uvwxyz123456")
assert result == "http://foo/records/programs/abcdefghijklmnopqrstuvwxyz123456/"
@override_settings(LEARNER_RECORD_MICROFRONTEND_URL="http://blah")
@override_settings(CREDENTIALS_PUBLIC_SERVICE_URL="http://foo")
@override_waffle_switch(USE_LEARNER_RECORD_MFE, False)
def test_get_credentials_records_mfe_url_waffle_disabled(self):
"""
A test that verifies the results of the `get_credentials_records_url` function when the
LEARNER_RECORD_MICROFRONTEND_URL setting exists but the USE_LEARNER_RECORD_MFE waffle flag is disabled.
"""
result = get_credentials_records_url()
assert result == "http://foo/records/"
result = get_credentials_records_url("abcdefgh-ijkl-mnop-qrst-uvwxyz123456")
assert result == "http://foo/records/programs/abcdefghijklmnopqrstuvwxyz123456/"
@override_settings(LEARNER_RECORD_MICROFRONTEND_URL="http://blah")
@override_settings(CREDENTIALS_PUBLIC_SERVICE_URL="http://foo")
@override_waffle_switch(USE_LEARNER_RECORD_MFE, True)
def test_get_credentials_records_mfe_url_waffle_enabled(self):
"""
A test that verifies the results of the `get_credentials_records_url` function when the
LEARNER_RECORD_MICROFRONTEND_URL setting exists but the USE_LEARNER_RECORD_MFE waffle flag is enabled.
"""
result = get_credentials_records_url()
assert result == "http://blah/"
result = get_credentials_records_url("abcdefgh-ijkl-mnop-qrst-uvwxyz123456")
assert result == "http://blah/abcdefghijklmnopqrstuvwxyz123456/"
@override_settings(CREDENTIALS_PUBLIC_SERVICE_URL=None)
@override_settings(LEARNER_RECORD_MICROFRONTEND_URL=None)
def test_get_credentials_records_url_expect_none(self):
"""
A test that verifieis the results of the `get_credentials_records_url` function when the system is configured
to use neither the Credentials IDA or the Learner Record MFE.
"""
result = get_credentials_records_url()
assert result is None
result = get_credentials_records_url("abcdefgh-ijkl-mnop-qrst-uvwxyz123456")
assert result is None
@override_settings(LEARNER_RECORD_MICROFRONTEND_URL="http://blah")
@override_settings(CREDENTIALS_PUBLIC_SERVICE_URL=None)
@override_waffle_switch(USE_LEARNER_RECORD_MFE, True)
def test_get_credentials_records_url_only_mfe_configured(self):
"""
A test that verifieis the results of the `get_credentials_records_url` function when the system is configured
to use only the Learner Record MFE.
"""
result = get_credentials_records_url()
assert result == "http://blah/"
result = get_credentials_records_url("abcdefgh-ijkl-mnop-qrst-uvwxyz123456")
assert result == "http://blah/abcdefghijklmnopqrstuvwxyz123456/"

View File

@@ -2,6 +2,9 @@
import requests
from edx_rest_api_client.auth import SuppliedJwtAuth
from django.conf import settings
from openedx.core.djangoapps.credentials.config import USE_LEARNER_RECORD_MFE
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
from openedx.core.lib.edx_api_utils import get_api_data
@@ -15,13 +18,27 @@ def get_credentials_records_url(program_uuid=None):
Arguments:
program_uuid (str): Optional program uuid to link for a program records URL
"""
base_url = CredentialsApiConfig.current().public_records_url
if base_url is None:
base_url = settings.CREDENTIALS_PUBLIC_SERVICE_URL
learner_record_mfe_base_url = settings.LEARNER_RECORD_MICROFRONTEND_URL
use_learner_record_mfe = USE_LEARNER_RECORD_MFE.is_enabled() and learner_record_mfe_base_url
if not base_url and not use_learner_record_mfe:
return None
# If we have a program uuid we build a link to the appropriate Program Record page in Credentials (or the Learner
# Record MFE)
if program_uuid:
# Credentials expects the uuid without dashes so we are converting here
return base_url + 'programs/{}/'.format(program_uuid.replace('-', ''))
return base_url
# Credentials expects the UUID without dashes so we strip them here
stripped_program_uuid = program_uuid.replace('-', '')
if use_learner_record_mfe:
return f"{learner_record_mfe_base_url}/{stripped_program_uuid}/"
return f"{base_url}/records/programs/{stripped_program_uuid}/"
else:
# Otherwise, build a link to the appropriate Learner Record index page
if use_learner_record_mfe:
return f"{learner_record_mfe_base_url}/"
else:
return f"{base_url}/records/"
def get_credentials_api_client(user):