From e63faf2b500cbccd5ad6f7ba5d2f3e4ea1efafec Mon Sep 17 00:00:00 2001 From: tjhunt Date: Thu, 20 Sep 2007 15:14:24 +0000 Subject: [PATCH] MDL-10376 - since roles and capabilities came along, the quiz was not very gracious if you were logged in as guest, or really logged in on the server, but using guest access to look a a particular course, or were enrolled in a course, but in a role that did not let you preview or attempt quizzes. This patch should clean up the logic for all these cases. --- lang/en_utf8/quiz.php | 1 + mod/quiz/attempt.php | 38 ++-- mod/quiz/view.php | 445 +++++++++++++++++++++--------------------- 3 files changed, 239 insertions(+), 245 deletions(-) diff --git a/lang/en_utf8/quiz.php b/lang/en_utf8/quiz.php index 0923b81234..e0a1a65c18 100644 --- a/lang/en_utf8/quiz.php +++ b/lang/en_utf8/quiz.php @@ -586,6 +586,7 @@ $string['xml'] = 'Moodle XML format'; $string['xmlimportnoname'] = 'Missing question name in xml file'; $string['xmlimportnoquestion'] = 'Missing question text in xml file'; $string['xmltypeunsupported'] = 'Question type $a is not supported by xml import'; +$string['youneedtoenrol'] = 'You need to enrol in this course before you can attempt this quiz'; $string['yourfinalgradeis'] = 'Your final grade for this quiz is $a.'; $string['zerosignificantfiguresnotallowed'] = 'The correct answer cannot have zero significant figures!'; diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php index 3f1ae33448..3adf670312 100644 --- a/mod/quiz/attempt.php +++ b/mod/quiz/attempt.php @@ -62,13 +62,17 @@ // if no questions have been set up yet redirect to edit.php if (!$quiz->questions and has_capability('mod/quiz:manage', $context)) { - redirect('edit.php?cmid='.$cm->id); + redirect($CFG->wwwroot . '/mod/quiz/edit.php?quizid=' . $quiz->id); } - // Get number for the next or unfinished attempt + if (!$ispreviewing) { + require_capability('mod/quiz:attempt', $context); + } + +/// Get number for the next or unfinished attempt if(!$attemptnumber = (int)get_field_sql('SELECT MAX(attempt)+1 FROM ' . - "{$CFG->prefix}quiz_attempts WHERE quiz = '{$quiz->id}' AND " . - "userid = '{$USER->id}' AND timefinish > 0 AND preview != 1")) { + "{$CFG->prefix}quiz_attempts WHERE quiz = '{$quiz->id}' AND " . + "userid = '{$USER->id}' AND timefinish > 0 AND preview != 1")) { $attemptnumber = 1; } @@ -76,22 +80,14 @@ $strquizzes = get_string("modulenameplural", "quiz"); $popup = $quiz->popup && !$ispreviewing; // Controls whether this is shown in a javascript-protected window. - // Check availability - if (isguestuser()) { - print_heading(get_string('guestsno', 'quiz')); - if (empty($popup)) { - print_footer($course); - } - exit; - } - +/// Check number of attempts $numberofpreviousattempts = count_records_select('quiz_attempts', "quiz = '{$quiz->id}' AND " . "userid = '{$USER->id}' AND timefinish > 0 AND preview != 1"); if ($quiz->attempts and $numberofpreviousattempts >= $quiz->attempts) { error(get_string('nomoreattempts', 'quiz'), "view.php?id={$cm->id}"); } - // Check subnet access +/// Check subnet access if ($quiz->subnet and !address_in_subnet(getremoteaddr(), $quiz->subnet)) { if ($ispreviewing) { notify(get_string('subnetnotice', 'quiz')); @@ -100,7 +96,7 @@ } } - // Check password access +/// Check password access if ($ispreviewing && $forcenew) { unset($SESSION->passwordcheckedquizzes[$quiz->id]); } @@ -171,7 +167,7 @@ } } - // Load attempt or create a new attempt if there is no unfinished one +/// Load attempt or create a new attempt if there is no unfinished one if ($ispreviewing and $forcenew) { // teacher wants a new preview // so we set a finish time on the current attempt (if any). @@ -324,7 +320,7 @@ // We have now finished processing form data } - // Finish attempt if requested +/// Finish attempt if requested if ($finishattempt) { // Set the attempt to be finished @@ -364,7 +360,7 @@ "$quiz->id", $cm->id); } - // Update the quiz attempt and the overall grade for the quiz +/// Update the quiz attempt and the overall grade for the quiz if ($responses || $finishattempt) { if (!update_record('quiz_attempts', $attempt)) { error('Failed to save the current quiz attempt!'); @@ -392,7 +388,7 @@ if ($finishattempt) { unset($SESSION->passwordcheckedquizzes[$quiz->id]); - redirect('review.php?attempt='.$attempt->id, 0); + redirect($CFG->wwwroot . '/mod/quiz/review.php?attempt='.$attempt->id, 0); } /// Print the quiz page //////////////////////////////////////////////////////// @@ -461,7 +457,7 @@ // Add a hidden field with the quiz id echo '
'; - // Print the navigation panel if required +/// Print the navigation panel if required $numpages = quiz_number_of_pages($attempt->layout); if ($numpages > 1) { ?> @@ -495,7 +491,7 @@ $number += $questions[$i]->length; } - // Print the submit buttons +/// Print the submit buttons $strconfirmattempt = addslashes(get_string("confirmclose", "quiz")); $onclick = "return confirm('$strconfirmattempt')"; echo "
\n"; diff --git a/mod/quiz/view.php b/mod/quiz/view.php index 25dc6dc453..36cf5bc041 100644 --- a/mod/quiz/view.php +++ b/mod/quiz/view.php @@ -133,14 +133,6 @@ } // 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 (isguestuser()) { $loginurl = $CFG->wwwroot.'/login/index.php'; if (!empty($CFG->loginhttps)) { @@ -149,20 +141,31 @@ notice_yesno('

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

