Пример #1
0
 function print_question(&$question, &$state, $number, $cmoptions, $options)
 {
     global $CFG;
     $isfinished = question_state_is_graded($state->last_graded) || $state->event == QUESTION_EVENTCLOSE;
     if (!empty($cmoptions->id)) {
         $cm = get_coursemodule_from_instance('quiz', $cmoptions->id);
         $cmorcourseid = '&cmid=' . $cm->id;
     } else {
         if (!empty($cmoptions->course)) {
             $cmorcourseid = '&courseid=' . $cmoptions->course;
         } else {
             error('Need to provide courseid or cmid to print_question.');
         }
     }
     // For editing teachers print a link to an editing popup window
     $editlink = '';
     if (question_has_capability_on($question, 'edit')) {
         $stredit = get_string('edit');
         $linktext = '<img src="' . $CFG->pixpath . '/t/edit.gif" alt="' . $stredit . '" />';
         $editlink = link_to_popup_window('/question/question.php?id=' . $question->id . $cmorcourseid, $stredit, $linktext, 450, 550, $stredit, '', true);
     }
     $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
     $image = get_question_image($question);
     $generalfeedback = '';
     if ($isfinished && $options->generalfeedback) {
         $generalfeedback = $this->format_text($question->generalfeedback, $question->questiontextformat, $cmoptions);
     }
     include "{$CFG->dirroot}/question/type/description/question.html";
 }
Пример #2
0
 function print_question(&$question, &$state, $number, $cmoptions, $options)
 {
     global $CFG;
     $isfinished = question_state_is_graded($state->last_graded) || $state->event == QUESTION_EVENTCLOSE;
     // For editing teachers print a link to an editing popup window
     $editlink = $this->get_question_edit_link($question, $cmoptions, $options);
     $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
     $generalfeedback = '';
     if ($isfinished && $options->generalfeedback) {
         $generalfeedback = $this->format_text($question->generalfeedback, $question->generalfeedbackformat, $cmoptions);
     }
     include "{$CFG->dirroot}/question/type/description/question.html";
 }
Пример #3
0
 function print_question(&$question, &$state, $number, $cmoptions, $options)
 {
     global $CFG;
     $isfinished = question_state_is_graded($state->last_graded) || $state->event == QUESTION_EVENTCLOSE;
     // For editing teachers print a link to an editing popup window
     $editlink = $this->get_question_edit_link($question, $cmoptions, $options);
     $context = $this->get_context_by_category_id($question->category);
     $question->questiontext = quiz_rewrite_question_urls($question->questiontext, 'pluginfile.php', $context->id, 'question', 'questiontext', array($state->attempt, $state->question), $question->id);
     $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
     $generalfeedback = '';
     if ($isfinished && $options->generalfeedback) {
         $question->generalfeedback = quiz_rewrite_question_urls($question->generalfeedback, 'pluginfile.php', $context->id, 'question', 'generalfeedback', array($state->attempt, $state->question), $question->id);
         $generalfeedback = $this->format_text($question->generalfeedback, $question->generalfeedbackformat, $cmoptions);
     }
     include "{$CFG->dirroot}/question/type/description/question.html";
 }
Пример #4
0
 function print_question(&$question, &$state, $number, $cmoptions, $options)
 {
     global $CFG;
     $isfinished = question_state_is_graded($state->last_graded) || $state->event == QUESTION_EVENTCLOSE;
     // For editing teachers print a link to an editing popup window
     $editlink = '';
     if (has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $cmoptions->course))) {
         $stredit = get_string('edit');
         $linktext = '<img src="' . $CFG->pixpath . '/t/edit.gif" alt="' . $stredit . '" />';
         $editlink = link_to_popup_window('/question/question.php?id=' . $question->id, $stredit, $linktext, 450, 550, $stredit, '', true);
     }
     $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
     $image = get_question_image($question, $cmoptions->course);
     $generalfeedback = '';
     if ($isfinished && $options->generalfeedback) {
         $generalfeedback = $this->format_text($question->generalfeedback, $question->questiontextformat, $cmoptions);
     }
     include "{$CFG->dirroot}/question/type/description/question.html";
 }
Пример #5
0
/**
* Processes an array of student responses, grading and saving them as appropriate
*
* @param object $question Full question object, passed by reference
* @param object $state    Full state object, passed by reference
* @param object $action   object with the fields ->responses which
*                         is an array holding the student responses,
*                         ->action which specifies the action, e.g., QUESTION_EVENTGRADE,
*                         and ->timestamp which is a timestamp from when the responses
*                         were submitted by the student.
* @param object $cmoptions
* @param object $attempt  The attempt is passed by reference so that
*                         during grading its ->sumgrades field can be updated
* @return boolean         Indicates success/failure
*/
function question_process_responses(&$question, &$state, $action, $cmoptions, &$attempt)
{
    global $QTYPES;
    // if no responses are set initialise to empty response
    if (!isset($action->responses)) {
        $action->responses = array('' => '');
    }
    // make sure these are gone!
    unset($action->responses['submit'], $action->responses['validate']);
    // Check the question session is still open
    if (question_state_is_closed($state)) {
        return true;
    }
    // If $action->event is not set that implies saving
    if (!isset($action->event)) {
        debugging('Ambiguous action in question_process_responses.', DEBUG_DEVELOPER);
        $action->event = QUESTION_EVENTSAVE;
    }
    // If submitted then compare against last graded
    // responses, not last given responses in this case
    if (question_isgradingevent($action->event)) {
        $state->responses = $state->last_graded->responses;
    }
    // Check for unchanged responses (exactly unchanged, not equivalent).
    // We also have to catch questions that the student has not yet attempted
    $sameresponses = $QTYPES[$question->qtype]->compare_responses($question, $action, $state);
    if (!empty($state->last_graded) && $state->last_graded->event == QUESTION_EVENTOPEN && question_isgradingevent($action->event)) {
        $sameresponses = false;
    }
    // If the response has not been changed then we do not have to process it again
    // unless the attempt is closing or validation is requested
    if ($sameresponses and QUESTION_EVENTCLOSE != $action->event and QUESTION_EVENTVALIDATE != $action->event) {
        return true;
    }
    // Roll back grading information to last graded state and set the new
    // responses
    $newstate = clone $state->last_graded;
    $newstate->responses = $action->responses;
    $newstate->seq_number = $state->seq_number + 1;
    $newstate->changed = true;
    // will assure that it gets saved to the database
    $newstate->last_graded = clone $state->last_graded;
    $newstate->timestamp = $action->timestamp;
    $state = $newstate;
    // Set the event to the action we will perform. The question type specific
    // grading code may override this by setting it to QUESTION_EVENTCLOSE if the
    // attempt at the question causes the session to close
    $state->event = $action->event;
    if (!question_isgradingevent($action->event)) {
        // Grade the response but don't update the overall grade
        if (!$QTYPES[$question->qtype]->grade_responses($question, $state, $cmoptions)) {
            return false;
        }
        // Temporary hack because question types are not given enough control over what is going
        // on. Used by Opaque questions.
        // TODO fix this code properly.
        if (!empty($state->believeevent)) {
            // If the state was graded we need to ...
            if (question_state_is_graded($state)) {
                question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
                // update the attempt grade
                $attempt->sumgrades -= (double) $state->last_graded->grade;
                $attempt->sumgrades += (double) $state->grade;
                // and update the last_graded field.
                unset($state->last_graded);
                $state->last_graded = clone $state;
                unset($state->last_graded->changed);
            }
        } else {
            // Don't allow the processing to change the event type
            $state->event = $action->event;
        }
    } else {
        // grading event
        // Unless the attempt is closing, we want to work out if the current responses
        // (or equivalent responses) were already given in the last graded attempt.
        if (QUESTION_EVENTCLOSE != $action->event && QUESTION_EVENTOPEN != $state->last_graded->event && $QTYPES[$question->qtype]->compare_responses($question, $state, $state->last_graded)) {
            $state->event = QUESTION_EVENTDUPLICATE;
        }
        // If we did not find a duplicate or if the attempt is closing, perform grading
        if (!$sameresponses and QUESTION_EVENTDUPLICATE != $state->event or QUESTION_EVENTCLOSE == $action->event) {
            if (!$QTYPES[$question->qtype]->grade_responses($question, $state, $cmoptions)) {
                return false;
            }
            // Calculate overall grade using correct penalty method
            question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
        }
        // If the state was graded we need to ...
        if (question_state_is_graded($state)) {
            // update the attempt grade
            $attempt->sumgrades -= (double) $state->last_graded->grade;
            $attempt->sumgrades += (double) $state->grade;
            // and update the last_graded field.
            unset($state->last_graded);
            $state->last_graded = clone $state;
            unset($state->last_graded->changed);
        }
    }
    $attempt->timemodified = $action->timestamp;
    return true;
}
Пример #6
0
/**
 * Determine render options
 *
 * @param int $reviewoptions
 * @param object $state
 */
