diff --git a/common/static/common/js/components/BlockBrowser/data/reducers/index.js b/common/static/common/js/components/BlockBrowser/data/reducers/index.js index 365e9153edd5..98e68e872cc2 100644 --- a/common/static/common/js/components/BlockBrowser/data/reducers/index.js +++ b/common/static/common/js/components/BlockBrowser/data/reducers/index.js @@ -27,7 +27,7 @@ export const blocks = (state = {}, action) => { } }; -export const selectedBlock = (state = null, action) => { +export const selectedBlock = (state = '', action) => { switch (action.type) { case courseBlocksActions.SELECT_BLOCK: return action.blockId; diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx index a9c9c5c61dd9..500e956c8bba 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx @@ -28,6 +28,7 @@ export default class Main extends React.Component { this.props.createProblemResponsesReportTask( this.props.problemResponsesEndpoint, this.props.taskStatusEndpoint, + this.props.reportDownloadEndpoint, this.props.selectedBlock, ); } @@ -71,6 +72,7 @@ Main.propTypes = { onSelectBlock: PropTypes.func.isRequired, selectedBlock: PropTypes.string, taskStatusEndpoint: PropTypes.string.isRequired, + reportDownloadEndpoint: PropTypes.string.isRequired, }; Main.defaultProps = { diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx index 55c40facf299..6282dd61f9e5 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx @@ -14,10 +14,10 @@ const mapDispatchToProps = dispatch => ({ (courseId, excludeBlockTypes) => dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)), createProblemResponsesReportTask: - (problemResponsesEndpoint, taskStatusEndpoint, problemLocation) => + (problemResponsesEndpoint, taskStatusEndpoint, reportDownloadEndpoint, problemLocation) => dispatch( createProblemResponsesReportTask( - problemResponsesEndpoint, taskStatusEndpoint, problemLocation, + problemResponsesEndpoint, taskStatusEndpoint, reportDownloadEndpoint, problemLocation, ), ), }); diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/ReportStatus/ReportStatus.jsx b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/ReportStatus/ReportStatus.jsx index 9715493aa914..3919963f7ad9 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/ReportStatus/ReportStatus.jsx +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/ReportStatus/ReportStatus.jsx @@ -15,10 +15,11 @@ const ReportStatus = ({ error, succeeded, inProgress, reportPath }) => { const successMessage = (
{gettext('Your report has being successfully generated.')} + {reportPath && + }
); diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/constants.js b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/constants.js index e643833285be..74a66ef2a37d 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/constants.js +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/constants.js @@ -2,3 +2,6 @@ export const REPORT_GENERATION_REQUEST = 'REPORT_GENERATION_REQUEST'; export const REPORT_GENERATION_SUCCESS = 'REPORT_GENERATION_SUCCESS'; export const REPORT_GENERATION_ERROR = 'REPORT_GENERATION_ERROR'; export const REPORT_GENERATION_REFRESH_STATUS = 'REPORT_GENERATION_REFRESH_STATUS'; +export const REPORT_DOWNLOADS_LIST_REQUEST = 'REPORT_DOWNLOADS_LIST_REQUEST'; +export const REPORT_DOWNLOADS_LIST_SUCCESS = 'REPORT_DOWNLOADS_LIST_SUCCESS'; +export const REPORT_DOWNLOADS_LIST_ERROR = 'REPORT_DOWNLOADS_LIST_ERROR'; diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/problemResponses.js b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/problemResponses.js index a129340767dd..a62c4cb2ea0a 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/problemResponses.js +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/actions/problemResponses.js @@ -1,5 +1,5 @@ /* global gettext */ -import { fetchTaskStatus, initiateProblemResponsesRequest } from '../api/client'; +import { fetchDownloadsList, fetchTaskStatus, initiateProblemResponsesRequest } from '../api/client'; import { REPORT_GENERATION_ERROR, REPORT_GENERATION_REQUEST, @@ -7,12 +7,12 @@ import { REPORT_GENERATION_REFRESH_STATUS, } from './constants'; -const taskStatusSuccess = (succeeded, inProgress, reportPath, reportName) => ({ +const taskStatusSuccess = (succeeded, inProgress, reportName, downloadsData) => ({ type: REPORT_GENERATION_SUCCESS, succeeded, inProgress, - reportPath, reportName, + downloadsData, }); const problemResponsesRequest = blockId => ({ @@ -30,8 +30,8 @@ const problemResponsesRefreshStatus = timeout => ({ timeout, }); -const getTaskStatus = (endpoint, taskId) => dispatch => - fetchTaskStatus(endpoint, taskId) +const getTaskStatus = (taskStatusEndpoint, reportDownloadEndpoint, taskId) => dispatch => + fetchTaskStatus(taskStatusEndpoint, taskId) .then((response) => { if (response.ok) { return response.json(); @@ -41,20 +41,27 @@ const getTaskStatus = (endpoint, taskId) => dispatch => .then( (statusData) => { if (statusData.in_progress) { - const timeout = setTimeout(() => dispatch(getTaskStatus(endpoint, taskId)), 2000); + const timeout = setTimeout( + () => dispatch(getTaskStatus(taskStatusEndpoint, reportDownloadEndpoint, taskId)), + 2000, + ); return dispatch(problemResponsesRefreshStatus(timeout)); } if (statusData.task_state === 'SUCCESS') { const taskProgress = statusData.task_progress; - const reportPath = taskProgress && taskProgress.report_path; const reportName = taskProgress && taskProgress.report_name; - return dispatch( - taskStatusSuccess( - true, - statusData.in_progress, - reportPath, - reportName, - ), + return fetchDownloadsList(reportDownloadEndpoint, reportName) + .then(response => response.json()) + .then( + data => dispatch( + taskStatusSuccess( + true, + statusData.in_progress, + reportName, + data.downloads, + ), + ), + () => dispatch(problemResponsesFailure(gettext('There was an error generating the report link.'))), ); } return dispatch(problemResponsesFailure(gettext('There was an error generating your report.'))); @@ -67,6 +74,7 @@ const getTaskStatus = (endpoint, taskId) => dispatch => const createProblemResponsesReportTask = ( problemResponsesEndpoint, taskStatusEndpoint, + reportDownloadEndpoint, blockId, ) => (dispatch) => { dispatch(problemResponsesRequest(blockId)); @@ -78,7 +86,7 @@ const createProblemResponsesReportTask = ( throw new Error(response); }) .then( - json => dispatch(getTaskStatus(taskStatusEndpoint, json.task_id)), + json => dispatch(getTaskStatus(taskStatusEndpoint, reportDownloadEndpoint, json.task_id)), () => dispatch(problemResponsesFailure(gettext('Unable to submit request to generate report.'))), ); }; diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/api/client.js b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/api/client.js index 532af508a5b9..843d754b7cda 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/api/client.js +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/api/client.js @@ -25,9 +25,25 @@ const fetchTaskStatus = (endpoint, taskId) => fetch( credentials: 'same-origin', method: 'get', headers: HEADERS, - }); + }, + ); + +const fetchDownloadsList = (endpoint, reportName) => { + const formData = new FormData(); + formData.set('report_name', reportName); + + return fetch( + endpoint, { + credentials: 'same-origin', + method: 'POST', + headers: HEADERS, + body: formData, + }, + ); +}; export { initiateProblemResponsesRequest, fetchTaskStatus, + fetchDownloadsList, }; diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/reducers/index.js b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/reducers/index.js index 0c0c6a8c270c..c9d5f2133cec 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/reducers/index.js +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/data/reducers/index.js @@ -1,5 +1,6 @@ import { combineReducers } from 'redux'; // eslint-disable-line import { blocks, selectedBlock, rootBlock } from 'BlockBrowser/data/reducers'; // eslint-disable-line +import blockBrowserActions from 'BlockBrowser/data/actions/constants'; // eslint-disable-line import { REPORT_GENERATION_ERROR, REPORT_GENERATION_SUCCESS, @@ -25,7 +26,7 @@ export const reportStatus = (state = initialState, action) => { ...state, inProgress: action.inProgress, succeeded: action.succeeded, - reportPath: action.reportPath, + reportPath: action.downloadsData && action.downloadsData[0].url, reportName: action.reportName, error: null, }; @@ -33,6 +34,8 @@ export const reportStatus = (state = initialState, action) => { return { ...state, error: action.error, succeeded: false }; case REPORT_GENERATION_REFRESH_STATUS: return { ...state, timeout: action.timeout }; + case blockBrowserActions.SELECT_BLOCK: + return initialState; default: return state; } diff --git a/lms/djangoapps/instructor_task/tasks_helper/grades.py b/lms/djangoapps/instructor_task/tasks_helper/grades.py index 1fda96f281a9..91d0cf69c8f7 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/grades.py +++ b/lms/djangoapps/instructor_task/tasks_helper/grades.py @@ -1010,11 +1010,10 @@ def generate(cls, _xmodule_instance_args, _entry_id, course_id, task_input, acti # Perform the upload csv_name = cls._generate_upload_file_name(problem_locations, filter_types) - report_name, report_path = upload_csv_to_report_store(rows, csv_name, course_id, start_date) + report_name = upload_csv_to_report_store(rows, csv_name, course_id, start_date) current_step = { 'step': 'CSV uploaded', 'report_name': report_name, - 'report_path': report_path, } return task_progress.update_task_state(extra_meta=current_step) diff --git a/lms/djangoapps/instructor_task/tasks_helper/utils.py b/lms/djangoapps/instructor_task/tasks_helper/utils.py index 607851f77f45..8a9afdb1eed4 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/utils.py +++ b/lms/djangoapps/instructor_task/tasks_helper/utils.py @@ -44,9 +44,8 @@ def upload_csv_to_report_store(rows, csv_name, course_id, timestamp, config_name ) report_store.store_rows(course_id, report_name, rows) - report_path = report_store.storage.url(report_store.path_to(course_id, report_name)) tracker_emit(csv_name) - return report_name, report_path + return report_name def upload_zip_to_report_store(file, zip_name, course_id, timestamp, config_name='GRADES_DOWNLOAD'): diff --git a/lms/templates/instructor/instructor_dashboard_2/data_download.html b/lms/templates/instructor/instructor_dashboard_2/data_download.html index 67bc40dba005..c402ebb3fdd3 100644 --- a/lms/templates/instructor/instructor_dashboard_2/data_download.html +++ b/lms/templates/instructor/instructor_dashboard_2/data_download.html @@ -66,7 +66,8 @@

${_("Reports")}

"courseId": course.id, "excludeBlockTypes": ['html', 'video', 'discussion'], "problemResponsesEndpoint": section_data['get_problem_responses_url'], - "taskStatusEndpoint": "/instructor_task_status" + "taskStatusEndpoint": "/instructor_task_status", + "reportDownloadEndpoint": section_data['list_report_downloads_url'] } )}