fix: [AA-1206] resolve access APIs (#838)

* fix: [AA-1206] resolve access APIs

As part of eliminating redundant fields course_access was removed from
 the Courseware metadata API. There are some differences between the
 two APIs - courseware returned an error if the course had flags
 preventing it from being loaded in the MFE, and courseHome had a
 second field, can_load_courseware, that returned a boolean.

 This fix unifies the handling of the access fields to behave consistently.
This commit is contained in:
Chris Deery
2022-03-03 16:12:14 -05:00
committed by GitHub
parent 4586f8a6ad
commit 55dac2696e
6 changed files with 34 additions and 24 deletions

View File

@@ -9,7 +9,7 @@ Factory.define('courseHomeMetadata')
title: 'Demonstration Course',
is_self_paced: false,
is_enrolled: false,
can_load_courseware: false,
can_load_courseware: true,
celebrations: null,
course_access: {
additional_context_user_message: null,

View File

@@ -21,7 +21,7 @@ Object {
"models": Object {
"courseHomeMeta": Object {
"course-v1:edX+DemoX+Demo_Course": Object {
"canLoadCourseware": false,
"canLoadCourseware": true,
"celebrations": null,
"courseAccess": Object {
"additionalContextUserMessage": null,
@@ -336,7 +336,7 @@ Object {
"models": Object {
"courseHomeMeta": Object {
"course-v1:edX+DemoX+Demo_Course": Object {
"canLoadCourseware": false,
"canLoadCourseware": true,
"celebrations": null,
"courseAccess": Object {
"additionalContextUserMessage": null,
@@ -531,7 +531,7 @@ Object {
"models": Object {
"courseHomeMeta": Object {
"course-v1:edX+DemoX+Demo_Course": Object {
"canLoadCourseware": false,
"canLoadCourseware": true,
"celebrations": null,
"courseAccess": Object {
"additionalContextUserMessage": null,

View File

@@ -471,13 +471,6 @@ describe('CoursewareContainer', () => {
expect(global.location.href).toEqual(`http://localhost/redirect/survey/${courseMetadata.id}`);
});
it('should go to legacy courseware for a microfrontend_disabled error code', async () => {
const { courseMetadata, unitBlocks } = setUpWithDeniedStatus('microfrontend_disabled');
await loadContainer();
expect(global.location.href).toEqual(`http://localhost/redirect/courseware/${courseMetadata.id}/unit/${unitBlocks[0].id}`);
});
it('should go to course home for an authentication_required error code', async () => {
const { courseMetadata } = setUpWithDeniedStatus('authentication_required');
await loadContainer();
@@ -507,4 +500,21 @@ describe('CoursewareContainer', () => {
expect(global.location.href).toEqual(`http://localhost/redirect/dashboard?notlive=${startDate}`);
});
});
describe('redirects when canLoadCourseware is false', () => {
it('should go to legacy courseware for disabled frontend', async () => {
const courseMetadata = Factory.build('courseMetadata');
const courseHomeMetadata = Factory.build('courseHomeMetadata', {
can_load_courseware: false,
});
const courseId = courseMetadata.id;
const { courseBlocks, sequenceBlocks, unitBlocks } = buildSimpleCourseBlocks(courseId, courseMetadata.name);
setUpMockRequests({ courseBlocks, courseMetadata, courseHomeMetadata });
history.push(`/course/${courseId}/${sequenceBlocks[0].id}/${unitBlocks[0].id}`);
await loadContainer();
expect(global.location.href).toEqual(`http://localhost/redirect/courseware/${courseMetadata.id}/unit/${unitBlocks[0].id}`);
});
});
});

View File

@@ -93,7 +93,9 @@ export function fetchCourse(courseId) {
logError(courseHomeMetadataResult.reason);
}
if (fetchedMetadata && fetchedCourseHomeMetadata) {
if (courseHomeMetadataResult.value.courseAccess.hasAccess && fetchedOutline) {
if (courseHomeMetadataResult.value.courseAccess.hasAccess
&& courseHomeMetadataResult.value.canLoadCourseware
&& fetchedOutline) {
// User has access
dispatch(fetchCourseSuccess({ courseId }));
return;

View File

@@ -4,7 +4,7 @@ import { getLocale } from '@edx/frontend-platform/i18n';
// This function inspects an access denied error and provides a redirect url (looks like a /redirect/... path),
// which then renders a nice little message while the browser loads the next page.
// This is basically a frontend version of check_course_access_with_redirect in the backend.
export function getAccessDeniedRedirectUrl(courseId, activeTabSlug, courseAccess, start, unitId) {
export function getAccessDeniedRedirectUrl(courseId, activeTabSlug, canLoadCourseware, courseAccess, start, unitId) {
let url = null;
switch (courseAccess.errorCode) {
case 'audit_expired':
@@ -21,19 +21,14 @@ export function getAccessDeniedRedirectUrl(courseId, activeTabSlug, courseAccess
case 'unfulfilled_milestones':
url = '/redirect/dashboard';
break;
case 'microfrontend_disabled':
// This code path is only used by the courseware right now. The course home tabs each have their own check for
// this in the tab-specific API calls. In those cases, the API will return an http status code if the MFE version
// of those tabs are disabled, rather than an access error like this. We could try to unify these approaches, but
// hopefully the legacy code isn't around long enough for that to be worth it.
if (unitId) {
url = `/redirect/courseware/${courseId}/unit/${unitId}`;
}
break;
case 'authentication_required':
case 'enrollment_required':
default:
if (activeTabSlug !== 'outline') {
// if the learner has access to the course, but it is not enabled in the mfe, there is no
// error message, canLoadCourseware will be false.
if (activeTabSlug === 'courseware' && canLoadCourseware === false && unitId) {
url = `/redirect/courseware/${courseId}/unit/${unitId}`;
} else if (activeTabSlug !== 'outline') {
url = `/redirect/course-home/${courseId}`;
}
}

View File

@@ -32,6 +32,7 @@ function TabPage({ intl, ...props }) {
} = useSelector(state => state.courseHome);
const dispatch = useDispatch();
const {
canLoadCourseware,
courseAccess,
number,
org,
@@ -52,7 +53,9 @@ function TabPage({ intl, ...props }) {
}
if (courseStatus === 'denied') {
const redirectUrl = getAccessDeniedRedirectUrl(courseId, activeTabSlug, courseAccess, start, unitId);
const redirectUrl = getAccessDeniedRedirectUrl(
courseId, activeTabSlug, canLoadCourseware, courseAccess, start, unitId,
);
if (redirectUrl) {
return (<Redirect to={redirectUrl} />);
}