function quiz_get_renderoptions($quiz, $attempt, $context, $state)
{
    $reviewoptions = $quiz->review;
    $options = new stdClass();
    $options->flags = quiz_get_flag_option($attempt, $context);
    // Show the question in readonly (review) mode if the question is in
    // the closed state
    $options->readonly = question_state_is_closed($state);
    // Show feedback once the question has been graded (if allowed by the quiz)
    $options->feedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show correct responses in readonly mode if the quiz allows it
    $options->correct_responses = $options->readonly && $reviewoptions & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_IMMEDIATELY;
    // Show general feedback if the question has been graded and the quiz allows it.
    $options->generalfeedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_GENERALFEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show overallfeedback once the attempt is over.
    $options->overallfeedback = false;
    // Always show responses and scores
    $options->responses = true;
    $options->scores = true;
    $options->quizstate = QUIZ_STATE_DURING;
    $options->history = false;
    return $options;
}
Пример #7
0
 /**
  * Checks to see if a question in a particular attempt is graded
  *
  * @return boolean
  * @todo Finnish documenting this function
  **/
 function is_graded($question, $attempt)
 {
     global $CFG;
     if (!($state = get_record_sql("SELECT state.id, state.event FROM\n                                        {$CFG->prefix}question_states state, {$CFG->prefix}question_sessions sess\n                                        WHERE sess.newest = state.id AND\n                                        sess.attemptid = {$attempt->uniqueid} AND\n                                        sess.questionid = {$question->id}"))) {
         error('Could not find question state');
     }
     return question_state_is_graded($state);
 }
Пример #8
0
 function other_cols($colname, $attempt)
 {
     global $QTYPES, $OUTPUT;
     static $states = array();
     if (preg_match('/^qsanswer([0-9]+)$/', $colname, $matches)) {
         if ($attempt->uniqueid == 0) {
             return '-';
         }
         $questionid = $matches[1];
         if (isset($this->gradedstatesbyattempt[$attempt->uniqueid][$questionid])) {
             $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->uniqueid][$questionid];
         } else {
             return '-';
         }
         $question = $this->questions[$questionid];
         restore_question_state($question, $stateforqinattempt);
         if (!$this->is_downloading() || $this->is_downloading() == 'xhtml') {
             $formathtml = true;
         } else {
             $formathtml = false;
         }
         $summary = $QTYPES[$question->qtype]->response_summary($question, $stateforqinattempt, QUIZ_REPORT_RESPONSES_MAX_LEN_TO_DISPLAY, $formathtml);
         if (!$this->is_downloading()) {
             if ($summary) {
                 $link = html_link::make("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}", $summary);
                 $link->add_action(new popup_action('click', $link->url, 'reviewquestion', array('height' => 450, 'width' => 650)));
                 $link->title = $question->formattedname;
                 $summary = $OUTPUT->link($link);
                 if (question_state_is_graded($stateforqinattempt) && $question->maxgrade > 0) {
                     $grade = $stateforqinattempt->grade / $question->maxgrade;
                     $qclass = question_get_feedback_class($grade);
                     $feedbackimg = question_get_feedback_image($grade);
                     $questionclass = "que";
                     return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $summary . "</span></span>{$feedbackimg}";
                 } else {
                     return $summary;
                 }
             } else {
                 return '';
             }
         } else {
             return $summary;
         }
     } else {
         return NULL;
     }
 }
Пример #9
0
function question_print_comment_box($question, $state, $attempt, $url)
{
    global $CFG, $QTYPES;
    $prefix = 'response';
    $usehtmleditor = can_use_richtext_editor();
    if (!question_state_is_graded($state) && $QTYPES[$question->qtype]->is_question_manual_graded($question, $attempt->layout)) {
        $grade = '';
    } else {
        $grade = round($state->last_graded->grade, 3);
    }
    echo '<form method="post" action="' . $url . '">';
    include $CFG->dirroot . '/question/comment.html';
    echo '<input type="hidden" name="attempt" value="' . $attempt->uniqueid . '" />';
    echo '<input type="hidden" name="question" value="' . $question->id . '" />';
    echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
    echo '<input type="submit" name="submit" value="' . get_string('save', 'quiz') . '" />';
    echo '</form>';
    if ($usehtmleditor) {
        use_html_editor();
    }
}
Пример #10
0
 /**
  * Prints questions with comment and grade form underneath each question
  *
  * @return void
  * @todo Finish documenting this function
  **/
 function print_questions_and_form($quiz, $question, $userid, $attemptid, $gradeungraded, $gradenextungraded, $ungraded)
 {
     global $CFG;
     // TODO get the context, and put in proper roles an permissions checks.
     $context = NULL;
     $questions[$question->id] =& $question;
     $usehtmleditor = can_use_richtext_editor();
     list($select, $from, $where) = $this->attempts_sql($quiz->id, false, $question->id, $userid, $attemptid, $gradeungraded, $gradenextungraded);
     $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
     if ($gradenextungraded) {
         $attempts = get_records_sql($select . $from . $where . $sort, 0, QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE);
     } else {
         $attempts = get_records_sql($select . $from . $where . $sort);
     }
     if ($attempts) {
         $firstattempt = current($attempts);
         $fullname = fullname($firstattempt);
         if ($gradeungraded) {
             // getting all ungraded attempts
             print_heading(get_string('gradingungraded', 'quiz_grading', $ungraded), '', 3);
         } else {
             if ($gradenextungraded) {
                 // getting next ungraded attempts
                 print_heading(get_string('gradingnextungraded', 'quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE), '', 3);
             } else {
                 if ($userid) {
                     print_heading(get_string('gradinguser', 'quiz_grading', $fullname), '', 3);
                 } else {
                     if ($attemptid) {
                         $a = new object();
                         $a->fullname = $fullname;
                         $a->attempt = $firstattempt->attempt;
                         print_heading(get_string('gradingattempt', 'quiz_grading', $a), '', 3);
                     } else {
                         print_heading(get_string('gradingall', 'quiz_grading', count($attempts)), '', 3);
                     }
                 }
             }
         }
         // Display the form with one part for each selected attempt
         echo '<form method="post" action="report.php">' . '<input type="hidden" name="mode" value="grading" />' . '<input type="hidden" name="q" value="' . $quiz->id . '" />' . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />' . '<input type="hidden" name="questionid" value="' . $question->id . '" />';
         foreach ($attempts as $attempt) {
             // Load the state for this attempt (The questions array was created earlier)
             $states = get_question_states($questions, $quiz, $attempt);
             // The $states array is indexed by question id but because we are dealing
             // with only one question there is only one entry in this array
             $state =& $states[$question->id];
             $options = quiz_get_reviewoptions($quiz, $attempt, $context);
             unset($options->questioncommentlink);
             $options->noeditlink = true;
             $copy = $state->manualcomment;
             $state->manualcomment = '';
             $options->readonly = 1;
             $gradedclass = question_state_is_graded($state) ? ' class="highlightgraded" ' : '';
             $gradedstring = question_state_is_graded($state) ? ' ' . get_string('graded', 'quiz_grading') : '';
             $a = new object();
             $a->fullname = fullname($attempt, true);
             $a->attempt = $attempt->attempt;
             // print the user name, attempt count, the question, and some more hidden fields
             echo '<div class="boxaligncenter" width="80%" style="clear:left;padding:15px;">';
             echo "<span{$gradedclass}>" . get_string('gradingattempt', 'quiz_grading', $a);
             echo $gradedstring . "</span>";
             print_question($question, $state, '', $quiz, $options);
             $prefix = "manualgrades[{$attempt->uniqueid}]";
             if (!question_state_is_graded($state)) {
                 $grade = '';
             } else {
                 $grade = round($state->last_graded->grade, 3);
             }
             $state->manualcomment = $copy;
             include $CFG->dirroot . '/question/comment.html';
             echo '</div>';
         }
         echo '<div class="boxaligncenter"><input type="submit" value="' . get_string('savechanges') . '" /></div>' . '</form>';
         if ($usehtmleditor) {
             use_html_editor();
         }
     } else {
         notify(get_string('noattemptstoshow', 'quiz'));
     }
 }
Пример #11
0
 /**
  * @param string $colname the name of the column.
  * @param object $attempt the row of data - see the SQL in display() in
  * mod/quiz/report/overview/report.php to see what fields are present,
  * and what they are called.
  * @return string the contents of the cell.
  */
 function other_cols($colname, $attempt)
 {
     if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)) {
         $questionid = $matches[1];
         $question = $this->questions[$questionid];
         if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])) {
             $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid];
         } else {
             $stateforqinattempt = false;
         }
         if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) {
             $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question');
             if (!$this->is_downloading()) {
                 if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])) {
                     $gradefromdb = $grade;
                     $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question');
                     $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question');
                     $grade = '<del>' . $oldgrade . '</del><br />' . $newgrade;
                 }
                 $linktopopup = link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' . $attempt->attempt . '&amp;question=' . $question->id, 'reviewquestion', $grade, 450, 650, get_string('reviewresponse', 'quiz'), 'none', true);
                 if ($this->questions[$questionid]->maxgrade != 0) {
                     $fractionofgrade = $stateforqinattempt->grade / $this->questions[$questionid]->maxgrade;
                     $qclass = question_get_feedback_class($fractionofgrade);
                     $feedbackimg = question_get_feedback_image($fractionofgrade);
                     $questionclass = "que";
                     return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $linktopopup . "</span></span>{$feedbackimg}";
                 } else {
                     return $linktopopup;
                 }
             } else {
                 return $grade;
             }
         } else {
             return '--';
         }
     } else {
         return NULL;
     }
 }
