diff --git a/mod/quiz/db/access.php b/mod/quiz/db/access.php new file mode 100644 index 00000000000..87ead77be6a --- /dev/null +++ b/mod/quiz/db/access.php @@ -0,0 +1,116 @@ + array( + + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_ALLOW, + 'student' => CAP_ALLOW, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + + // Ability to do the quiz as a 'student'. + 'mod/quiz:attempt' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_ALLOW, + 'teacher' => CAP_PREVENT, + 'editingteacher' => CAP_PREVENT, + 'coursecreator' => CAP_PREVENT, + 'admin' => CAP_PREVENT + ) + ), + + // Edit the quiz settings, add and remove questions. + 'mod/quiz:manage' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_PREVENT, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + + // Preview the quiz. + 'mod/quiz:preview' => array( + + 'captype' => 'write', // Only just a write. + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + + // Manually grade and comment on student attempts at a question. + 'mod/quiz:grade' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + + // View the quiz reports. + 'mod/quiz:viewreports' => array( + + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + + // Delete attempts using the overview report. + 'mod/quiz:deleteattempts' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_PREVENT, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ) +); + +?> \ No newline at end of file diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php index d69f186f0c8..365af7172c1 100644 --- a/mod/quiz/locallib.php +++ b/mod/quiz/locallib.php @@ -78,9 +78,17 @@ function quiz_create_attempt($quiz, $attemptnumber) { return $attempt; } +/** + * Returns an unfinished attempt (if there is one) for the given + * user on the given quiz. This function does not return preview attempts. + * + * @param integer $quizid the id of the quiz. + * @param integer $userid the id of the user. + * + * @return mixed the unfinished attempt if there is one, false if not. + */ function quiz_get_user_attempt_unfinished($quizid, $userid) { -// Returns an object containing an unfinished attempt (if there is one) - return get_record("quiz_attempts", "quiz", $quizid, "userid", $userid, "timefinish", 0); + return get_record_select("quiz_attempts", "quiz = $quizid AND userid = $userid AND timefinish = 0 AND preview = 0"); } /** @@ -623,16 +631,24 @@ function quiz_get_renderoptions($reviewoptions, $state) { /** -* Determine review options -*/ -function quiz_get_reviewoptions($quiz, $attempt, $isteacher=false) { + * Determine review options + * + * @param object $quiz the quiz instance. + * @param object $attempt the attempt in question. + * @param $context the roles and permissions context, + * normally the context for the quiz module instance. + * + * @return object an object with boolean fields responses, scores, feedback, + * correct_responses, solutions and commentary + */ +function quiz_get_reviewoptions($quiz, $attempt, $context=null) { $options = new stdClass; $options->readonly = true; // Provide the links to the question review and comment script $options->questionreviewlink = '/mod/quiz/reviewquestion.php'; - if ($isteacher and !$attempt->preview) { + if ($context && has_capability('mod/quiz:viewreports'. $context) and !$attempt->preview) { // The teacher should be shown everything except during preview when the teachers // wants to see just what the students see $options->responses = true; diff --git a/mod/quiz/report/grading/report.php b/mod/quiz/report/grading/report.php index 9400bbf5207..a95729865a6 100644 --- a/mod/quiz/report/grading/report.php +++ b/mod/quiz/report/grading/report.php @@ -321,6 +321,9 @@ class quiz_report extends quiz_default_report { $userid = optional_param('userid', 0, PARAM_INT); $attemptid = optional_param('attemptid', 0, PARAM_INT); + // TODO get the context, and put in proper roles an permissions checks. + $context = NULL; + $questions[$question->id] = &$question; $usehtmleditor = can_use_richtext_editor(); $users = get_course_students($quiz->course); @@ -365,7 +368,7 @@ class quiz_report extends quiz_default_report { // with only one question there is only one entry in this array $state = &$states[$question->id]; - $options = quiz_get_reviewoptions($quiz, $attempt, true); + $options = quiz_get_reviewoptions($quiz, $attempt, $context); unset($options->questioncommentlink); $copy = $state->manualcomment; $state->manualcomment = ''; diff --git a/mod/quiz/review.php b/mod/quiz/review.php index ef267c76ae2..d4dcb460ff8 100644 --- a/mod/quiz/review.php +++ b/mod/quiz/review.php @@ -43,7 +43,7 @@ $context = get_context_instance(CONTEXT_MODULE, $cm->id); $coursecontext = get_context_instance(CONTEXT_COURSE, $cm->course); $isteacher = isteacher($course->id); - $options = quiz_get_reviewoptions($quiz, $attempt, $isteacher); + $options = quiz_get_reviewoptions($quiz, $attempt, $context); $popup = $isteacher ? 0 : $quiz->popup; // Controls whether this is shown in a javascript-protected window. // this capability is not correct, need to find the right one diff --git a/mod/quiz/reviewquestion.php b/mod/quiz/reviewquestion.php index 24cda7a7e8b..c260d144281 100644 --- a/mod/quiz/reviewquestion.php +++ b/mod/quiz/reviewquestion.php @@ -58,9 +58,9 @@ } require_login($course->id, false, $cm); - $isteacher = isteacher($course->id); + $context = get_context_instance(CONTEXT_MODULE, $cm->id); - if (!$isteacher) { + if (!has_capability('mod/quiz:viewreports', $context)) { if (!$attempt->timefinish) { redirect('attempt.php?q='.$quiz->id); } @@ -112,9 +112,9 @@ restore_question_state($question, $state); $state->last_graded = $state; - $options = quiz_get_reviewoptions($quiz, $attempt, $isteacher); + $options = quiz_get_reviewoptions($quiz, $attempt, $context); $options->validation = ($state->event == QUESTION_EVENTVALIDATE); - $options->history = ($isteacher and !$attempt->preview) ? 'all' : 'graded'; + $options->history = (has_capability('mod/quiz:viewreports', $context) and !$attempt->preview) ? 'all' : 'graded'; /// Print infobox $table->align = array("right", "left"); @@ -126,7 +126,7 @@ } // print quiz name $table->data[] = array(get_string('modulename', 'quiz').':', format_string($quiz->name)); - if ($isteacher and count($attempts = get_records_select('quiz_attempts', "quiz = '$quiz->id' AND userid = '$attempt->userid'", 'attempt ASC')) > 1) { + if (has_capability('mod/quiz:viewreports', $context) and count($attempts = get_records_select('quiz_attempts', "quiz = '$quiz->id' AND userid = '$attempt->userid'", 'attempt ASC')) > 1) { // print list of attempts $attemptlist = ''; foreach ($attempts as $at) { diff --git a/mod/quiz/tabs.php b/mod/quiz/tabs.php index f4c5367418b..0866d8e4335 100644 --- a/mod/quiz/tabs.php +++ b/mod/quiz/tabs.php @@ -29,18 +29,24 @@ $row = array(); $inactive = array(); - if (has_capability('mod/quiz:viewreports', $context)) { + if (has_capability('mod/quiz:view', $context)) { $row[] = new tabobject('info', "$CFG->wwwroot/mod/quiz/view.php?q=$quiz->id", get_string('info', 'quiz')); + } + if (has_capability('mod/quiz:viewreports', $context)) { $row[] = new tabobject('reports', "$CFG->wwwroot/mod/quiz/report.php?q=$quiz->id", get_string('results', 'quiz')); } - if (has_capability('mod/quiz:viewreports', $context)) { + if (has_capability('mod/quiz:preview', $context)) { $row[] = new tabobject('preview', "$CFG->wwwroot/mod/quiz/attempt.php?q=$quiz->id", get_string('preview', 'quiz')); } - if (has_capability('mod/quiz:preview', $context)) { + if (has_capability('mod/quiz:manage', $context)) { $row[] = new tabobject('edit', "$CFG->wwwroot/mod/quiz/edit.php?quizid=$quiz->id", get_string('edit')); } - $tabs[] = $row; + if ($currenttab == 'info' && count($row) == 1) { + // Don't show only an info tab (e.g. to students). + } else { + $tabs[] = $row; + } if ($currenttab == 'reports' and isset($mode)) { $inactive[] = 'reports'; diff --git a/mod/quiz/version.php b/mod/quiz/version.php index a9c4f46ea0f..be8dcd05a36 100644 --- a/mod/quiz/version.php +++ b/mod/quiz/version.php @@ -5,7 +5,7 @@ // This fragment is called by moodle_needs_upgrading() and /admin/index.php //////////////////////////////////////////////////////////////////////////////// -$module->version = 2006082400; // The (date) version of this module +$module->version = 2006082500; // The (date) version of this module $module->requires = 2006080900; // Requires this Moodle version $module->cron = 0; // How often should cron check this module (seconds)? diff --git a/mod/quiz/view.php b/mod/quiz/view.php index ef34ea0730a..913037e072a 100644 --- a/mod/quiz/view.php +++ b/mod/quiz/view.php @@ -10,7 +10,7 @@ $id = optional_param('id', 0, PARAM_INT); // Course Module ID, or $q = optional_param('q', 0, PARAM_INT); // quiz ID $edit = optional_param('edit', -1, PARAM_BOOL); - + if ($id) { if (! $cm = get_coursemodule_from_id('quiz', $id)) { error("There is no coursemodule with id $id"); @@ -36,18 +36,18 @@ } } + // Check login and get context. require_login($course->id, false, $cm); - $isteacher = isteacher($course->id); + $context = get_context_instance(CONTEXT_MODULE, $cm->id); + require_capability('mod/quiz:view', $context); // if no questions have been set up yet redirect to edit.php - if (!$quiz->questions and isteacheredit($course->id)) { + if (!$quiz->questions and has_capability('mod/quiz:manage', $context)) { redirect('edit.php?quizid='.$quiz->id); } add_to_log($course->id, "quiz", "view", "view.php?id=$cm->id", $quiz->id, $cm->id); - $timenow = time(); - // Initialize $PAGE, compute blocks $PAGE = page_create_instance($quiz->id); $pageblocks = blocks_setup($PAGE); @@ -59,8 +59,8 @@ } //only check pop ups if the user is not a teacher, and popup is set - - $bodytags = (isteacher($course->id) or !$quiz->popup)?'':'onload="popupchecker(\'This section of the test is in secure mode, this means that you need to take the quiz in a secure window. Please turn off your popup blocker. Thank you.\');"'; + + $bodytags = (has_capability('mod/quiz:attempt', $context) && $quiz->popup)?'onload="popupchecker(\'This section of the test is in secure mode, this means that you need to take the quiz in a secure window. Please turn off your popup blocker. Thank you.\');"':''; $PAGE->print_header($course->shortname.': %fullname%','',$bodytags); echo ''; @@ -73,16 +73,12 @@ echo '
'; - $available = ($quiz->timeopen < $timenow and ($timenow < $quiz->timeclose or !$quiz->timeclose)) || $isteacher; - // Print the main part of the page - // Print heading and tabs for teacher - if ($isteacher) { - $currenttab = 'info'; - include('tabs.php'); - } - + // Print heading and tabs (if there is more than one). + $currenttab = 'info'; + include('tabs.php'); + // Print quiz name and description. print_heading(format_string($quiz->name)); @@ -94,12 +90,14 @@ // Print information about number of attempts and grading method. if ($quiz->attempts > 1) { echo "

".get_string("attemptsallowed", "quiz").": $quiz->attempts

"; - } + } if ($quiz->attempts != 1) { echo "

".get_string("grademethod", "quiz").": ".$QUIZ_GRADE_METHOD[$quiz->grademethod]."

"; } - + // Print information about timings. + $timenow = time(); + $available = ($quiz->timeopen < $timenow and ($timenow < $quiz->timeclose or !$quiz->timeclose)); if ($available) { if ($quiz->timelimit) { echo "

".get_string("quiztimelimit","quiz", format_time($quiz->timelimit * 60))."

"; @@ -111,299 +109,278 @@ echo "

".get_string("quizclosed", "quiz", userdate($quiz->timeclose)); } - - // This is all the teacher will get - if ($isteacher) { + // Show number of attempts summary to those who can view reports. + if (has_capability('mod/quiz:viewreports', $context)) { if ($a->attemptnum = count_records('quiz_attempts', 'quiz', $quiz->id, 'preview', 0)) { $a->studentnum = count_records_select('quiz_attempts', "quiz = '$quiz->id' AND preview = '0'", 'COUNT(DISTINCT userid)'); $a->studentstring = $course->students; - + notify("id\">".get_string('numattempts', 'quiz', $a).''); } - - end_page($course); - exit; } - // Guests can't do a quiz, so offer them a choice of logging in going back. + // Guests can't do a quiz, so offer them a choice of logging in or going back. + + // TODO, work out what to do about this under roles and permissions. + // You have to be logged in to do a quiz, because attempts are tied to + // userid, and so if guests were allowed to attempt quizzes, all guests + // would see all attempts, and it would be confusing. + // + // So for courses that allow guest access, it is good to offer people an easy + // way to log in at this point if they have got this far before logging in. if (isguest()) { $loginurl = $CFG->wwwroot.'/login/index.php'; if (!empty($CFG->loginhttps)) { $loginurl = str_replace('http:','https:', $loginurl); } - notice_yesno('

