public function load_choices()
 {
     global $CFG;
     if (is_array($this->choices)) {
         return true;
     }
     require_once $CFG->dirroot . '/mod/quiz/locallib.php';
     $this->choices = quiz_access_manager::get_browser_security_choices();
     return true;
 }
Beispiel #2
0
 /**
  * Used by {create()} and {create_from_usage_id()}.
  * @param array $conditions passed to $DB->get_record('quiz_attempts', $conditions).
  */
 protected static function create_helper($conditions)
 {
     global $DB;
     $attempt = $DB->get_record('quiz_attempts', $conditions, '*', MUST_EXIST);
     $quiz = quiz_access_manager::load_quiz_and_settings($attempt->quiz);
     $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
     $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id, false, MUST_EXIST);
     // Update quiz with override information.
     $quiz = quiz_update_effective_access($quiz, $attempt->userid);
     return new quiz_attempt($attempt, $quiz, $cm, $course);
 }
Beispiel #3
0
}

// Check login and get context.
require_login($course, false, $cm);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
require_capability('mod/quiz:view', $context);

// Cache some other capabilities we use several times.
$canattempt = has_capability('mod/quiz:attempt', $context);
$canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context);
$canpreview = has_capability('mod/quiz:preview', $context);

// Create an object to manage all the other (non-roles) access rules.
$timenow = time();
$quizobj = quiz::create($cm->instance, $USER->id);
$accessmanager = new quiz_access_manager($quizobj, $timenow,
        has_capability('mod/quiz:ignoretimelimits', $context, null, false));
$quiz = $quizobj->get_quiz();

// Log this request.
add_to_log($course->id, 'quiz', 'view', 'view.php?id=' . $cm->id, $quiz->id, $cm->id);

$completion = new completion_info($course);
$completion->set_module_viewed($cm);

// Initialize $PAGE, compute blocks
$PAGE->set_url('/mod/quiz/view.php', array('id' => $cm->id));

// Get this user's attempts.
$attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
$lastfinishedattempt = end($attempts);
$unfinished = false;
Beispiel #4
0
 /**
  * Return access information for a given attempt in a quiz.
  *
  * @param int $quizid quiz instance id
  * @param int $attemptid attempt id, 0 for the user last attempt if exists
  * @return array of warnings and the access information
  * @since Moodle 3.1
  * @throws  moodle_quiz_exception
  */
 public static function get_attempt_access_information($quizid, $attemptid = 0)
 {
     global $DB, $USER;
     $warnings = array();
     $params = array('quizid' => $quizid, 'attemptid' => $attemptid);
     $params = self::validate_parameters(self::get_attempt_access_information_parameters(), $params);
     list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']);
     $attempttocheck = 0;
     if (!empty($params['attemptid'])) {
         $attemptobj = quiz_attempt::create($params['attemptid']);
         if ($attemptobj->get_userid() != $USER->id) {
             throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
         }
         $attempttocheck = $attemptobj->get_attempt();
     }
     // Access manager now.
     $quizobj = quiz::create($cm->instance, $USER->id);
     $ignoretimelimits = has_capability('mod/quiz:ignoretimelimits', $context, null, false);
     $timenow = time();
     $accessmanager = new quiz_access_manager($quizobj, $timenow, $ignoretimelimits);
     $attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
     $lastfinishedattempt = end($attempts);
     if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) {
         $attempts[] = $unfinishedattempt;
         // Check if the attempt is now overdue. In that case the state will change.
         $quizobj->create_attempt_object($unfinishedattempt)->handle_if_time_expired(time(), false);
         if ($unfinishedattempt->state != quiz_attempt::IN_PROGRESS and $unfinishedattempt->state != quiz_attempt::OVERDUE) {
             $lastfinishedattempt = $unfinishedattempt;
         }
     }
     $numattempts = count($attempts);
     if (!$attempttocheck) {
         $attempttocheck = $unfinishedattempt ? $unfinishedattempt : $lastfinishedattempt;
     }
     $result = array();
     $result['isfinished'] = $accessmanager->is_finished($numattempts, $lastfinishedattempt);
     $result['preventnewattemptreasons'] = $accessmanager->prevent_new_attempt($numattempts, $lastfinishedattempt);
     if ($attempttocheck) {
         $endtime = $accessmanager->get_end_time($attempttocheck);
         $result['endtime'] = $endtime === false ? 0 : $endtime;
         $attemptid = $unfinishedattempt ? $unfinishedattempt->id : null;
         $result['ispreflightcheckrequired'] = $accessmanager->is_preflight_check_required($attemptid);
     }
     $result['warnings'] = $warnings;
     return $result;
 }