Пример #12
0
 /**
  * @param string $colname the name of the column.
  * @param object $attempt the row of data - see the SQL in display() in
  * mod/quiz/report/overview/report.php to see what fields are present,
  * and what they are called.
  * @return string the contents of the cell.
  */
 function other_cols($colname, $attempt)
 {
     global $OUTPUT;
     if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)) {
         $questionid = $matches[1];
         $question = $this->questions[$questionid];
         if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])) {
             $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid];
         } else {
             $stateforqinattempt = false;
         }
         if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) {
             $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question');
             if (!$this->is_downloading()) {
                 if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])) {
                     $gradefromdb = $grade;
                     $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question');
                     $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question');
                     $grade = '<del>' . $oldgrade . '</del><br />' . $newgrade;
                 }
                 $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}");
                 $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650));
                 $linktopopup = $OUTPUT->action_link($link, $grade, $action, array('title' => get_string('reviewresponsetoq', 'quiz', $question->formattedname)));
                 if ($this->questions[$questionid]->maxgrade != 0) {
                     $fractionofgrade = $stateforqinattempt->grade / $this->questions[$questionid]->maxgrade;
                     $qclass = question_get_feedback_class($fractionofgrade);
                     $feedbackimg = question_get_feedback_image($fractionofgrade);
                     $questionclass = "que";
                     return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $linktopopup . "</span></span>{$feedbackimg}";
                 } else {
                     return $linktopopup;
                 }
             } else {
                 return $grade;
             }
         } else {
             if ($stateforqinattempt && question_state_is_closed($stateforqinattempt)) {
                 $text = get_string('requiresgrading', 'quiz_overview');
                 if (!$this->is_downloading()) {
                     $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}");
                     $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650));
                     return $OUTPUT->action_link($link, $text, $action, array('title' => get_string('reviewresponsetoq', 'quiz', $question->formattedname)));
                 } else {
                     return $text;
                 }
             } else {
                 return '--';
             }
         }
     } else {
         return NULL;
     }
 }
/**
* This is a copy & paste of original shortanswer/questiontype.php print_question_grading_details() but 
* filters correct answers before printing.
*/
function wrsqz_print_question_grading_details($questionType, $dbType, &$question, &$state, $cmoptions, $options){
	if($questionType=='shortanswer'){
	    global $QTYPES ;
        // MDL-7496 show correct answer after "Incorrect"
        $correctanswer = '';
		
        if ($correctanswers =  wrsqz_get_correct_responses('shortanswer', 'wshanprom', null, $question, $state, 'W')) {
            if ($options->readonly && $options->correct_responses) {
                $delimiter = '';
                if ($correctanswers) {
                    foreach ($correctanswers as $ca) {
                        $correctanswer .= $delimiter.$ca;
                        $delimiter = ', ';
                    }
                }
            }
        }
        if (QUESTION_EVENTDUPLICATE == $state->event) {
            echo ' ';
            print_string('duplicateresponse', 'quiz');
        }
        if (!empty($question->maxgrade) && $options->scores) {
            if (question_state_is_graded($state->last_graded)) {
                // Display the grading details from the last graded state
                $grade = new stdClass;
                $grade->cur = round($state->last_graded->grade, $cmoptions->decimalpoints);
                $grade->max = $question->maxgrade;
                $grade->raw = round($state->last_graded->raw_grade, $cmoptions->decimalpoints);

                // let student know wether the answer was correct
                echo '<div class="correctness ';
                if ($state->last_graded->raw_grade >= $question->maxgrade/1.01) { // We divide by 1.01 so that rounding errors dont matter.
                    echo ' correct">';
                    print_string('correct', 'quiz');
                } else if ($state->last_graded->raw_grade > 0) {
                    echo ' partiallycorrect">';
                    print_string('partiallycorrect', 'quiz');
                    // MDL-7496
                    if ($correctanswer) {
                        echo ('<div class="correctness">');
                        $format_options = new StdClass();
                        $format_options->filter=true;
                        $format_options->smiley=false;
                        $format_options->para=false;
                        $format_options->newlines=false;
                        $filtered_correct_answer = format_text($correctanswer, $question->questiontextformat, $format_options, $cmoptions->course);
                        print_string('correctansweris', 'quiz', $filtered_correct_answer);
                        echo ('</div>');
                    }
                } else {
                    echo ' incorrect">';
                    // MDL-7496
                    print_string('incorrect', 'quiz');
                    if ($correctanswer) {
                        echo ('<div class="correctness">');
                        $format_options = new StdClass();
                        $format_options->filter=true;
                        $format_options->smiley=false;
                        $format_options->para=false;
                        $format_options->newlines=false;
                        $filtered_correct_answer = format_text($correctanswer, FORMAT_MOODLE, $format_options, $cmoptions->course);
                        print_string('correctansweris', 'quiz', $filtered_correct_answer);
                        echo ('</div>');
                    }
                }
                echo '</div>';

                echo '<div class="gradingdetails">';
                // print grade for this submission
                print_string('gradingdetails', 'quiz', $grade);
                if ($cmoptions->penaltyscheme) {
                    // print details of grade adjustment due to penalties
                    if ($state->last_graded->raw_grade > $state->last_graded->grade){
                        echo ' ';
                        print_string('gradingdetailsadjustment', 'quiz', $grade);
                    }
                    // print info about new penalty
                    // penalty is relevant only if the answer is not correct and further attempts are possible
                    if (($state->last_graded->raw_grade < $question->maxgrade) and (QUESTION_EVENTCLOSEANDGRADE != $state->event)) {
                        if ('' !== $state->last_graded->penalty && ((float)$state->last_graded->penalty) > 0.0) {
                            // A penalty was applied so display it
                            echo ' ';
                            print_string('gradingdetailspenalty', 'quiz', $state->last_graded->penalty);
                        } else {
                            /* No penalty was applied even though the answer was
                            not correct (eg. a syntax error) so tell the student
                            that they were not penalised for the attempt */
                            echo ' ';
                            print_string('gradingdetailszeropenalty', 'quiz');
                        }
                    }
                }
                echo '</div>';
            }
        }
	}
}
Пример #14
0
 function other_cols($colname, $attempt)
 {
     global $QTYPES;
     static $states = array();
     if (preg_match('/^qsanswer([0-9]+)$/', $colname, $matches)) {
         if ($attempt->uniqueid == 0) {
             return '-';
         }
         $questionid = $matches[1];
         if (isset($this->gradedstatesbyattempt[$attempt->uniqueid][$questionid])) {
             $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->uniqueid][$questionid];
         } else {
             return '-';
         }
         $question = $this->questions[$questionid];
         restore_question_state($question, $stateforqinattempt);
         if (!$this->is_downloading() || $this->is_downloading() == 'xhtml') {
             $formathtml = true;
         } else {
             $formathtml = false;
         }
         $summary = $QTYPES[$question->qtype]->response_summary($question, $stateforqinattempt, QUIZ_REPORT_RESPONSES_MAX_LEN_TO_DISPLAY, $formathtml);
         if (!$this->is_downloading()) {
             if ($summary) {
                 $summary = link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' . $attempt->attempt . '&amp;question=' . $question->id, 'reviewquestion', $summary, 450, 650, get_string('reviewresponse', 'quiz'), 'none', true);
                 if (question_state_is_graded($stateforqinattempt) && $question->maxgrade > 0) {
                     $grade = $stateforqinattempt->grade / $question->maxgrade;
                     $qclass = question_get_feedback_class($grade);
                     $feedbackimg = question_get_feedback_image($grade);
                     $questionclass = "que";
                     return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $summary . "</span></span>{$feedbackimg}";
                 } else {
                     return $summary;
                 }
             } else {
                 return '';
             }
         } else {
             return $summary;
         }
     } else {
         return NULL;
     }
 }
