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:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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} />);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user