\n\n

" . get_string('liketologin') . '

', $loginurl, get_referer(false)); + finish_page($course); } - if (has_capability('mod/quiz:attempt', $context)) { + if (!(has_capability('mod/quiz:attempt', $context) || has_capability('mod/quiz:preview', $context))) { + print_box('

' . get_string('youneedtoenrol', 'quiz') . '

' . + print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id, true) . + '

', 'generalbox', 'notice'); + finish_page($course); + } - // 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); + // 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); + + // Print table with existing attempts + if ($attempts) { - $mygrade = quiz_get_best_grade($quiz, $USER->id); + print_heading('Summary of your previous attempts'); // Get some strings. $strattempt = get_string("attempt", "quiz"); @@ -172,234 +175,229 @@ $strmarks = get_string('marks', 'quiz'); $strfeedback = get_string('feedback', 'quiz'); - // Print table with existing attempts - if ($attempts) { - - print_heading('Summary of your previous attempts'); - - // Work out which columns we need, taking account what data is available in each attempt. - list($someoptions, $alloptions) = quiz_get_combined_reviewoptions($quiz, $attempts, $context); - - $gradecolumn = $someoptions->scores && $quiz->grade && $quiz->sumgrades; - $markcolumn = $gradecolumn && ($quiz->grade != $quiz->sumgrades); - $overallstats = $alloptions->scores; + // Work out which columns we need, taking account what data is available in each attempt. + list($someoptions, $alloptions) = quiz_get_combined_reviewoptions($quiz, $attempts, $context); + + $gradecolumn = $someoptions->scores && $quiz->grade && $quiz->sumgrades; + $markcolumn = $gradecolumn && ($quiz->grade != $quiz->sumgrades); + $overallstats = $alloptions->scores; + + $feedbackcolumn = quiz_has_feedback($quiz->id); + $overallfeedback = $feedbackcolumn && $alloptions->overallfeedback; + + // prepare table header + $table->class = 'generaltable quizattemptsummary'; + $table->head = array($strattempt, $strtimecompleted); + $table->align = array("center", "left"); + $table->size = array("", ""); + if ($markcolumn) { + $table->head[] = "$strmarks / $quiz->sumgrades"; + $table->align[] = 'center'; + $table->size[] = ''; + } + if ($gradecolumn) { + $table->head[] = "$strgrade / $quiz->grade"; + $table->align[] = 'center'; + $table->size[] = ''; + } + if ($feedbackcolumn) { + $table->head[] = $strfeedback; + $table->align[] = 'left'; + $table->size[] = ''; + } + if (isset($quiz->showtimetaken)) { + $table->head[] = $strtimetaken; + $table->align[] = 'left'; + $table->size[] = ''; + } - $feedbackcolumn = quiz_has_feedback($quiz->id); - $overallfeedback = $feedbackcolumn && $alloptions->overallfeedback; + // One row for each attempt + foreach ($attempts as $attempt) { + $attemptoptions = quiz_get_reviewoptions($quiz, $attempt, $context); + $row = array(); - // prepare table header - $table->class = 'generaltable quizattemptsummary'; - $table->head = array($strattempt, $strtimecompleted); - $table->align = array("center", "left"); - $table->size = array("", ""); - if ($markcolumn) { - $table->head[] = "$strmarks / $quiz->sumgrades"; - $table->align[] = 'center'; - $table->size[] = ''; - } - if ($gradecolumn) { - $table->head[] = "$strgrade / $quiz->grade"; - $table->align[] = 'center'; - $table->size[] = ''; - } - if ($feedbackcolumn) { - $table->head[] = $strfeedback; - $table->align[] = 'left'; - $table->size[] = ''; - } - if (isset($quiz->showtimetaken)) { - $table->head[] = $strtimetaken; - $table->align[] = 'left'; - $table->size[] = ''; + // Add the attempt number, making it a link, if appropriate. + if ($attempt->preview) { + $row[] = make_review_link(get_string('preview', 'quiz'), $quiz, $attempt); + } else { + $row[] = make_review_link($attempt->attempt, $quiz, $attempt); } - // 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. - if ($attempt->preview) { - $row[] = make_review_link(get_string('preview', 'quiz'), $quiz, $attempt); - } else { - $row[] = make_review_link($attempt->attempt, $quiz, $attempt); - } - - // prepare strings for time taken and date completed + // 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. $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. - $timetaken = ''; - $datecompleted = ''; - } - $row[] = $datecompleted; + } + $row[] = $datecompleted; - if ($markcolumn) { - if ($attemptoptions->scores) { - $row[] = make_review_link(round($attempt->sumgrades, $quiz->decimalpoints), $quiz, $attempt); - } else { - $row[] = ''; - } + if ($markcolumn) { + if ($attemptoptions->scores) { + $row[] = make_review_link(round($attempt->sumgrades, $quiz->decimalpoints), $quiz, $attempt); + } else { + $row[] = ''; } + } - // Ouside the if because we may be showing feedback but not grades. - $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz); - - if ($gradecolumn) { - if ($attemptoptions->scores) { - $formattedgrade = $attemptgrade; - // highlight the highest grade if appropriate - if ($overallstats && $numattempts > 1 && !is_null($mygrade) && $attemptgrade == $mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) { - $table->rowclass[$attempt->attempt] = 'bestrow'; - } + // Ouside the if because we may be showing feedback but not grades. + $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz); - $row[] = make_review_link($formattedgrade, $quiz, $attempt); - } else { - $row[] = ''; + if ($gradecolumn) { + if ($attemptoptions->scores) { + $formattedgrade = $attemptgrade; + // highlight the highest grade if appropriate + if ($overallstats && $numattempts > 1 && !is_null($mygrade) && $attemptgrade == $mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) { + $table->rowclass[$attempt->attempt] = 'bestrow'; } - } - if ($feedbackcolumn) { - if ($attemptoptions->overallfeedback) { - $row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id); - } else { - $row[] = ''; - } + $row[] = make_review_link($formattedgrade, $quiz, $attempt); + } else { + $row[] = ''; } + } - if (isset($quiz->showtimetaken)) { - $row[] = $timetaken; + if ($feedbackcolumn) { + if ($attemptoptions->overallfeedback) { + $row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id); + } else { + $row[] = ''; } + } - $table->data[$attempt->attempt] = $row; - } // End of loop over attempts. - print_table($table); - } + if (isset($quiz->showtimetaken)) { + $row[] = $timetaken; + } - // 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")); - } + $table->data[$attempt->attempt] = $row; + } // End of loop over attempts. + print_table($table); + } - if ($numattempts && $quiz->sumgrades && !is_null($mygrade)) { - if ($overallstats) { - if ($available && $moreattempts) { - $a = new stdClass; - $a->method = quiz_get_grading_option_name($quiz->grademethod); - $a->mygrade = $mygrade; - $a->quizgrade = $quiz->grade; - print_heading(get_string('gradesofar', 'quiz', $a)); - } else { - print_heading(get_string('yourfinalgradeis', 'quiz', "$mygrade / $quiz->grade")); - } - } + // 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 ($overallfeedback) { - echo '

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