Пример #15
0
 /**
  * Display the report.
  */
 function display($quiz, $cm, $course)
 {
     global $CFG, $db;
     // Define some strings
     $strreallydel = addslashes(get_string('deleteattemptcheck', 'quiz'));
     $strtimeformat = get_string('strftimedatetime');
     $strreviewquestion = get_string('reviewresponse', 'quiz');
     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
     // Only print headers if not asked to download data
     if (!($download = optional_param('download', NULL))) {
         $this->print_header_and_tabs($cm, $course, $quiz, "overview");
     }
     if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
         //attempts need to be deleted
         require_capability('mod/quiz:deleteattempts', $context);
         $attemptids = optional_param('attemptid', array(), PARAM_INT);
         foreach ($attemptids as $attemptid) {
             add_to_log($course->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id, $attemptid, $cm->id);
             quiz_delete_attempt($attemptid, $quiz);
         }
         //No need for a redirect, any attemptids that do not exist are ignored.
         //So no problem if the user refreshes and tries to delete the same attempts
         //twice.
     }
     // Work out some display options - whether there is feedback, and whether scores should be shown.
     $hasfeedback = quiz_has_feedback($quiz->id) && $quiz->grade > 1.0E-7 && $quiz->sumgrades > 1.0E-7;
     $fakeattempt = new stdClass();
     $fakeattempt->preview = false;
     $fakeattempt->timefinish = $quiz->timeopen;
     $reviewoptions = quiz_get_reviewoptions($quiz, $fakeattempt, $context);
     $showgrades = $quiz->grade && $quiz->sumgrades && $reviewoptions->scores;
     $pageoptions = array();
     $pageoptions['id'] = $cm->id;
     $pageoptions['q'] = $quiz->id;
     $pageoptions['mode'] = 'overview';
     /// find out current groups mode
     $currentgroup = groups_get_activity_group($cm, true);
     $reporturl = new moodle_url($CFG->wwwroot . '/mod/quiz/report.php', $pageoptions);
     $qmsubselect = quiz_report_qm_filter_select($quiz);
     $mform = new mod_quiz_report_overview_settings($reporturl, compact('qmsubselect', 'quiz', 'currentgroup'));
     if ($fromform = $mform->get_data()) {
         $attemptsmode = $fromform->attemptsmode;
         if ($qmsubselect) {
             //control is not on the form if
             //the grading method is not set
             //to grade one attempt per user eg. for average attempt grade.
             $qmfilter = $fromform->qmfilter;
         } else {
             $qmfilter = 0;
         }
         set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks);
         set_user_preference('quiz_report_pagesize', $fromform->pagesize);
         $detailedmarks = $fromform->detailedmarks;
         $pagesize = $fromform->pagesize;
     } else {
         $qmfilter = optional_param('qmfilter', 0, PARAM_INT);
         $attemptsmode = optional_param('attemptsmode', QUIZ_REPORT_ATTEMPTS_ALL, PARAM_INT);
         $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1);
         $pagesize = get_user_preferences('quiz_report_pagesize', 0);
     }
     if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL && $currentgroup) {
         $attemptsmode = QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH;
     }
     if (!$reviewoptions->scores) {
         $detailedmarks = 0;
     }
     if ($pagesize < 1) {
         $pagesize = QUIZ_REPORT_DEFAULT_PAGE_SIZE;
     }
     // We only want to show the checkbox to delete attempts
     // if the user has permissions and if the report mode is showing attempts.
     $candelete = has_capability('mod/quiz:deleteattempts', $context) && $attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO;
     $displayoptions = array();
     $displayoptions['attemptsmode'] = $attemptsmode;
     $displayoptions['qmfilter'] = $qmfilter;
     $reporturlwithdisplayoptions = new moodle_url($CFG->wwwroot . '/mod/quiz/report.php', $pageoptions + $displayoptions);
     if ($groupmode = groups_get_activity_groupmode($cm)) {
         // Groups are being used
         if (!$download) {
             groups_print_activity_menu($cm, $reporturlwithdisplayoptions->out());
         }
     }
     // Print information on the number of existing attempts
     if (!$download) {
         //do not print notices when downloading
         if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
             echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
         }
     }
     $nostudents = false;
     if (!($students = get_users_by_capability($context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '', '', '', false))) {
         notify(get_string('nostudentsyet'));
         $nostudents = true;
         $studentslist = '';
     } else {
         $studentslist = join(',', array_keys($students));
     }
     if (empty($currentgroup)) {
         // all users who can attempt quizzes
         $groupstudentslist = '';
         $allowedlist = $studentslist;
     } else {
         // all users who can attempt quizzes and who are in the currently selected group
         if (!($groupstudents = get_users_by_capability($context, 'mod/quiz:attempt', '', '', '', '', $currentgroup, '', false))) {
             notify(get_string('nostudentsingroup'));
             $nostudents = true;
             $groupstudents = array();
         }
         $groupstudentslist = join(',', array_keys($groupstudents));
         $allowedlist = $groupstudentslist;
     }
     if (!$nostudents || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) {
         // Print information on the grading method and whether we are displaying
         //
         if (!$download) {
             //do not print notices when downloading
             if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) {
                 echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
             }
         }
         // Now check if asked download of data
         if ($download) {
             $filename = clean_filename("{$course->shortname} " . format_string($quiz->name, true));
         }
         // Define table columns
         $columns = array();
         $headers = array();
         if (!$download && $candelete) {
             $columns[] = 'checkbox';
             $headers[] = NULL;
         }
         if (!$download && $CFG->grade_report_showuserimage) {
             $columns[] = 'picture';
             $headers[] = '';
         }
         $columns[] = 'fullname';
         $headers[] = get_string('name');
         if ($CFG->grade_report_showuseridnumber) {
             $columns[] = 'idnumber';
             $headers[] = get_string('idnumber');
         }
         $columns[] = 'timestart';
         $headers[] = get_string('startedon', 'quiz');
         $columns[] = 'timefinish';
         $headers[] = get_string('timecompleted', 'quiz');
         $columns[] = 'duration';
         $headers[] = get_string('attemptduration', 'quiz');
         if ($showgrades) {
             $columns[] = 'sumgrades';
             $headers[] = get_string('grade', 'quiz') . '/' . $quiz->grade;
         }
         if ($detailedmarks) {
             // we want to display marks for all questions
             $questions = quiz_report_load_questions($quiz);
             foreach ($questions as $id => $question) {
                 // Ignore questions of zero length
                 $columns[] = 'qsgrade' . $id;
                 $headers[] = '#' . $question->number;
             }
         }
         if ($hasfeedback) {
             $columns[] = 'feedbacktext';
             $headers[] = get_string('feedback', 'quiz');
         }
         if (!$download) {
             // Set up the table
             $table = new flexible_table('mod-quiz-report-overview-report');
             $table->define_columns($columns);
             $table->define_headers($headers);
             $table->define_baseurl($reporturlwithdisplayoptions->out());
             $table->sortable(true);
             $table->collapsible(true);
             $table->column_suppress('picture');
             $table->column_suppress('fullname');
             $table->column_suppress('idnumber');
             $table->no_sorting('feedbacktext');
             $table->column_class('picture', 'picture');
             $table->column_class('fullname', 'bold');
             $table->column_class('sumgrades', 'bold');
             $table->set_attribute('cellspacing', '0');
             $table->set_attribute('id', 'attempts');
             $table->set_attribute('class', 'generaltable generalbox');
             // Start working -- this is necessary as soon as the niceties are over
             $table->setup();
         } else {
             if ($download == 'ODS') {
                 require_once "{$CFG->libdir}/odslib.class.php";
                 $filename .= ".ods";
                 // Creating a workbook
                 $workbook = new MoodleODSWorkbook("-");
                 // Sending HTTP headers
                 $workbook->send($filename);
                 // Creating the first worksheet
                 $sheettitle = get_string('reportoverview', 'quiz');
                 $myxls =& $workbook->add_worksheet($sheettitle);
                 // format types
                 $format =& $workbook->add_format();
                 $format->set_bold(0);
                 $formatbc =& $workbook->add_format();
                 $formatbc->set_bold(1);
                 $formatbc->set_align('center');
                 $formatb =& $workbook->add_format();
                 $formatb->set_bold(1);
                 $formaty =& $workbook->add_format();
                 $formaty->set_bg_color('yellow');
                 $formatc =& $workbook->add_format();
                 $formatc->set_align('center');
                 $formatr =& $workbook->add_format();
                 $formatr->set_bold(1);
                 $formatr->set_color('red');
                 $formatr->set_align('center');
                 $formatg =& $workbook->add_format();
                 $formatg->set_bold(1);
                 $formatg->set_color('green');
                 $formatg->set_align('center');
                 // Here starts workshhet headers
                 $colnum = 0;
                 foreach ($headers as $item) {
                     $myxls->write(0, $colnum, $item, $formatbc);
                     $colnum++;
                 }
                 $rownum = 1;
             } else {
                 if ($download == 'Excel') {
                     require_once "{$CFG->libdir}/excellib.class.php";
                     $filename .= ".xls";
                     // Creating a workbook
                     $workbook = new MoodleExcelWorkbook("-");
                     // Sending HTTP headers
                     $workbook->send($filename);
                     // Creating the first worksheet
                     $sheettitle = get_string('reportoverview', 'quiz');
                     $myxls =& $workbook->add_worksheet($sheettitle);
                     // format types
                     $format =& $workbook->add_format();
                     $format->set_bold(0);
                     $formatbc =& $workbook->add_format();
                     $formatbc->set_bold(1);
                     $formatbc->set_align('center');
                     $formatb =& $workbook->add_format();
                     $formatb->set_bold(1);
                     $formaty =& $workbook->add_format();
                     $formaty->set_bg_color('yellow');
                     $formatc =& $workbook->add_format();
                     $formatc->set_align('center');
                     $formatr =& $workbook->add_format();
                     $formatr->set_bold(1);
                     $formatr->set_color('red');
                     $formatr->set_align('center');
                     $formatg =& $workbook->add_format();
                     $formatg->set_bold(1);
                     $formatg->set_color('green');
                     $formatg->set_align('center');
                     $colnum = 0;
                     foreach ($headers as $item) {
                         $myxls->write(0, $colnum, $item, $formatbc);
                         $colnum++;
                     }
                     $rownum = 1;
                 } else {
                     if ($download == 'CSV') {
                         $filename .= ".txt";
                         header("Content-Type: application/download\n");
                         header("Content-Disposition: attachment; filename=\"{$filename}\"");
                         header("Expires: 0");
                         header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
                         header("Pragma: public");
                         echo implode("\t", $headers) . " \n";
                     }
                 }
             }
         }
         // Construct the SQL
         $select = 'SELECT ' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ' AS uniqueid, ';
         if ($qmsubselect) {
             $select .= "(CASE " . "   WHEN {$qmsubselect} THEN 1" . "   ELSE 0 " . "END) AS gradedattempt, ";
         }
         $select .= 'qa.uniqueid AS attemptuniqueid, qa.id AS attempt, ' . 'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, ' . 'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration ';
         // This part is the same for all cases - join users and quiz_attempts tables
         $from = 'FROM ' . $CFG->prefix . 'user u ';
         $from .= 'LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON qa.userid = u.id AND qa.quiz = ' . $quiz->id;
         if ($qmsubselect && $qmfilter) {
             $from .= ' AND ' . $qmsubselect;
         }
         switch ($attemptsmode) {
             case QUIZ_REPORT_ATTEMPTS_ALL:
                 // Show all attempts, including students who are no longer in the course
                 $where = ' WHERE qa.id IS NOT NULL AND qa.preview = 0';
                 break;
             case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH:
                 // Show only students with attempts
                 $where = ' WHERE u.id IN (' . $allowedlist . ') AND qa.preview = 0 AND qa.id IS NOT NULL';
                 break;
             case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
                 // Show only students without attempts
                 $where = ' WHERE u.id IN (' . $allowedlist . ') AND qa.id IS NULL';
                 break;
             case QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS:
                 // Show all students with or without attempts
                 $where = ' WHERE u.id IN (' . $allowedlist . ') AND (qa.preview = 0 OR qa.preview IS NULL)';
                 break;
         }
         $countsql = 'SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)') . ')) ' . $from . $where;
         // Add table joins so we can sort by question grade
         // unfortunately can't join all tables necessary to fetch all grades
         // to get the state for one question per attempt row we must join two tables
         // and there is a limit to how many joins you can have in one query. In MySQL it
         // is 61. This means that when having more than 29 questions the query will fail.
         // So we join just the tables needed to sort the attempts.
         if (!$download && ($sort = $table->get_sql_sort())) {
             if (!$download && $detailedmarks) {
                 $from .= ' ';
                 $sortparts = explode(',', $sort);
                 $matches = array();
                 foreach ($sortparts as $sortpart) {
                     $sortpart = trim($sortpart);
                     if (preg_match('/^qsgrade([0-9]+)/', $sortpart, $matches)) {
                         $qid = intval($matches[1]);
                         $select .= ", qs{$qid}.grade AS qsgrade{$qid}, qs{$qid}.event AS qsevent{$qid}, qs{$qid}.id AS qsid{$qid}";
                         $from .= "LEFT JOIN {$CFG->prefix}question_sessions qns{$qid} ON qns{$qid}.attemptid = qa.uniqueid AND qns{$qid}.questionid = {$qid} ";
                         $from .= "LEFT JOIN  {$CFG->prefix}question_states qs{$qid} ON qs{$qid}.id = qns{$qid}.newgraded ";
                     } else {
                         $newsort[] = $sortpart;
                     }
                 }
                 $select .= ' ';
             }
         }
         if ($download) {
             $sort = '';
         }
         // Fix some wired sorting
         if (empty($sort)) {
             $sort = ' ORDER BY uniqueid';
         } else {
             $sort = ' ORDER BY ' . $sort;
         }
         if (!$download) {
             // Add extra limits due to initials bar
             if ($table->get_sql_where()) {
                 $where .= ' AND ' . $table->get_sql_where();
             }
             if (!empty($countsql)) {
                 $totalinitials = count_records_sql($countsql);
                 if ($table->get_sql_where()) {
                     $countsql .= ' AND ' . $table->get_sql_where();
                 }
                 $total = count_records_sql($countsql);
             }
             $table->pagesize($pagesize, $total);
         }
         // Fetch the attempts
         if (!$download) {
             $attempts = get_records_sql($select . $from . $where . $sort, $table->get_page_start(), $table->get_page_size());
         } else {
             $attempts = get_records_sql($select . $from . $where . $sort);
         }
         // Build table rows
         if (!$download) {
             $table->initialbars($totalinitials > 20);
         }
         if ($attempts) {
             if ($detailedmarks) {
                 //get all the attempt ids we want to display on this page
                 //or to export for download.
                 $attemptids = array();
                 foreach ($attempts as $attempt) {
                     if ($attempt->attemptuniqueid > 0) {
                         $attemptids[] = $attempt->attemptuniqueid;
                     }
                 }
                 $gradedstatesbyattempt = quiz_get_newgraded_states($attemptids, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt');
             }
             foreach ($attempts as $attempt) {
                 // Username columns.
                 $row = array();
                 if (in_array('checkbox', $columns)) {
                     if ($attempt->attempt) {
                         $row[] = '<input type="checkbox" name="attemptid[]" value="' . $attempt->attempt . '" />';
                     } else {
                         $row[] = '';
                     }
                 }
                 if (in_array('picture', $columns)) {
                     $attempt->id = $attempt->userid;
                     $picture = print_user_picture($attempt, $course->id, NULL, false, true);
                     $row[] = $picture;
                 }
                 if (!$download) {
                     $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $attempt->userid . '&amp;course=' . $course->id . '">' . fullname($attempt) . '</a>';
                     $row[] = $userlink;
                 } else {
                     $row[] = fullname($attempt);
                 }
                 if (in_array('idnumber', $columns)) {
                     $row[] = $attempt->idnumber;
                 }
                 // Timing columns.
                 if ($attempt->attempt) {
                     $startdate = userdate($attempt->timestart, $strtimeformat);
                     if (!$download) {
                         $row[] = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $startdate . '</a>';
                     } else {
                         $row[] = $startdate;
                     }
                     if ($attempt->timefinish) {
                         $timefinish = userdate($attempt->timefinish, $strtimeformat);
                         $duration = format_time($attempt->duration);
                         if (!$download) {
                             $row[] = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $timefinish . '</a>';
                         } else {
                             $row[] = $timefinish;
                         }
                         $row[] = $duration;
                     } else {
                         $row[] = '-';
                         $row[] = get_string('unfinished', 'quiz');
                     }
                 } else {
                     $row[] = '-';
                     $row[] = '-';
                     $row[] = '-';
                 }
                 // Grades columns.
                 if ($showgrades) {
                     if ($attempt->timefinish) {
                         $grade = quiz_rescale_grade($attempt->sumgrades, $quiz);
                         if (!$download) {
                             $gradehtml = '<a href="review.php?q=' . $quiz->id . '&amp;attempt=' . $attempt->attempt . '">' . $grade . '</a>';
                             if ($qmsubselect && $attempt->gradedattempt) {
                                 $gradehtml = '<div class="highlight">' . $gradehtml . '</div>';
                             }
                             $row[] = $gradehtml;
                         } else {
                             $row[] = $grade;
                         }
                     } else {
                         $row[] = '-';
                     }
                 }
                 if ($detailedmarks) {
                     if (empty($attempt->attempt)) {
                         foreach ($questions as $question) {
                             $row[] = '-';
                         }
                     } else {
                         foreach ($questions as $questionid => $question) {
                             $stateforqinattempt = $gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid];
                             if (question_state_is_graded($stateforqinattempt)) {
                                 $grade = quiz_rescale_grade($stateforqinattempt->grade, $quiz);
                             } else {
                                 $grade = '--';
                             }
                             if (!$download) {
                                 $grade = $grade . '/' . quiz_rescale_grade($question->grade, $quiz);
                                 $row[] = link_to_popup_window('/mod/quiz/reviewquestion.php?state=' . $stateforqinattempt->id . '&amp;number=' . $question->number, 'reviewquestion', $grade, 450, 650, $strreviewquestion, 'none', true);
                             } else {
                                 $row[] = $grade;
                             }
                         }
                     }
                 }
                 // Feedback column.
                 if ($hasfeedback) {
                     if ($attempt->timefinish) {
                         $row[] = quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $quiz), $quiz->id);
                     } else {
                         $row[] = '-';
                     }
                 }
                 if (!$download) {
                     $table->add_data($row);
                 } else {
                     if ($download == 'Excel' or $download == 'ODS') {
                         $colnum = 0;
                         foreach ($row as $item) {
                             $myxls->write($rownum, $colnum, $item, $format);
                             $colnum++;
                         }
                         $rownum++;
                     } else {
                         if ($download == 'CSV') {
                             $text = implode("\t", $row);
                             echo $text . " \n";
                         }
                     }
                 }
             }
             //end of adding data from attempts data to table / download
             //now add averages :
             if (!$download && $attempts) {
                 $averagesql = "SELECT AVG(qg.grade) AS grade " . "FROM {$CFG->prefix}quiz_grades qg " . "WHERE quiz=" . $quiz->id;
                 $table->add_separator();
                 if ($groupstudentslist) {
                     $groupaveragesql = $averagesql . " AND qg.userid IN ({$groupstudentslist})";
                     $groupaverage = get_record_sql($groupaveragesql);
                     $groupaveragerow = array('fullname' => get_string('groupavg', 'grades'), 'sumgrades' => round($groupaverage->grade, $quiz->decimalpoints), 'feedbacktext' => quiz_report_feedback_for_grade($groupaverage->grade, $quiz->id));
                     if ($detailedmarks && $qmsubselect) {
                         $avggradebyq = quiz_get_average_grade_for_questions($quiz, $groupstudentslist);
                         $groupaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download);
                     }
                     $table->add_data_keyed($groupaveragerow);
                 }
                 $overallaverage = get_record_sql($averagesql . " AND qg.userid IN ({$studentslist})");
                 $overallaveragerow = array('fullname' => get_string('overallaverage', 'grades'), 'sumgrades' => round($overallaverage->grade, $quiz->decimalpoints), 'feedbacktext' => quiz_report_feedback_for_grade($overallaverage->grade, $quiz->id));
                 if ($detailedmarks && $qmsubselect) {
                     $avggradebyq = quiz_get_average_grade_for_questions($quiz, $studentslist);
                     $overallaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download);
                 }
                 $table->add_data_keyed($overallaveragerow);
             }
             if (!$download) {
                 // Start form
                 echo '<div id="tablecontainer">';
                 echo '<form id="attemptsform" method="post" action="' . $reporturlwithdisplayoptions->out(true) . '" onsubmit="return confirm(\'' . $strreallydel . '\');">';
                 echo '<div style="display: none;">';
                 echo $reporturlwithdisplayoptions->hidden_params_out();
                 echo '</div>';
                 echo '<div>';
                 // Print table
                 $table->print_html();
                 // Print "Select all" etc.
                 if (!empty($attempts) && $candelete) {
                     echo '<table id="commands">';
                     echo '<tr><td>';
                     echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectall', 'quiz') . '</a> / ';
                     echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectnone', 'quiz') . '</a> ';
                     echo '&nbsp;&nbsp;';
                     echo '<input type="submit" value="' . get_string('deleteselected', 'quiz_overview') . '"/>';
                     echo '</td></tr></table>';
                 }
                 // Close form
                 echo '</div>';
                 echo '</form></div>';
                 if (!empty($attempts)) {
                     echo '<table class="boxaligncenter"><tr>';
                     echo '<td>';
                     print_single_button($reporturl->out(true), $pageoptions + $displayoptions + array('download' => 'ODS'), get_string('downloadods'));
                     echo "</td>\n";
                     echo '<td>';
                     print_single_button($reporturl->out(true), $pageoptions + $displayoptions + array('download' => 'Excel'), get_string('downloadexcel'));
                     echo "</td>\n";
                     echo '<td>';
                     print_single_button($reporturl->out(true), $pageoptions + $displayoptions + array('download' => 'CSV'), get_string('downloadtext'));
                     echo "</td>\n";
                     echo "<td>";
                     helpbutton('overviewdownload', get_string('overviewdownload', 'quiz_overview'), 'quiz');
                     echo "</td>\n";
                     echo '</tr></table>';
                 }
             }
         } else {
             if (!$download) {
                 $table->print_html();
             }
         }
         if ($download == 'Excel' or $download == 'ODS') {
             $workbook->close();
             exit;
         } else {
             if ($download == 'CSV') {
                 exit;
             }
         }
     }
     if (!$download) {
         // Print display options
         $mform->set_data($displayoptions + compact('detailedmarks', 'pagesize'));
         $mform->display();
         //should be quicker than a COUNT to test if there is at least one record :
         if ($showgrades && record_exists('quiz_grades', 'quiz', $quiz->id)) {
             $imageurl = $CFG->wwwroot . '/mod/quiz/report/overview/overviewgraph.php?id=' . $quiz->id;
             print_heading(get_string('overviewreportgraph', 'quiz_overview'));
             echo '<div class="mdl-align"><img src="' . $imageurl . '" alt="' . get_string('overviewreportgraph', 'quiz_overview') . '" /></div>';
         }
     }
     return true;
 }