Beispiel #5
0
    if (!($cm = get_coursemodule_from_instance("quiz", $quiz->id, $course->id))) {
        print_error('invalidcoursemodule');
    }
}
// Check login and get context.
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/quiz:view', $context);
// Cache some other capabilities we use several times.
$canattempt = has_capability('mod/quiz:attempt', $context);
$canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context);
$canpreview = has_capability('mod/quiz:preview', $context);
// Create an object to manage all the other (non-roles) access rules.
$timenow = time();
$quizobj = quiz::create($cm->instance, $USER->id);
$accessmanager = new quiz_access_manager($quizobj, $timenow, has_capability('mod/quiz:ignoretimelimits', $context, null, false));
$quiz = $quizobj->get_quiz();
// Trigger course_module_viewed event and completion.
quiz_view($quiz, $course, $cm, $context);
// Initialize $PAGE, compute blocks.
$PAGE->set_url('/mod/quiz/view.php', array('id' => $cm->id));
// Create view object which collects all the information the renderer will need.
$viewobj = new mod_quiz_view_object();
$viewobj->accessmanager = $accessmanager;
$viewobj->canreviewmine = $canreviewmine;
// Get this user's attempts.
$attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
$lastfinishedattempt = end($attempts);
$unfinished = false;
$unfinishedattemptid = null;
if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) {
Beispiel #6
0
 public function validation($data, $files)
 {
     $errors = parent::validation($data, $files);
     // Check open and close times are consistent.
     if ($data['timeopen'] != 0 && $data['timeclose'] != 0 && $data['timeclose'] < $data['timeopen']) {
         $errors['timeclose'] = get_string('closebeforeopen', 'quiz');
     }
     // Check that the grace period is not too short.
     if ($data['overduehandling'] == 'graceperiod') {
         $graceperiodmin = get_config('quiz', 'graceperiodmin');
         if ($data['graceperiod'] <= $graceperiodmin) {
             $errors['graceperiod'] = get_string('graceperiodtoosmall', 'quiz', format_time($graceperiodmin));
         }
     }
     // Check the boundary value is a number or a percentage, and in range.
     $i = 0;
     while (!empty($data['feedbackboundaries'][$i])) {
         $boundary = trim($data['feedbackboundaries'][$i]);
         if (strlen($boundary) > 0) {
             if ($boundary[strlen($boundary) - 1] == '%') {
                 $boundary = trim(substr($boundary, 0, -1));
                 if (is_numeric($boundary)) {
                     $boundary = $boundary * $data['grade'] / 100.0;
                 } else {
                     $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorboundaryformat', 'quiz', $i + 1);
                 }
             } else {
                 if (!is_numeric($boundary)) {
                     $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorboundaryformat', 'quiz', $i + 1);
                 }
             }
         }
         if (is_numeric($boundary) && $boundary <= 0 || $boundary >= $data['grade']) {
             $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorboundaryoutofrange', 'quiz', $i + 1);
         }
         if (is_numeric($boundary) && $i > 0 && $boundary >= $data['feedbackboundaries'][$i - 1]) {
             $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrororder', 'quiz', $i + 1);
         }
         $data['feedbackboundaries'][$i] = $boundary;
         $i += 1;
     }
     $numboundaries = $i;
     // Check there is nothing in the remaining unused fields.
     if (!empty($data['feedbackboundaries'])) {
         for ($i = $numboundaries; $i < count($data['feedbackboundaries']); $i += 1) {
             if (!empty($data['feedbackboundaries'][$i]) && trim($data['feedbackboundaries'][$i]) != '') {
                 $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorjunkinboundary', 'quiz', $i + 1);
             }
         }
     }
     for ($i = $numboundaries + 1; $i < count($data['feedbacktext']); $i += 1) {
         if (!empty($data['feedbacktext'][$i]['text']) && trim($data['feedbacktext'][$i]['text']) != '') {
             $errors["feedbacktext[{$i}]"] = get_string('feedbackerrorjunkinfeedback', 'quiz', $i + 1);
         }
     }
     // Any other rule plugins.
     $errors = quiz_access_manager::validate_settings_form_fields($errors, $data, $files, $this);
     return $errors;
 }
Beispiel #7
0
    }
    if (!($cm = get_coursemodule_from_instance("quiz", $quiz->id, $course->id))) {
        print_error('invalidcoursemodule');
    }
}
/// Check login and get context.
require_login($course->id, false, $cm);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
require_capability('mod/quiz:view', $context);
/// Cache some other capabilites we use several times.
$canattempt = has_capability('mod/quiz:attempt', $context);
$canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context);
$canpreview = has_capability('mod/quiz:preview', $context);
/// Create an object to manage all the other (non-roles) access rules.
$timenow = time();
$accessmanager = new quiz_access_manager(new quiz($quiz, $cm, $course), $timenow, has_capability('mod/quiz:ignoretimelimits', $context, NULL, false));
/// If no questions have been set up yet redirect to edit.php
if (!$quiz->questions && has_capability('mod/quiz:manage', $context)) {
    redirect($CFG->wwwroot . '/mod/quiz/edit.php?cmid=' . $cm->id);
}
/// Log this request.
add_to_log($course->id, "quiz", "view", "view.php?id={$cm->id}", $quiz->id, $cm->id);
/// Initialize $PAGE, compute blocks
$PAGE->set_url('mod/quiz/view.php', array('id' => $cm->id));
$edit = optional_param('edit', -1, PARAM_BOOL);
if ($edit != -1 && $PAGE->user_allowed_editing()) {
    $USER->editing = $edit;
}
/// Print the page header
$bodytags = '';
if ($accessmanager->securewindow_required($canpreview)) {
Beispiel #8
0
 public function data_preprocessing(&$toform)
 {
     if (isset($toform['grade'])) {
         // Convert to a real number, so we don't get 0.0000.
         $toform['grade'] = $toform['grade'] + 0;
     }
     if (count($this->_feedbacks)) {
         $key = 0;
         foreach ($this->_feedbacks as $feedback) {
             $draftid = file_get_submitted_draft_itemid('feedbacktext[' . $key . ']');
             $toform['feedbacktext[' . $key . ']']['text'] = file_prepare_draft_area($draftid, $this->context->id, 'mod_quiz', 'feedback', !empty($feedback->id) ? (int) $feedback->id : null, null, $feedback->feedbacktext);
             $toform['feedbacktext[' . $key . ']']['format'] = $feedback->feedbacktextformat;
             $toform['feedbacktext[' . $key . ']']['itemid'] = $draftid;
             if ($toform['grade'] == 0) {
                 // When a quiz is un-graded, there can only be one lot of
                 // feedback. If the quiz previously had a maximum grade and
                 // several lots of feedback, we must now avoid putting text
                 // into input boxes that are disabled, but which the
                 // validation will insist are blank.
                 break;
             }
             if ($feedback->mingrade > 0) {
                 $toform['feedbackboundaries[' . $key . ']'] = 100.0 * $feedback->mingrade / $toform['grade'] . '%';
             }
             $key++;
         }
     }
     if (isset($toform['timelimit'])) {
         $toform['timelimitenable'] = $toform['timelimit'] > 0;
     }
     $this->preprocessing_review_settings($toform, 'during', mod_quiz_display_options::DURING);
     $this->preprocessing_review_settings($toform, 'immediately', mod_quiz_display_options::IMMEDIATELY_AFTER);
     $this->preprocessing_review_settings($toform, 'open', mod_quiz_display_options::LATER_WHILE_OPEN);
     $this->preprocessing_review_settings($toform, 'closed', mod_quiz_display_options::AFTER_CLOSE);
     $toform['attemptduring'] = true;
     $toform['overallfeedbackduring'] = false;
     // Password field - different in form to stop browsers that remember
     // passwords from getting confused.
     if (isset($toform['password'])) {
         $toform['quizpassword'] = $toform['password'];
         unset($toform['password']);
     }
     // Load any settings belonging to the access rules.
     if (!empty($toform['instance'])) {
         $accesssettings = quiz_access_manager::load_settings($toform['instance']);
         foreach ($accesssettings as $name => $value) {
             $toform[$name] = $value;
         }
     }
 }
Beispiel #9
0
/**
 * This function is called at the end of quiz_add_instance
 * and quiz_update_instance, to do the common processing.
 *
 * @param object $quiz the quiz object.
 */
function quiz_after_add_or_update($quiz) {
    global $DB;
    $cmid = $quiz->coursemodule;

    // We need to use context now, so we need to make sure all needed info is already in db.
    $DB->set_field('course_modules', 'instance', $quiz->id, array('id'=>$cmid));
    $context = context_module::instance($cmid);

    // Save the feedback.
    $DB->delete_records('quiz_feedback', array('quizid' => $quiz->id));

    for ($i = 0; $i <= $quiz->feedbackboundarycount; $i++) {
        $feedback = new stdClass();
        $feedback->quizid = $quiz->id;
        $feedback->feedbacktext = $quiz->feedbacktext[$i]['text'];
        $feedback->feedbacktextformat = $quiz->feedbacktext[$i]['format'];
        $feedback->mingrade = $quiz->feedbackboundaries[$i];
        $feedback->maxgrade = $quiz->feedbackboundaries[$i - 1];
        $feedback->id = $DB->insert_record('quiz_feedback', $feedback);
        $feedbacktext = file_save_draft_area_files((int)$quiz->feedbacktext[$i]['itemid'],
                $context->id, 'mod_quiz', 'feedback', $feedback->id,
                array('subdirs' => false, 'maxfiles' => -1, 'maxbytes' => 0),
                $quiz->feedbacktext[$i]['text']);
        $DB->set_field('quiz_feedback', 'feedbacktext', $feedbacktext,
                array('id' => $feedback->id));
    }

    // Store any settings belonging to the access rules.
    quiz_access_manager::save_settings($quiz);

    // Update the events relating to this quiz.
    quiz_update_events($quiz);

    // Update related grade item.
    quiz_grade_item_update($quiz);
}
Beispiel #10
0
 /**
  * Returns a list of quizzes in a provided list of courses,
  * if no list is provided all quizzes that the user can view will be returned.
  *
  * @param array $courseids Array of course ids
  * @return array of quizzes details
  * @since Moodle 3.1
  */
 public static function get_quizzes_by_courses($courseids = array())
 {
     global $USER;
     $warnings = array();
     $returnedquizzes = array();
     $params = array('courseids' => $courseids);
     $params = self::validate_parameters(self::get_quizzes_by_courses_parameters(), $params);
     $mycourses = array();
     if (empty($params['courseids'])) {
         $mycourses = enrol_get_my_courses();
         $params['courseids'] = array_keys($mycourses);
     }
     // Ensure there are courseids to loop through.
     if (!empty($params['courseids'])) {
         list($courses, $warnings) = external_util::validate_courses($params['courseids'], $mycourses);
         // Get the quizzes in this course, this function checks users visibility permissions.
         // We can avoid then additional validate_context calls.
         $quizzes = get_all_instances_in_courses("quiz", $courses);
         foreach ($quizzes as $quiz) {
             $context = context_module::instance($quiz->coursemodule);
             // Update quiz with override information.
             $quiz = quiz_update_effective_access($quiz, $USER->id);
             // Entry to return.
             $quizdetails = array();
             // First, we return information that any user can see in the web interface.
             $quizdetails['id'] = $quiz->id;
             $quizdetails['coursemodule'] = $quiz->coursemodule;
             $quizdetails['course'] = $quiz->course;
             $quizdetails['name'] = external_format_string($quiz->name, $context->id);
             if (has_capability('mod/quiz:view', $context)) {
                 // Format intro.
                 list($quizdetails['intro'], $quizdetails['introformat']) = external_format_text($quiz->intro, $quiz->introformat, $context->id, 'mod_quiz', 'intro', null);
                 $viewablefields = array('timeopen', 'timeclose', 'grademethod', 'section', 'visible', 'groupmode', 'groupingid');
                 $timenow = time();
                 $quizobj = quiz::create($quiz->id, $USER->id);
                 $accessmanager = new quiz_access_manager($quizobj, $timenow, has_capability('mod/quiz:ignoretimelimits', $context, null, false));
                 // Fields the user could see if have access to the quiz.
                 if (!$accessmanager->prevent_access()) {
                     // Some times this function returns just empty.
                     $hasfeedback = quiz_has_feedback($quiz);
                     $quizdetails['hasfeedback'] = !empty($hasfeedback) ? 1 : 0;
                     $quizdetails['hasquestions'] = (int) $quizobj->has_questions();
                     $quizdetails['autosaveperiod'] = get_config('quiz', 'autosaveperiod');
                     $additionalfields = array('timelimit', 'attempts', 'attemptonlast', 'grademethod', 'decimalpoints', 'questiondecimalpoints', 'reviewattempt', 'reviewcorrectness', 'reviewmarks', 'reviewspecificfeedback', 'reviewgeneralfeedback', 'reviewrightanswer', 'reviewoverallfeedback', 'questionsperpage', 'navmethod', 'sumgrades', 'grade', 'browsersecurity', 'delay1', 'delay2', 'showuserpicture', 'showblocks', 'completionattemptsexhausted', 'completionpass', 'overduehandling', 'graceperiod', 'preferredbehaviour', 'canredoquestions');
                     $viewablefields = array_merge($viewablefields, $additionalfields);
                 }
                 // Fields only for managers.
                 if (has_capability('moodle/course:manageactivities', $context)) {
                     $additionalfields = array('shuffleanswers', 'timecreated', 'timemodified', 'password', 'subnet');
                     $viewablefields = array_merge($viewablefields, $additionalfields);
                 }
                 foreach ($viewablefields as $field) {
                     $quizdetails[$field] = $quiz->{$field};
                 }
             }
             $returnedquizzes[] = $quizdetails;
         }
     }
     $result = array();
     $result['quizzes'] = $returnedquizzes;
     $result['warnings'] = $warnings;
     return $result;
 }
Beispiel #11
0
/**
 * Obtains the automatic completion state for this quiz on any conditions
 * in quiz settings, such as if all attempts are used or a certain grade is achieved.
 *
 * @param object $course Course
 * @param object $cm Course-module
 * @param int $userid User ID
 * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
 * @return bool True if completed, false if not. (If no conditions, then return
 *   value depends on comparison type)
 */
function quiz_get_completion_state($course, $cm, $userid, $type)
{
    global $DB;
    global $CFG;
    $quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST);
    if (!$quiz->completionattemptsexhausted && !$quiz->completionpass) {
        return $type;
    }
    // Check if the user has used up all attempts.
    if ($quiz->completionattemptsexhausted) {
        $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true);
        if ($attempts) {
            $lastfinishedattempt = end($attempts);
            $context = context_module::instance($cm->id);
            $quizobj = quiz::create($quiz->id, $userid);
            $accessmanager = new quiz_access_manager($quizobj, time(), has_capability('mod/quiz:ignoretimelimits', $context, $userid, false));
            if ($accessmanager->is_finished(count($attempts), $lastfinishedattempt)) {
                return true;
            }
        }
    }
    // Check for passing grade.
    if ($quiz->completionpass) {
        require_once $CFG->libdir . '/gradelib.php';
        $item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $cm->instance, 'outcomeid' => null));
        if ($item) {
            $grades = grade_grade::fetch_users_grades($item, array($userid), false);
            if (!empty($grades[$userid])) {
                return $grades[$userid]->is_passed($item);
            }
        }
    }
    return false;
}
function prepareQuizAttempt($q)
{
    global $DB;
    if ($id) {
        if (!($cm = get_coursemodule_from_id('quiz', $id))) {
            print_error('invalidcoursemodule');
        }
        if (!($course = $DB->get_record('course', array('id' => $cm->course)))) {
            print_error('coursemisconf');
        }
        if (!($quiz = $DB->get_record('quiz', array('id' => $cm->instance)))) {
            print_error('invalidcoursemodule');
        }
    } else {
        if (!($quiz = $DB->get_record('quiz', array('id' => $q)))) {
            print_error('invalidquizid', 'quiz');
        }
        if (!($course = $DB->get_record('course', array('id' => $quiz->course)))) {
            print_error('invalidcourseid');
        }
        if (!($cm = get_coursemodule_from_instance("quiz", $quiz->id, $course->id))) {
            print_error('invalidcoursemodule');
        }
    }
    /// Check login and get context.
    require_login($course->id, false, $cm);
    $context = get_context_instance(CONTEXT_MODULE, $cm->id);
    require_capability('mod/quiz:view', $context);
    /// Cache some other capabilites we use several times.
    $canattempt = has_capability('mod/quiz:attempt', $context);
    $canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context);
    $canpreview = has_capability('mod/quiz:preview', $context);
    /// Create an object to manage all the other (non-roles) access rules.
    $timenow = time();
    $accessmanager = new quiz_access_manager(new quiz($quiz, $cm, $course), $timenow, has_capability('mod/quiz:ignoretimelimits', $context, NULL, false));
    /// Print information about the student's best score for this quiz if possible.
    $moreattempts = $unfinished || !$accessmanager->is_finished($numattempts, $lastfinishedattempt);
    /// Determine if we should be showing a start/continue attempt button,
    /// or a button to go back to the course page.
    print_box_start('quizattempt');
    $buttontext = '';
    // This will be set something if as start/continue attempt button should appear.
    if (!$quiz->questions) {
        print_heading(get_string("noquestions", "quiz"));
    } else {
        if ($unfinished) {
            if ($canattempt) {
                $buttontext = get_string('continueattemptquiz', 'quiz');
            } else {
                if ($canpreview) {
                    $buttontext = get_string('continuepreview', 'quiz');
                }
            }
        } else {
            if ($canattempt) {
                $messages = $accessmanager->prevent_new_attempt($numattempts, $lastfinishedattempt);
                if ($messages) {
                    $accessmanager->print_messages($messages);
                } else {
                    if ($numattempts == 0) {
                        $buttontext = get_string('attemptquiznow', 'quiz');
                    } else {
                        $buttontext = get_string('reattemptquiz', 'quiz');
                    }
                }
            } else {
                if ($canpreview) {
                    $buttontext = get_string('previewquiznow', 'quiz');
                }
            }
        }
        // If, so far, we think a button should be printed, so check if they will be allowed to access it.
        if ($buttontext) {
            if (!$moreattempts) {
                $buttontext = '';
            } else {
                if ($canattempt && ($messages = $accessmanager->prevent_access())) {
                    $accessmanager->print_messages($messages);
                    $buttontext = '';
                }
            }
        }
    }
    /// Now actually print the appropriate button.
    if ($buttontext) {
        $accessmanager->print_start_attempt_button($canpreview, $buttontext, $unfinished);
    } else {
        print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id);
    }
    print_box_end();
}
 public function test_cannot_review_message()
 {
     $quiz = new stdClass();
     $quiz->reviewattempt = 0x10010;
     $quiz->timeclose = 0;
     $quiz->attempts = 0;
     $quiz->questions = '1,2,0,3,4,0';
     $cm = new stdClass();
     $cm->id = 123;
     $quizobj = new quiz($quiz, $cm, new stdClass(), false);
     $am = new quiz_access_manager($quizobj, time(), false);
     $this->assertEqual('', $am->cannot_review_message(mod_quiz_display_options::DURING));
     $this->assertEqual('', $am->cannot_review_message(mod_quiz_display_options::IMMEDIATELY_AFTER));
     $this->assertEqual(get_string('noreview', 'quiz'), $am->cannot_review_message(mod_quiz_display_options::LATER_WHILE_OPEN));
     $this->assertEqual(get_string('noreview', 'quiz'), $am->cannot_review_message(mod_quiz_display_options::AFTER_CLOSE));
     $closetime = time() + 10000;
     $quiz->timeclose = $closetime;
     $quizobj = new quiz($quiz, $cm, new stdClass(), false);
     $am = new quiz_access_manager($quizobj, time(), false);
     $this->assertEqual(get_string('noreviewuntil', 'quiz', userdate($closetime)), $am->cannot_review_message(mod_quiz_display_options::LATER_WHILE_OPEN));
 }