' . get_string('guestsno', 'quiz') . "

\n\n

" . + notice_yesno('

' . get_string('guestsno', 'quiz') . "

\n\n

" . get_string('liketologin') . '

', $loginurl, $_SERVER['HTTP_REFERER']); - - end_page($course); - exit; } - // Get this user's attempts. - $attempts = quiz_get_user_attempts($quiz->id, $USER->id); - $unfinished = false; - if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { - $attempts[] = $unfinishedattempt; - $unfinished = true; - } - $numattempts = count($attempts); + if (has_capability('mod/quiz:attempt', $context)) { - $strattempt = get_string("attempt", "quiz"); - $strtimetaken = get_string("timetaken", "quiz"); - $strtimecompleted = get_string("timecompleted", "quiz"); - $strgrade = get_string("grade"); - $strmarks = get_string('marks', 'quiz'); - $strfeedback = get_string('feedback', 'quiz'); + // Get this user's attempts. + $attempts = quiz_get_user_attempts($quiz->id, $USER->id); + $unfinished = false; + if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { + $attempts[] = $unfinishedattempt; + $unfinished = true; + } + $numattempts = count($attempts); - $mygrade = quiz_get_best_grade($quiz, $USER->id); + $mygrade = quiz_get_best_grade($quiz, $USER->id); + + // Get some strings. + $strattempt = get_string("attempt", "quiz"); + $strtimetaken = get_string("timetaken", "quiz"); + $strtimecompleted = get_string("timecompleted", "quiz"); + $strgrade = get_string("grade"); + $strmarks = get_string('marks', 'quiz'); + $strfeedback = get_string('feedback', 'quiz'); - if ($attempts) { // Print table with existing attempts + if ($attempts) { - // Work out which columns we need, taking account what data is available in each attempt. - $gradecolumn = 0; - $overallstats = 1; - foreach ($attempts as $attempt) { - $attemptoptions = quiz_get_reviewoptions($quiz, $attempt, $isteacher); - if ($attemptoptions->scores) { - $gradecolumn = 1; - } else { - $overallstats = 0; + // Work out which columns we need, taking account what data is available in each attempt. + $gradecolumn = 0; + $overallstats = 1; + foreach ($attempts as $attempt) { + $attemptoptions = quiz_get_reviewoptions($quiz, $attempt, $context); + if ($attemptoptions->scores) { + $gradecolumn = 1; + } else { + $overallstats = 0; + } } - } - $gradecolumn = $gradecolumn && $quiz->grade && $quiz->sumgrades; - $markcolumn = $gradecolumn && ($quiz->grade <> $quiz->sumgrades); - $feedbackcolumn = quiz_has_feedback($quiz->id); + $gradecolumn = $gradecolumn && $quiz->grade && $quiz->sumgrades; + $markcolumn = $gradecolumn && ($quiz->grade <> $quiz->sumgrades); + $feedbackcolumn = quiz_has_feedback($quiz->id); - // prepare table header - $table->head = array($strattempt, $strtimecompleted); - $table->align = array("center", "left"); - $table->size = array("", ""); - if ($markcolumn) { - $table->head[] = "$strmarks / $quiz->sumgrades"; - $table->align[] = 'right'; - $table->size[] = ''; - } - if ($gradecolumn) { - $table->head[] = "$strgrade / $quiz->grade"; - $table->align[] = 'right'; - $table->size[] = ''; - } - if ($feedbackcolumn) { - $table->head[] = $strfeedback; - $table->align[] = 'left'; - $table->size[] = ''; - } - if (isset($quiz->showtimetaken)) { - $table->head[] = $strtimetaken; - $table->align[] = 'left'; - $table->size[] = ''; - } + // prepare table header + $table->head = array($strattempt, $strtimecompleted); + $table->align = array("center", "left"); + $table->size = array("", ""); + if ($markcolumn) { + $table->head[] = "$strmarks / $quiz->sumgrades"; + $table->align[] = 'right'; + $table->size[] = ''; + } + if ($gradecolumn) { + $table->head[] = "$strgrade / $quiz->grade"; + $table->align[] = 'right'; + $table->size[] = ''; + } + if ($feedbackcolumn) { + $table->head[] = $strfeedback; + $table->align[] = 'left'; + $table->size[] = ''; + } + if (isset($quiz->showtimetaken)) { + $table->head[] = $strtimetaken; + $table->align[] = 'left'; + $table->size[] = ''; + } - // One row for each attempt - foreach ($attempts as $attempt) { - $attemptoptions = quiz_get_reviewoptions($quiz, $attempt, $isteacher); - $row = array(); - - // Add the attempt number, making it a link, if appropriate. - $row[] = make_review_link('#' . $attempt->attempt, $quiz, $attempt); - - // prepare strings for time taken and date completed - $timetaken = ''; - $datecompleted = ''; - if ($attempt->timefinish > 0) { - // attempt has finished - $timetaken = format_time($attempt->timefinish - $attempt->timestart); - $datecompleted = userdate($attempt->timefinish); - } else if ($available) { - // The attempt is still in progress. - $timetaken = format_time(time() - $attempt->timestart); - $datecompleted = ''; - } else if ($quiz->timeclose) { - // The attempt was not completed but is also not available any more becuase the quiz is closed. - $timetaken = format_time($quiz->timeclose - $attempt->timestart); - $datecompleted = userdate($quiz->timeclose); - } else { - // Something wheird happened. + // One row for each attempt + foreach ($attempts as $attempt) { + $attemptoptions = quiz_get_reviewoptions($quiz, $attempt, $context); + $row = array(); + + // Add the attempt number, making it a link, if appropriate. + $row[] = make_review_link('#' . $attempt->attempt, $quiz, $attempt); + + // prepare strings for time taken and date completed $timetaken = ''; $datecompleted = ''; - } - $row[] = $datecompleted; - - if ($markcolumn) { - if ($attemptoptions->scores) { - $row[] = make_review_link(round($attempt->sumgrades, $quiz->decimalpoints), $quiz, $attempt); + if ($attempt->timefinish > 0) { + // attempt has finished + $timetaken = format_time($attempt->timefinish - $attempt->timestart); + $datecompleted = userdate($attempt->timefinish); + } else if ($available) { + // The attempt is still in progress. + $timetaken = format_time(time() - $attempt->timestart); + $datecompleted = ''; + } else if ($quiz->timeclose) { + // The attempt was not completed but is also not available any more becuase the quiz is closed. + $timetaken = format_time($quiz->timeclose - $attempt->timestart); + $datecompleted = userdate($quiz->timeclose); } else { - $row[] = ''; + // Something wheird happened. + $timetaken = ''; + $datecompleted = ''; } - } + $row[] = $datecompleted; - // Ouside the if becuase we may be showing feedback but not grades. - $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz); - if ($gradecolumn) { - if ($attemptoptions->scores) { - // highlight the highest grade if appropriate - if ($overallstats && !is_null($mygrade) && $attemptgrade == $mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) { - $formattedgrade = "$attemptgrade"; + if ($markcolumn) { + if ($attemptoptions->scores) { + $row[] = make_review_link(round($attempt->sumgrades, $quiz->decimalpoints), $quiz, $attempt); } else { - $formattedgrade = $attemptgrade; + $row[] = ''; } - - $row[] = make_review_link($formattedgrade, $quiz, $attempt); - } else { - $row[] = ''; } - } - - if ($feedbackcolumn) { - if ($attemptoptions->feedback) { - $row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id); - } else { - $row[] = ''; - } - } - - if (isset($quiz->showtimetaken)) { - $row[] = $timetaken; - } - - $table->data[] = $row; - } - print_table($table); - } - // Print information about the student's best score for this quiz if possible. - $moreattempts = $numattempts < $quiz->attempts || $quiz->attempts == 0; - if (!$moreattempts) { - print_heading(get_string("nomoreattempts", "quiz")); - } - - if ($numattempts && $quiz->sumgrades) { - if (!is_null($mygrade)) { - if ($available && $moreattempts) { - $strbestgrade = $QUIZ_GRADE_METHOD[$quiz->grademethod]; - $grademessage = "$strbestgrade: $mygrade / $quiz->grade."; - } else { - $grademessage = get_string("yourfinalgradeis", "quiz", "$mygrade / $quiz->grade"); + // Ouside the if because we may be showing feedback but not grades. + $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz); + + if ($gradecolumn) { + if ($attemptoptions->scores) { + // highlight the highest grade if appropriate + if ($overallstats && !is_null($mygrade) && $attemptgrade == $mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) { + $formattedgrade = "$attemptgrade"; + } else { + $formattedgrade = $attemptgrade; + } + + $row[] = make_review_link($formattedgrade, $quiz, $attempt); + } else { + $row[] = ''; + } + } + + if ($feedbackcolumn) { + if ($attemptoptions->feedback) { + $row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id); + } else { + $row[] = ''; + } + } + + if (isset($quiz->showtimetaken)) { + $row[] = $timetaken; + } + + $table->data[] = $row; + } // End of loop over attempts. + print_table($table); + } + + // Print information about the student's best score for this quiz if possible. + $moreattempts = $unfinished || $numattempts < $quiz->attempts || $quiz->attempts == 0; + if (!$moreattempts) { + print_heading(get_string("nomoreattempts", "quiz")); + } + + if ($numattempts && $quiz->sumgrades) { + if (!is_null($mygrade)) { + if ($available && $moreattempts) { + $strbestgrade = $QUIZ_GRADE_METHOD[$quiz->grademethod]; + $grademessage = "$strbestgrade: $mygrade / $quiz->grade."; + } else { + $grademessage = get_string("yourfinalgradeis", "quiz", "$mygrade / $quiz->grade"); + } + + if ($overallstats) { + print_heading($grademessage); + } + + if ($feedbackcolumn) { + echo '

', quiz_feedback_for_grade($mygrade, $quiz->id), '

'; + } } - - if ($overallstats) { - print_heading($grademessage); - } - - if ($feedbackcolumn) { - echo '

', quiz_feedback_for_grade($mygrade, $quiz->id), '

'; + + if (!($moreattempts && $available)) { + print_continue($CFG->webroot . '/course/view.php?id=' . $course->id); } } - if (!($moreattempts && $available)) { - print_continue($CFG->webroot . '/course/view.php?id=' . $course->id); - } - } - - if ($quiz->questions) { - // Print a button to start the quiz if appropriate. - if ($available && $moreattempts) { + // Print a button to start/continue an attempt, if appropriate. + if ($quiz->questions && $available && $moreattempts) { + echo "
"; echo "
"; - if ($quiz->delay1 or $quiz->delay2) { - //quiz enforced time delay - $lastattempt_obj = get_record_select('quiz_attempts', "quiz = $quiz->id AND attempt = $numattempts AND userid = $USER->id", 'timefinish'); - if ($lastattempt_obj) { - $lastattempt = $lastattempt_obj->timefinish; - } - if($numattempts == 1 && $quiz->delay1) { - if ($timenow - $quiz->delay1 > $lastattempt) { - print_start_quiz_button($quiz, $attempts, $numattempts, $unfinished, $cm); - } else { - $notify_msg = get_string('temporaryblocked', 'quiz') . ''. userdate($lastattempt + $quiz->delay1). ''; - print_simple_box($notify_msg, "center"); - } - } else if($numattempts > 1 && $quiz->delay2) { - if ($timenow - $quiz->delay2 > $lastattempt) { - print_start_quiz_button($quiz, $attempts, $numattempts, $unfinished, $cm); - } else { - $notify_msg = get_string('temporaryblocked', 'quiz') . ''. userdate($lastattempt + $quiz->delay2). ''; - print_simple_box($notify_msg, "center"); - } - } else { - print_start_quiz_button($quiz, $attempts, $numattempts, $unfinished, $cm); - } + + if ($unfinished) { + $buttontext = get_string('continueattemptquiz', 'quiz'); } else { - print_start_quiz_button($quiz, $attempts, $numattempts, $unfinished, $cm); - } - echo "
\n"; - } - } else { - // No questions in quiz. - print_heading(get_string("noquestions", "quiz")); - } - // Finish the page - this needs to be the same as in the if teacher block above. - echo '
'; - print_footer($course); + // Work out the appropriate button caption. + if ($numattempts == 0) { + $buttontext = get_string('attemptquiznow', 'quiz'); + } else { + $buttontext = get_string('reattemptquiz', 'quiz'); + } -// Utility functions ================================================================= + // Work out if the quiz is temporarily unavailable becuase of the delay option. + if (!empty($attempts)) { + $tempunavailable = ''; + $lastattempttime = end($attempts)->timefinish; + if ($numattempts == 1 && $quiz->delay1 && $timenow <= $lastattempttime + $quiz->delay1) { + $tempunavailable = get_string('temporaryblocked', 'quiz') . + ''. userdate($lastattempt + $quiz->delay1). ''; + } else if ($numattempts > 1 && $quiz->delay2 && $timenow <= $lastattempttime + $quiz->delay2) { + $tempunavailable = get_string('temporaryblocked', 'quiz') . + ''. userdate($lastattempt + $quiz->delay2). ''; + } -function quiz_review_allowed($quiz) { - // If not even responses are to be shown in review then we - // don't allow any review - if (!($quiz->review & QUIZ_REVIEW_RESPONSES)) { - return false; - } - if ((!$quiz->timeclose or time() < $quiz->timeclose) and !($quiz->review & QUIZ_REVIEW_OPEN)) { - return false; - } - if (($quiz->timeclose and time() > $quiz->timeclose) and !($quiz->review & QUIZ_REVIEW_CLOSED)) { - return false; - } - return true; -} + // If so, display a message and prevent the start button from appearing. + if ($tempunavailable) { + print_simple_box($tempunavailable, "center"); + $buttontext = ''; + } + } + } + // Actually print the start button. + if ($buttontext) { + $buttontext = htmlspecialchars($buttontext, ENT_QUOTES); -function print_start_quiz_button($quiz, $attempts, $numattempts, $unfinished, $cm) { - $strconfirmstartattempt = ''; - - if ($unfinished) { - $buttontext = get_string('continueattemptquiz', 'quiz'); - } else { - if ($numattempts) { - $buttontext = get_string('reattemptquiz', 'quiz'); - } else { - $buttontext = get_string('attemptquiznow', 'quiz'); - } - if ($quiz->timelimit && $quiz->attempts) { - $strconfirmstartattempt = addslashes(get_string('confirmstartattempttimelimit','quiz', $quiz->attempts)); - } else if ($quiz->timelimit) { - $strconfirmstartattempt = addslashes(get_string('confirmstarttimelimit','quiz')); - } else if ($quiz->attempts) { - $strconfirmstartattempt = addslashes(get_string('confirmstartattemptlimit','quiz', $quiz->attempts)); - } - } - $buttontext = htmlspecialchars($buttontext, ENT_QUOTES); + // Do we need a confirm javascript alert? + $strconfirmstartattempt = ''; + if ($quiz->timelimit && $quiz->attempts) { + $strconfirmstartattempt = addslashes(get_string('confirmstartattempttimelimit','quiz', $quiz->attempts)); + } else if ($quiz->timelimit) { + $strconfirmstartattempt = addslashes(get_string('confirmstarttimelimit','quiz')); + } else if ($quiz->attempts) { + $strconfirmstartattempt = addslashes(get_string('confirmstartattemptlimit','quiz', $quiz->attempts)); + } - if (!empty($quiz->popup)) { - $window = 'quizpopup'; - $windowoptions = "left=0, top=0, height='+window.screen.height+', " . - "width='+window.screen.width+', channelmode=yes, fullscreen=yes, " . - "scrollbars=yes, resizeable=no, directories=no, toolbar=no, " . - "titlebar=no, location=no, status=no, menubar=no"; - } else { - $window = '_self'; - $windowoptions = ''; - } + // Prepare options depending on whether the quiz should be a popup. + if (!empty($quiz->popup)) { + $window = 'quizpopup'; + $windowoptions = "left=0, top=0, height='+window.screen.height+', " . + "width='+window.screen.width+', channelmode=yes, fullscreen=yes, " . + "scrollbars=yes, resizeable=no, directories=no, toolbar=no, " . + "titlebar=no, location=no, status=no, menubar=no"; + } else { + $window = '_self'; + $windowoptions = ''; + } - $attempturl = "attempt.php?id=$cm->id"; - if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) { - $attempturl = sid_process_url($attempturl); - } + // Determine the URL to use. + $attempturl = "attempt.php?id=$cm->id"; + if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) { + $attempturl = sid_process_url($attempturl); + } + + // TODO eliminate this nasty JavaScript that prints the button. ?> @@ -411,27 +388,57 @@ document.write('\n"; - $link = $linktext; - - if ($attempt->timefinish && quiz_review_allowed($quiz)) { - $url = "review.php?q=$quiz->id&attempt=$attempt->id"; - if ($quiz->popup) { - $link = link_to_popup_window('/mod/quiz/' . $url, 'quizpopup', $linktext, '+window.screen.height+', '+window.screen.width+', '', $windowoptions, true); - } else { - $link = "$linktext"; + } else if (!$quiz->questions) { + print_heading(get_string("noquestions", "quiz")); } } - return $link; -} + // Should we not be seeing if we need to print right-hand-side blocks? -function end_page($course) { + // Finish the page. echo ''; print_footer($course); + +// Utility functions ================================================================= + +function quiz_review_allowed($quiz) { + return true; +} + +/** Make some text into a link to review the quiz, if that is appropriate. */ +function make_review_link($linktext, $quiz, $attempt) { + // If not even responses are to be shown in review then we don't allow any review + if (!($quiz->review & QUIZ_REVIEW_RESPONSES)) { + return $linktext; + } + + // If the quiz is still open, are reviews allowed? + if ((!$quiz->timeclose or time() < $quiz->timeclose) and !($quiz->review & QUIZ_REVIEW_OPEN)) { + // If not, don't link. + return $linktext; + } + + // If the quiz is closed, are reviews allowed? + if (($quiz->timeclose and time() > $quiz->timeclose) and !($quiz->review & QUIZ_REVIEW_CLOSED)) { + // If not, don't link. + return $linktext; + } + + // If the attempt is still open, don't link. + if ($attempt->timefinish) { + return $linktext; + } + + $url = "review.php?q=$quiz->id&attempt=$attempt->id"; + if ($quiz->popup) { + $windowoptions = "left=0, top=0, channelmode=yes, fullscreen=yes, scrollbars=yes, resizeable=no, directories=no, toolbar=no, titlebar=no, location=no, status=no, menubar=no"; + return link_to_popup_window('/mod/quiz/' . $url, 'quizpopup', $linktext, '+window.screen.height+', '+window.screen.width+', '', $windowoptions, true); + } else { + return "$linktext"; + } } ?>