'; + if ($numattempts && $quiz->sumgrades && !is_null($mygrade)) { + if ($overallstats) { + if ($available && $moreattempts) { + $a = new stdClass; + $a->method = quiz_get_grading_option_name($quiz->grademethod); + $a->mygrade = $mygrade; + $a->quizgrade = $quiz->grade; + print_heading(get_string('gradesofar', 'quiz', $a)); + } else { + print_heading(get_string('yourfinalgradeis', 'quiz', "$mygrade / $quiz->grade")); } } - // Print a button to start/continue an attempt, if appropriate. - if (!$quiz->questions) { - print_heading(get_string("noquestions", "quiz")); + if ($overallfeedback) { + echo '

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

'; + } + } - } else if ($available && $moreattempts) { - echo "
"; - echo "
"; + // Print a button to start/continue an attempt, if appropriate. + if (!$quiz->questions) { + print_heading(get_string("noquestions", "quiz")); - if ($unfinished) { - if (has_capability('mod/quiz:preview', $context)) { - $buttontext = get_string('continuepreview', 'quiz'); - } else { - $buttontext = get_string('continueattemptquiz', 'quiz'); - } + } else if ($available && $moreattempts) { + echo "
"; + echo "
"; + + if ($unfinished) { + if (has_capability('mod/quiz:preview', $context)) { + $buttontext = get_string('continuepreview', 'quiz'); } else { + $buttontext = get_string('continueattemptquiz', 'quiz'); + } + } else { - // Work out the appropriate button caption. - if (has_capability('mod/quiz:preview', $context)) { - $buttontext = get_string('previewquiznow', 'quiz'); - } else if ($numattempts == 0) { - $buttontext = get_string('attemptquiznow', 'quiz'); - } else { - $buttontext = get_string('reattemptquiz', 'quiz'); - } + // Work out the appropriate button caption. + if (has_capability('mod/quiz:preview', $context)) { + $buttontext = get_string('previewquiznow', 'quiz'); + } else if ($numattempts == 0) { + $buttontext = get_string('attemptquiznow', 'quiz'); + } else { + $buttontext = get_string('reattemptquiz', 'quiz'); + } - // Work out if the quiz is temporarily unavailable because of the delay option. - if (!empty($attempts)) { - $tempunavailable = ''; - $lastattempt = end($attempts); - $lastattempttime = $lastattempt->timefinish; - if ($numattempts == 1 && $quiz->delay1 && $timenow <= $lastattempttime + $quiz->delay1) { - $tempunavailable = get_string('temporaryblocked', 'quiz') . - ' '. userdate($lastattempttime + $quiz->delay1). ''; - } else if ($numattempts > 1 && $quiz->delay2 && $timenow <= $lastattempttime + $quiz->delay2) { - $tempunavailable = get_string('temporaryblocked', 'quiz') . - ' '. userdate($lastattempttime + $quiz->delay2). ''; - } + // Work out if the quiz is temporarily unavailable because of the delay option. + if (!empty($attempts)) { + $tempunavailable = ''; + $lastattempt = end($attempts); + $lastattempttime = $lastattempt->timefinish; + if ($numattempts == 1 && $quiz->delay1 && $timenow <= $lastattempttime + $quiz->delay1) { + $tempunavailable = get_string('temporaryblocked', 'quiz') . + ' '. userdate($lastattempttime + $quiz->delay1). ''; + } else if ($numattempts > 1 && $quiz->delay2 && $timenow <= $lastattempttime + $quiz->delay2) { + $tempunavailable = get_string('temporaryblocked', 'quiz') . + ' '. userdate($lastattempttime + $quiz->delay2). ''; + } - // If so, display a message and prevent the start button from appearing. - if ($tempunavailable) { - print_simple_box($tempunavailable, "center"); - print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id); - $buttontext = ''; - } + // If so, display a message and prevent the start button from appearing. + if ($tempunavailable) { + print_simple_box($tempunavailable, "center"); + print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id); + $buttontext = ''; } } + } - // Actually print the start button. - if ($buttontext) { - $buttontext = htmlspecialchars($buttontext, ENT_QUOTES); - - // Do we need a confirm javascript alert? - if ($unfinished) { - $strconfirmstartattempt = ''; - } else 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)); - } else { - $strconfirmstartattempt = ''; - } + // Actually print the start button. + if ($buttontext) { + $buttontext = htmlspecialchars($buttontext, ENT_QUOTES); - // 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 = ''; - } + // Do we need a confirm javascript alert? + if ($unfinished) { + $strconfirmstartattempt = ''; + } else 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)); + } else { + $strconfirmstartattempt = ''; + } - // Determine the URL to use. - $attempturl = "attempt.php?id=$cm->id"; - if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) { - $attempturl = sid_process_url($attempturl); - } - - echo ''; + // 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 = ''; + } + + // Determine the URL to use. + $attempturl = "attempt.php?id=$cm->id"; + if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) { + $attempturl = sid_process_url($attempturl); + } + + echo ''; ?>
\n"; - } else { - print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id); } + + echo "
\n"; + } else { + print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id); } // Should we not be seeing if we need to print right-hand-side blocks? - // Finish the page. - if (!empty($THEME->customcorners)) print_custom_corners_end(); - echo ''; - print_footer($course); + finish_page($course); // Utility functions ================================================================= -function quiz_review_allowed($quiz) { - return true; +function finish_page($course) { + if (!empty($THEME->customcorners)) print_custom_corners_end(); + echo ''; + print_footer($course); + exit; } /** Make some text into a link to review the quiz, if that is appropriate. */ -- 2.39.5