Пример #16
0
 function check_file_access($question, $state, $options, $contextid, $component, $filearea, $args)
 {
     if ($component == 'question' && $filearea == 'questiontext') {
         // Question text always visible.
         return true;
     } else {
         if ($component == 'question' && ($filearea = 'generalfeedback')) {
             return $options->generalfeedback && question_state_is_graded($state->last_graded);
         } else {
             // Unrecognised component or filearea.
             return false;
         }
     }
 }
Пример #17
0
 function test_question_state_is_graded()
 {
     $state = new stdClass();
     $state->event = QUESTION_EVENTOPEN;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTNAVIGATE;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTSAVE;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTDUPLICATE;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTVALIDATE;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTSUBMIT;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTCLOSE;
     $this->assertFalse(question_state_is_graded($state));
     $state->event = QUESTION_EVENTCLOSEANDGRADE;
     $this->assertTrue(question_state_is_graded($state));
     $state->event = QUESTION_EVENTMANUALGRADE;
     $this->assertTrue(question_state_is_graded($state));
     $state->event = QUESTION_EVENTGRADE;
     $this->assertTrue(question_state_is_graded($state));
 }
Пример #18
0
function question_print_comment_fields($question, $state, $prefix, $cmoptions, $caption = '')
{
    global $QTYPES;
    $idprefix = preg_replace('/[^-_a-zA-Z0-9]/', '', $prefix);
    $otherquestionsinuse = '';
    if (!empty($cmoptions->questions)) {
        $otherquestionsinuse = $cmoptions->questions;
    }
    if (!question_state_is_graded($state) && $QTYPES[$question->qtype]->is_question_manual_graded($question, $otherquestionsinuse)) {
        $grade = '';
    } else {
        $grade = question_format_grade($cmoptions, $state->last_graded->grade);
    }
    $maxgrade = question_format_grade($cmoptions, $question->maxgrade);
    $fieldsize = strlen($maxgrade) - 1;
    if (empty($caption)) {
        $caption = format_string($question->name);
    }
    ?>
<fieldset class="que comment clearfix">
    <legend class="ftoggler"><?php 
    echo $caption;
    ?>
</legend>
    <div class="fcontainer clearfix">
        <div class="fitem">
            <div class="fitemtitle">
                <label for="<?php 
    echo $idprefix;
    ?>
_comment_box"><?php 
    print_string('comment', 'quiz');
    ?>
</label>
            </div>
            <div class="felement fhtmleditor">
                <?php 
    print_textarea(can_use_html_editor(), 15, 60, 630, 300, $prefix . '[comment]', $state->manualcomment, 0, false, $idprefix . '_comment_box');
    ?>
            </div>
        </div>
        <div class="fitem">
            <div class="fitemtitle">
                <label for="<?php 
    echo $idprefix;
    ?>
_grade_field"><?php 
    print_string('grade', 'quiz');
    ?>
</label>
            </div>
            <div class="felement ftext">
                <input type="text" name="<?php 
    echo $prefix;
    ?>
[grade]" size="<?php 
    echo $fieldsize;
    ?>
" id="<?php 
    echo $idprefix;
    ?>
_grade_field" value="<?php 
    echo $grade;
    ?>
" /> / <?php 
    echo $maxgrade;
    ?>
            </div>
        </div>
    </div>
</fieldset>
    <?php 
}
Пример #19
0
 /**
  * Prints the score obtained and maximum score available plus any penalty
  * information
  *
  * This function prints a summary of the scoring in the most recently
  * graded state (the question may not have been submitted for marking at
  * the current state). The default implementation should be suitable for most
  * question types.
  * @param object $question The question for which the grading details are
  *                         to be rendered. Question type specific information
  *                         is included. The maximum possible grade is in
  *                         ->maxgrade.
  * @param object $state    The state. In particular the grading information
  *                          is in ->grade, ->raw_grade and ->penalty.
  * @param object $cmoptions
  * @param object $options  An object describing the rendering options.
  */
 function print_question_grading_details(&$question, &$state, $cmoptions, $options)
 {
     /* The default implementation prints the number of marks if no attempt
        has been made. Otherwise it displays the grade obtained out of the
        maximum grade available and a warning if a penalty was applied for the
        attempt and displays the overall grade obtained counting all previous
        responses (and penalties) */
     global $QTYPES;
     // MDL-7496 show correct answer after "Incorrect"
     $correctanswer = '';
     if ($correctanswers = $QTYPES[$question->qtype]->get_correct_responses($question, $state)) {
         if ($options->readonly && $options->correct_responses) {
             $delimiter = '';
             if ($correctanswers) {
                 foreach ($correctanswers as $ca) {
                     $correctanswer .= $delimiter . $ca;
                     $delimiter = ', ';
                 }
             }
         }
     }
     if (QUESTION_EVENTDUPLICATE == $state->event) {
         echo ' ';
         print_string('duplicateresponse', 'quiz');
     }
     if ($question->maxgrade > 0 && $options->scores) {
         if (question_state_is_graded($state->last_graded)) {
             // Display the grading details from the last graded state
             $grade = new stdClass();
             $grade->cur = question_format_grade($cmoptions, $state->last_graded->grade);
             $grade->max = question_format_grade($cmoptions, $question->maxgrade);
             $grade->raw = question_format_grade($cmoptions, $state->last_graded->raw_grade);
             // let student know wether the answer was correct
             $class = question_get_feedback_class($state->last_graded->raw_grade / $question->maxgrade);
             echo '<div class="correctness ' . $class . '">' . get_string($class, 'quiz');
             if ($correctanswer != '' && ($class == 'partiallycorrect' || $class == 'incorrect')) {
                 echo '<div class="correctness">';
                 print_string('correctansweris', 'quiz', s($correctanswer));
                 echo '</div>';
             }
             echo '</div>';
             echo '<div class="gradingdetails">';
             // print grade for this submission
             print_string('gradingdetails', 'quiz', $grade);
             // A unit penalty for numerical was applied so display it
             // a temporary solution for unit rendering in numerical
             // waiting for the new question engine code for a permanent one
             if (isset($state->options->raw_unitpenalty) && $state->options->raw_unitpenalty > 0.0) {
                 echo ' ';
                 print_string('unitappliedpenalty', 'qtype_numerical', question_format_grade($cmoptions, $state->options->raw_unitpenalty));
             }
             if ($cmoptions->penaltyscheme) {
                 // print details of grade adjustment due to penalties
                 if ($state->last_graded->raw_grade > $state->last_graded->grade) {
                     echo ' ';
                     print_string('gradingdetailsadjustment', 'quiz', $grade);
                 }
                 // print info about new penalty
                 // penalty is relevant only if the answer is not correct and further attempts are possible
                 if ($state->last_graded->raw_grade < $question->maxgrade and QUESTION_EVENTCLOSEANDGRADE != $state->event) {
                     if ('' !== $state->last_graded->penalty && (double) $state->last_graded->penalty > 0.0) {
                         echo ' ';
                         print_string('gradingdetailspenalty', 'quiz', question_format_grade($cmoptions, $state->last_graded->penalty));
                     } else {
                         /* No penalty was applied even though the answer was
                            not correct (eg. a syntax error) so tell the student
                            that they were not penalised for the attempt */
                         echo ' ';
                         print_string('gradingdetailszeropenalty', 'quiz');
                     }
                 }
             }
             echo '</div>';
         }
     }
 }
