Coursemology/coursemology2

View on GitHub
client/app/bundles/course/assessment/submission/actions/submissions.js

Summary

Maintainability
C
7 hrs
Test Coverage
import CourseAPI from 'api/course';
import { setNotification } from 'lib/actions';
import pollJob from 'lib/helpers/jobHelpers';

import actionTypes from '../constants';
import translations from '../translations';

const DOWNLOAD_SUBMISSIONS_JOB_POLL_INTERVAL_MS = 2000;
const DOWNLOAD_STATISTICS_JOB_POLL_INTERVAL_MS = 2000;
const DELETE_ALL_SUBMISSIONS_JOB_POLL_INTERVAL_MS = 1000;
const FORCE_SUBMIT_JOB_POLL_INTERVAL_MS = 1000;
const PUBLISH_ALL_SUBMISSIONS_JOB_POLL_INTERVAL_MS = 1000;
const UNSUBMIT_ALL_SUBMISSIONS_JOB_POLL_INTERVAL_MS = 1000;

export function fetchSubmissions() {
  return (dispatch) => {
    dispatch({ type: actionTypes.FETCH_SUBMISSIONS_REQUEST });

    return CourseAPI.assessment.submissions
      .index()
      .then((response) => response.data)
      .then((data) => {
        dispatch({
          type: actionTypes.FETCH_SUBMISSIONS_SUCCESS,
          payload: data,
        });
      })
      .catch(() => dispatch({ type: actionTypes.FETCH_SUBMISSIONS_FAILURE }));
  };
}

export function publishSubmissions(type) {
  return (dispatch) => {
    dispatch({ type: actionTypes.PUBLISH_SUBMISSIONS_REQUEST });

    const handleSuccess = () => {
      dispatch({ type: actionTypes.PUBLISH_SUBMISSIONS_SUCCESS });
      dispatch(setNotification(translations.publishSuccess));
      fetchSubmissions()(dispatch);
    };

    const handleFailure = () => {
      dispatch({ type: actionTypes.PUBLISH_SUBMISSIONS_FAILURE });
      dispatch(setNotification(translations.requestFailure));
    };

    return CourseAPI.assessment.submissions
      .publishAll(type)
      .then((response) => {
        if (response.data.jobUrl) {
          dispatch(setNotification(translations.publishJobPending));
          pollJob(
            response.data.jobUrl,
            handleSuccess,
            handleFailure,
            PUBLISH_ALL_SUBMISSIONS_JOB_POLL_INTERVAL_MS,
          );
        } else {
          handleSuccess();
        }
      })
      .catch(handleFailure);
  };
}

export function forceSubmitSubmissions(type) {
  return (dispatch) => {
    dispatch({ type: actionTypes.FORCE_SUBMIT_SUBMISSIONS_REQUEST });

    const handleSuccess = () => {
      dispatch({ type: actionTypes.FORCE_SUBMIT_SUBMISSIONS_SUCCESS });
      dispatch(setNotification(translations.forceSubmitSuccess));
      fetchSubmissions()(dispatch);
    };

    const handleFailure = () => {
      dispatch({ type: actionTypes.FORCE_SUBMIT_SUBMISSIONS_FAILURE });
      dispatch(setNotification(translations.requestFailure));
    };

    return CourseAPI.assessment.submissions
      .forceSubmitAll(type)
      .then((response) => {
        dispatch(setNotification(translations.forceSubmitJobPending));
        if (response.data.jobUrl) {
          pollJob(
            response.data.jobUrl,
            handleSuccess,
            handleFailure,
            FORCE_SUBMIT_JOB_POLL_INTERVAL_MS,
          );
        } else {
          handleSuccess();
        }
      })
      .catch(handleFailure);
  };
}

export function sendAssessmentReminderEmail(assessmentId, type) {
  return (dispatch) => {
    dispatch({ type: actionTypes.SEND_ASSESSMENT_REMINDER_REQUEST });
    return CourseAPI.assessment.assessments
      .remind(assessmentId, type)
      .then(() => {
        dispatch({ type: actionTypes.SEND_ASSESSMENT_REMINDER_SUCCESS });
        dispatch(setNotification(translations.sendReminderEmailSuccess));
      })
      .catch(() => {
        dispatch({ type: actionTypes.SEND_ASSESSMENT_REMINDER_FAILURE });
        dispatch(setNotification(translations.requestFailure));
      });
  };
}

/**
 * Download submissions for indicated user types in a given format (zip or csv)
 *
 * @param {String} [type] user types to be included in the downloaded submissions. Possible value includes:
 *  ['my_students'|'my_students_w_phantom'|'students'|'students_w_phantom'|'staff'|'staff_w_phantom']
 * @param {String} [downloadFormat=zip|csv] submission download format
 * @returns {function(*)} The thunk to download submissions
 */
