diff --git a/lang/en_utf8/quiz.php b/lang/en_utf8/quiz.php index 0923b81234e..e0a1a65c185 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 3f1ae33448e..3adf6703120 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 25dc6dc4530..36cf5bc041c 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); + $mygrade = quiz_get_best_grade($quiz, $USER->id); + + // Print table with existing attempts + if ($attempts) { + + 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) { + // 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); - print_heading('Summary of your previous attempts'); + $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); + $feedbackcolumn = quiz_has_feedback($quiz->id); + $overallfeedback = $feedbackcolumn && $alloptions->overallfeedback; - $gradecolumn = $someoptions->scores && $quiz->grade && $quiz->sumgrades; - $markcolumn = $gradecolumn && ($quiz->grade != $quiz->sumgrades); - $overallstats = $alloptions->scores; + // 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); + } + $row[] = $datecompleted; + + if ($markcolumn) { + if ($attemptoptions->scores) { + $row[] = make_review_link(round($attempt->sumgrades, $quiz->decimalpoints), $quiz, $attempt); } else { - // Something wheird happened. - $timetaken = ''; - $datecompleted = ''; - } - $row[] = $datecompleted; - - 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'; - } - - $row[] = make_review_link($formattedgrade, $quiz, $attempt); - } else { - $row[] = ''; - } - } - - if ($feedbackcolumn) { - if ($attemptoptions->overallfeedback) { - $row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id); - } else { - $row[] = ''; - } - } - - if (isset($quiz->showtimetaken)) { - $row[] = $timetaken; - } - - $table->data[$attempt->attempt] = $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 && !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")); + $row[] = ''; } } - if ($overallfeedback) { - echo '

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

'; - } - } + // Ouside the if because we may be showing feedback but not grades. + $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz); - // Print a button to start/continue an attempt, if appropriate. - if (!$quiz->questions) { - print_heading(get_string("noquestions", "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'; + } - } else if ($available && $moreattempts) { - echo "
"; - echo "
"; - - if ($unfinished) { - if (has_capability('mod/quiz:preview', $context)) { - $buttontext = get_string('continuepreview', 'quiz'); + $row[] = make_review_link($formattedgrade, $quiz, $attempt); } else { - $buttontext = get_string('continueattemptquiz', 'quiz'); + $row[] = ''; } + } + + if ($feedbackcolumn) { + if ($attemptoptions->overallfeedback) { + $row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id); + } else { + $row[] = ''; + } + } + + if (isset($quiz->showtimetaken)) { + $row[] = $timetaken; + } + + $table->data[$attempt->attempt] = $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 && !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")); + } + } - // 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'); - } + if ($overallfeedback) { + echo '

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

'; + } + } - // 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). ''; - } + // Print a button to start/continue an attempt, if appropriate. + if (!$quiz->questions) { + print_heading(get_string("noquestions", "quiz")); - // 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 = ''; - } - } + } 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'); } - // 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 = ''; + // 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). ''; } - // 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 = ''; + // 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 = ''; } + } + } - // 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 ''; + // 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 = ''; + } + + // 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. */