Beispiel #14
0
 public function validation($data, $files)
 {
     $errors = parent::validation($data, $files);
     // Check open and close times are consistent.
     if ($data['timeopen'] != 0 && $data['timeclose'] != 0 && $data['timeclose'] < $data['timeopen']) {
         $errors['timeclose'] = get_string('closebeforeopen', 'quiz');
     }
     // Check that the grace period is not too short.
     if ($data['overduehandling'] == 'graceperiod') {
         $graceperiodmin = get_config('quiz', 'graceperiodmin');
         if ($data['graceperiod'] <= $graceperiodmin) {
             $errors['graceperiod'] = get_string('graceperiodtoosmall', 'quiz', format_time($graceperiodmin));
         }
     }
     if (array_key_exists('completion', $data) && $data['completion'] == COMPLETION_TRACKING_AUTOMATIC) {
         $completionpass = isset($data['completionpass']) ? $data['completionpass'] : $this->current->completionpass;
         // Show an error if require passing grade was selected and the grade to pass was set to 0.
         if ($completionpass && (empty($data['gradepass']) || grade_floatval($data['gradepass']) == 0)) {
             if (isset($data['completionpass'])) {
                 $errors['completionpassgroup'] = get_string('gradetopassnotset', 'quiz');
             } else {
                 $errors['gradepass'] = get_string('gradetopassmustbeset', 'quiz');
             }
         }
     }
     // Check the boundary value is a number or a percentage, and in range.
     $i = 0;
     while (!empty($data['feedbackboundaries'][$i])) {
         $boundary = trim($data['feedbackboundaries'][$i]);
         if (strlen($boundary) > 0) {
             if ($boundary[strlen($boundary) - 1] == '%') {
                 $boundary = trim(substr($boundary, 0, -1));
                 if (is_numeric($boundary)) {
                     $boundary = $boundary * $data['grade'] / 100.0;
                 } else {
                     $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorboundaryformat', 'quiz', $i + 1);
                 }
             } else {
                 if (!is_numeric($boundary)) {
                     $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorboundaryformat', 'quiz', $i + 1);
                 }
             }
         }
         if (is_numeric($boundary) && $boundary <= 0 || $boundary >= $data['grade']) {
             $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorboundaryoutofrange', 'quiz', $i + 1);
         }
         if (is_numeric($boundary) && $i > 0 && $boundary >= $data['feedbackboundaries'][$i - 1]) {
             $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrororder', 'quiz', $i + 1);
         }
         $data['feedbackboundaries'][$i] = $boundary;
         $i += 1;
     }
     $numboundaries = $i;
     // Check there is nothing in the remaining unused fields.
     if (!empty($data['feedbackboundaries'])) {
         for ($i = $numboundaries; $i < count($data['feedbackboundaries']); $i += 1) {
             if (!empty($data['feedbackboundaries'][$i]) && trim($data['feedbackboundaries'][$i]) != '') {
                 $errors["feedbackboundaries[{$i}]"] = get_string('feedbackerrorjunkinboundary', 'quiz', $i + 1);
             }
         }
     }
     for ($i = $numboundaries + 1; $i < count($data['feedbacktext']); $i += 1) {
         if (!empty($data['feedbacktext'][$i]['text']) && trim($data['feedbacktext'][$i]['text']) != '') {
             $errors["feedbacktext[{$i}]"] = get_string('feedbackerrorjunkinfeedback', 'quiz', $i + 1);
         }
     }
     // Any other rule plugins.
     $errors = quiz_access_manager::validate_settings_form_fields($errors, $data, $files, $this);
     return $errors;
 }