Пример #20
0
 /**
  * Prints the score obtained and maximum score available plus any penalty
  * information
  *
  * This function prints a summary of the scoring in the most recently
  * graded state (the question may not have been submitted for marking at
  * the current state). The default implementation should be suitable for most
  * question types.
  * @param object $question The question for which the grading details are
  *                         to be rendered. Question type specific information
  *                         is included. The maximum possible grade is in
  *                         ->maxgrade.
  * @param object $state    The state. In particular the grading information
  *                          is in ->grade, ->raw_grade and ->penalty.
  * @param object $cmoptions
  * @param object $options  An object describing the rendering options.
  */
 function print_question_grading_details(&$question, &$state, $cmoptions, $options)
 {
     /* The default implementation prints the number of marks if no attempt
        has been made. Otherwise it displays the grade obtained out of the
        maximum grade available and a warning if a penalty was applied for the
        attempt and displays the overall grade obtained counting all previous
        responses (and penalties) */
     if (QUESTION_EVENTDUPLICATE == $state->event) {
         echo ' ';
         print_string('duplicateresponse', 'quiz');
     }
     if (!empty($question->maxgrade) && $options->scores) {
         if (question_state_is_graded($state->last_graded)) {
             // Display the grading details from the last graded state
             $grade = new stdClass();
             $grade->cur = round($state->last_graded->grade, $cmoptions->decimalpoints);
             $grade->max = $question->maxgrade;
             $grade->raw = round($state->last_graded->raw_grade, $cmoptions->decimalpoints);
             // let student know wether the answer was correct
             echo '<div class="correctness ';
             if ($state->last_graded->raw_grade >= $question->maxgrade / 1.01) {
                 // We divide by 1.01 so that rounding errors dont matter.
                 echo ' correct">';
                 print_string('correct', 'quiz');
             } else {
                 if ($state->last_graded->raw_grade > 0) {
                     echo ' partiallycorrect">';
                     print_string('partiallycorrect', 'quiz');
                 } else {
                     echo ' incorrect">';
                     print_string('incorrect', 'quiz');
                 }
             }
             echo '</div>';
             echo '<div class="gradingdetails">';
             // print grade for this submission
             print_string('gradingdetails', 'quiz', $grade);
             if ($cmoptions->penaltyscheme) {
                 // print details of grade adjustment due to penalties
                 if ($state->last_graded->raw_grade > $state->last_graded->grade) {
                     echo ' ';
                     print_string('gradingdetailsadjustment', 'quiz', $grade);
                 }
                 // print info about new penalty
                 // penalty is relevant only if the answer is not correct and further attempts are possible
                 if ($state->last_graded->raw_grade < $question->maxgrade / 1.01 and QUESTION_EVENTCLOSEANDGRADE != $state->event) {
                     if ('' !== $state->last_graded->penalty && (double) $state->last_graded->penalty > 0.0) {
                         // A penalty was applied so display it
                         echo ' ';
                         print_string('gradingdetailspenalty', 'quiz', $state->last_graded->penalty);
                     } else {
                         /* No penalty was applied even though the answer was
                            not correct (eg. a syntax error) so tell the student
                            that they were not penalised for the attempt */
                         echo ' ';
                         print_string('gradingdetailszeropenalty', 'quiz');
                     }
                 }
             }
             echo '</div>';
         }
     }
 }