export function downloadSubmissions(type, downloadFormat) {
  const actions =
    downloadFormat === 'zip'
      ? {
          request: actionTypes.DOWNLOAD_SUBMISSIONS_FILES_REQUEST,
          success: actionTypes.DOWNLOAD_SUBMISSIONS_FILES_SUCCESS,
          failure: actionTypes.DOWNLOAD_SUBMISSIONS_FILES_FAILURE,
        }
      : {
          request: actionTypes.DOWNLOAD_SUBMISSIONS_CSV_REQUEST,
          success: actionTypes.DOWNLOAD_SUBMISSIONS_CSV_SUCCESS,
          failure: actionTypes.DOWNLOAD_SUBMISSIONS_CSV_FAILURE,
        };
  return (dispatch) => {
    dispatch({ type: actions.request });

    const handleSuccess = (successData) => {
      window.location.href = successData.redirectUrl;
      dispatch({ type: actions.success });
      dispatch(setNotification(translations.downloadRequestSuccess));
    };

    const handleFailure = () => {
      dispatch({ type: actions.failure });
      dispatch(setNotification(translations.requestFailure));
    };

    return CourseAPI.assessment.submissions
      .downloadAll(type, downloadFormat)
      .then((response) => {
        dispatch(setNotification(translations.downloadSubmissionsJobPending));
        pollJob(
          response.data.jobUrl,
          handleSuccess,
          handleFailure,
          DOWNLOAD_SUBMISSIONS_JOB_POLL_INTERVAL_MS,
        );
      })
      .catch(handleFailure);
  };
}

export function downloadStatistics(type) {
  return (dispatch) => {
    dispatch({ type: actionTypes.DOWNLOAD_STATISTICS_REQUEST });

    const handleSuccess = (successData) => {
      window.location.href = successData.redirectUrl;
      dispatch({ type: actionTypes.DOWNLOAD_STATISTICS_SUCCESS });
      dispatch(setNotification(translations.downloadRequestSuccess));
    };

    const handleFailure = (error) => {
      const message =
        error?.response?.data?.error ||
        error?.message ||
        translations.requestFailure;
      dispatch({ type: actionTypes.DOWNLOAD_STATISTICS_FAILURE });
      dispatch(setNotification(message));
    };

    return CourseAPI.assessment.submissions
      .downloadStatistics(type)
      .then((response) => {
        dispatch(setNotification(translations.downloadStatisticsJobPending));
        pollJob(
          response.data.jobUrl,
          handleSuccess,
          handleFailure,
          DOWNLOAD_STATISTICS_JOB_POLL_INTERVAL_MS,
        );
      })
      .catch(handleFailure);
  };
}

export function unsubmitSubmission(submissionId, successMessage) {
  return (dispatch) => {
    dispatch({ type: actionTypes.UNSUBMIT_SUBMISSION_REQUEST });

    return CourseAPI.assessment.submissions
      .unsubmitSubmission(submissionId)
      .then(() => {
        dispatch({
          type: actionTypes.UNSUBMIT_SUBMISSION_SUCCESS,
        });
        fetchSubmissions()(dispatch);
        dispatch(setNotification(successMessage));
      })
      .catch(() => {
        dispatch({
          type: actionTypes.UNSUBMIT_SUBMISSION_FAILURE,
        });
        dispatch(setNotification(translations.requestFailure));
      });
  };
}

export function unsubmitAllSubmissions(type) {
  return (dispatch) => {
    dispatch({ type: actionTypes.UNSUBMIT_ALL_SUBMISSIONS_REQUEST });

    const handleSuccess = () => {
      dispatch({ type: actionTypes.UNSUBMIT_ALL_SUBMISSIONS_SUCCESS });
      dispatch(setNotification(translations.unsubmitAllSubmissionsSuccess));
      fetchSubmissions()(dispatch);
    };

    const handleFailure = () => {
      dispatch({ type: actionTypes.UNSUBMIT_ALL_SUBMISSIONS_FAILURE });
      dispatch(setNotification(translations.requestFailure));
    };

    return CourseAPI.assessment.submissions
      .unsubmitAll(type)
      .then((response) => {
        dispatch(
          setNotification(translations.unsubmitAllSubmissionsJobPending),
        );
        if (response.data.jobUrl) {
          pollJob(
            response.data.jobUrl,
            handleSuccess,
            handleFailure,
            UNSUBMIT_ALL_SUBMISSIONS_JOB_POLL_INTERVAL_MS,
          );
        } else {
          handleSuccess();
        }
      })
      .catch(handleFailure);
  };
}

export function deleteSubmission(submissionId, successMessage) {
  return (dispatch) => {
    dispatch({ type: actionTypes.DELETE_SUBMISSION_REQUEST });

    return CourseAPI.assessment.submissions
      .deleteSubmission(submissionId)
      .then(() => {
        dispatch({
          type: actionTypes.DELETE_SUBMISSION_SUCCESS,
        });
        dispatch(setNotification(successMessage));
        fetchSubmissions()(dispatch);
      })
      .catch(() => {
        dispatch({
          type: actionTypes.DELETE_SUBMISSION_FAILURE,
        });
        dispatch(setNotification(translations.requestFailure));
      });
  };
}

export function deleteAllSubmissions(type) {
  return (dispatch) => {
    dispatch({ type: actionTypes.DELETE_ALL_SUBMISSIONS_REQUEST });

    const handleSuccess = () => {
      dispatch({ type: actionTypes.DELETE_ALL_SUBMISSIONS_SUCCESS });
      dispatch(setNotification(translations.deleteAllSubmissionsSuccess));
      fetchSubmissions()(dispatch);
    };

    const handleFailure = () => {
      dispatch({ type: actionTypes.DELETE_ALL_SUBMISSIONS_FAILURE });
      dispatch(setNotification(translations.requestFailure));
    };

    return CourseAPI.assessment.submissions
      .deleteAll(type)
      .then((response) => {
        dispatch(setNotification(translations.deleteAllSubmissionsJobPending));
        if (response.data.jobUrl) {
          pollJob(
            response.data.jobUrl,
            handleSuccess,
            handleFailure,
            DELETE_ALL_SUBMISSIONS_JOB_POLL_INTERVAL_MS,
          );
        } else {
          handleSuccess();
        }
      })
      .catch(handleFailure);
  };
}