Beispiel #15
0
/**
 * Validate permissions for creating a new attempt and start a new preview attempt if required.
 *
 * @param  quiz $quizobj quiz object
 * @param  quiz_access_manager $accessmanager quiz access manager
 * @param  bool $forcenew whether was required to start a new preview attempt
 * @param  int $page page to jump to in the attempt
 * @param  bool $redirect whether to redirect or throw exceptions (for web or ws usage)
 * @return array an array containing the attempt information, access error messages and the page to jump to in the attempt
 * @throws moodle_quiz_exception
 * @since Moodle 3.1
 */
function quiz_validate_new_attempt(quiz $quizobj, quiz_access_manager $accessmanager, $forcenew, $page, $redirect)
{
    global $DB, $USER;
    $timenow = time();
    if ($quizobj->is_preview_user() && $forcenew) {
        $accessmanager->current_attempt_finished();
    }
    // Check capabilities.
    if (!$quizobj->is_preview_user()) {
        $quizobj->require_capability('mod/quiz:attempt');
    }
    // Check to see if a new preview was requested.
    if ($quizobj->is_preview_user() && $forcenew) {
        // To force the creation of a new preview, we mark the current attempt (if any)
        // as finished. It will then automatically be deleted below.
        $DB->set_field('quiz_attempts', 'state', quiz_attempt::FINISHED, array('quiz' => $quizobj->get_quizid(), 'userid' => $USER->id));
    }
    // Look for an existing attempt.
    $attempts = quiz_get_user_attempts($quizobj->get_quizid(), $USER->id, 'all', true);
    $lastattempt = end($attempts);
    $attemptnumber = null;
    // If an in-progress attempt exists, check password then redirect to it.
    if ($lastattempt && ($lastattempt->state == quiz_attempt::IN_PROGRESS || $lastattempt->state == quiz_attempt::OVERDUE)) {
        $currentattemptid = $lastattempt->id;
        $messages = $accessmanager->prevent_access();
        // If the attempt is now overdue, deal with that.
        $quizobj->create_attempt_object($lastattempt)->handle_if_time_expired($timenow, true);
        // And, if the attempt is now no longer in progress, redirect to the appropriate place.
        if ($lastattempt->state == quiz_attempt::ABANDONED || $lastattempt->state == quiz_attempt::FINISHED) {
            if ($redirect) {
                redirect($quizobj->review_url($lastattempt->id));
            } else {
                throw new moodle_quiz_exception($quizobj, 'attemptalreadyclosed');
            }
        }
        // If the page number was not explicitly in the URL, go to the current page.
        if ($page == -1) {
            $page = $lastattempt->currentpage;
        }
    } else {
        while ($lastattempt && $lastattempt->preview) {
            $lastattempt = array_pop($attempts);
        }
        // Get number for the next or unfinished attempt.
        if ($lastattempt) {
            $attemptnumber = $lastattempt->attempt + 1;
        } else {
            $lastattempt = false;
            $attemptnumber = 1;
        }
        $currentattemptid = null;
        $messages = $accessmanager->prevent_access() + $accessmanager->prevent_new_attempt(count($attempts), $lastattempt);
        if ($page == -1) {
            $page = 0;
        }
    }
    return array($currentattemptid, $attemptnumber, $lastattempt, $messages, $page);
}
    }
    if (!($cm = get_coursemodule_from_instance("quiz", $quiz->id, $course->id))) {
        print_error('invalidcoursemodule');
    }
}
// Check login and get context.
require_login($course->id, false, $cm);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
require_capability('mod/quiz:view', $context);
// Cache some other capabilities we use several times.
$canattempt = has_capability('mod/quiz:attempt', $context);
$canreviewmine = has_capability('mod/quiz:reviewmyattempts', $context);
$canpreview = has_capability('mod/quiz:preview', $context);
// Create an object to manage all the other (non-roles) access rules.
$timenow = time();
$accessmanager = new quiz_access_manager(quiz::create($quiz->id, $USER->id), $timenow, has_capability('mod/quiz:ignoretimelimits', $context, null, false));
// Log this request.
add_to_log($course->id, 'quiz', 'view', 'view.php?id=' . $cm->id, $quiz->id, $cm->id);
$completion = new completion_info($course);
$completion->set_module_viewed($cm);
// Initialize $PAGE, compute blocks
$PAGE->set_url('/mod/quiz/view.php', array('id' => $cm->id));
$edit = optional_param('edit', -1, PARAM_BOOL);
if ($edit != -1 && $PAGE->user_allowed_editing()) {
    $USER->editing = $edit;
}
// Update the quiz with overrides for the current user
$quiz = quiz_update_effective_access($quiz, $USER->id);
// Get this user's attempts.
$attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
$lastfinishedattempt = end($attempts);