Пример #21
0
 /**
  * Prints questions with comment and grade form underneath each question
  *
  * @return void
  * @todo Finish documenting this function
  **/
 function print_questions_and_form($quiz, $question, $userid, $attemptid, $gradeungraded, $gradenextungraded, $ungraded)
 {
     global $CFG, $DB, $OUTPUT;
     $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
     $questions[$question->id] =& $question;
     $usehtmleditor = can_use_html_editor();
     list($select, $from, $where, $params) = $this->attempts_sql($quiz->id, false, $question->id, $userid, $attemptid, $gradeungraded, $gradenextungraded);
     $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
     if ($gradenextungraded) {
         $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params, 0, QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE);
     } else {
         $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params);
     }
     if ($attempts) {
         $firstattempt = current($attempts);
         $fullname = fullname($firstattempt);
         if ($gradeungraded) {
             // getting all ungraded attempts
             echo $OUTPUT->heading(get_string('gradingungraded', 'quiz_grading', $ungraded), 3);
         } else {
             if ($gradenextungraded) {
                 // getting next ungraded attempts
                 echo $OUTPUT->heading(get_string('gradingnextungraded', 'quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE), 3);
             } else {
                 if ($userid) {
                     echo $OUTPUT->heading(get_string('gradinguser', 'quiz_grading', $fullname), 3);
                 } else {
                     if ($attemptid) {
                         $a = new object();
                         $a->fullname = $fullname;
                         $a->attempt = $firstattempt->attempt;
                         echo $OUTPUT->heading(get_string('gradingattempt', 'quiz_grading', $a), 3);
                     } else {
                         echo $OUTPUT->heading(get_string('gradingall', 'quiz_grading', count($attempts)), 3);
                     }
                 }
             }
         }
         // Display the form with one part for each selected attempt
         echo '<form method="post" action="report.php" class="mform" id="manualgradingform">' . '<input type="hidden" name="mode" value="grading" />' . '<input type="hidden" name="q" value="' . $quiz->id . '" />' . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />' . '<input type="hidden" name="questionid" value="' . $question->id . '" />';
         foreach ($attempts as $attempt) {
             // Load the state for this attempt (The questions array was created earlier)
             $states = get_question_states($questions, $quiz, $attempt);
             // The $states array is indexed by question id but because we are dealing
             // with only one question there is only one entry in this array
             $state =& $states[$question->id];
             $options = quiz_get_reviewoptions($quiz, $attempt, $context);
             unset($options->questioncommentlink);
             $options->readonly = 1;
             if (question_state_is_graded($state)) {
                 $gradedclass = 'main highlightgraded';
                 $gradedstring = ' ' . get_string('graded', 'quiz_grading');
             } else {
                 $gradedclass = 'main';
                 $gradedstring = '';
             }
             $a = new object();
             $a->fullname = fullname($attempt, true);
             $a->attempt = $attempt->attempt;
             // print the user name, attempt count, the question, and some more hidden fields
             echo '<div class="boxaligncenter" width="80%" style="clear:left;padding:15px;">';
             echo $OUTPUT->heading(get_string('gradingattempt', 'quiz_grading', $a) . $gradedstring, 3, $gradedclass);
             // Print the question, without showing any previous comment.
             $copy = $state->manualcomment;
             $state->manualcomment = '';
             $options->noeditlink = true;
             print_question($question, $state, '', $quiz, $options);
             // The print the comment and grade fields, putting back the previous comment.
             $state->manualcomment = $copy;
             question_print_comment_fields($question, $state, 'manualgrades[' . $attempt->uniqueid . ']', $quiz, get_string('manualgrading', 'quiz'));
             echo '</div>';
         }
         echo '<div class="boxaligncenter"><input type="submit" value="' . get_string('savechanges') . '" /></div>' . '</form>';
     } else {
         echo $OUTPUT->notification(get_string('noattemptstoshow', 'quiz'));
     }
 }
Пример #22
0
/**
 * Determine render options
 *
 * @param int $reviewoptions
 * @param object $state
 */
function quiz_get_renderoptions($reviewoptions, $state)
{
    $options = new stdClass();
    // Show the question in readonly (review) mode if the question is in
    // the closed state
    $options->readonly = question_state_is_closed($state);
    // Show feedback once the question has been graded (if allowed by the quiz)
    $options->feedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show validation only after a validation event
    $options->validation = QUESTION_EVENTVALIDATE === $state->event;
    // Show correct responses in readonly mode if the quiz allows it
    $options->correct_responses = $options->readonly && $reviewoptions & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_IMMEDIATELY;
    // Show general feedback if the question has been graded and the quiz allows it.
    $options->generalfeedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_GENERALFEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show overallfeedback once the attempt is over.
    $options->overallfeedback = false;
    // Always show responses and scores
    $options->responses = true;
    $options->scores = true;
    $options->quizstate = QUIZ_STATE_DURING;
    return $options;
}
Пример #23
0
function reader_get_renderoptions($reviewoptions, $state)
{
    $options = new stdClass();
    $options->readonly = question_state_is_closed($state);
    $options->feedback = question_state_is_graded($state) && $reviewoptions & READER_REVIEW_FEEDBACK & READER_REVIEW_IMMEDIATELY;
    $options->validation = QUESTION_EVENTVALIDATE === $state->event;
    $options->correct_responses = $options->readonly && $reviewoptions & READER_REVIEW_ANSWERS & READER_REVIEW_IMMEDIATELY;
    $options->generalfeedback = question_state_is_graded($state) && $reviewoptions & READER_REVIEW_GENERALFEEDBACK & READER_REVIEW_IMMEDIATELY;
    $options->overallfeedback = false;
    $options->responses = true;
    $options->scores = true;
    $options->readerstate = READER_STATE_DURING;
    return $options;
}