Example #1
0
      ([exam, examLogs, examAttemptLogs]) => {
        if (exam.closed) {
          router.getInstance().replace({ name: PageNames.EXAM_LIST });
          return;
        }
        const currentChannel = getChannelObject(store.state, exam.channel_id);
        if (!currentChannel) {
          router.replace({ name: PageNames.CONTENT_UNAVAILABLE });
          return;
        }

        const attemptLogs = {};

        if (store.state.core.session.user_id) {
          if (examLogs.length > 0 && examLogs.some(log => !log.closed)) {
            store.dispatch('SET_EXAM_LOG', _examLoggingState(examLogs.find(log => !log.closed)));
          } else {
            const examLogModel = ExamLogResource.createModel({
              user: store.state.core.session.user_id,
              exam: id,
              closed: false,
            });
            examLogModel.save().then(newExamLog => {
              store.dispatch('SET_EXAM_LOG', newExamLog);
              ExamLogResource.unCacheCollection({
                user: store.state.core.session.user_id,
                exam: id,
              });
            });
          }
          // Sort through all the exam attempt logs retrieved and organize them into objects
          // keyed first by content_id and then item id under that.
          if (examAttemptLogs.length > 0) {
            examAttemptLogs.forEach(log => {
              if (!attemptLogs[log.content_id]) {
                attemptLogs[log.content_id] = {};
              }
              attemptLogs[log.content_id][log.item] = Object.assign({}, log);
            });
          }
        }

        const seed = exam.seed;
        const questionSources = exam.question_sources;

        // Create an array of objects with contentId and assessmentItemIndex
        // These will be used to select specific questions from the content node
        // The indices referred to shuffled positions in the content node's assessment_item_ids
        // property.
        // Wrap this all in a seededShuffle to give a consistent, repeatable shuffled order.
        const shuffledQuestions = seededShuffle.shuffle(
          createQuestionList(questionSources),
          seed,
          true
        );

        if (!shuffledQuestions[questionNumber]) {
          // Illegal question number!
          handleError(store, `Question number ${questionNumber} is not valid for this exam`);
        } else {
          const contentPromise = ContentNodeResource.getCollection({
            ids: questionSources.map(item => item.exercise_id),
          }).fetch();

          contentPromise.only(
            samePageCheckGenerator(store),
            contentNodes => {
              const contentNodeMap = {};

              contentNodes.forEach(node => {
                contentNodeMap[node.pk] = node;
              });

              const questions = shuffledQuestions.map(question => ({
                itemId: selectQuestionFromExercise(
                  question.assessmentItemIndex,
                  seed,
                  contentNodeMap[question.contentId]
                ),
                contentId: question.contentId,
              }));

              if (questions.every(question => !question.itemId)) {
                // Exam is drawing solely on malformed exercise data, best to quit now
                handleError(store, `This exam has no valid questions`);
              } else {
                const itemId = questions[questionNumber].itemId;

                const channelId = exam.channel_id;

                const currentQuestion = questions[questionNumber];

                const questionsAnswered = Math.max(
                  store.state.pageState.questionsAnswered || 0,
                  calcQuestionsAnswered(attemptLogs)
                );

                const pageState = {
                  exam: _examState(exam),
                  itemId,
                  questions,
                  currentQuestion,
                  questionNumber,
                  content: contentState(contentNodeMap[questions[questionNumber].contentId]),
                  channelId,
                  questionsAnswered,
                };
                if (!attemptLogs[currentQuestion.contentId]) {
                  attemptLogs[currentQuestion.contentId] = {};
                }
                if (!attemptLogs[currentQuestion.contentId][itemId]) {
                  attemptLogs[currentQuestion.contentId][itemId] = {
                    start_timestamp: now(),
                    completion_timestamp: null,
                    end_timestamp: null,
                    item: itemId,
                    complete: false,
                    time_spent: 0,
                    correct: 0,
                    answer: null,
                    simple_answer: '',
                    interaction_history: [],
                    hinted: false,
                    channel_id: channelId,
                    content_id: currentQuestion.contentId,
                  };
                }
                pageState.currentAttempt = attemptLogs[currentQuestion.contentId][itemId];
                store.dispatch('SET_EXAM_ATTEMPT_LOGS', attemptLogs);
                store.dispatch('SET_PAGE_STATE', pageState);
                store.dispatch('CORE_SET_PAGE_LOADING', false);
                store.dispatch('CORE_SET_ERROR', null);
                store.dispatch(
                  'CORE_SET_TITLE',
                  translator.$tr('currentExamPageTitle', {
                    currentExamTitle: pageState.exam.title,
                    currentChannelTitle: currentChannel.title,
                  })
                );
              }
            },
            error => {
              handleApiError(store, error);
            }
          );
        }
      },
Example #2
0
            contentNodes => {
              const contentNodeMap = {};

              contentNodes.forEach(node => {
                contentNodeMap[node.pk] = node;
              });

              const questions = shuffledQuestions.map(question => ({
                itemId: selectQuestionFromExercise(
                  question.assessmentItemIndex,
                  seed,
                  contentNodeMap[question.contentId]
                ),
                contentId: question.contentId,
              }));

              if (questions.every(question => !question.itemId)) {
                // Exam is drawing solely on malformed exercise data, best to quit now
                handleError(store, `This exam has no valid questions`);
              } else {
                const itemId = questions[questionNumber].itemId;

                const channelId = exam.channel_id;

                const currentQuestion = questions[questionNumber];

                const questionsAnswered = Math.max(
                  store.state.pageState.questionsAnswered || 0,
                  calcQuestionsAnswered(attemptLogs)
                );

                const pageState = {
                  exam: _examState(exam),
                  itemId,
                  questions,
                  currentQuestion,
                  questionNumber,
                  content: contentState(contentNodeMap[questions[questionNumber].contentId]),
                  channelId,
                  questionsAnswered,
                };
                if (!attemptLogs[currentQuestion.contentId]) {
                  attemptLogs[currentQuestion.contentId] = {};
                }
                if (!attemptLogs[currentQuestion.contentId][itemId]) {
                  attemptLogs[currentQuestion.contentId][itemId] = {
                    start_timestamp: now(),
                    completion_timestamp: null,
                    end_timestamp: null,
                    item: itemId,
                    complete: false,
                    time_spent: 0,
                    correct: 0,
                    answer: null,
                    simple_answer: '',
                    interaction_history: [],
                    hinted: false,
                    channel_id: channelId,
                    content_id: currentQuestion.contentId,
                  };
                }
                pageState.currentAttempt = attemptLogs[currentQuestion.contentId][itemId];
                store.dispatch('SET_EXAM_ATTEMPT_LOGS', attemptLogs);
                store.dispatch('SET_PAGE_STATE', pageState);
                store.dispatch('CORE_SET_PAGE_LOADING', false);
                store.dispatch('CORE_SET_ERROR', null);
                store.dispatch(
                  'CORE_SET_TITLE',
                  translator.$tr('currentExamPageTitle', {
                    currentExamTitle: pageState.exam.title,
                    currentChannelTitle: currentChannel.title,
                  })
                );
              }
            },
Example #3
0
 error => handleError(store, error)