fix: staff debug actions depended on legacy courseware URL (#26658)

The Staff Debug Actions didn't work in the Learning MFE
because the underlying JS depended on the URL being
formatted as /courses/<course_key>/... in order to
parse out the course key. This worked in the legacy
experience, but breaks in the chromeless xblock view,
which is rendered under the URL /xblock/<usage_key>/...

The fix is to explicitly pass the course key into the
templated courseware HTML as a data attribute.

TNL-7955
This commit is contained in:
Kyle McCormick
2021-02-22 15:14:31 -05:00
committed by GitHub
parent f8eb7bfd52
commit 6d78f6aab2
4 changed files with 59 additions and 45 deletions

View File

@@ -9,7 +9,8 @@ define([
var StaffDebug = window.StaffDebug;
describe('StaffDebugActions', function() {
var location = 'i4x://edX/Open_DemoX/edx_demo_course/problem/test_loc';
var courseId = 'course-v1:edX+DemoX+1';
var location = 'block-v1:edX+DemoX+1+type@problem+block@9518dd51055b40cd82feb01502644c89';
var locationName = 'test_loc';
var usernameFixtureID = 'sd_fu_' + locationName;
var $usernameFixture = $('<input>', {id: usernameFixtureID, placeholder: 'userman'});
@@ -24,19 +25,15 @@ define([
describe('getURL ', function() {
it('defines url to courseware ajax entry point', function() {
spyOn(StaffDebug, 'getCurrentUrl')
.and.returnValue('/courses/edX/Open_DemoX/edx_demo_course/courseware/stuff');
expect(StaffDebug.getURL('rescore_problem'))
.toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor/api/rescore_problem');
expect(StaffDebug.getURL(courseId, 'rescore_problem'))
.toBe('/courses/course-v1:edX+DemoX+1/instructor/api/rescore_problem');
});
});
describe('getURL ', function() {
it('defines that getCurrentUrl works on instructor page as expected', function() {
spyOn(StaffDebug, 'getCurrentUrl')
.and.returnValue('/courses/edx_demo_course/instructor#view-open_response_assessment');
expect(StaffDebug.getURL('rescore_problem'))
.toBe('/courses/edx_demo_course/instructor/api/rescore_problem');
it('defines url to courseware ajax entry point for deprecated courses', function() {
expect(StaffDebug.getURL('edX/DemoX/1', 'rescore_problem'))
.toBe('/courses/edX/DemoX/1/instructor/api/rescore_problem');
});
});
@@ -87,6 +84,7 @@ define([
$('body').append($escapableResultArea);
var requests = AjaxHelpers.requests(this);
var action = {
courseId: courseId,
locationName: esclocationName,
success_msg: 'Successfully reset the attempts for user userman'
};
@@ -101,6 +99,7 @@ define([
$('body').append($escapableResultArea);
var requests = AjaxHelpers.requests(this);
var action = {
courseId: courseId,
locationName: esclocationName,
error_msg: 'Failed to reset attempts for user.'
};
@@ -115,7 +114,7 @@ define([
$('body').append($usernameFixture);
spyOn($, 'ajax');
StaffDebug.reset(locationName, location);
StaffDebug.reset(courseId, locationName, location);
expect($.ajax.calls.mostRecent().args[0].type).toEqual('POST');
expect($.ajax.calls.mostRecent().args[0].data).toEqual({
@@ -126,7 +125,7 @@ define([
score: undefined
});
expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/reset_student_attempts'
'/courses/course-v1:edX+DemoX+1/instructor/api/reset_student_attempts'
);
$('#' + usernameFixtureID).remove();
});
@@ -136,7 +135,7 @@ define([
$('body').append($usernameFixture);
spyOn($, 'ajax');
StaffDebug.deleteStudentState(locationName, location);
StaffDebug.deleteStudentState(courseId, locationName, location);
expect($.ajax.calls.mostRecent().args[0].type).toEqual('POST');
expect($.ajax.calls.mostRecent().args[0].data).toEqual({
@@ -147,7 +146,7 @@ define([
score: undefined
});
expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/reset_student_attempts'
'/courses/course-v1:edX+DemoX+1/instructor/api/reset_student_attempts'
);
$('#' + usernameFixtureID).remove();
@@ -158,7 +157,7 @@ define([
$('body').append($usernameFixture);
spyOn($, 'ajax');
StaffDebug.rescore(locationName, location);
StaffDebug.rescore(courseId, locationName, location);
expect($.ajax.calls.mostRecent().args[0].type).toEqual('POST');
expect($.ajax.calls.mostRecent().args[0].data).toEqual({
@@ -169,7 +168,7 @@ define([
score: undefined
});
expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/rescore_problem'
'/courses/course-v1:edX+DemoX+1/instructor/api/rescore_problem'
);
$('#' + usernameFixtureID).remove();
});
@@ -179,7 +178,7 @@ define([
$('body').append($usernameFixture);
spyOn($, 'ajax');
StaffDebug.rescoreIfHigher(locationName, location);
StaffDebug.rescoreIfHigher(courseId, locationName, location);
expect($.ajax.calls.mostRecent().args[0].type).toEqual('POST');
expect($.ajax.calls.mostRecent().args[0].data).toEqual({
@@ -190,7 +189,7 @@ define([
score: undefined
});
expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/rescore_problem'
'/courses/course-v1:edX+DemoX+1/instructor/api/rescore_problem'
);
$('#' + usernameFixtureID).remove();
});
@@ -201,7 +200,7 @@ define([
$('body').append($scoreFixture);
$('#' + scoreFixtureID).val('1');
spyOn($, 'ajax');
StaffDebug.overrideScore(locationName, location);
StaffDebug.overrideScore(courseId, locationName, location);
expect($.ajax.calls.mostRecent().args[0].type).toEqual('POST');
expect($.ajax.calls.mostRecent().args[0].data).toEqual({
@@ -212,7 +211,7 @@ define([
score: '1'
});
expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/override_problem_score'
'/courses/course-v1:edX+DemoX+1/instructor/api/override_problem_score'
);
$('#' + usernameFixtureID).remove();
});

View File

@@ -1,14 +1,8 @@
/* globals _ */
// Build StaffDebug object
var StaffDebug = (function() {
/* global getCurrentUrl:true */
var getURL = function(action) {
var pathname = this.getCurrentUrl();
var index = pathname.indexOf('/courseware');
if (index <= 0) {
index = pathname.indexOf('/', '/courses/'.length);
}
return pathname.substr(0, index) + '/instructor/api/' + action;
var getURL = function(courseId, action) {
return '/courses/' + courseId + '/instructor/api/' + action;
};
var sanitizeString = function(string) {
@@ -43,7 +37,7 @@ var StaffDebug = (function() {
};
$.ajax({
type: 'POST',
url: getURL(action.method),
url: getURL(action.courseId, action.method),
data: pdata,
success: function(data) {
var text = _.template(action.success_msg, {interpolate: /\{(.+?)\}/g})(
@@ -82,8 +76,9 @@ var StaffDebug = (function() {
});
};
var reset = function(locname, location) {
var reset = function(courseId, locname, location) {
this.doInstructorDashAction({
courseId: courseId,
locationName: locname,
location: location,
method: 'reset_student_attempts',
@@ -93,8 +88,9 @@ var StaffDebug = (function() {
});
};
var deleteStudentState = function(locname, location) {
var deleteStudentState = function(courseId, locname, location) {
this.doInstructorDashAction({
courseId: courseId,
locationName: locname,
location: location,
method: 'reset_student_attempts',
@@ -104,8 +100,9 @@ var StaffDebug = (function() {
});
};
var rescore = function(locname, location) {
var rescore = function(courseId, locname, location) {
this.doInstructorDashAction({
courseId: courseId,
locationName: locname,
location: location,
method: 'rescore_problem',
@@ -115,8 +112,9 @@ var StaffDebug = (function() {
});
};
var rescoreIfHigher = function(locname, location) {
var rescoreIfHigher = function(courseId, locname, location) {
this.doInstructorDashAction({
courseId: courseId,
locationName: locname,
location: location,
method: 'rescore_problem',
@@ -126,8 +124,9 @@ var StaffDebug = (function() {
});
};
var overrideScore = function(locname, location) {
var overrideScore = function(courseId, locname, location) {
this.doInstructorDashAction({
courseId: courseId,
locationName: locname,
location: location,
method: 'override_problem_score',
@@ -137,10 +136,6 @@ var StaffDebug = (function() {
});
};
getCurrentUrl = function() {
return window.location.pathname;
};
return {
reset: reset,
deleteStudentState: deleteStudentState,
@@ -150,7 +145,6 @@ var StaffDebug = (function() {
// export for testing
doInstructorDashAction: doInstructorDashAction,
getCurrentUrl: getCurrentUrl,
getURL: getURL,
getUser: getUser,
getScore: getScore,
@@ -160,26 +154,47 @@ var StaffDebug = (function() {
// Register click handlers
$(document).ready(function() {
var $mainContainer = $('#main');
$mainContainer.on('click', '.staff-debug-reset', function() {
StaffDebug.reset($(this).parent().data('location-name'), $(this).parent().data('location'));
StaffDebug.reset(
$(this).parent().data('course-id'),
$(this).parent().data('location-name'),
$(this).parent().data('location')
);
return false;
});
$mainContainer.on('click', '.staff-debug-sdelete', function() {
StaffDebug.deleteStudentState($(this).parent().data('location-name'), $(this).parent().data('location'));
StaffDebug.deleteStudentState(
$(this).parent().data('course-id'),
$(this).parent().data('location-name'),
$(this).parent().data('location')
);
return false;
});
$mainContainer.on('click', '.staff-debug-rescore', function() {
StaffDebug.rescore($(this).parent().data('location-name'), $(this).parent().data('location'));
StaffDebug.rescore(
$(this).parent().data('course-id'),
$(this).parent().data('location-name'),
$(this).parent().data('location')
);
return false;
});
$mainContainer.on('click', '.staff-debug-rescore-if-higher', function() {
StaffDebug.rescoreIfHigher($(this).parent().data('location-name'), $(this).parent().data('location'));
StaffDebug.rescoreIfHigher(
$(this).parent().data('course-id'),
$(this).parent().data('location-name'),
$(this).parent().data('location')
);
return false;
});
$mainContainer.on('click', '.staff-debug-override-score', function() {
StaffDebug.overrideScore($(this).parent().data('location-name'), $(this).parent().data('location'));
StaffDebug.overrideScore(
$(this).parent().data('course-id'),
$(this).parent().data('location-name'),
$(this).parent().data('location')
);
return false;
});
});

View File

@@ -76,7 +76,7 @@ ${block_content | n, decode.utf8}
<label for="sd_fs_${location.block_id}"> / ${max_problem_score}</label>
</div>
% endif
<div data-location="${location}" data-location-name="${location.block_id}">
<div data-location="${location}" data-location-name="${location.block_id}" data-course-id="${location.course_key}">
[
% if can_reset_attempts:
<button type="button" class="btn-link staff-debug-reset">${_('Reset Learner\'s Attempts to Zero')}</button>