Coursemology/coursemology2

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

Summary

Maintainability
B
4 hrs
Test Coverage
import CourseAPI from 'api/course';
import { setNotification } from 'lib/actions';
import { SAVING_STATUS } from 'lib/constants/sharedConstants';

import actionTypes from '../../constants';
import translations from '../../translations';
import { convertAnswerDataToInitialValue } from '../../utils/answers';
import { buildErrorMessage } from '../utils';

import { dispatchUpdateAnswerFlagSavingStatus } from '.';

// Ensure that there are no existing files with the same filenames
const validateUniqueFilenames = (files) => {
  const filenames = files.map((file) => file.filename);
  const uniqueFilenames = filenames.filter(
    (name, index, self) => self.indexOf(name) === index,
  );
  return filenames.length === uniqueFilenames.length;
};

const validateFilesByLanguageMap = {
  java: (files) => {
    // Used to ensure that only java files can be uploaded.
    const regex = /\.(java)$/i;
    return (
      files.filter((file) => regex.test(file.filename)).length === files.length
    );
  },
};

const validateFilesByLanguageErrorMessageMap = {
  java: translations.invalidJavaFileUpload,
};

const validateProgrammingFilesErrorMsg = (language, files) => {
  if (!validateUniqueFilenames(files)) {
    return translations.similarFileNameExists;
  }
  const specificLanguageValidator = validateFilesByLanguageMap[language];
  if (specificLanguageValidator && !specificLanguageValidator(files)) {
    return validateFilesByLanguageErrorMessageMap[language];
  }
  return null;
};

export function importProgrammingFiles(answerId, files, language, resetField) {
  const filesPayload = files.map((file) => ({
    id: file.id,
    filename: file.filename,
    content: file.content,
  }));
  const payload = {
    answer: {
      id: answerId,
      files_attributes: filesPayload,
    },
  };

  return (dispatch) => {
    dispatch({
      type: actionTypes.UPLOAD_PROGRAMMING_FILES_REQUEST,
      payload: { answerId },
    });
    dispatch(
      dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Saving),
    );

    const validationErrorMessage = validateProgrammingFilesErrorMsg(
      language,
      filesPayload,
    );

    if (validationErrorMessage) {
      dispatch({
        type: actionTypes.UPLOAD_PROGRAMMING_FILES_FAILURE,
      });
      resetField(`${answerId}.import_files`, {
        defaultValue: null,
      });
      dispatch(
        dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Failed),
      );
      dispatch(setNotification(validationErrorMessage));
      return;
    }

    CourseAPI.assessment.answer.programming
      .createProgrammingFiles(answerId, payload)
      .then((response) => {
        const updatedAnswer = response.data;
        dispatch({
          type: actionTypes.UPLOAD_PROGRAMMING_FILES_SUCCESS,
          payload: updatedAnswer,
        });
        resetField(`${answerId}`, {
          defaultValue: convertAnswerDataToInitialValue(updatedAnswer),
        });
        dispatch(
          dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Saved),
        );
      })
      .catch((error) => {
        dispatch({
          type: actionTypes.UPLOAD_PROGRAMMING_FILES_FAILURE,
        });
        dispatch(
          dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Failed),
        );
        resetField(`${answerId}.import_files`, {
          defaultValue: null,
        });
        dispatch(
          setNotification(
            translations.importFilesFailure,
            buildErrorMessage(error),
          ),
        );
      });
  };
}

export function deleteProgrammingFile(answer, fileId, onDeleteSuccess) {
  const answerId = answer.id;
  const payload = {
    answer: { id: answerId, file_id: fileId },
  };

  return (dispatch) => {
    dispatch({
      type: actionTypes.DELETE_PROGRAMMING_FILE_REQUEST,
      payload: { answerId: payload.answer.id },
    });
    dispatch(
      dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Saving),
    );

    return CourseAPI.assessment.answer.programming
      .deleteProgrammingFile(answerId, payload)
      .then(() => {
        dispatch({
          type: actionTypes.DELETE_PROGRAMMING_FILE_SUCCESS,
        });
        dispatch(
          dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Saved),
        );
        onDeleteSuccess();
        dispatch(setNotification(translations.deleteFileSuccess));
      })
      .catch((error) => {
        dispatch({
          type: actionTypes.DELETE_PROGRAMMING_FILE_FAILURE,
        });
        dispatch(
          dispatchUpdateAnswerFlagSavingStatus(answerId, SAVING_STATUS.Failed),
        );
        dispatch(
          setNotification(
            translations.deleteFileFailure,
            buildErrorMessage(error),
          ),
        );
      });
  };
}