mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 13:38:32 +01:00
Merge branch 'MDL-76614' of https://github.com/timhunt/moodle
This commit is contained in:
commit
6f1c9d3b53
@ -16,6 +16,9 @@
|
||||
|
||||
namespace tool_recyclebin;
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Recycle bin course tests.
|
||||
*
|
||||
@ -237,7 +240,7 @@ class course_bin_test extends \advanced_testcase {
|
||||
$attempts = quiz_get_user_attempts($cm->instance, $student->id);
|
||||
$this->assertEquals(1, count($attempts));
|
||||
$attempt = array_pop($attempts);
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
$this->assertEquals($student->id, $attemptobj->get_userid());
|
||||
$this->assertEquals(true, $attemptobj->is_finished());
|
||||
}
|
||||
@ -300,17 +303,17 @@ class course_bin_test extends \advanced_testcase {
|
||||
quiz_add_quiz_question($numq->id, $quiz);
|
||||
|
||||
// Create quiz attempt.
|
||||
$quizobj = \quiz::create($quiz->id, $student->id);
|
||||
$quizobj = \mod_quiz\quiz_settings::create($quiz->id, $student->id);
|
||||
$quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
|
||||
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
|
||||
$timenow = time();
|
||||
$attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id);
|
||||
quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
|
||||
quiz_attempt_save_started($quizobj, $quba, $attempt);
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
$tosubmit = array(1 => array('answer' => '0'));
|
||||
$attemptobj->process_submitted_actions($timenow, false, $tosubmit);
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
$attemptobj->process_finish($timenow, false);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
namespace core_backup;
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
@ -379,7 +381,7 @@ class restore_stepslib_date_test extends \restore_date_testcase {
|
||||
// Make a user to do the quiz.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$quizobj = \quiz::create($quiz->id, $user1->id);
|
||||
$quizobj = \mod_quiz\quiz_settings::create($quiz->id, $user1->id);
|
||||
|
||||
// Start the attempt.
|
||||
$quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
|
||||
@ -393,7 +395,7 @@ class restore_stepslib_date_test extends \restore_date_testcase {
|
||||
quiz_attempt_save_started($quizobj, $quba, $attempt);
|
||||
|
||||
// Process some responses from the student.
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
|
||||
$prefix1 = $quba->get_field_prefix(1);
|
||||
$prefix2 = $quba->get_field_prefix(2);
|
||||
@ -404,7 +406,7 @@ class restore_stepslib_date_test extends \restore_date_testcase {
|
||||
$attemptobj->process_submitted_actions($timenow, false, $tosubmit);
|
||||
|
||||
// Finish the attempt.
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
$attemptobj->process_finish($timenow, false);
|
||||
|
||||
$questionattemptstepdates = [];
|
||||
@ -419,7 +421,7 @@ class restore_stepslib_date_test extends \restore_date_testcase {
|
||||
|
||||
// Get the quiz for this new restored course.
|
||||
$quizdata = $DB->get_record('quiz', ['course' => $newcourseid]);
|
||||
$quizobj = \quiz::create($quizdata->id, $user1->id);
|
||||
$quizobj = \mod_quiz\quiz_settings::create($quizdata->id, $user1->id);
|
||||
|
||||
$questionusage = $DB->get_record('question_usages', [
|
||||
'component' => 'mod_quiz',
|
||||
|
@ -841,7 +841,7 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
|
||||
/**
|
||||
* Given a list of ids, load the basic information about a set of questions from
|
||||
* the questions table. The $join and $extrafields arguments can be used together
|
||||
* to pull in extra data. See, for example, the usage in mod/quiz/attemptlib.php, and
|
||||
* to pull in extra data. See, for example, the usage in {@see \mod_quiz\quiz_attempt}, and
|
||||
* read the code below to see how the SQL is assembled. Throws exceptions on error.
|
||||
*
|
||||
* @param array $questionids array of question ids to load. If null, then all
|
||||
|
@ -15,549 +15,11 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Classes to enforce the various access rules that can apply to a quiz.
|
||||
* File only retained to prevent fatal errors in code that tries to require/include this.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-76612 delete this file as part of Moodle 4.6 development.
|
||||
* @deprecated This file is no longer required in Moodle 4.2+.
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_quiz\question\display_options;
|
||||
|
||||
/**
|
||||
* This class keeps track of the various access rules that apply to a particular
|
||||
* quiz, with convinient methods for seeing whether access is allowed.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.2
|
||||
*/
|
||||
class quiz_access_manager {
|
||||
/** @var quiz the quiz settings object. */
|
||||
protected $quizobj;
|
||||
/** @var int the time to be considered as 'now'. */
|
||||
protected $timenow;
|
||||
/** @var array of quiz_access_rule_base. */
|
||||
protected $rules = array();
|
||||
|
||||
/**
|
||||
* Create an instance for a particular quiz.
|
||||
* @param object $quizobj An instance of the class quiz from attemptlib.php.
|
||||
* The quiz we will be controlling access to.
|
||||
* @param int $timenow The time to use as 'now'.
|
||||
* @param bool $canignoretimelimits Whether this user is exempt from time
|
||||
* limits (has_capability('mod/quiz:ignoretimelimits', ...)).
|
||||
*/
|
||||
public function __construct($quizobj, $timenow, $canignoretimelimits) {
|
||||
$this->quizobj = $quizobj;
|
||||
$this->timenow = $timenow;
|
||||
$this->rules = $this->make_rules($quizobj, $timenow, $canignoretimelimits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all the rules relevant to a particular quiz.
|
||||
* @param quiz $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
* @param bool $canignoretimelimits whether the current user is exempt from
|
||||
* time limits by the mod/quiz:ignoretimelimits capability.
|
||||
* @return array of {@link quiz_access_rule_base}s.
|
||||
*/
|
||||
protected function make_rules($quizobj, $timenow, $canignoretimelimits) {
|
||||
|
||||
$rules = array();
|
||||
foreach (self::get_rule_classes() as $ruleclass) {
|
||||
$rule = $ruleclass::make($quizobj, $timenow, $canignoretimelimits);
|
||||
if ($rule) {
|
||||
$rules[$ruleclass] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
$superceededrules = array();
|
||||
foreach ($rules as $rule) {
|
||||
$superceededrules += $rule->get_superceded_rules();
|
||||
}
|
||||
|
||||
foreach ($superceededrules as $superceededrule) {
|
||||
unset($rules['quizaccess_' . $superceededrule]);
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of all the installed rule class names.
|
||||
*/
|
||||
protected static function get_rule_classes() {
|
||||
return core_component::get_plugin_list_with_class('quizaccess', '', 'rule.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any form fields that the access rules require to the settings form.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism, becuase all their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param mod_quiz_mod_form $quizform the quiz settings form that is being built.
|
||||
* @param MoodleQuickForm $mform the wrapped MoodleQuickForm.
|
||||
*/
|
||||
public static function add_settings_form_fields(
|
||||
mod_quiz_mod_form $quizform, MoodleQuickForm $mform) {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$rule::add_settings_form_fields($quizform, $mform);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The the options for the Browser security settings menu.
|
||||
*
|
||||
* @return array key => lang string.
|
||||
*/
|
||||
public static function get_browser_security_choices() {
|
||||
$options = array('-' => get_string('none', 'quiz'));
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$options += $rule::get_browser_security_choices();
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the data from any form fields added using {@link add_settings_form_fields()}.
|
||||
* @param array $errors the errors found so far.
|
||||
* @param array $data the submitted form data.
|
||||
* @param array $files information about any uploaded files.
|
||||
* @param mod_quiz_mod_form $quizform the quiz form object.
|
||||
* @return array $errors the updated $errors array.
|
||||
*/
|
||||
public static function validate_settings_form_fields(array $errors,
|
||||
array $data, $files, mod_quiz_mod_form $quizform) {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$errors = $rule::validate_settings_form_fields($errors, $data, $files, $quizform);
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any submitted settings when the quiz settings form is submitted.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism because their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param object $quiz the data from the quiz form, including $quiz->id
|
||||
* which is the id of the quiz being saved.
|
||||
*/
|
||||
public static function save_settings($quiz) {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$rule::save_settings($quiz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete any rule-specific settings when the quiz is deleted.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism because their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param object $quiz the data from the database, including $quiz->id
|
||||
* which is the id of the quiz being deleted.
|
||||
* @since Moodle 2.7.1, 2.6.4, 2.5.7
|
||||
*/
|
||||
public static function delete_settings($quiz) {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$rule::delete_settings($quiz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL for loading all the access settings in one go.
|
||||
* @param int $quizid the quiz id.
|
||||
* @param string $basefields initial part of the select list.
|
||||
* @return array with two elements, the sql and the placeholder values.
|
||||
* If $basefields is '' then you must allow for the possibility that
|
||||
* there is no data to load, in which case this method returns $sql = ''.
|
||||
*/
|
||||
protected static function get_load_sql($quizid, $rules, $basefields) {
|
||||
$allfields = $basefields;
|
||||
$alljoins = '{quiz} quiz';
|
||||
$allparams = array('quizid' => $quizid);
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
list($fields, $joins, $params) = $rule::get_settings_sql($quizid);
|
||||
if ($fields) {
|
||||
if ($allfields) {
|
||||
$allfields .= ', ';
|
||||
}
|
||||
$allfields .= $fields;
|
||||
}
|
||||
if ($joins) {
|
||||
$alljoins .= ' ' . $joins;
|
||||
}
|
||||
if ($params) {
|
||||
$allparams += $params;
|
||||
}
|
||||
}
|
||||
|
||||
if ($allfields === '') {
|
||||
return array('', array());
|
||||
}
|
||||
|
||||
return array("SELECT $allfields FROM $alljoins WHERE quiz.id = :quizid", $allparams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load any settings required by the access rules. We try to do this with
|
||||
* a single DB query.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism, becuase all their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param int $quizid the quiz id.
|
||||
* @return array setting value name => value. The value names should all
|
||||
* start with the name of the corresponding plugin to avoid collisions.
|
||||
*/
|
||||
public static function load_settings($quizid) {
|
||||
global $DB;
|
||||
|
||||
$rules = self::get_rule_classes();
|
||||
list($sql, $params) = self::get_load_sql($quizid, $rules, '');
|
||||
|
||||
if ($sql) {
|
||||
$data = (array) $DB->get_record_sql($sql, $params);
|
||||
} else {
|
||||
$data = array();
|
||||
}
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
$data += $rule::get_extra_settings($quizid);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the quiz settings and any settings required by the access rules.
|
||||
* We try to do this with a single DB query.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism, becuase all their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param int $quizid the quiz id.
|
||||
* @return object mdl_quiz row with extra fields.
|
||||
*/
|
||||
public static function load_quiz_and_settings($quizid) {
|
||||
global $DB;
|
||||
|
||||
$rules = self::get_rule_classes();
|
||||
list($sql, $params) = self::get_load_sql($quizid, $rules, 'quiz.*');
|
||||
$quiz = $DB->get_record_sql($sql, $params, MUST_EXIST);
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
foreach ($rule::get_extra_settings($quizid) as $name => $value) {
|
||||
$quiz->$name = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $quiz;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array the class names of all the active rules. Mainly useful for
|
||||
* debugging.
|
||||
*/
|
||||
public function get_active_rule_names() {
|
||||
$classnames = array();
|
||||
foreach ($this->rules as $rule) {
|
||||
$classnames[] = get_class($rule);
|
||||
}
|
||||
return $classnames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates an array of messages.
|
||||
* @param array $messages the current list of messages.
|
||||
* @param string|array $new the new messages or messages.
|
||||
* @return array the updated array of messages.
|
||||
*/
|
||||
protected function accumulate_messages($messages, $new) {
|
||||
if (is_array($new)) {
|
||||
$messages = array_merge($messages, $new);
|
||||
} else if (is_string($new) && $new) {
|
||||
$messages[] = $new;
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a description of the rules that apply to this quiz, such
|
||||
* as is shown at the top of the quiz view page. Note that not all
|
||||
* rules consider themselves important enough to output a description.
|
||||
*
|
||||
* @return array an array of description messages which may be empty. It
|
||||
* would be sensible to output each one surrounded by <p> tags.
|
||||
*/
|
||||
public function describe_rules() {
|
||||
$result = array();
|
||||
foreach ($this->rules as $rule) {
|
||||
$result = $this->accumulate_messages($result, $rule->description());
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not a user should be allowed to start a new attempt at this quiz now.
|
||||
* If there are any restrictions in force now, return an array of reasons why access
|
||||
* should be blocked. If access is OK, return false.
|
||||
*
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object|false $lastattempt information about the user's last completed attempt.
|
||||
* if there is not a previous attempt, the false is passed.
|
||||
* @return mixed An array of reason why access is not allowed, or an empty array
|
||||
* (== false) if access should be allowed.
|
||||
*/
|
||||
public function prevent_new_attempt($numprevattempts, $lastattempt) {
|
||||
$reasons = array();
|
||||
foreach ($this->rules as $rule) {
|
||||
$reasons = $this->accumulate_messages($reasons,
|
||||
$rule->prevent_new_attempt($numprevattempts, $lastattempt));
|
||||
}
|
||||
return $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user should be blocked from starting a new attempt or continuing
|
||||
* an attempt now. If there are any restrictions in force now, return an array
|
||||
* of reasons why access should be blocked. If access is OK, return false.
|
||||
*
|
||||
* @return mixed An array of reason why access is not allowed, or an empty array
|
||||
* (== false) if access should be allowed.
|
||||
*/
|
||||
public function prevent_access() {
|
||||
$reasons = array();
|
||||
foreach ($this->rules as $rule) {
|
||||
$reasons = $this->accumulate_messages($reasons, $rule->prevent_access());
|
||||
}
|
||||
return $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return bool whether a check is required before the user starts/continues
|
||||
* their attempt.
|
||||
*/
|
||||
public function is_preflight_check_required($attemptid) {
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->is_preflight_check_required($attemptid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the form required to do the pre-flight checks.
|
||||
* @param moodle_url $url the form action URL.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return mod_quiz_preflight_check_form the form.
|
||||
*/
|
||||
public function get_preflight_check_form(moodle_url $url, $attemptid) {
|
||||
// This form normally wants POST submissins. However, it also needs to
|
||||
// accept GET submissions. Since formslib is strict, we have to detect
|
||||
// which case we are in, and set the form property appropriately.
|
||||
$method = 'post';
|
||||
if (!empty($_GET['_qf__mod_quiz_preflight_check_form'])) {
|
||||
$method = 'get';
|
||||
}
|
||||
return new mod_quiz_preflight_check_form($url->out_omit_querystring(),
|
||||
array('rules' => $this->rules, 'quizobj' => $this->quizobj,
|
||||
'attemptid' => $attemptid, 'hidden' => $url->params()), $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* The pre-flight check has passed. This is a chance to record that fact in
|
||||
* some way.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
*/
|
||||
public function notify_preflight_check_passed($attemptid) {
|
||||
foreach ($this->rules as $rule) {
|
||||
$rule->notify_preflight_check_passed($attemptid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the rules that the current attempt is finished. This is use, for example
|
||||
* by the password rule, to clear the flag in the session.
|
||||
*/
|
||||
public function current_attempt_finished() {
|
||||
foreach ($this->rules as $rule) {
|
||||
$rule->current_attempt_finished();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do any of the rules mean that this student will no be allowed any further attempts at this
|
||||
* quiz. Used, for example, to change the label by the grade displayed on the view page from
|
||||
* 'your current grade is' to 'your final grade is'.
|
||||
*
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return bool true if there is no way the user will ever be allowed to attempt
|
||||
* this quiz again.
|
||||
*/
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->is_finished($numprevattempts, $lastattempt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the attempt (review or summary) page with any properties required
|
||||
* by the access rules.
|
||||
*
|
||||
* @param moodle_page $page the page object to initialise.
|
||||
*/
|
||||
public function setup_attempt_page($page) {
|
||||
foreach ($this->rules as $rule) {
|
||||
$rule->setup_attempt_page($page);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute when the attempt must be submitted.
|
||||
*
|
||||
* @param object $attempt the data from the relevant quiz_attempts row.
|
||||
* @return int|false the attempt close time.
|
||||
* False if there is no limit.
|
||||
*/
|
||||
public function get_end_time($attempt) {
|
||||
$timeclose = false;
|
||||
foreach ($this->rules as $rule) {
|
||||
$ruletimeclose = $rule->end_time($attempt);
|
||||
if ($ruletimeclose !== false && ($timeclose === false || $ruletimeclose < $timeclose)) {
|
||||
$timeclose = $ruletimeclose;
|
||||
}
|
||||
}
|
||||
return $timeclose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute what should be displayed to the user for time remaining in this attempt.
|
||||
*
|
||||
* @param object $attempt the data from the relevant quiz_attempts row.
|
||||
* @param int $timenow the time to consider as 'now'.
|
||||
* @return int|false the number of seconds remaining for this attempt.
|
||||
* False if no limit should be displayed.
|
||||
*/
|
||||
public function get_time_left_display($attempt, $timenow) {
|
||||
$timeleft = false;
|
||||
foreach ($this->rules as $rule) {
|
||||
$ruletimeleft = $rule->time_left_display($attempt, $timenow);
|
||||
if ($ruletimeleft !== false && ($timeleft === false || $ruletimeleft < $timeleft)) {
|
||||
$timeleft = $ruletimeleft;
|
||||
}
|
||||
}
|
||||
return $timeleft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bolean if this quiz should only be shown to students in a popup window.
|
||||
*/
|
||||
public function attempt_must_be_in_popup() {
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->attempt_must_be_in_popup()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array any options that are required for showing the attempt page
|
||||
* in a popup window.
|
||||
*/
|
||||
public function get_popup_options() {
|
||||
$options = array();
|
||||
foreach ($this->rules as $rule) {
|
||||
$options += $rule->get_popup_options();
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the user back to the quiz view page. Normally this is just a redirect, but
|
||||
* If we were in a secure window, we close this window, and reload the view window we came from.
|
||||
*
|
||||
* This method does not return;
|
||||
*
|
||||
* @param mod_quiz_renderer $output the quiz renderer.
|
||||
* @param string $message optional message to output while redirecting.
|
||||
*/
|
||||
public function back_to_view_page($output, $message = '') {
|
||||
if ($this->attempt_must_be_in_popup()) {
|
||||
echo $output->close_attempt_popup($this->quizobj->view_url(), $message);
|
||||
die();
|
||||
} else {
|
||||
redirect($this->quizobj->view_url(), $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make some text into a link to review the quiz, if that is appropriate.
|
||||
*
|
||||
* @param string $linktext some text.
|
||||
* @param object $attempt the attempt object
|
||||
* @return string some HTML, the $linktext either unmodified or wrapped in a
|
||||
* link to the review page.
|
||||
*/
|
||||
public function make_review_link($attempt, $reviewoptions, $output) {
|
||||
|
||||
// If the attempt is still open, don't link.
|
||||
if (in_array($attempt->state, array(quiz_attempt::IN_PROGRESS, quiz_attempt::OVERDUE))) {
|
||||
return $output->no_review_message('');
|
||||
}
|
||||
|
||||
$when = quiz_attempt_state($this->quizobj->get_quiz(), $attempt);
|
||||
$reviewoptions = display_options::make_from_quiz(
|
||||
$this->quizobj->get_quiz(), $when);
|
||||
|
||||
if (!$reviewoptions->attempt) {
|
||||
return $output->no_review_message($this->quizobj->cannot_review_message($when, true));
|
||||
|
||||
} else {
|
||||
return $output->review_link($this->quizobj->review_url($attempt->id),
|
||||
$this->attempt_must_be_in_popup(), $this->get_popup_options());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the preflight checks using the given data in all the rules supporting them.
|
||||
*
|
||||
* @param array $data passed data for validation
|
||||
* @param array $files un-used, Moodle seems to not support it anymore
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return array of errors, empty array means no erros
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function validate_preflight_check($data, $files, $attemptid) {
|
||||
$errors = array();
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->is_preflight_check_required($attemptid)) {
|
||||
$errors = $rule->validate_preflight_check($data, $files, $errors, $attemptid);
|
||||
}
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER);
|
||||
|
@ -15,58 +15,11 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines the form that limits student's access to attempt a quiz.
|
||||
* File only retained to prevent fatal errors in code that tries to require/include this.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-76612 delete this file as part of Moodle 4.6 development.
|
||||
* @deprecated This file is no longer required in Moodle 4.2+.
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* A form that limits student's access to attempt a quiz.
|
||||
*
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_quiz_preflight_check_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
$mform = $this->_form;
|
||||
$this->_form->updateAttributes(array('id' => 'mod_quiz_preflight_form'));
|
||||
|
||||
foreach ($this->_customdata['hidden'] as $name => $value) {
|
||||
if ($name === 'sesskey') {
|
||||
continue;
|
||||
}
|
||||
$mform->addElement('hidden', $name, $value);
|
||||
$mform->setType($name, PARAM_INT);
|
||||
}
|
||||
|
||||
foreach ($this->_customdata['rules'] as $rule) {
|
||||
if ($rule->is_preflight_check_required($this->_customdata['attemptid'])) {
|
||||
$rule->add_preflight_check_form_fields($this, $mform,
|
||||
$this->_customdata['attemptid']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->add_action_buttons(true, get_string('startattempt', 'quiz'));
|
||||
$this->set_display_vertical();
|
||||
$mform->setDisableShortforms();
|
||||
}
|
||||
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
$timenow = time();
|
||||
$accessmanager = $this->_customdata['quizobj']->get_access_manager($timenow);
|
||||
$errors = array_merge($errors, $accessmanager->validate_preflight_check($data, $files, $this->_customdata['attemptid']));
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER);
|
||||
|
@ -15,322 +15,13 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Base class for rules that restrict the ability to attempt a quiz.
|
||||
* File only retained to prevent fatal errors in code that tries to require/include this.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-76612 delete this file as part of Moodle 4.6 development.
|
||||
* @deprecated This file is no longer required in Moodle 4.2+.
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER);
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
|
||||
/**
|
||||
* A base class that defines the interface for the various quiz access rules.
|
||||
* Most of the methods are defined in a slightly unnatural way because we either
|
||||
* want to say that access is allowed, or explain the reason why it is block.
|
||||
* Therefore instead of is_access_allowed(...) we have prevent_access(...) that
|
||||
* return false if access is permitted, or a string explanation (which is treated
|
||||
* as true) if access should be blocked. Slighly unnatural, but actually the easiest
|
||||
* way to implement this.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.2
|
||||
*/
|
||||
abstract class quiz_access_rule_base {
|
||||
/** @var stdClass the quiz settings. */
|
||||
protected $quiz;
|
||||
/** @var quiz the quiz object. */
|
||||
protected $quizobj;
|
||||
/** @var int the time to use as 'now'. */
|
||||
protected $timenow;
|
||||
|
||||
/**
|
||||
* Create an instance of this rule for a particular quiz.
|
||||
* @param quiz $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
*/
|
||||
public function __construct($quizobj, $timenow) {
|
||||
$this->quizobj = $quizobj;
|
||||
$this->quiz = $quizobj->get_quiz();
|
||||
$this->timenow = $timenow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an appropriately configured instance of this rule, if it is applicable
|
||||
* to the given quiz, otherwise return null.
|
||||
* @param quiz $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
* @param bool $canignoretimelimits whether the current user is exempt from
|
||||
* time limits by the mod/quiz:ignoretimelimits capability.
|
||||
* @return quiz_access_rule_base|null the rule, if applicable, else null.
|
||||
*/
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not a user should be allowed to start a new attempt at this quiz now.
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return string false if access should be allowed, a message explaining the
|
||||
* reason if access should be prevented.
|
||||
*/
|
||||
public function prevent_new_attempt($numprevattempts, $lastattempt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user should be blocked from starting a new attempt or continuing
|
||||
* an attempt now.
|
||||
* @return string false if access should be allowed, a message explaining the
|
||||
* reason if access should be prevented.
|
||||
*/
|
||||
public function prevent_access() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return bool whether a check is required before the user starts/continues
|
||||
* their attempt.
|
||||
*/
|
||||
public function is_preflight_check_required($attemptid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any field you want to pre-flight check form. You should only do
|
||||
* something here if {@link is_preflight_check_required()} returned true.
|
||||
*
|
||||
* @param mod_quiz_preflight_check_form $quizform the form being built.
|
||||
* @param MoodleQuickForm $mform The wrapped MoodleQuickForm.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
*/
|
||||
public function add_preflight_check_form_fields(mod_quiz_preflight_check_form $quizform,
|
||||
MoodleQuickForm $mform, $attemptid) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the pre-flight check form submission. You should only do
|
||||
* something here if {@link is_preflight_check_required()} returned true.
|
||||
*
|
||||
* If the form validates, the user will be allowed to continue.
|
||||
*
|
||||
* @param array $data the submitted form data.
|
||||
* @param array $files any files in the submission.
|
||||
* @param array $errors the list of validation errors that is being built up.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return array the update $errors array;
|
||||
*/
|
||||
public function validate_preflight_check($data, $files, $errors, $attemptid) {
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* The pre-flight check has passed. This is a chance to record that fact in
|
||||
* some way.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
*/
|
||||
public function notify_preflight_check_passed($attemptid) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the current attempt at the quiz is finished. This is
|
||||
* used, for example by the password rule, to clear the flag in the session.
|
||||
*/
|
||||
public function current_attempt_finished() {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* Information, such as might be shown on the quiz view page, relating to this restriction.
|
||||
* There is no obligation to return anything. If it is not appropriate to tell students
|
||||
* about this rule, then just return ''.
|
||||
* @return mixed a message, or array of messages, explaining the restriction
|
||||
* (may be '' if no message is appropriate).
|
||||
*/
|
||||
public function description() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* If this rule can determine that this user will never be allowed another attempt at
|
||||
* this quiz, then return true. This is used so we can know whether to display a
|
||||
* final grade on the view page. This will only be called if there is not a currently
|
||||
* active attempt for this user.
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return bool true if this rule means that this user will never be allowed another
|
||||
* attempt at this quiz.
|
||||
*/
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If, because of this rule, the user has to finish their attempt by a certain time,
|
||||
* you should override this method to return the attempt end time.
|
||||
* @param object $attempt the current attempt
|
||||
* @return mixed the attempt close time, or false if there is no close time.
|
||||
*/
|
||||
public function end_time($attempt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user should be shown a different amount of time than $timenow - $this->end_time(), then
|
||||
* override this method. This is useful if the time remaining is large enough to be omitted.
|
||||
* @param object $attempt the current attempt
|
||||
* @param int $timenow the time now. We don't use $this->timenow, so we can
|
||||
* give the user a more accurate indication of how much time is left.
|
||||
* @return mixed the time left in seconds (can be negative) or false if there is no limit.
|
||||
*/
|
||||
public function time_left_display($attempt, $timenow) {
|
||||
$endtime = $this->end_time($attempt);
|
||||
if ($endtime === false) {
|
||||
return false;
|
||||
}
|
||||
return $endtime - $timenow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean whether this rule requires that the attemp (and review)
|
||||
* pages must be displayed in a pop-up window.
|
||||
*/
|
||||
public function attempt_must_be_in_popup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array any options that are required for showing the attempt page
|
||||
* in a popup window.
|
||||
*/
|
||||
public function get_popup_options() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the attempt (review or summary) page with any special extra
|
||||
* properties required by this rule. securewindow rule is an example of where
|
||||
* this is used.
|
||||
*
|
||||
* @param moodle_page $page the page object to initialise.
|
||||
*/
|
||||
public function setup_attempt_page($page) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible for one rule to override other rules.
|
||||
*
|
||||
* The aim is that third-party rules should be able to replace sandard rules
|
||||
* if they want. See, for example MDL-13592.
|
||||
*
|
||||
* @return array plugin names of other rules that this one replaces.
|
||||
* For example array('ipaddress', 'password').
|
||||
*/
|
||||
public function get_superceded_rules() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any fields that this rule requires to the quiz settings form. This
|
||||
* method is called from {@link mod_quiz_mod_form::definition()}, while the
|
||||
* security seciton is being built.
|
||||
* @param mod_quiz_mod_form $quizform the quiz settings form that is being built.
|
||||
* @param MoodleQuickForm $mform the wrapped MoodleQuickForm.
|
||||
*/
|
||||
public static function add_settings_form_fields(
|
||||
mod_quiz_mod_form $quizform, MoodleQuickForm $mform) {
|
||||
// By default do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the data from any form fields added using {@link add_settings_form_fields()}.
|
||||
* @param array $errors the errors found so far.
|
||||
* @param array $data the submitted form data.
|
||||
* @param array $files information about any uploaded files.
|
||||
* @param mod_quiz_mod_form $quizform the quiz form object.
|
||||
* @return array $errors the updated $errors array.
|
||||
*/
|
||||
public static function validate_settings_form_fields(array $errors,
|
||||
array $data, $files, mod_quiz_mod_form $quizform) {
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array key => lang string any choices to add to the quiz Browser
|
||||
* security settings menu.
|
||||
*/
|
||||
public static function get_browser_security_choices() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any submitted settings when the quiz settings form is submitted. This
|
||||
* is called from {@link quiz_after_add_or_update()} in lib.php.
|
||||
* @param object $quiz the data from the quiz form, including $quiz->id
|
||||
* which is the id of the quiz being saved.
|
||||
*/
|
||||
public static function save_settings($quiz) {
|
||||
// By default do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete any rule-specific settings when the quiz is deleted. This is called
|
||||
* from {@link quiz_delete_instance()} in lib.php.
|
||||
* @param object $quiz the data from the database, including $quiz->id
|
||||
* which is the id of the quiz being deleted.
|
||||
* @since Moodle 2.7.1, 2.6.4, 2.5.7
|
||||
*/
|
||||
public static function delete_settings($quiz) {
|
||||
// By default do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bits of SQL needed to load all the settings from all the access
|
||||
* plugins in one DB query. The easiest way to understand what you need to do
|
||||
* here is probalby to read the code of {@link quiz_access_manager::load_settings()}.
|
||||
*
|
||||
* If you have some settings that cannot be loaded in this way, then you can
|
||||
* use the {@link get_extra_settings()} method instead, but that has
|
||||
* performance implications.
|
||||
*
|
||||
* @param int $quizid the id of the quiz we are loading settings for. This
|
||||
* can also be accessed as quiz.id in the SQL. (quiz is a table alisas for {quiz}.)
|
||||
* @return array with three elements:
|
||||
* 1. fields: any fields to add to the select list. These should be alised
|
||||
* if neccessary so that the field name starts the name of the plugin.
|
||||
* 2. joins: any joins (should probably be LEFT JOINS) with other tables that
|
||||
* are needed.
|
||||
* 3. params: array of placeholder values that are needed by the SQL. You must
|
||||
* used named placeholders, and the placeholder names should start with the
|
||||
* plugin name, to avoid collisions.
|
||||
*/
|
||||
public static function get_settings_sql($quizid) {
|
||||
return array('', '', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* You can use this method to load any extra settings your plugin has that
|
||||
* cannot be loaded efficiently with get_settings_sql().
|
||||
* @param int $quizid the quiz id.
|
||||
* @return array setting value name => value. The value names should all
|
||||
* start with the name of your plugin to avoid collisions.
|
||||
*/
|
||||
public static function get_extra_settings($quizid) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
@ -14,30 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_delaybetweenattempts plugin.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage delaybetweenattempts
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule imposing the delay between attempts settings.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package quizaccess_delaybetweenattempts
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_delaybetweenattempts extends quiz_access_rule_base {
|
||||
class quizaccess_delaybetweenattempts extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
if (empty($quizobj->get_quiz()->delay1) && empty($quizobj->get_quiz()->delay2)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_delaybetweenattempts;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_delaybetweenattempts;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -43,7 +43,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timeclose = 0;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->timefinish = 10000;
|
||||
|
||||
@ -77,7 +77,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timeclose = 0;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->timefinish = 10000;
|
||||
|
||||
@ -116,7 +116,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timeclose = 0;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->timefinish = 10000;
|
||||
|
||||
@ -167,7 +167,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timeclose = 15000;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->timefinish = 13000;
|
||||
|
||||
@ -223,7 +223,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timeclose = 0;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->timestart = 9900;
|
||||
$attempt->timefinish = 10100;
|
||||
|
@ -14,30 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_ipaddress plugin.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage ipaddress
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule implementing the ipaddress check against the ->subnet setting.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package quizaccess_ipaddress
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_ipaddress extends quiz_access_rule_base {
|
||||
class quizaccess_ipaddress extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
if (empty($quizobj->get_quiz()->subnet)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_ipaddress;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_ipaddress;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -44,7 +44,7 @@ class rule_test extends \basic_testcase {
|
||||
// does not always work, for example using the mac install package on my laptop.
|
||||
$quiz->subnet = getremoteaddr(null);
|
||||
if (!empty($quiz->subnet)) {
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_ipaddress($quizobj, 0);
|
||||
|
||||
$this->assertFalse($rule->prevent_access());
|
||||
@ -56,7 +56,7 @@ class rule_test extends \basic_testcase {
|
||||
}
|
||||
|
||||
$quiz->subnet = '0.0.0.0';
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_ipaddress($quizobj, 0);
|
||||
|
||||
$this->assertNotEmpty($rule->prevent_access());
|
||||
|
@ -14,30 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_numattempts plugin.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage numattempts
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule controlling the number of attempts allowed.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package quizaccess_numattempts
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_numattempts extends quiz_access_rule_base {
|
||||
class quizaccess_numattempts extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
|
||||
if ($quizobj->get_num_attempts_allowed() == 0) {
|
||||
return null;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_numattempts;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_numattempts;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -39,7 +39,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->attempts = 3;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_numattempts($quizobj, 0);
|
||||
$attempt = new \stdClass();
|
||||
|
||||
|
@ -14,29 +14,21 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_offlineattempts plugin.
|
||||
*
|
||||
* @package quizaccess_offlineattempts
|
||||
* @copyright 2016 Juan Leyva
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
use mod_quiz\form\preflight_check_form;
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule implementing the offlineattempts check.
|
||||
*
|
||||
* @package quizaccess_offlineattempts
|
||||
* @copyright 2016 Juan Leyva
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 3.2
|
||||
*/
|
||||
class quizaccess_offlineattempts extends quiz_access_rule_base {
|
||||
class quizaccess_offlineattempts extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
global $CFG;
|
||||
|
||||
// If mobile services are off, the user won't be able to use any external app.
|
||||
@ -63,7 +55,7 @@ class quizaccess_offlineattempts extends quiz_access_rule_base {
|
||||
}
|
||||
}
|
||||
|
||||
public function add_preflight_check_form_fields(mod_quiz_preflight_check_form $quizform,
|
||||
public function add_preflight_check_form_fields(preflight_check_form $quizform,
|
||||
MoodleQuickForm $mform, $attemptid) {
|
||||
global $DB;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_offlineattempts;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_offlineattempts;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -38,7 +38,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->allowofflineattempts = 1;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_offlineattempts($quizobj, 0);
|
||||
$attempt = new \stdClass();
|
||||
|
||||
|
@ -14,30 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_openclosedate plugin.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage openclosedate
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule enforcing open and close dates.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package quizaccess_openclosedate
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_openclosedate extends quiz_access_rule_base {
|
||||
class quizaccess_openclosedate extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
// This rule is always used, even if the quiz has no open or close date.
|
||||
return new self($quizobj, $timenow);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_openclosedate;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_openclosedate;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -41,7 +41,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->overduehandling = 'autosubmit';
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->preview = 0;
|
||||
|
||||
@ -68,7 +68,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->overduehandling = 'autosubmit';
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->preview = 0;
|
||||
|
||||
@ -95,7 +95,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->overduehandling = 'autosubmit';
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->preview = 0;
|
||||
|
||||
@ -129,7 +129,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->overduehandling = 'autosubmit';
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->preview = 0;
|
||||
|
||||
@ -170,7 +170,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->graceperiod = 1000;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$attempt = new \stdClass();
|
||||
$attempt->preview = 0;
|
||||
|
||||
|
@ -14,30 +14,20 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_password plugin.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage password
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
use mod_quiz\form\preflight_check_form;
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule implementing the password check.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package quizaccess_password
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_password extends quiz_access_rule_base {
|
||||
class quizaccess_password extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
if (empty($quizobj->get_quiz()->password)) {
|
||||
return null;
|
||||
}
|
||||
@ -54,7 +44,7 @@ class quizaccess_password extends quiz_access_rule_base {
|
||||
return empty($SESSION->passwordcheckedquizzes[$this->quiz->id]);
|
||||
}
|
||||
|
||||
public function add_preflight_check_form_fields(mod_quiz_preflight_check_form $quizform,
|
||||
public function add_preflight_check_form_fields(preflight_check_form $quizform,
|
||||
MoodleQuickForm $mform, $attemptid) {
|
||||
|
||||
$mform->addElement('header', 'passwordheader', get_string('password'));
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_password;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_password;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -39,7 +39,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->password = 'frog';
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_password($quizobj, 0);
|
||||
$attempt = new \stdClass();
|
||||
|
||||
|
@ -58,7 +58,7 @@ class backup_quizaccess_seb_subplugin extends backup_mod_quiz_access_subplugin {
|
||||
$subplugintemplatesettings = new backup_nested_element('quizaccess_seb_template', null, $templatekeys);
|
||||
|
||||
// Get quiz settings keys to save.
|
||||
$settings = new \quizaccess_seb\quiz_settings();
|
||||
$settings = new \quizaccess_seb\seb_quiz_settings();
|
||||
$blanksettingsarray = (array) $settings->to_record();
|
||||
unset($blanksettingsarray['id']); // We don't need to save reference to settings record in current instance.
|
||||
// We don't need to save the data about who last modified the settings as they will be overwritten on restore. Also
|
||||
@ -77,7 +77,7 @@ class backup_quizaccess_seb_subplugin extends backup_mod_quiz_access_subplugin {
|
||||
$subpluginquizsettings->add_child($subplugintemplatesettings);
|
||||
|
||||
// Set source to populate the settings data by referencing the ID of quiz being backed up.
|
||||
$subpluginquizsettings->set_source_table(quizaccess_seb\quiz_settings::TABLE, ['quizid' => $quizid]);
|
||||
$subpluginquizsettings->set_source_table(quizaccess_seb\seb_quiz_settings::TABLE, ['quizid' => $quizid]);
|
||||
|
||||
$subpluginquizsettings->annotate_files('quizaccess_seb', 'filemanager_sebconfigfile', null);
|
||||
|
||||
@ -86,4 +86,4 @@ class backup_quizaccess_seb_subplugin extends backup_mod_quiz_access_subplugin {
|
||||
|
||||
return $subplugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use quizaccess_seb\quiz_settings;
|
||||
use quizaccess_seb\seb_quiz_settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -73,7 +73,7 @@ class restore_quizaccess_seb_subplugin extends restore_mod_quiz_access_subplugin
|
||||
unset($data->id);
|
||||
$data->timecreated = $data->timemodified = time();
|
||||
$data->usermodified = $USER->id;
|
||||
$DB->insert_record(quizaccess_seb\quiz_settings::TABLE, $data);
|
||||
$DB->insert_record(quizaccess_seb\seb_quiz_settings::TABLE, $data);
|
||||
|
||||
// Process attached files.
|
||||
$this->add_related_files('quizaccess_seb', 'filemanager_sebconfigfile', null);
|
||||
@ -112,7 +112,7 @@ class restore_quizaccess_seb_subplugin extends restore_mod_quiz_access_subplugin
|
||||
}
|
||||
|
||||
// Update the restored quiz settings to use restored template.
|
||||
$DB->set_field(\quizaccess_seb\quiz_settings::TABLE, 'templateid', $template->get('id'), ['quizid' => $quizid]);
|
||||
$DB->set_field(\quizaccess_seb\seb_quiz_settings::TABLE, 'templateid', $template->get('id'), ['quizid' => $quizid]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
namespace quizaccess_seb\event;
|
||||
|
||||
use core\event\base;
|
||||
use quizaccess_seb\access_manager;
|
||||
use quizaccess_seb\seb_access_manager;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -44,13 +44,13 @@ class access_prevented extends base {
|
||||
* Define strict parameters to create event with instead of relying on internal validation of array. Better code practice.
|
||||
* Easier for consumers of this class to know what data must be supplied and observers can have more trust in event data.
|
||||
*
|
||||
* @param access_manager $accessmanager Access manager.
|
||||
* @param seb_access_manager $accessmanager Access manager.
|
||||
* @param string $reason Reason that access was prevented.
|
||||
* @param string|null $configkey A Safe Exam Browser config key.
|
||||
* @param string|null $browserexamkey A Safe Exam Browser browser exam key.
|
||||
* @return base
|
||||
*/
|
||||
public static function create_strict(access_manager $accessmanager, string $reason,
|
||||
public static function create_strict(seb_access_manager $accessmanager, string $reason,
|
||||
?string $configkey = null, ?string $browserexamkey = null) : base {
|
||||
global $USER;
|
||||
|
||||
|
@ -25,12 +25,10 @@ use external_function_parameters;
|
||||
use external_single_structure;
|
||||
use external_value;
|
||||
use invalid_parameter_exception;
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_seb\event\access_prevented;
|
||||
use quizaccess_seb\access_manager;
|
||||
use quizaccess_seb\seb_access_manager;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessmanager.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
/**
|
||||
@ -97,7 +95,7 @@ class validate_quiz_keys extends external_api {
|
||||
|
||||
$result = ['configkey' => true, 'browserexamkey' => true];
|
||||
|
||||
$accessmanager = new access_manager(quiz::create($quizid));
|
||||
$accessmanager = new seb_access_manager(quiz_settings::create($quizid));
|
||||
|
||||
// Check if there is a valid config key.
|
||||
if (!$accessmanager->validate_config_key($configkey, $url)) {
|
||||
|
@ -121,7 +121,7 @@ class helper {
|
||||
require_login($cm->course, false, $cm);
|
||||
|
||||
// Retrieve the config for quiz.
|
||||
$config = quiz_settings::get_config_by_quiz_id($cm->instance);
|
||||
$config = seb_quiz_settings::get_config_by_quiz_id($cm->instance);
|
||||
if (empty($config)) {
|
||||
throw new \moodle_exception('noconfigfound', 'quizaccess_seb', '', $cm->id);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ use core_privacy\local\request\contextlist;
|
||||
use core_privacy\local\request\transform;
|
||||
use core_privacy\local\request\userlist;
|
||||
use core_privacy\local\request\writer;
|
||||
use quizaccess_seb\quiz_settings;
|
||||
use quizaccess_seb\seb_quiz_settings;
|
||||
use quizaccess_seb\template;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -162,7 +162,7 @@ class provider implements
|
||||
$index++;
|
||||
$subcontext = [
|
||||
get_string('pluginname', 'quizaccess_seb'),
|
||||
quiz_settings::TABLE,
|
||||
seb_quiz_settings::TABLE,
|
||||
$index
|
||||
];
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
namespace quizaccess_seb;
|
||||
|
||||
use context_module;
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -39,7 +39,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2020 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class access_manager {
|
||||
class seb_access_manager {
|
||||
|
||||
/** Header sent by Safe Exam Browser containing the Config Key hash. */
|
||||
private const CONFIG_KEY_HEADER = 'HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH';
|
||||
@ -47,10 +47,10 @@ class access_manager {
|
||||
/** Header sent by Safe Exam Browser containing the Browser Exam Key hash. */
|
||||
private const BROWSER_EXAM_KEY_HEADER = 'HTTP_X_SAFEEXAMBROWSER_REQUESTHASH';
|
||||
|
||||
/** @var quiz $quiz A quiz object containing all information pertaining to current quiz. */
|
||||
/** @var quiz_settings $quiz A quiz object containing all information pertaining to current quiz. */
|
||||
private $quiz;
|
||||
|
||||
/** @var quiz_settings $quizsettings A quiz settings persistent object containing plugin settings */
|
||||
/** @var seb_quiz_settings $quizsettings A quiz settings persistent object containing plugin settings */
|
||||
private $quizsettings;
|
||||
|
||||
/** @var context_module $context Context of this quiz activity. */
|
||||
@ -62,13 +62,13 @@ class access_manager {
|
||||
/**
|
||||
* The access_manager constructor.
|
||||
*
|
||||
* @param quiz $quiz The details of the quiz.
|
||||
* @param quiz_settings $quiz The details of the quiz.
|
||||
*/
|
||||
public function __construct(quiz $quiz) {
|
||||
public function __construct(quiz_settings $quiz) {
|
||||
$this->quiz = $quiz;
|
||||
$this->context = context_module::instance($quiz->get_cmid());
|
||||
$this->quizsettings = quiz_settings::get_by_quiz_id($quiz->get_quizid());
|
||||
$this->validconfigkey = quiz_settings::get_config_key_by_quiz_id($quiz->get_quizid());
|
||||
$this->quizsettings = seb_quiz_settings::get_by_quiz_id($quiz->get_quizid());
|
||||
$this->validconfigkey = seb_quiz_settings::get_config_key_by_quiz_id($quiz->get_quizid());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,9 +219,9 @@ class access_manager {
|
||||
/**
|
||||
* Getter for the quiz object.
|
||||
*
|
||||
* @return quiz
|
||||
* @return \mod_quiz\quiz_settings
|
||||
*/
|
||||
public function get_quiz() : quiz {
|
||||
public function get_quiz() : quiz_settings {
|
||||
return $this->quiz;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2020 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_settings extends persistent {
|
||||
class seb_quiz_settings extends persistent {
|
||||
|
||||
/** Table name for the persistent. */
|
||||
const TABLE = 'quizaccess_seb_quizsettings';
|
||||
@ -193,7 +193,7 @@ class quiz_settings extends persistent {
|
||||
* This method gets data from cache before doing any DB calls.
|
||||
*
|
||||
* @param int $quizid Quiz id.
|
||||
* @return false|\quizaccess_seb\quiz_settings
|
||||
* @return false|\quizaccess_seb\seb_quiz_settings
|
||||
*/
|
||||
public static function get_by_quiz_id(int $quizid) {
|
||||
if ($data = self::get_quiz_settings_cache()->get($quizid)) {
|
||||
@ -567,7 +567,7 @@ class quiz_settings extends persistent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quitURL if found in the quiz_settings.
|
||||
* Sets the quitURL if found in the seb_quiz_settings.
|
||||
*/
|
||||
private function process_quit_url_from_settings() {
|
||||
$settings = $this->to_record();
|
@ -395,7 +395,7 @@ class settings_provider {
|
||||
self::freeze_element($quizform, $mform, 'seb_showsebdownloadlink');
|
||||
self::freeze_element($quizform, $mform, 'seb_allowedbrowserexamkeys');
|
||||
|
||||
$quizsettings = quiz_settings::get_by_quiz_id((int) $quizform->get_instance());
|
||||
$quizsettings = seb_quiz_settings::get_by_quiz_id((int) $quizform->get_instance());
|
||||
|
||||
// If the file has been uploaded, then replace it with the link to download the file.
|
||||
if (!empty($quizsettings) && $quizsettings->get('requiresafeexambrowser') == self::USE_SEB_UPLOAD_CONFIG) {
|
||||
@ -528,7 +528,7 @@ class settings_provider {
|
||||
return false;
|
||||
}
|
||||
|
||||
$settings = quiz_settings::get_record(['cmid' => (int) $context->instanceid]);
|
||||
$settings = seb_quiz_settings::get_record(['cmid' => (int) $context->instanceid]);
|
||||
|
||||
if (empty($settings)) {
|
||||
return false;
|
||||
|
@ -125,7 +125,7 @@ class template extends persistent {
|
||||
$result = true;
|
||||
|
||||
if ($this->get('id')) {
|
||||
$settings = quiz_settings::get_records(['templateid' => $this->get('id')]);
|
||||
$settings = seb_quiz_settings::get_records(['templateid' => $this->get('id')]);
|
||||
$result = empty($settings);
|
||||
}
|
||||
|
||||
|
31
mod/quiz/accessrule/seb/db/renamedclasses.php
Normal file
31
mod/quiz/accessrule/seb/db/renamedclasses.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file contains mappings for classes that have been renamed.
|
||||
*
|
||||
* @package quizaccess_seb
|
||||
* @copyright 2022 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$renamedclasses = [
|
||||
// Since Moodle 4.2.
|
||||
'quizaccess_seb\quiz_settings' => 'quizaccess_seb\seb_quiz_settings',
|
||||
'quizaccess_seb\access_manager' => 'quizaccess_seb\seb_access_manager',
|
||||
];
|
@ -14,6 +14,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use quizaccess_seb\seb_access_manager;
|
||||
use quizaccess_seb\seb_quiz_settings;
|
||||
use quizaccess_seb\settings_provider;
|
||||
use quizaccess_seb\event\access_prevented;
|
||||
|
||||
/**
|
||||
* Implementation of the quizaccess_seb plugin.
|
||||
*
|
||||
@ -23,36 +30,19 @@
|
||||
* @copyright 2019 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_seb extends access_rule_base {
|
||||
|
||||
use quizaccess_seb\access_manager;
|
||||
use quizaccess_seb\quiz_settings;
|
||||
use quizaccess_seb\settings_provider;
|
||||
use \quizaccess_seb\event\access_prevented;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
/**
|
||||
* Implementation of the quizaccess_seb plugin.
|
||||
*
|
||||
* @copyright 2020 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_seb extends quiz_access_rule_base {
|
||||
|
||||
/** @var access_manager $accessmanager Instance to manage the access to the quiz for this plugin. */
|
||||
/** @var seb_access_manager $accessmanager Instance to manage the access to the quiz for this plugin. */
|
||||
private $accessmanager;
|
||||
|
||||
/**
|
||||
* Create an instance of this rule for a particular quiz.
|
||||
*
|
||||
* @param quiz $quizobj information about the quiz in question.
|
||||
* @param \mod_quiz\quiz_settings $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
* @param access_manager $accessmanager the quiz accessmanager.
|
||||
* @param seb_access_manager $accessmanager the quiz accessmanager.
|
||||
*/
|
||||
public function __construct(quiz $quizobj, int $timenow, access_manager $accessmanager) {
|
||||
public function __construct(\mod_quiz\quiz_settings $quizobj, int $timenow, seb_access_manager $accessmanager) {
|
||||
parent::__construct($quizobj, $timenow);
|
||||
$this->accessmanager = $accessmanager;
|
||||
}
|
||||
@ -61,14 +51,14 @@ class quizaccess_seb extends quiz_access_rule_base {
|
||||
* Return an appropriately configured instance of this rule, if it is applicable
|
||||
* to the given quiz, otherwise return null.
|
||||
*
|
||||
* @param quiz $quizobj information about the quiz in question.
|
||||
* @param \mod_quiz\quiz_settings $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
* @param bool $canignoretimelimits whether the current user is exempt from
|
||||
* time limits by the mod/quiz:ignoretimelimits capability.
|
||||
* @return quiz_access_rule_base|null the rule, if applicable, else null.
|
||||
* @return access_rule_base|null the rule, if applicable, else null.
|
||||
*/
|
||||
public static function make (quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
$accessmanager = new access_manager($quizobj);
|
||||
public static function make(\mod_quiz\quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
$accessmanager = new seb_access_manager($quizobj);
|
||||
// If Safe Exam Browser is not required, this access rule is not applicable.
|
||||
if (!$accessmanager->seb_required()) {
|
||||
return null;
|
||||
@ -120,7 +110,7 @@ class quizaccess_seb extends quiz_access_rule_base {
|
||||
$settings = settings_provider::filter_plugin_settings((object) $data);
|
||||
|
||||
// Validate basic settings using persistent class.
|
||||
$quizsettings = (new quiz_settings())->from_record($settings);
|
||||
$quizsettings = (new seb_quiz_settings())->from_record($settings);
|
||||
// Set non-form fields.
|
||||
$quizsettings->set('quizid', $quizid);
|
||||
$quizsettings->set('cmid', $cmid);
|
||||
@ -186,9 +176,9 @@ class quizaccess_seb extends quiz_access_rule_base {
|
||||
$settings->cmid = $cm->id;
|
||||
|
||||
// Get existing settings or create new settings if none exist.
|
||||
$quizsettings = quiz_settings::get_by_quiz_id($quiz->id);
|
||||
$quizsettings = seb_quiz_settings::get_by_quiz_id($quiz->id);
|
||||
if (empty($quizsettings)) {
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
} else {
|
||||
$settings->id = $quizsettings->get('id');
|
||||
$quizsettings->from_record($settings);
|
||||
@ -218,7 +208,7 @@ class quizaccess_seb extends quiz_access_rule_base {
|
||||
* which is the id of the quiz being deleted.
|
||||
*/
|
||||
public static function delete_settings($quiz) {
|
||||
$quizsettings = quiz_settings::get_by_quiz_id($quiz->id);
|
||||
$quizsettings = seb_quiz_settings::get_by_quiz_id($quiz->id);
|
||||
// Check that there are existing settings.
|
||||
if ($quizsettings !== false) {
|
||||
$quizsettings->delete();
|
||||
@ -228,7 +218,7 @@ class quizaccess_seb extends quiz_access_rule_base {
|
||||
/**
|
||||
* Return the bits of SQL needed to load all the settings from all the access
|
||||
* plugins in one DB query. The easiest way to understand what you need to do
|
||||
* here is probalby to read the code of {@link quiz_access_manager::load_settings()}.
|
||||
* here is probably to read the code of {@see \mod_quiz\access_manager::load_settings()}.
|
||||
*
|
||||
* If you have some settings that cannot be loaded in this way, then you can
|
||||
* use the {@link get_extra_settings()} method instead, but that has
|
||||
|
@ -27,7 +27,7 @@ require_once(__DIR__ . '/test_helper_trait.php');
|
||||
* @author Andrew Madden <andrewmadden@catalyst-au.net>
|
||||
* @copyright 2020 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \quizaccess_seb\access_manager
|
||||
* @covers \quizaccess_seb\seb_access_manager
|
||||
*/
|
||||
class access_manager_test extends \advanced_testcase {
|
||||
use \quizaccess_seb_test_helper_trait;
|
||||
@ -53,7 +53,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
|
||||
$this->assertFalse($accessmanager->seb_required());
|
||||
|
||||
$reflection = new \ReflectionClass('\quizaccess_seb\access_manager');
|
||||
$reflection = new \ReflectionClass('\quizaccess_seb\seb_access_manager');
|
||||
$property = $reflection->getProperty('quizsettings');
|
||||
$property->setAccessible(true);
|
||||
|
||||
@ -153,7 +153,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
|
||||
$accessmanager = $this->get_access_manager();
|
||||
|
||||
$configkey = quiz_settings::get_record(['quizid' => $this->quiz->id])->get_config_key();
|
||||
$configkey = seb_quiz_settings::get_record(['quizid' => $this->quiz->id])->get_config_key();
|
||||
|
||||
// Set up dummy request.
|
||||
$FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
|
||||
@ -171,7 +171,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
$url = 'https://www.example.com/moodle';
|
||||
$accessmanager = $this->get_access_manager();
|
||||
|
||||
$configkey = quiz_settings::get_record(['quizid' => $this->quiz->id])->get_config_key();
|
||||
$configkey = seb_quiz_settings::get_record(['quizid' => $this->quiz->id])->get_config_key();
|
||||
$fullconfigkey = hash('sha256', $url . $configkey);
|
||||
|
||||
$this->assertTrue($accessmanager->validate_config_key($fullconfigkey, $url));
|
||||
@ -202,7 +202,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
public function test_no_browser_exam_keys_cause_check_to_be_successful() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('allowedbrowserexamkeys', '');
|
||||
$settings->save();
|
||||
$accessmanager = $this->get_access_manager();
|
||||
@ -216,7 +216,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
public function test_access_keys_fail_if_browser_exam_key_header_does_not_exist() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('allowedbrowserexamkeys', hash('sha256', 'one') . "\n" . hash('sha256', 'two'));
|
||||
$settings->save();
|
||||
$accessmanager = $this->get_access_manager();
|
||||
@ -229,7 +229,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
public function test_access_keys_fail_if_browser_exam_key_header_does_not_match_provided_hash() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('allowedbrowserexamkeys', hash('sha256', 'one') . "\n" . hash('sha256', 'two'));
|
||||
$settings->save();
|
||||
$accessmanager = $this->get_access_manager();
|
||||
@ -244,7 +244,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
global $FULLME;
|
||||
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$browserexamkey = hash('sha256', 'browserexamkey');
|
||||
$settings->set('allowedbrowserexamkeys', $browserexamkey); // Add a hashed BEK.
|
||||
$settings->save();
|
||||
@ -263,7 +263,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
public function test_browser_exam_keys_match_provided_browser_exam_key() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
$url = 'https://www.example.com/moodle';
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$browserexamkey = hash('sha256', 'browserexamkey');
|
||||
$fullbrowserexamkey = hash('sha256', $url . $browserexamkey);
|
||||
$settings->set('allowedbrowserexamkeys', $browserexamkey); // Add a hashed BEK.
|
||||
@ -315,7 +315,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
|
||||
// Use template.
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $this->create_template()->get('id'));
|
||||
$quizsettings->save();
|
||||
@ -324,7 +324,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
|
||||
// Use uploaded config.
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); // Doesn't check basic header.
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
@ -362,7 +362,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
* @dataProvider should_validate_basic_header_data_provider
|
||||
*/
|
||||
public function test_should_validate_basic_header($type, $expected) {
|
||||
$accessmanager = $this->getMockBuilder(access_manager::class)
|
||||
$accessmanager = $this->getMockBuilder(seb_access_manager::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['get_seb_use_type'])
|
||||
->getMock();
|
||||
@ -396,7 +396,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
* @dataProvider should_validate_config_key_data_provider
|
||||
*/
|
||||
public function test_should_validate_config_key($type, $expected) {
|
||||
$accessmanager = $this->getMockBuilder(access_manager::class)
|
||||
$accessmanager = $this->getMockBuilder(seb_access_manager::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['get_seb_use_type'])
|
||||
->getMock();
|
||||
@ -429,7 +429,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
* @dataProvider should_validate_browser_exam_key_data_provider
|
||||
*/
|
||||
public function test_should_validate_browser_exam_key($type, $expected) {
|
||||
$accessmanager = $this->getMockBuilder(access_manager::class)
|
||||
$accessmanager = $this->getMockBuilder(seb_access_manager::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['get_seb_use_type'])
|
||||
->getMock();
|
||||
@ -457,7 +457,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
$this->assertTrue($accessmanager->validate_config_key());
|
||||
|
||||
// Change settings (but don't save) and check that still can validate config key.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('showsebtaskbar', 0);
|
||||
$this->assertNotEquals($quizsettings->get_config_key(), $configkey);
|
||||
$this->assertTrue($accessmanager->validate_config_key());
|
||||
@ -479,7 +479,7 @@ class access_manager_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_NO);
|
||||
$accessmanager = $this->get_access_manager();
|
||||
|
||||
$this->assertEmpty(quiz_settings::get_record(['quizid' => $this->quiz->id]));
|
||||
$this->assertEmpty(seb_quiz_settings::get_record(['quizid' => $this->quiz->id]));
|
||||
$this->assertNull($accessmanager->get_valid_config_key());
|
||||
|
||||
}
|
||||
|
@ -54,11 +54,11 @@ class backup_restore_test extends \advanced_testcase {
|
||||
/**
|
||||
* A helper method to create a quiz with template usage of SEB.
|
||||
*
|
||||
* @return quiz_settings
|
||||
* @return seb_quiz_settings
|
||||
*/
|
||||
protected function create_quiz_with_template() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $this->template->get('id'));
|
||||
$quizsettings->save();
|
||||
@ -129,10 +129,10 @@ class backup_restore_test extends \advanced_testcase {
|
||||
* @param cm_info $newcm Restored course_module object.
|
||||
*/
|
||||
protected function validate_backup_restore(\cm_info $newcm) {
|
||||
$this->assertEquals(2, quiz_settings::count_records());
|
||||
$actual = quiz_settings::get_record(['quizid' => $newcm->instance]);
|
||||
$this->assertEquals(2, seb_quiz_settings::count_records());
|
||||
$actual = seb_quiz_settings::get_record(['quizid' => $newcm->instance]);
|
||||
|
||||
$expected = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals($expected->get('templateid'), $actual->get('templateid'));
|
||||
$this->assertEquals($expected->get('requiresafeexambrowser'), $actual->get('requiresafeexambrowser'));
|
||||
$this->assertEquals($expected->get('showsebdownloadlink'), $actual->get('showsebdownloadlink'));
|
||||
@ -152,10 +152,10 @@ class backup_restore_test extends \advanced_testcase {
|
||||
*/
|
||||
public function test_backup_restore_no_seb() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_NO);
|
||||
$this->assertEquals(0, quiz_settings::count_records());
|
||||
$this->assertEquals(0, seb_quiz_settings::count_records());
|
||||
|
||||
$this->backup_and_restore_quiz();
|
||||
$this->assertEquals(0, quiz_settings::count_records());
|
||||
$this->assertEquals(0, seb_quiz_settings::count_records());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,12 +164,12 @@ class backup_restore_test extends \advanced_testcase {
|
||||
public function test_backup_restore_manual_config() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
$expected = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected->set('showsebdownloadlink', 0);
|
||||
$expected->set('quitpassword', '123');
|
||||
$expected->save();
|
||||
|
||||
$this->assertEquals(1, quiz_settings::count_records());
|
||||
$this->assertEquals(1, seb_quiz_settings::count_records());
|
||||
|
||||
$newcm = $this->backup_and_restore_quiz();
|
||||
$this->validate_backup_restore($newcm);
|
||||
@ -181,13 +181,13 @@ class backup_restore_test extends \advanced_testcase {
|
||||
public function test_backup_restore_template_config() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
$expected = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$template = $this->create_template();
|
||||
$expected->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$expected->set('templateid', $template->get('id'));
|
||||
$expected->save();
|
||||
|
||||
$this->assertEquals(1, quiz_settings::count_records());
|
||||
$this->assertEquals(1, seb_quiz_settings::count_records());
|
||||
|
||||
$newcm = $this->backup_and_restore_quiz();
|
||||
$this->validate_backup_restore($newcm);
|
||||
@ -199,13 +199,13 @@ class backup_restore_test extends \advanced_testcase {
|
||||
public function test_backup_restore_uploaded_config() {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
$expected = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
$expected->save();
|
||||
|
||||
$this->assertEquals(1, quiz_settings::count_records());
|
||||
$this->assertEquals(1, seb_quiz_settings::count_records());
|
||||
|
||||
$newcm = $this->backup_and_restore_quiz();
|
||||
$this->validate_backup_restore($newcm);
|
||||
@ -224,14 +224,14 @@ class backup_restore_test extends \advanced_testcase {
|
||||
$this->create_quiz_with_template();
|
||||
$backupid = $this->backup_quiz();
|
||||
|
||||
$this->assertEquals(1, quiz_settings::count_records());
|
||||
$this->assertEquals(1, seb_quiz_settings::count_records());
|
||||
$this->assertEquals(1, template::count_records());
|
||||
|
||||
$this->change_site();
|
||||
$this->restore_quiz($backupid);
|
||||
|
||||
// Should see additional setting record, but no new template record.
|
||||
$this->assertEquals(2, quiz_settings::count_records());
|
||||
$this->assertEquals(2, seb_quiz_settings::count_records());
|
||||
$this->assertEquals(1, template::count_records());
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ class backup_restore_test extends \advanced_testcase {
|
||||
$this->create_quiz_with_template();
|
||||
$backupid = $this->backup_quiz();
|
||||
|
||||
$this->assertEquals(1, quiz_settings::count_records());
|
||||
$this->assertEquals(1, seb_quiz_settings::count_records());
|
||||
$this->assertEquals(1, template::count_records());
|
||||
|
||||
$this->template->set('name', 'New name for template');
|
||||
@ -253,7 +253,7 @@ class backup_restore_test extends \advanced_testcase {
|
||||
$this->restore_quiz($backupid);
|
||||
|
||||
// Should see additional setting record, and new template record.
|
||||
$this->assertEquals(2, quiz_settings::count_records());
|
||||
$this->assertEquals(2, seb_quiz_settings::count_records());
|
||||
$this->assertEquals(2, template::count_records());
|
||||
}
|
||||
|
||||
@ -267,7 +267,7 @@ class backup_restore_test extends \advanced_testcase {
|
||||
$this->create_quiz_with_template();
|
||||
$backupid = $this->backup_quiz();
|
||||
|
||||
$this->assertEquals(1, quiz_settings::count_records());
|
||||
$this->assertEquals(1, seb_quiz_settings::count_records());
|
||||
$this->assertEquals(1, template::count_records());
|
||||
|
||||
$newxml = file_get_contents($CFG->dirroot . '/mod/quiz/accessrule/seb/tests/fixtures/simpleunencrypted.seb');
|
||||
@ -278,7 +278,7 @@ class backup_restore_test extends \advanced_testcase {
|
||||
$this->restore_quiz($backupid);
|
||||
|
||||
// Should see additional setting record, and new template record.
|
||||
$this->assertEquals(2, quiz_settings::count_records());
|
||||
$this->assertEquals(2, seb_quiz_settings::count_records());
|
||||
$this->assertEquals(2, template::count_records());
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_seb\event;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -53,7 +53,7 @@ class events_test extends \advanced_testcase {
|
||||
|
||||
$this->setAdminUser();
|
||||
$quiz = $this->create_test_quiz($this->course, \quizaccess_seb\settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$accessmanager = new \quizaccess_seb\access_manager(new quiz($quiz,
|
||||
$accessmanager = new \quizaccess_seb\seb_access_manager(new quiz_settings($quiz,
|
||||
get_coursemodule_from_id('quiz', $quiz->cmid), $this->course));
|
||||
|
||||
// Set up event with data.
|
||||
@ -103,7 +103,7 @@ class events_test extends \advanced_testcase {
|
||||
|
||||
$this->setAdminUser();
|
||||
$quiz = $this->create_test_quiz($this->course, \quizaccess_seb\settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$accessmanager = new \quizaccess_seb\access_manager(new quiz($quiz,
|
||||
$accessmanager = new \quizaccess_seb\seb_access_manager(new quiz_settings($quiz,
|
||||
get_coursemodule_from_id('quiz', $quiz->cmid), $this->course));
|
||||
|
||||
// Set up event with data.
|
||||
|
@ -20,7 +20,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
use quizaccess_seb\quiz_settings;
|
||||
use quizaccess_seb\seb_quiz_settings;
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
@ -164,7 +164,7 @@ class validate_quiz_access_test extends \advanced_testcase {
|
||||
$url = 'https://www.example.com/moodle';
|
||||
|
||||
// Create the quiz settings.
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$quizsettings->save();
|
||||
|
||||
$fullconfigkey = hash('sha256', $url . $quizsettings->get_config_key());
|
||||
@ -188,7 +188,7 @@ class validate_quiz_access_test extends \advanced_testcase {
|
||||
]);
|
||||
|
||||
// Create the quiz settings.
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$quizsettings->save();
|
||||
|
||||
$result = validate_quiz_keys::execute($this->quiz->cmid, 'https://www.example.com/moodle', 'badconfigkey');
|
||||
@ -217,7 +217,7 @@ class validate_quiz_access_test extends \advanced_testcase {
|
||||
]);
|
||||
|
||||
// Create the quiz settings.
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$quizsettings->save();
|
||||
|
||||
$fullbrowserexamkey = hash('sha256', $url . $validbrowserexamkey);
|
||||
@ -243,7 +243,7 @@ class validate_quiz_access_test extends \advanced_testcase {
|
||||
]);
|
||||
|
||||
// Create the quiz settings.
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$quizsettings->save();
|
||||
|
||||
$result = validate_quiz_keys::execute($this->quiz->cmid, 'https://www.example.com/moodle', null,
|
||||
|
@ -31,7 +31,7 @@ use core_privacy\local\request\writer;
|
||||
use core_privacy\tests\request\approved_contextlist;
|
||||
use core_privacy\tests\provider_testcase;
|
||||
use quizaccess_seb\privacy\provider;
|
||||
use quizaccess_seb\quiz_settings;
|
||||
use quizaccess_seb\seb_quiz_settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -62,7 +62,7 @@ class provider_test extends provider_testcase {
|
||||
|
||||
$template = $this->create_template();
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
// Modify settings so usermodified is updated. This is the user data we are testing for.
|
||||
$quizsettings->set('requiresafeexambrowser', \quizaccess_seb\settings_provider::USE_SEB_TEMPLATE);
|
||||
@ -126,7 +126,7 @@ class provider_test extends provider_testcase {
|
||||
$index = '1'; // Get first data returned from the quizsettings table metadata.
|
||||
$data = $writer->get_data([
|
||||
get_string('pluginname', 'quizaccess_seb'),
|
||||
quiz_settings::TABLE,
|
||||
seb_quiz_settings::TABLE,
|
||||
$index,
|
||||
]);
|
||||
$this->assertNotEmpty($data);
|
||||
@ -142,7 +142,7 @@ class provider_test extends provider_testcase {
|
||||
$index = '2'; // There should not be more than one instance with data.
|
||||
$data = $writer->get_data([
|
||||
get_string('pluginname', 'quizaccess_seb'),
|
||||
quiz_settings::TABLE,
|
||||
seb_quiz_settings::TABLE,
|
||||
$index,
|
||||
]);
|
||||
$this->assertEmpty($data);
|
||||
@ -180,11 +180,11 @@ class provider_test extends provider_testcase {
|
||||
'quizaccess_seb', [$this->user->id]);
|
||||
|
||||
// Test data exists.
|
||||
$this->assertNotEmpty(quiz_settings::get_record(['quizid' => $this->quiz->id]));
|
||||
$this->assertNotEmpty(seb_quiz_settings::get_record(['quizid' => $this->quiz->id]));
|
||||
|
||||
// Test data is deleted.
|
||||
provider::delete_data_for_users($approveduserlist);
|
||||
$record = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$record = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEmpty($record->get('usermodified'));
|
||||
|
||||
$template = \quizaccess_seb\template::get_record(['id' => $record->get('templateid')]);
|
||||
@ -202,11 +202,11 @@ class provider_test extends provider_testcase {
|
||||
'quizaccess_seb', [$context->id]);
|
||||
|
||||
// Test data exists.
|
||||
$this->assertNotEmpty(quiz_settings::get_record(['quizid' => $this->quiz->id]));
|
||||
$this->assertNotEmpty(seb_quiz_settings::get_record(['quizid' => $this->quiz->id]));
|
||||
|
||||
// Test data is deleted.
|
||||
provider::delete_data_for_user($approvedcontextlist);
|
||||
$record = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$record = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEmpty($record->get('usermodified'));
|
||||
|
||||
$template = \quizaccess_seb\template::get_record(['id' => $record->get('templateid')]);
|
||||
@ -222,7 +222,7 @@ class provider_test extends provider_testcase {
|
||||
$context = \context_module::instance($this->quiz->cmid);
|
||||
|
||||
// Test data exists.
|
||||
$record = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$record = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$template = \quizaccess_seb\template::get_record(['id' => $record->get('templateid')]);
|
||||
$this->assertNotEmpty($record->get('usermodified'));
|
||||
$this->assertNotEmpty($template->get('usermodified'));
|
||||
@ -230,7 +230,7 @@ class provider_test extends provider_testcase {
|
||||
// Test data is deleted.
|
||||
provider::delete_data_for_all_users_in_context($context);
|
||||
|
||||
$record = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$record = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$template = \quizaccess_seb\template::get_record(['id' => $record->get('templateid')]);
|
||||
$this->assertEmpty($record->get('usermodified'));
|
||||
$this->assertEmpty($template->get('usermodified'));
|
||||
|
@ -16,12 +16,15 @@
|
||||
|
||||
namespace quizaccess_seb;
|
||||
|
||||
use context_module;
|
||||
use moodle_url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/test_helper_trait.php');
|
||||
|
||||
/**
|
||||
* PHPUnit tests for quiz_settings class.
|
||||
* PHPUnit tests for seb_quiz_settings class.
|
||||
*
|
||||
* @package quizaccess_seb
|
||||
* @author Andrew Madden <andrewmadden@catalyst-au.net>
|
||||
@ -66,7 +69,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
]);
|
||||
|
||||
// Obtain the existing record that is created when using a generator.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
// Update the settings with values from the test function.
|
||||
$quizsettings->from_record($settings);
|
||||
@ -100,7 +103,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
]);
|
||||
|
||||
// Obtain the existing record that is created when using a generator.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
// Update the settings with values from the test function.
|
||||
$quizsettings->from_record($settings);
|
||||
@ -145,7 +148,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
public function test_config_key_is_created_from_quiz_settings() {
|
||||
$settings = $this->get_test_settings();
|
||||
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$configkey = $quizsettings->get_config_key();
|
||||
$this->assertEquals("65ff7a3b8aec80e58fbe2e7968826c33cbf0ac444a748055ebe665829cbf4201",
|
||||
$configkey
|
||||
@ -158,7 +161,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
public function test_config_key_is_updated_from_quiz_settings() {
|
||||
$settings = $this->get_test_settings();
|
||||
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$configkey = $quizsettings->get_config_key();
|
||||
$this->assertEquals("65ff7a3b8aec80e58fbe2e7968826c33cbf0ac444a748055ebe665829cbf4201",
|
||||
$configkey);
|
||||
@ -178,7 +181,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* @dataProvider filter_rules_provider
|
||||
*/
|
||||
public function test_filter_rules_added_to_config(\stdClass $settings, string $expectedxml) {
|
||||
$quizsettings = new quiz_settings(0, $settings);
|
||||
$quizsettings = new seb_quiz_settings(0, $settings);
|
||||
$config = $quizsettings->get_config();
|
||||
$this->assertEquals($expectedxml, $config);
|
||||
}
|
||||
@ -187,7 +190,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test that browser keys are validated and retrieved as an array instead of string.
|
||||
*/
|
||||
public function test_browser_exam_keys_are_retrieved_as_array() {
|
||||
$quizsettings = new quiz_settings();
|
||||
$quizsettings = new seb_quiz_settings();
|
||||
$quizsettings->set('allowedbrowserexamkeys', "one two,three\nfour");
|
||||
$retrievedkeys = $quizsettings->get('allowedbrowserexamkeys');
|
||||
$this->assertEquals(['one', 'two', 'three', 'four'], $retrievedkeys);
|
||||
@ -202,7 +205,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* @dataProvider bad_browser_exam_key_provider
|
||||
*/
|
||||
public function test_browser_exam_keys_validation_errors($bek, $expectederrorstring) {
|
||||
$quizsettings = new quiz_settings();
|
||||
$quizsettings = new seb_quiz_settings();
|
||||
$quizsettings->set('allowedbrowserexamkeys', $bek);
|
||||
$quizsettings->validate();
|
||||
$errors = $quizsettings->get_errors();
|
||||
@ -220,7 +223,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
. "<key>allowWlan</key><false/><key>startURL</key><string>$url</string>"
|
||||
. "<key>sendBrowserExamKey</key><true/><key>browserWindowWebView</key><integer>3</integer></dict></plist>\n";
|
||||
$itemid = $this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$quizsettings->save();
|
||||
$config = $quizsettings->get_config();
|
||||
@ -231,7 +234,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test test_no_config_file_uploaded
|
||||
*/
|
||||
public function test_no_config_file_uploaded() {
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$cmid = $quizsettings->get('cmid');
|
||||
$this->expectException(\moodle_exception::class);
|
||||
@ -279,7 +282,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
$this->assertStringContainsString("<key>allowQuit</key><true/>", $template->get('content'));
|
||||
$this->assertStringContainsString("<key>hashedQuitPassword</key><string>password</string>", $template->get('content'));
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $template->get('id'));
|
||||
$quizsettings->set('allowuserquitseb', 1);
|
||||
@ -318,7 +321,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
$this->assertStringNotContainsString("<key>allowQuit</key><true/>", $template->get('content'));
|
||||
$this->assertStringNotContainsString("<key>hashedQuitPassword</key><string>password</string>", $template->get('content'));
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $template->get('id'));
|
||||
$quizsettings->set('allowuserquitseb', 1);
|
||||
@ -347,7 +350,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
$xml = $this->get_config_xml(true, 'password');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$quizsettings->set('allowuserquitseb', 0);
|
||||
$quizsettings->set('quitpassword', '');
|
||||
@ -384,7 +387,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
$xml = $this->get_config_xml();
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$quizsettings->set('allowuserquitseb', 1);
|
||||
$quizsettings->set('quitpassword', '');
|
||||
@ -424,7 +427,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
|
||||
$template = $this->create_template($xml);
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $template->get('id'));
|
||||
|
||||
@ -446,7 +449,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
. "<key>sendBrowserExamKey</key><true/></dict></plist>\n";
|
||||
|
||||
$itemid = $this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
|
||||
$this->assertEmpty($quizsettings->get('linkquitseb'));
|
||||
@ -460,7 +463,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test template id set correctly.
|
||||
*/
|
||||
public function test_templateid_set_correctly_when_save_settings() {
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals(0, $quizsettings->get('templateid'));
|
||||
|
||||
$template = $this->create_template();
|
||||
@ -468,12 +471,12 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
|
||||
// Initially set to USE_SEB_TEMPLATE with a template id.
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals($templateid, $quizsettings->get('templateid'));
|
||||
|
||||
// Case for USE_SEB_NO, ensure template id reverts to 0.
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_NO);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals(0, $quizsettings->get('templateid'));
|
||||
|
||||
// Reverting back to USE_SEB_TEMPLATE.
|
||||
@ -481,7 +484,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
|
||||
// Case for USE_SEB_CONFIG_MANUALLY, ensure template id reverts to 0.
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals(0, $quizsettings->get('templateid'));
|
||||
|
||||
// Reverting back to USE_SEB_TEMPLATE.
|
||||
@ -489,7 +492,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
|
||||
// Case for USE_SEB_CLIENT_CONFIG, ensure template id reverts to 0.
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals(0, $quizsettings->get('templateid'));
|
||||
|
||||
// Reverting back to USE_SEB_TEMPLATE.
|
||||
@ -499,19 +502,19 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals(0, $quizsettings->get('templateid'));
|
||||
|
||||
// Case for USE_SEB_TEMPLATE, ensure template id is correct.
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals($templateid, $quizsettings->get('templateid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function in tests to set USE_SEB_TEMPLATE and a template id on the quiz settings.
|
||||
*
|
||||
* @param quiz_settings $quizsettings Given quiz settings instance.
|
||||
* @param seb_quiz_settings $quizsettings Given quiz settings instance.
|
||||
* @param int $savetype Type of SEB usage.
|
||||
* @param int $templateid Template ID.
|
||||
*/
|
||||
@ -695,13 +698,13 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test that config and config key are null when expected.
|
||||
*/
|
||||
public function test_generates_config_values_as_null_when_expected() {
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertNotNull($quizsettings->get_config());
|
||||
$this->assertNotNull($quizsettings->get_config_key());
|
||||
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_NO);
|
||||
$quizsettings->save();
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertNull($quizsettings->get_config());
|
||||
$this->assertNull($quizsettings->get_config());
|
||||
|
||||
@ -709,20 +712,20 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
$quizsettings->save();
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertNotNull($quizsettings->get_config());
|
||||
$this->assertNotNull($quizsettings->get_config_key());
|
||||
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG);
|
||||
$quizsettings->save();
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertNull($quizsettings->get_config());
|
||||
$this->assertNull($quizsettings->get_config_key());
|
||||
|
||||
$template = $this->create_template();
|
||||
$templateid = $template->get('id');
|
||||
$this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertNotNull($quizsettings->get_config());
|
||||
$this->assertNotNull($quizsettings->get_config_key());
|
||||
}
|
||||
@ -731,7 +734,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test that quizsettings cache exists after creation.
|
||||
*/
|
||||
public function test_quizsettings_cache_exists_after_creation() {
|
||||
$expected = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals($expected->to_record(), \cache::make('quizaccess_seb', 'quizsettings')->get($this->quiz->id));
|
||||
}
|
||||
|
||||
@ -741,30 +744,30 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
public function test_quizsettings_cache_purged_after_deletion() {
|
||||
$this->assertNotEmpty(\cache::make('quizaccess_seb', 'quizsettings')->get($this->quiz->id));
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->delete();
|
||||
|
||||
$this->assertFalse(\cache::make('quizaccess_seb', 'quizsettings')->get($this->quiz->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can get quiz_settings by quiz id.
|
||||
* Test that we can get seb_quiz_settings by quiz id.
|
||||
*/
|
||||
public function test_get_quiz_settings_by_quiz_id() {
|
||||
$expected = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
$this->assertEquals($expected->to_record(), quiz_settings::get_by_quiz_id($this->quiz->id)->to_record());
|
||||
$this->assertEquals($expected->to_record(), seb_quiz_settings::get_by_quiz_id($this->quiz->id)->to_record());
|
||||
|
||||
// Check that data is getting from cache.
|
||||
$expected->set('showsebtaskbar', 0);
|
||||
$this->assertNotEquals($expected->to_record(), quiz_settings::get_by_quiz_id($this->quiz->id)->to_record());
|
||||
$this->assertNotEquals($expected->to_record(), seb_quiz_settings::get_by_quiz_id($this->quiz->id)->to_record());
|
||||
|
||||
// Now save and check that cached as been updated.
|
||||
$expected->save();
|
||||
$this->assertEquals($expected->to_record(), quiz_settings::get_by_quiz_id($this->quiz->id)->to_record());
|
||||
$this->assertEquals($expected->to_record(), seb_quiz_settings::get_by_quiz_id($this->quiz->id)->to_record());
|
||||
|
||||
// Returns false for non existing quiz.
|
||||
$this->assertFalse(quiz_settings::get_by_quiz_id(7777777));
|
||||
$this->assertFalse(seb_quiz_settings::get_by_quiz_id(7777777));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -780,7 +783,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
public function test_config_cache_purged_after_deletion() {
|
||||
$this->assertNotEmpty(\cache::make('quizaccess_seb', 'config')->get($this->quiz->id));
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->delete();
|
||||
|
||||
$this->assertFalse(\cache::make('quizaccess_seb', 'config')->get($this->quiz->id));
|
||||
@ -790,21 +793,21 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test that we can get SEB config by quiz id.
|
||||
*/
|
||||
public function test_get_config_by_quiz_id() {
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = $quizsettings->get_config();
|
||||
|
||||
$this->assertEquals($expected, quiz_settings::get_config_by_quiz_id($this->quiz->id));
|
||||
$this->assertEquals($expected, seb_quiz_settings::get_config_by_quiz_id($this->quiz->id));
|
||||
|
||||
// Check that data is getting from cache.
|
||||
$quizsettings->set('showsebtaskbar', 0);
|
||||
$this->assertNotEquals($quizsettings->get_config(), quiz_settings::get_config_by_quiz_id($this->quiz->id));
|
||||
$this->assertNotEquals($quizsettings->get_config(), seb_quiz_settings::get_config_by_quiz_id($this->quiz->id));
|
||||
|
||||
// Now save and check that cached as been updated.
|
||||
$quizsettings->save();
|
||||
$this->assertEquals($quizsettings->get_config(), quiz_settings::get_config_by_quiz_id($this->quiz->id));
|
||||
$this->assertEquals($quizsettings->get_config(), seb_quiz_settings::get_config_by_quiz_id($this->quiz->id));
|
||||
|
||||
// Returns null for non existing quiz.
|
||||
$this->assertNull(quiz_settings::get_config_by_quiz_id(7777777));
|
||||
$this->assertNull(seb_quiz_settings::get_config_by_quiz_id(7777777));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -820,7 +823,7 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
public function test_config_key_cache_purged_after_deletion() {
|
||||
$this->assertNotEmpty(\cache::make('quizaccess_seb', 'configkey')->get($this->quiz->id));
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->delete();
|
||||
|
||||
$this->assertFalse(\cache::make('quizaccess_seb', 'configkey')->get($this->quiz->id));
|
||||
@ -830,21 +833,21 @@ class quiz_settings_test extends \advanced_testcase {
|
||||
* Test that we can get SEB config key by quiz id.
|
||||
*/
|
||||
public function test_get_config_key_by_quiz_id() {
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$expected = $quizsettings->get_config_key();
|
||||
|
||||
$this->assertEquals($expected, quiz_settings::get_config_key_by_quiz_id($this->quiz->id));
|
||||
$this->assertEquals($expected, seb_quiz_settings::get_config_key_by_quiz_id($this->quiz->id));
|
||||
|
||||
// Check that data is getting from cache.
|
||||
$quizsettings->set('showsebtaskbar', 0);
|
||||
$this->assertNotEquals($quizsettings->get_config_key(), quiz_settings::get_config_key_by_quiz_id($this->quiz->id));
|
||||
$this->assertNotEquals($quizsettings->get_config_key(), seb_quiz_settings::get_config_key_by_quiz_id($this->quiz->id));
|
||||
|
||||
// Now save and check that cached as been updated.
|
||||
$quizsettings->save();
|
||||
$this->assertEquals($quizsettings->get_config_key(), quiz_settings::get_config_key_by_quiz_id($this->quiz->id));
|
||||
$this->assertEquals($quizsettings->get_config_key(), seb_quiz_settings::get_config_key_by_quiz_id($this->quiz->id));
|
||||
|
||||
// Returns null for non existing quiz.
|
||||
$this->assertNull(quiz_settings::get_config_key_by_quiz_id(7777777));
|
||||
$this->assertNull(seb_quiz_settings::get_config_key_by_quiz_id(7777777));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz->seb_requiresafeexambrowser = settings_provider::USE_SEB_NO;
|
||||
quizaccess_seb::save_settings($this->quiz);
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$this->assertEquals(settings_provider::USE_SEB_CONFIG_MANUALLY, $quizsettings->get('requiresafeexambrowser'));
|
||||
}
|
||||
|
||||
@ -388,7 +388,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
@ -414,7 +414,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $this->create_template()->get('id'));
|
||||
$quizsettings->save();
|
||||
@ -442,7 +442,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->setUser($user);
|
||||
|
||||
// Set quiz setting to require seb.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
// Set up dummy request.
|
||||
$FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
|
||||
@ -463,7 +463,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $this->create_template()->get('id'));
|
||||
$quizsettings->save();
|
||||
@ -490,7 +490,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
@ -522,7 +522,7 @@ class rule_test extends \advanced_testcase {
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$browserexamkey = hash('sha256', 'testkey');
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
|
||||
$quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
|
||||
$quizsettings->save();
|
||||
@ -548,7 +548,7 @@ class rule_test extends \advanced_testcase {
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$browserexamkey = hash('sha256', 'testkey');
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
@ -643,7 +643,7 @@ class rule_test extends \advanced_testcase {
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$browserexamkey = hash('sha256', 'testkey');
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
|
||||
$quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
|
||||
$quizsettings->save();
|
||||
@ -666,7 +666,7 @@ class rule_test extends \advanced_testcase {
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$browserexamkey = hash('sha256', 'testkey');
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
@ -698,7 +698,7 @@ class rule_test extends \advanced_testcase {
|
||||
|
||||
// Set quiz setting to require seb and save BEK.
|
||||
$browserexamkey = hash('sha256', 'testkey');
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
|
||||
$quizsettings->set('templateid', $this->create_template()->get('id'));
|
||||
@ -730,7 +730,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->setUser($user);
|
||||
|
||||
// Set quiz setting to require seb.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
|
||||
$quizsettings->save();
|
||||
|
||||
@ -752,7 +752,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->setUser($user);
|
||||
|
||||
// Set quiz setting to require seb.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
|
||||
$quizsettings->save();
|
||||
|
||||
@ -795,7 +795,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
// Set quiz setting to require seb.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); // Doesn't check basic header.
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$this->create_module_test_file($xml, $this->quiz->cmid);
|
||||
@ -824,7 +824,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
// Set quiz setting to require seb.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$quizsettings->set('templateid', $this->create_template()->get('id'));
|
||||
$quizsettings->save();
|
||||
@ -853,7 +853,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->setUser($user);
|
||||
|
||||
// Set quiz setting to not require seb.
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_NO);
|
||||
$quizsettings->save();
|
||||
|
||||
@ -1044,7 +1044,7 @@ class rule_test extends \advanced_testcase {
|
||||
$method = $reflection->getMethod('get_action_buttons');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
// Should see link when using manually.
|
||||
$this->assertStringContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
|
||||
@ -1161,7 +1161,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$roleid = $this->getDataGenerator()->create_role();
|
||||
@ -1268,7 +1268,7 @@ class rule_test extends \advanced_testcase {
|
||||
$this->setAdminUser();
|
||||
|
||||
$this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
|
||||
$quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$quizsettings->save();
|
||||
// Set access for Moodle session.
|
||||
$SESSION->quizaccess_seb_access = [$this->quiz->cmid => true];
|
||||
|
@ -111,7 +111,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
* Test that settings types to be added to quiz settings, are part of quiz_settings persistent class.
|
||||
*/
|
||||
public function test_setting_elements_are_part_of_quiz_settings_table() {
|
||||
$dbsettings = (array) (new quiz_settings())->to_record();
|
||||
$dbsettings = (array) (new seb_quiz_settings())->to_record();
|
||||
$settingelements = settings_provider::get_seb_config_elements();
|
||||
$settingelements = (array) $this->strip_all_prefixes((object) $settingelements);
|
||||
|
||||
@ -704,7 +704,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
|
||||
$template = $this->create_template();
|
||||
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('templateid', $template->get('id'));
|
||||
$settings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$settings->save();
|
||||
@ -731,7 +731,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
|
||||
// Setup conflicting permissions.
|
||||
$template = $this->create_template();
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('templateid', $template->get('id'));
|
||||
$settings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$settings->save();
|
||||
@ -794,7 +794,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
|
||||
$template = $this->create_template();
|
||||
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('templateid', $template->get('id'));
|
||||
$settings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$settings->save();
|
||||
@ -989,7 +989,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
|
||||
settings_provider::save_filemanager_sebconfigfile_draftarea($draftitemid, $this->quiz->cmid);
|
||||
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$settings->save();
|
||||
|
||||
@ -1167,7 +1167,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
|
||||
// Create a template.
|
||||
$template = $this->create_template();
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('templateid', $template->get('id'));
|
||||
$settings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
|
||||
$settings->save();
|
||||
@ -1197,7 +1197,7 @@ class settings_provider_test extends \advanced_testcase {
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
|
||||
$draftitemid = $this->create_test_draftarea_file($xml);
|
||||
settings_provider::save_filemanager_sebconfigfile_draftarea($draftitemid, $this->quiz->cmid);
|
||||
$settings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings = seb_quiz_settings::get_record(['quizid' => $this->quiz->id]);
|
||||
$settings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
|
||||
$settings->save();
|
||||
|
||||
|
@ -108,7 +108,7 @@ class template_test extends \advanced_testcase {
|
||||
$template->save();
|
||||
$this->assertTrue($template->can_delete());
|
||||
|
||||
$DB->insert_record(quiz_settings::TABLE, (object) [
|
||||
$DB->insert_record(seb_quiz_settings::TABLE, (object) [
|
||||
'quizid' => 1,
|
||||
'cmid' => 1,
|
||||
'templateid' => $template->get('id'),
|
||||
|
@ -23,7 +23,9 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use quizaccess_seb\access_manager;
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use quizaccess_seb\seb_access_manager;
|
||||
use quizaccess_seb\settings_provider;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -189,7 +191,7 @@ trait quizaccess_seb_test_helper_trait {
|
||||
$this->setUser($user);
|
||||
|
||||
$starttime = time();
|
||||
$quizobj = \quiz::create($quiz->id, $user->id);
|
||||
$quizobj = mod_quiz\quiz_settings::create($quiz->id, $user->id);
|
||||
|
||||
$quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
|
||||
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
|
||||
@ -200,7 +202,7 @@ trait quizaccess_seb_test_helper_trait {
|
||||
quiz_attempt_save_started($quizobj, $quba, $attempt);
|
||||
|
||||
// Answer the questions.
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
|
||||
$tosubmit = [
|
||||
1 => ['answer' => 'frog'],
|
||||
@ -210,7 +212,7 @@ trait quizaccess_seb_test_helper_trait {
|
||||
$attemptobj->process_submitted_actions($starttime, false, $tosubmit);
|
||||
|
||||
// Finish the attempt.
|
||||
$attemptobj = \quiz_attempt::create($attempt->id);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
$attemptobj->process_finish($starttime, false);
|
||||
|
||||
$this->setUser();
|
||||
@ -237,21 +239,21 @@ trait quizaccess_seb_test_helper_trait {
|
||||
/**
|
||||
* Get access manager for testing.
|
||||
*
|
||||
* @return \quizaccess_seb\access_manager
|
||||
* @return \quizaccess_seb\seb_access_manager
|
||||
*/
|
||||
protected function get_access_manager() {
|
||||
return new access_manager(new \quiz($this->quiz,
|
||||
return new seb_access_manager(new mod_quiz\quiz_settings($this->quiz,
|
||||
get_coursemodule_from_id('quiz', $this->quiz->cmid), $this->course));
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to make the rule form the currently created quiz and course.
|
||||
*
|
||||
* @return \quiz_access_rule_base|null
|
||||
* @return access_rule_base|null
|
||||
*/
|
||||
protected function make_rule() {
|
||||
return \quizaccess_seb::make(
|
||||
new \quiz($this->quiz, get_coursemodule_from_id('quiz', $this->quiz->cmid), $this->course),
|
||||
new mod_quiz\quiz_settings($this->quiz, get_coursemodule_from_id('quiz', $this->quiz->cmid), $this->course),
|
||||
0,
|
||||
true
|
||||
);
|
||||
|
@ -14,29 +14,18 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_securewindow plugin.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage securewindow
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* A rule for ensuring that the quiz is opened in a popup, with some JavaScript
|
||||
* to prevent copying and pasting, etc.
|
||||
*
|
||||
* @package quizaccess_securewindow
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_securewindow extends quiz_access_rule_base {
|
||||
class quizaccess_securewindow extends access_rule_base {
|
||||
/** @var array options that should be used for opening the secure popup. */
|
||||
protected static $popupoptions = array(
|
||||
'left' => 0,
|
||||
@ -52,7 +41,7 @@ class quizaccess_securewindow extends quiz_access_rule_base {
|
||||
'menubar' => false,
|
||||
);
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
|
||||
if ($quizobj->get_quiz()->browsersecurity !== 'securewindow') {
|
||||
return null;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_securewindow;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_securewindow;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -32,7 +32,7 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/securewindow/rule.php');
|
||||
* @copyright 2008 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*
|
||||
* @covers \quiz_access_rule_base
|
||||
* @covers \mod_quiz\local\access_rule_base
|
||||
* @covers \quizaccess_securewindow
|
||||
*/
|
||||
class rule_test extends \basic_testcase {
|
||||
@ -42,7 +42,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->browsersecurity = 'securewindow';
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_securewindow($quizobj, 0);
|
||||
$attempt = new \stdClass();
|
||||
|
||||
|
@ -14,31 +14,23 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use mod_quiz\form\preflight_check_form;
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* Implementaton of the quizaccess_timelimit plugin.
|
||||
* A rule representing the time limit.
|
||||
*
|
||||
* @package quizaccess
|
||||
* @subpackage timelimit
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
|
||||
/**
|
||||
* A rule representing the time limit. It does not actually restrict access, but we use this
|
||||
* It does not actually restrict access, but we use this
|
||||
* class to encapsulate some of the relevant code.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package quizaccess_timelimit
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quizaccess_timelimit extends quiz_access_rule_base {
|
||||
class quizaccess_timelimit extends access_rule_base {
|
||||
|
||||
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
|
||||
if (empty($quizobj->get_quiz()->timelimit) || $canignoretimelimits) {
|
||||
return null;
|
||||
@ -74,7 +66,7 @@ class quizaccess_timelimit extends quiz_access_rule_base {
|
||||
return $attemptid === null;
|
||||
}
|
||||
|
||||
public function add_preflight_check_form_fields(mod_quiz_preflight_check_form $quizform,
|
||||
public function add_preflight_check_form_fields(preflight_check_form $quizform,
|
||||
MoodleQuickForm $mform, $attemptid) {
|
||||
$mform->addElement('header', 'honestycheckheader',
|
||||
get_string('confirmstartheader', 'quizaccess_timelimit'));
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace quizaccess_timelimit;
|
||||
|
||||
use quiz;
|
||||
use mod_quiz\quiz_settings;
|
||||
use quizaccess_timelimit;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -39,7 +39,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timelimit = 3600;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_timelimit($quizobj, 10000);
|
||||
$attempt = new \stdClass();
|
||||
|
||||
@ -88,7 +88,7 @@ class rule_test extends \basic_testcase {
|
||||
$quiz->timelimit = $timelimit;
|
||||
$cm = new \stdClass();
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$quizobj = new quiz_settings($quiz, $cm, null);
|
||||
$rule = new quizaccess_timelimit($quizobj, $timenow);
|
||||
$attempt = new \stdClass();
|
||||
|
||||
|
@ -2,6 +2,17 @@ This files describes API changes for quiz access rule plugins.
|
||||
|
||||
Overview of this plugin type at http://docs.moodle.org/dev/Quiz_access_rules
|
||||
|
||||
=== 4.2 ===
|
||||
|
||||
* Note that class mod_quiz_preflight_check_form has been renamed to
|
||||
mod_quiz\form\preflight_check_form.
|
||||
* The base class quiz_access_rule_base has been moved to mod_quiz\local\access_rule_base.
|
||||
Please:
|
||||
1. update your class declaration to ... extends access_rule_base {
|
||||
2. Add use mod_quiz\local\access_rule_base;
|
||||
3. Remove require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
|
||||
|
||||
|
||||
=== 2.8, 2.7.1, 2.6.4 and 2.5.7 ===
|
||||
|
||||
* New static method delete_settings for access rules, which is called when a
|
||||
|
@ -26,9 +26,9 @@
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/addrandomform.php');
|
||||
require_once($CFG->dirroot . '/question/editlib.php');
|
||||
|
||||
use mod_quiz\form\add_random_form;
|
||||
use qbank_managecategories\question_category_object;
|
||||
|
||||
list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) =
|
||||
@ -75,7 +75,7 @@ $qcobject = new question_category_object(
|
||||
null,
|
||||
$contexts->having_cap('moodle/question:add'));
|
||||
|
||||
$mform = new quiz_add_random_form(new moodle_url('/mod/quiz/addrandom.php'),
|
||||
$mform = new add_random_form(new moodle_url('/mod/quiz/addrandom.php'),
|
||||
array('contexts' => $contexts, 'cat' => $pagevars['cat']));
|
||||
|
||||
if ($mform->is_cancelled()) {
|
||||
|
@ -15,134 +15,11 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines the Moodle forum used to add random questions to the quiz.
|
||||
* File only retained to prevent fatal errors in code that tries to require/include this.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2008 Olli Savolainen
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-76612 delete this file as part of Moodle 4.6 development.
|
||||
* @deprecated This file is no longer required in Moodle 4.2+.
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* The add random questions form.
|
||||
*
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_add_random_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
global $OUTPUT, $PAGE, $CFG;
|
||||
|
||||
$mform = $this->_form;
|
||||
$mform->setDisableShortforms();
|
||||
|
||||
$contexts = $this->_customdata['contexts'];
|
||||
$usablecontexts = $contexts->having_cap('moodle/question:useall');
|
||||
|
||||
// Random from existing category section.
|
||||
$mform->addElement('header', 'existingcategoryheader',
|
||||
get_string('randomfromexistingcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category'),
|
||||
array('contexts' => $usablecontexts, 'top' => true));
|
||||
$mform->setDefault('category', $this->_customdata['cat']);
|
||||
|
||||
$mform->addElement('checkbox', 'includesubcategories', '', get_string('recurse', 'quiz'));
|
||||
|
||||
$tops = question_get_top_categories_for_contexts(array_column($contexts->all(), 'id'));
|
||||
$mform->hideIf('includesubcategories', 'category', 'in', $tops);
|
||||
|
||||
if ($CFG->usetags) {
|
||||
$tagstrings = array();
|
||||
$tags = core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $usablecontexts);
|
||||
foreach ($tags as $tag) {
|
||||
$tagstrings["{$tag->id},{$tag->name}"] = $tag->name;
|
||||
}
|
||||
$options = array(
|
||||
'multiple' => true,
|
||||
'noselectionstring' => get_string('anytags', 'quiz'),
|
||||
);
|
||||
$mform->addElement('autocomplete', 'fromtags', get_string('randomquestiontags', 'mod_quiz'), $tagstrings, $options);
|
||||
$mform->addHelpButton('fromtags', 'randomquestiontags', 'mod_quiz');
|
||||
}
|
||||
|
||||
// TODO: in the past, the drop-down used to only show sensible choices for
|
||||
// number of questions to add. That is, if the currently selected filter
|
||||
// only matched 9 questions (not already in the quiz), then the drop-down would
|
||||
// only offer choices 1..9. This nice UI hint got lost when the UI became Ajax-y.
|
||||
// We should add it back.
|
||||
$mform->addElement('select', 'numbertoadd', get_string('randomnumber', 'quiz'),
|
||||
$this->get_number_of_questions_to_add_choices());
|
||||
|
||||
$previewhtml = $OUTPUT->render_from_template('mod_quiz/random_question_form_preview', []);
|
||||
$mform->addElement('html', $previewhtml);
|
||||
|
||||
$mform->addElement('submit', 'existingcategory', get_string('addrandomquestion', 'quiz'));
|
||||
|
||||
// If the manage categories plugins is enabled, add the elements to create a new category in the form.
|
||||
if (\core\plugininfo\qbank::is_plugin_enabled(\qbank_managecategories\helper::PLUGINNAME)) {
|
||||
// Random from a new category section.
|
||||
$mform->addElement('header', 'newcategoryheader',
|
||||
get_string('randomquestionusinganewcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('text', 'name', get_string('name'), 'maxlength="254" size="50"');
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
$mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'question'),
|
||||
array('contexts' => $usablecontexts, 'top' => true));
|
||||
$mform->addHelpButton('parent', 'parentcategory', 'question');
|
||||
|
||||
$mform->addElement('submit', 'newcategory',
|
||||
get_string('createcategoryandaddrandomquestion', 'quiz'));
|
||||
}
|
||||
|
||||
// Cancel button.
|
||||
$mform->addElement('cancel');
|
||||
$mform->closeHeaderBefore('cancel');
|
||||
|
||||
$mform->addElement('hidden', 'addonpage', 0, 'id="rform_qpage"');
|
||||
$mform->setType('addonpage', PARAM_SEQUENCE);
|
||||
$mform->addElement('hidden', 'cmid', 0);
|
||||
$mform->setType('cmid', PARAM_INT);
|
||||
$mform->addElement('hidden', 'returnurl', 0);
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
|
||||
// Add the javascript required to enhance this mform.
|
||||
$PAGE->requires->js_call_amd('mod_quiz/add_random_form', 'init', [
|
||||
$mform->getAttribute('id'),
|
||||
$contexts->lowest()->id,
|
||||
$tops,
|
||||
$CFG->usetags
|
||||
]);
|
||||
}
|
||||
|
||||
public function validation($fromform, $files) {
|
||||
$errors = parent::validation($fromform, $files);
|
||||
|
||||
if (!empty($fromform['newcategory']) && trim($fromform['name']) == '') {
|
||||
$errors['name'] = get_string('categorynamecantbeblank', 'question');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an arbitrary array for the dropdown menu
|
||||
*
|
||||
* @param int $maxrand
|
||||
* @return array of integers [1, 2, ..., 100] (or to the smaller of $maxrand and 100.)
|
||||
*/
|
||||
private function get_number_of_questions_to_add_choices($maxrand = 100) {
|
||||
$randomcount = array();
|
||||
for ($i = 1; $i <= min(100, $maxrand); $i++) {
|
||||
$randomcount[$i] = $i;
|
||||
}
|
||||
return $randomcount;
|
||||
}
|
||||
}
|
||||
debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER);
|
||||
|
@ -22,6 +22,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\output\navigation_panel_attempt;
|
||||
use mod_quiz\output\renderer;
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
@ -57,7 +61,7 @@ if ($attemptobj->get_userid() != $USER->id) {
|
||||
if ($attemptobj->has_capability('mod/quiz:viewreports')) {
|
||||
redirect($attemptobj->review_url(null, $page));
|
||||
} else {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
|
||||
throw new moodle_exception('notyourattempt', 'quiz', $quizobj->view_url());
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +86,7 @@ if ($attemptobj->is_finished()) {
|
||||
// Check the access rules.
|
||||
$accessmanager = $attemptobj->get_access_manager(time());
|
||||
$accessmanager->setup_attempt_page($PAGE);
|
||||
/** @var renderer $output */
|
||||
$output = $PAGE->get_renderer('mod_quiz');
|
||||
$messages = $accessmanager->prevent_access();
|
||||
if (!$attemptobj->is_preview_user() && $messages) {
|
||||
@ -107,7 +112,7 @@ $slots = $attemptobj->get_slots($page);
|
||||
|
||||
// Check.
|
||||
if (empty($slots)) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noquestionsfound');
|
||||
throw new moodle_exception('noquestionsfound', 'quiz', $quizobj->view_url());
|
||||
}
|
||||
|
||||
// Update attempt page, redirecting the user if $page is not valid.
|
||||
@ -121,7 +126,7 @@ $PAGE->requires->js_init_call('M.mod_quiz.init_attempt_form', null, false, quiz_
|
||||
\core\session\manager::keepalive(); // Try to prevent sessions expiring during quiz attempts.
|
||||
|
||||
// Arrange for the navigation to be displayed in the first region on the page.
|
||||
$navbc = $attemptobj->get_navigation_panel($output, 'quiz_attempt_nav_panel', $page);
|
||||
$navbc = $attemptobj->get_navigation_panel($output, navigation_panel_attempt::class, $page);
|
||||
$regions = $PAGE->blocks->get_regions();
|
||||
$PAGE->blocks->add_fake_block($navbc, reset($regions));
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,7 +45,7 @@ require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
|
||||
|
||||
// Check that this attempt belongs to this user.
|
||||
if ($attemptobj->get_userid() != $USER->id) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
|
||||
throw new moodle_exception('notyourattempt', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// Check capabilities.
|
||||
@ -55,8 +55,7 @@ if (!$attemptobj->is_preview_user()) {
|
||||
|
||||
// If the attempt is already closed, send them to the review page.
|
||||
if ($attemptobj->is_finished()) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(),
|
||||
'attemptalreadyclosed', null, $attemptobj->review_url());
|
||||
throw new moodle_exception('attemptalreadyclosed', 'quiz', $attemptobj->review_url());
|
||||
}
|
||||
|
||||
$attemptobj->process_auto_save($timenow);
|
||||
|
586
mod/quiz/classes/access_manager.php
Normal file
586
mod/quiz/classes/access_manager.php
Normal file
@ -0,0 +1,586 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz;
|
||||
|
||||
use core_component;
|
||||
use mod_quiz\form\preflight_check_form;
|
||||
use mod_quiz\local\access_rule_base;
|
||||
use mod_quiz\question\display_options;
|
||||
use mod_quiz_mod_form;
|
||||
use mod_quiz\output\renderer;
|
||||
use moodle_page;
|
||||
use moodle_url;
|
||||
use MoodleQuickForm;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* This class aggregates the access rules that apply to a particular quiz.
|
||||
*
|
||||
* This provides a convenient API which other parts of the quiz code can use
|
||||
* to interact with the access rules.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.2
|
||||
*/
|
||||
class access_manager {
|
||||
/** @var quiz_settings the quiz settings object. */
|
||||
protected $quizobj;
|
||||
|
||||
/** @var int the time to be considered as 'now'. */
|
||||
protected $timenow;
|
||||
|
||||
/** @var access_rule_base instances of the active rules for this quiz. */
|
||||
protected $rules = [];
|
||||
|
||||
/**
|
||||
* Create an instance for a particular quiz.
|
||||
*
|
||||
* @param quiz_settings $quizobj the quiz settings.
|
||||
* The quiz we will be controlling access to.
|
||||
* @param int $timenow The time to use as 'now'.
|
||||
* @param bool $canignoretimelimits Whether this user is exempt from time
|
||||
* limits (has_capability('mod/quiz:ignoretimelimits', ...)).
|
||||
*/
|
||||
public function __construct(quiz_settings $quizobj, int $timenow, bool $canignoretimelimits) {
|
||||
$this->quizobj = $quizobj;
|
||||
$this->timenow = $timenow;
|
||||
$this->rules = $this->make_rules($quizobj, $timenow, $canignoretimelimits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all the rules relevant to a particular quiz.
|
||||
*
|
||||
* @param quiz_settings $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
* @param bool $canignoretimelimits whether the current user is exempt from
|
||||
* time limits by the mod/quiz:ignoretimelimits capability.
|
||||
* @return access_rule_base[] rules that apply to this quiz.
|
||||
*/
|
||||
protected function make_rules(quiz_settings $quizobj, int $timenow, bool $canignoretimelimits): array {
|
||||
|
||||
$rules = [];
|
||||
foreach (self::get_rule_classes() as $ruleclass) {
|
||||
$rule = $ruleclass::make($quizobj, $timenow, $canignoretimelimits);
|
||||
if ($rule) {
|
||||
$rules[$ruleclass] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
$superceededrules = [];
|
||||
foreach ($rules as $rule) {
|
||||
$superceededrules += $rule->get_superceded_rules();
|
||||
}
|
||||
|
||||
foreach ($superceededrules as $superceededrule) {
|
||||
unset($rules['quizaccess_' . $superceededrule]);
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get that names of all the installed rule classes.
|
||||
*
|
||||
* @return array of class names.
|
||||
*/
|
||||
protected static function get_rule_classes(): array {
|
||||
return core_component::get_plugin_list_with_class('quizaccess', '', 'rule.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any form fields that the access rules require to the settings form.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism, becuase all their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param mod_quiz_mod_form $quizform the quiz settings form that is being built.
|
||||
* @param MoodleQuickForm $mform the wrapped MoodleQuickForm.
|
||||
*/
|
||||
public static function add_settings_form_fields(
|
||||
mod_quiz_mod_form $quizform, MoodleQuickForm $mform): void {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$rule::add_settings_form_fields($quizform, $mform);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The the options for the Browser security settings menu.
|
||||
*
|
||||
* @return array key => lang string.
|
||||
*/
|
||||
public static function get_browser_security_choices(): array {
|
||||
$options = ['-' => get_string('none', 'quiz')];
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$options += $rule::get_browser_security_choices();
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the data from any form fields added using {@see add_settings_form_fields()}.
|
||||
*
|
||||
* @param array $errors the errors found so far.
|
||||
* @param array $data the submitted form data.
|
||||
* @param array $files information about any uploaded files.
|
||||
* @param mod_quiz_mod_form $quizform the quiz form object.
|
||||
* @return array $errors the updated $errors array.
|
||||
*/
|
||||
public static function validate_settings_form_fields(array $errors,
|
||||
array $data, array $files, mod_quiz_mod_form $quizform): array {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$errors = $rule::validate_settings_form_fields($errors, $data, $files, $quizform);
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any submitted settings when the quiz settings form is submitted.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism because their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param stdClass $quiz the data from the quiz form, including $quiz->id
|
||||
* which is the id of the quiz being saved.
|
||||
*/
|
||||
public static function save_settings(stdClass $quiz): void {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$rule::save_settings($quiz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete any rule-specific settings when the quiz is deleted.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism because their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param stdClass $quiz the data from the database, including $quiz->id
|
||||
* which is the id of the quiz being deleted.
|
||||
* @since Moodle 2.7.1, 2.6.4, 2.5.7
|
||||
*/
|
||||
public static function delete_settings(stdClass $quiz): void {
|
||||
|
||||
foreach (self::get_rule_classes() as $rule) {
|
||||
$rule::delete_settings($quiz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL for loading all the access settings in one go.
|
||||
*
|
||||
* @param int $quizid the quiz id.
|
||||
* @param array $rules list of rule plugins, from {@see get_rule_classes()}.
|
||||
* @param string $basefields initial part of the select list.
|
||||
* @return array with two elements, the sql and the placeholder values.
|
||||
* If $basefields is '' then you must allow for the possibility that
|
||||
* there is no data to load, in which case this method returns $sql = ''.
|
||||
*/
|
||||
protected static function get_load_sql(int $quizid, array $rules, string $basefields): array {
|
||||
$allfields = $basefields;
|
||||
$alljoins = '{quiz} quiz';
|
||||
$allparams = ['quizid' => $quizid];
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
[$fields, $joins, $params] = $rule::get_settings_sql($quizid);
|
||||
if ($fields) {
|
||||
if ($allfields) {
|
||||
$allfields .= ', ';
|
||||
}
|
||||
$allfields .= $fields;
|
||||
}
|
||||
if ($joins) {
|
||||
$alljoins .= ' ' . $joins;
|
||||
}
|
||||
if ($params) {
|
||||
$allparams += $params;
|
||||
}
|
||||
}
|
||||
|
||||
if ($allfields === '') {
|
||||
return ['', []];
|
||||
}
|
||||
|
||||
return ["SELECT $allfields FROM $alljoins WHERE quiz.id = :quizid", $allparams];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load any settings required by the access rules. We try to do this with
|
||||
* a single DB query.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism, becuase all their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param int $quizid the quiz id.
|
||||
* @return array setting value name => value. The value names should all
|
||||
* start with the name of the corresponding plugin to avoid collisions.
|
||||
*/
|
||||
public static function load_settings(int $quizid): array {
|
||||
global $DB;
|
||||
|
||||
$rules = self::get_rule_classes();
|
||||
[$sql, $params] = self::get_load_sql($quizid, $rules, '');
|
||||
|
||||
if ($sql) {
|
||||
$data = (array) $DB->get_record_sql($sql, $params);
|
||||
} else {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
$data += $rule::get_extra_settings($quizid);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the quiz settings and any settings required by the access rules.
|
||||
* We try to do this with a single DB query.
|
||||
*
|
||||
* Note that the standard plugins do not use this mechanism, becuase all their
|
||||
* settings are stored in the quiz table.
|
||||
*
|
||||
* @param int $quizid the quiz id.
|
||||
* @return stdClass mdl_quiz row with extra fields.
|
||||
*/
|
||||
public static function load_quiz_and_settings(int $quizid): stdClass {
|
||||
global $DB;
|
||||
|
||||
$rules = self::get_rule_classes();
|
||||
[$sql, $params] = self::get_load_sql($quizid, $rules, 'quiz.*');
|
||||
$quiz = $DB->get_record_sql($sql, $params, MUST_EXIST);
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
foreach ($rule::get_extra_settings($quizid) as $name => $value) {
|
||||
$quiz->$name = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $quiz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the class names of all the active rules.
|
||||
*
|
||||
* Mainly useful for debugging.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_active_rule_names(): array {
|
||||
$classnames = [];
|
||||
foreach ($this->rules as $rule) {
|
||||
$classnames[] = get_class($rule);
|
||||
}
|
||||
return $classnames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates an array of messages.
|
||||
*
|
||||
* @param array $messages the current list of messages.
|
||||
* @param string|array $new the new messages or messages.
|
||||
* @return array the updated array of messages.
|
||||
*/
|
||||
protected function accumulate_messages(array $messages, $new): array {
|
||||
if (is_array($new)) {
|
||||
$messages = array_merge($messages, $new);
|
||||
} else if (is_string($new) && $new) {
|
||||
$messages[] = $new;
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a description of the rules that apply to this quiz, such
|
||||
* as is shown at the top of the quiz view page. Note that not all
|
||||
* rules consider themselves important enough to output a description.
|
||||
*
|
||||
* @return array an array of description messages which may be empty. It
|
||||
* would be sensible to output each one surrounded by <p> tags.
|
||||
*/
|
||||
public function describe_rules(): array {
|
||||
$result = [];
|
||||
foreach ($this->rules as $rule) {
|
||||
$result = $this->accumulate_messages($result, $rule->description());
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a user should be allowed to start a new attempt at this quiz now.
|
||||
* If there are any restrictions in force now, return an array of reasons why access
|
||||
* should be blocked. If access is OK, return false.
|
||||
*
|
||||
* @param int $numprevattempts the number of previous attempts this user has made.
|
||||
* @param stdClass|false $lastattempt information about the user's last completed attempt.
|
||||
* if there is not a previous attempt, the false is passed.
|
||||
* @return array an array of reason why access is not allowed. An empty array
|
||||
* (== false) if access should be allowed.
|
||||
*/
|
||||
public function prevent_new_attempt(int $numprevattempts, $lastattempt): array {
|
||||
$reasons = [];
|
||||
foreach ($this->rules as $rule) {
|
||||
$reasons = $this->accumulate_messages($reasons,
|
||||
$rule->prevent_new_attempt($numprevattempts, $lastattempt));
|
||||
}
|
||||
return $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user should be blocked from starting a new attempt or continuing
|
||||
* an attempt now. If there are any restrictions in force now, return an array
|
||||
* of reasons why access should be blocked. If access is OK, return false.
|
||||
*
|
||||
* @return array An array of reason why access is not allowed, or an empty array
|
||||
* (== false) if access should be allowed.
|
||||
*/
|
||||
public function prevent_access(): array {
|
||||
$reasons = [];
|
||||
foreach ($this->rules as $rule) {
|
||||
$reasons = $this->accumulate_messages($reasons, $rule->prevent_access());
|
||||
}
|
||||
return $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a UI check is required before the user starts/continues their attempt.
|
||||
*
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return bool whether a check is required.
|
||||
*/
|
||||
public function is_preflight_check_required(?int $attemptid): bool {
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->is_preflight_check_required($attemptid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the form required to do the pre-flight checks.
|
||||
* @param moodle_url $url the form action URL.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return preflight_check_form the form.
|
||||
*/
|
||||
public function get_preflight_check_form(moodle_url $url, ?int $attemptid): preflight_check_form {
|
||||
// This form normally wants POST submissions. However, it also needs to
|
||||
// accept GET submissions. Since formslib is strict, we have to detect
|
||||
// which case we are in, and set the form property appropriately.
|
||||
$method = 'post';
|
||||
if (!empty($_GET['_qf__preflight_check_form'])) {
|
||||
$method = 'get';
|
||||
}
|
||||
return new preflight_check_form($url->out_omit_querystring(),
|
||||
['rules' => $this->rules, 'quizobj' => $this->quizobj,
|
||||
'attemptid' => $attemptid, 'hidden' => $url->params()], $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* The pre-flight check has passed. This is a chance to record that fact in some way.
|
||||
*
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
*/
|
||||
public function notify_preflight_check_passed(?int $attemptid): void {
|
||||
foreach ($this->rules as $rule) {
|
||||
$rule->notify_preflight_check_passed($attemptid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the rules that the current attempt is finished.
|
||||
*
|
||||
* This is use, for example by the password rule, to clear the flag in the session.
|
||||
*/
|
||||
public function current_attempt_finished(): void {
|
||||
foreach ($this->rules as $rule) {
|
||||
$rule->current_attempt_finished();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do any of the rules mean that this student will no be allowed any further attempts at this
|
||||
* quiz. Used, for example, to change the label by the grade displayed on the view page from
|
||||
* 'your current grade is' to 'your final grade is'.
|
||||
*
|
||||
* @param int $numprevattempts the number of previous attempts this user has made.
|
||||
* @param stdClass|false $lastattempt information about the user's last completed attempt.
|
||||
* @return bool true if there is no way the user will ever be allowed to attempt
|
||||
* this quiz again.
|
||||
*/
|
||||
public function is_finished(int $numprevattempts, $lastattempt): bool {
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->is_finished($numprevattempts, $lastattempt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the attempt (review or summary) page with any properties required
|
||||
* by the access rules.
|
||||
*
|
||||
* @param moodle_page $page the page object to initialise.
|
||||
*/
|
||||
public function setup_attempt_page(moodle_page $page): void {
|
||||
foreach ($this->rules as $rule) {
|
||||
$rule->setup_attempt_page($page);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute when the attempt must be submitted.
|
||||
*
|
||||
* @param stdClass $attempt the data from the relevant quiz_attempts row.
|
||||
* @return int|false the attempt close time. False if there is no limit.
|
||||
*/
|
||||
public function get_end_time(stdClass $attempt) {
|
||||
$timeclose = false;
|
||||
foreach ($this->rules as $rule) {
|
||||
$ruletimeclose = $rule->end_time($attempt);
|
||||
if ($ruletimeclose !== false && ($timeclose === false || $ruletimeclose < $timeclose)) {
|
||||
$timeclose = $ruletimeclose;
|
||||
}
|
||||
}
|
||||
return $timeclose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute what should be displayed to the user for time remaining in this attempt.
|
||||
*
|
||||
* @param stdClass $attempt the data from the relevant quiz_attempts row.
|
||||
* @param int $timenow the time to consider as 'now'.
|
||||
* @return int|false the number of seconds remaining for this attempt.
|
||||
* False if no limit should be displayed.
|
||||
*/
|
||||
public function get_time_left_display(stdClass $attempt, int $timenow) {
|
||||
$timeleft = false;
|
||||
foreach ($this->rules as $rule) {
|
||||
$ruletimeleft = $rule->time_left_display($attempt, $timenow);
|
||||
if ($ruletimeleft !== false && ($timeleft === false || $ruletimeleft < $timeleft)) {
|
||||
$timeleft = $ruletimeleft;
|
||||
}
|
||||
}
|
||||
return $timeleft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this quiz required to be shown in a popup window?
|
||||
*
|
||||
* @return bool true if a popup is required.
|
||||
*/
|
||||
public function attempt_must_be_in_popup(): bool {
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->attempt_must_be_in_popup()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options required for opening the attempt in a popup window.
|
||||
*
|
||||
* @return array any options that are required for showing the attempt page
|
||||
* in a popup window.
|
||||
*/
|
||||
public function get_popup_options(): array {
|
||||
$options = [];
|
||||
foreach ($this->rules as $rule) {
|
||||
$options += $rule->get_popup_options();
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the user back to the quiz view page. Normally this is just a redirect, but
|
||||
* If we were in a secure window, we close this window, and reload the view window we came from.
|
||||
*
|
||||
* This method does not return;
|
||||
*
|
||||
* @param renderer $output the quiz renderer.
|
||||
* @param string $message optional message to output while redirecting.
|
||||
*/
|
||||
public function back_to_view_page(renderer $output, string $message = ''): void {
|
||||
// Actually return type 'never' on the previous line, once 8.1 is our minimum PHP version.
|
||||
if ($this->attempt_must_be_in_popup()) {
|
||||
echo $output->close_attempt_popup(new moodle_url($this->quizobj->view_url()), $message);
|
||||
die();
|
||||
} else {
|
||||
redirect($this->quizobj->view_url(), $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make some text into a link to review the quiz, if that is appropriate.
|
||||
*
|
||||
* @param stdClass $attempt the attempt object
|
||||
* @param mixed $nolongerused not used any more.
|
||||
* @param renderer $output quiz renderer instance.
|
||||
* @return string some HTML, the $linktext either unmodified or wrapped in a
|
||||
* link to the review page.
|
||||
*/
|
||||
public function make_review_link(stdClass $attempt, $nolongerused, renderer $output): string {
|
||||
|
||||
// If the attempt is still open, don't link.
|
||||
if (in_array($attempt->state, [quiz_attempt::IN_PROGRESS, quiz_attempt::OVERDUE])) {
|
||||
return $output->no_review_message('');
|
||||
}
|
||||
|
||||
$when = quiz_attempt_state($this->quizobj->get_quiz(), $attempt);
|
||||
$reviewoptions = display_options::make_from_quiz(
|
||||
$this->quizobj->get_quiz(), $when);
|
||||
|
||||
if (!$reviewoptions->attempt) {
|
||||
return $output->no_review_message($this->quizobj->cannot_review_message($when, true));
|
||||
|
||||
} else {
|
||||
return $output->review_link($this->quizobj->review_url($attempt->id),
|
||||
$this->attempt_must_be_in_popup(), $this->get_popup_options());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the preflight checks using the given data in all the rules supporting them.
|
||||
*
|
||||
* @param array $data passed data for validation
|
||||
* @param array $files un-used, Moodle seems to not support it anymore
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return array of errors, empty array means no errors
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function validate_preflight_check(array $data, array $files, ?int $attemptid): array {
|
||||
$errors = [];
|
||||
foreach ($this->rules as $rule) {
|
||||
if ($rule->is_preflight_check_required($attemptid)) {
|
||||
$errors = $rule->validate_preflight_check($data, $files, $errors, $attemptid);
|
||||
}
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@
|
||||
|
||||
namespace mod_quiz\admin;
|
||||
|
||||
use mod_quiz\access_manager;
|
||||
|
||||
/**
|
||||
* Admin settings class for the quiz browser security option.
|
||||
*
|
||||
@ -35,7 +37,7 @@ class browser_security_setting extends \admin_setting_configselect_with_advanced
|
||||
}
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
$this->choices = \quiz_access_manager::get_browser_security_choices();
|
||||
$this->choices = access_manager::get_browser_security_choices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -20,10 +20,8 @@ namespace mod_quiz\completion;
|
||||
|
||||
use context_module;
|
||||
use core_completion\activity_custom_completion;
|
||||
use grade_grade;
|
||||
use grade_item;
|
||||
use quiz;
|
||||
use quiz_access_manager;
|
||||
use mod_quiz\quiz_settings;
|
||||
use mod_quiz\access_manager;
|
||||
|
||||
/**
|
||||
* Activity custom completion subclass for the quiz activity.
|
||||
@ -71,8 +69,8 @@ class custom_completion extends activity_custom_completion {
|
||||
}
|
||||
$lastfinishedattempt = end($attempts);
|
||||
$context = context_module::instance($this->cm->id);
|
||||
$quizobj = quiz::create($this->cm->instance, $this->userid);
|
||||
$accessmanager = new quiz_access_manager(
|
||||
$quizobj = quiz_settings::create($this->cm->instance, $this->userid);
|
||||
$accessmanager = new access_manager(
|
||||
$quizobj,
|
||||
time(),
|
||||
has_capability('mod/quiz:ignoretimelimits', $context, $this->userid, false)
|
||||
|
@ -25,6 +25,9 @@
|
||||
*/
|
||||
|
||||
use core_course\external\helper_for_get_mods_by_courses;
|
||||
use mod_quiz\access_manager;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
@ -111,8 +114,8 @@ class mod_quiz_external extends external_api {
|
||||
$quizdetails['hasfeedback'] = (!empty($hasfeedback)) ? 1 : 0;
|
||||
|
||||
$timenow = time();
|
||||
$quizobj = quiz::create($quiz->id, $USER->id);
|
||||
$accessmanager = new quiz_access_manager($quizobj, $timenow, has_capability('mod/quiz:ignoretimelimits',
|
||||
$quizobj = quiz_settings::create($quiz->id, $USER->id);
|
||||
$accessmanager = new access_manager($quizobj, $timenow, has_capability('mod/quiz:ignoretimelimits',
|
||||
$context, null, false));
|
||||
|
||||
// Fields the user could see if have access to the quiz.
|
||||
@ -304,7 +307,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param int $quizid quiz instance id
|
||||
* @return array of warnings and status result
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public static function view_quiz($quizid) {
|
||||
global $DB;
|
||||
@ -365,10 +367,9 @@ class mod_quiz_external extends external_api {
|
||||
* @param bool $includepreviews whether to include previews or not
|
||||
* @return array of warnings and the list of attempts
|
||||
* @since Moodle 3.1
|
||||
* @throws invalid_parameter_exception
|
||||
*/
|
||||
public static function get_user_attempts($quizid, $userid = 0, $status = 'finished', $includepreviews = false) {
|
||||
global $DB, $USER;
|
||||
global $USER;
|
||||
|
||||
$warnings = array();
|
||||
|
||||
@ -710,7 +711,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param bool $forcenew Whether to force a new attempt or not.
|
||||
* @return array of warnings and the attempt basic data
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_quiz_exception
|
||||
*/
|
||||
public static function start_attempt($quizid, $preflightdata = array(), $forcenew = false) {
|
||||
global $DB, $USER;
|
||||
@ -728,11 +728,11 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']);
|
||||
|
||||
$quizobj = quiz::create($cm->instance, $USER->id);
|
||||
$quizobj = quiz_settings::create($cm->instance, $USER->id);
|
||||
|
||||
// Check questions.
|
||||
if (!$quizobj->has_questions()) {
|
||||
throw new moodle_quiz_exception($quizobj, 'noquestionsfound');
|
||||
throw new moodle_exception('noquestionsfound', 'quiz', $quizobj->view_url());
|
||||
}
|
||||
|
||||
// Create an object to manage all the other (non-roles) access rules.
|
||||
@ -766,7 +766,7 @@ class mod_quiz_external extends external_api {
|
||||
$errors = $accessmanager->validate_preflight_check($provideddata, [], $currentattemptid);
|
||||
|
||||
if (!empty($errors)) {
|
||||
throw new moodle_quiz_exception($quizobj, array_shift($errors));
|
||||
throw new moodle_exception(array_shift($errors), 'quiz', $quizobj->view_url());
|
||||
}
|
||||
|
||||
// Pre-flight check passed.
|
||||
@ -775,9 +775,9 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
if ($currentattemptid) {
|
||||
if ($lastattempt->state == quiz_attempt::OVERDUE) {
|
||||
throw new moodle_quiz_exception($quizobj, 'stateoverdue');
|
||||
throw new moodle_exception('stateoverdue', 'quiz', $quizobj->view_url());
|
||||
} else {
|
||||
throw new moodle_quiz_exception($quizobj, 'attemptstillinprogress');
|
||||
throw new moodle_exception('attemptstillinprogress', 'quiz', $quizobj->view_url());
|
||||
}
|
||||
}
|
||||
$offlineattempt = WS_SERVER ? true : false;
|
||||
@ -812,7 +812,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param bool $checkaccessrules whether to check the quiz access rules or not
|
||||
* @param bool $failifoverdue whether to return error if the attempt is overdue
|
||||
* @return array containing the attempt object and access messages
|
||||
* @throws moodle_quiz_exception
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
protected static function validate_attempt($params, $checkaccessrules = true, $failifoverdue = true) {
|
||||
@ -825,7 +824,7 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
// Check that this attempt belongs to this user.
|
||||
if ($attemptobj->get_userid() != $USER->id) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
|
||||
throw new moodle_exception('notyourattempt', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// General capabilities check.
|
||||
@ -843,15 +842,15 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
$messages = $accessmanager->prevent_access();
|
||||
if (!$ispreviewuser && $messages) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'attempterror');
|
||||
throw new moodle_exception('attempterror', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt closed?.
|
||||
if ($attemptobj->is_finished()) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'attemptalreadyclosed');
|
||||
throw new moodle_exception('attemptalreadyclosed', 'quiz', $attemptobj->view_url());
|
||||
} else if ($failifoverdue && $attemptobj->get_state() == quiz_attempt::OVERDUE) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'stateoverdue');
|
||||
throw new moodle_exception('stateoverdue', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// User submitted data (like the quiz password).
|
||||
@ -863,7 +862,7 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
$errors = $accessmanager->validate_preflight_check($provideddata, [], $params['attemptid']);
|
||||
if (!empty($errors)) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), array_shift($errors));
|
||||
throw new moodle_exception(array_shift($errors), 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
// Pre-flight check passed.
|
||||
$accessmanager->notify_preflight_check_passed($params['attemptid']);
|
||||
@ -872,19 +871,19 @@ class mod_quiz_external extends external_api {
|
||||
if (isset($params['page'])) {
|
||||
// Check if the page is out of range.
|
||||
if ($params['page'] != $attemptobj->force_page_number_into_range($params['page'])) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'Invalid page number');
|
||||
throw new moodle_exception('Invalid page number', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// Prevent out of sequence access.
|
||||
if (!$attemptobj->check_page_access($params['page'])) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'Out of sequence access');
|
||||
throw new moodle_exception('Out of sequence access', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// Check slots.
|
||||
$slots = $attemptobj->get_slots($params['page']);
|
||||
|
||||
if (empty($slots)) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noquestionsfound');
|
||||
throw new moodle_exception('noquestionsfound', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1047,7 +1046,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param array $preflightdata preflight required data (like passwords)
|
||||
* @return array of warnings and the attempt data, next page, message and questions
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_quiz_exceptions
|
||||
*/
|
||||
public static function get_attempt_data($attemptid, $page, $preflightdata = array()) {
|
||||
global $PAGE;
|
||||
@ -1371,8 +1369,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param array $params Array of parameters including the attemptid
|
||||
* @return array containing the attempt object and display options
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_exception
|
||||
* @throws moodle_quiz_exception
|
||||
*/
|
||||
protected static function validate_attempt_review($params) {
|
||||
|
||||
@ -1382,13 +1378,13 @@ class mod_quiz_external extends external_api {
|
||||
$displayoptions = $attemptobj->get_display_options(true);
|
||||
if ($attemptobj->is_own_attempt()) {
|
||||
if (!$attemptobj->is_finished()) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'attemptclosed');
|
||||
throw new moodle_exception('attemptclosed', 'quiz', $attemptobj->view_url());
|
||||
} else if (!$displayoptions->attempt) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noreview', null, '',
|
||||
throw new moodle_exception('noreview', 'quiz', $attemptobj->view_url(), null,
|
||||
$attemptobj->cannot_review_message());
|
||||
}
|
||||
} else if (!$attemptobj->is_review_allowed()) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noreviewattempt');
|
||||
throw new moodle_exception('noreviewattempt', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
return array($attemptobj, $displayoptions);
|
||||
}
|
||||
@ -1416,8 +1412,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param int $page page number, empty for all the questions in all the pages
|
||||
* @return array of warnings and the attempt data, feedback and questions
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_exception
|
||||
* @throws moodle_quiz_exception
|
||||
*/
|
||||
public static function get_attempt_review($attemptid, $page = -1) {
|
||||
global $PAGE;
|
||||
@ -1547,7 +1541,7 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
// Update attempt page, throwing an exception if $page is not valid.
|
||||
if (!$attemptobj->set_currentpage($params['page'])) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'Out of sequence access');
|
||||
throw new moodle_exception('Out of sequence access', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
$result = array();
|
||||
@ -1713,7 +1707,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param float $grade the grade to check
|
||||
* @return array of warnings and status result
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public static function get_quiz_feedback_for_grade($quizid, $grade) {
|
||||
global $DB;
|
||||
@ -1784,7 +1777,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param int $quizid quiz instance id
|
||||
* @return array of warnings and the access information
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_quiz_exception
|
||||
*/
|
||||
public static function get_quiz_access_information($quizid) {
|
||||
global $DB, $USER;
|
||||
@ -1807,10 +1799,10 @@ class mod_quiz_external extends external_api {
|
||||
$result['canviewreports'] = has_capability('mod/quiz:viewreports', $context);;
|
||||
|
||||
// Access manager now.
|
||||
$quizobj = quiz::create($cm->instance, $USER->id);
|
||||
$quizobj = quiz_settings::create($cm->instance, $USER->id);
|
||||
$ignoretimelimits = has_capability('mod/quiz:ignoretimelimits', $context, null, false);
|
||||
$timenow = time();
|
||||
$accessmanager = new quiz_access_manager($quizobj, $timenow, $ignoretimelimits);
|
||||
$accessmanager = new access_manager($quizobj, $timenow, $ignoretimelimits);
|
||||
|
||||
$result['accessrules'] = $accessmanager->describe_rules();
|
||||
$result['activerulenames'] = $accessmanager->get_active_rule_names();
|
||||
@ -1868,7 +1860,6 @@ class mod_quiz_external extends external_api {
|
||||
* @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;
|
||||
@ -1883,20 +1874,20 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']);
|
||||
|
||||
$attempttocheck = 0;
|
||||
$attempttocheck = null;
|
||||
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');
|
||||
throw new moodle_exception('notyourattempt', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
$attempttocheck = $attemptobj->get_attempt();
|
||||
}
|
||||
|
||||
// Access manager now.
|
||||
$quizobj = quiz::create($cm->instance, $USER->id);
|
||||
$quizobj = quiz_settings::create($cm->instance, $USER->id);
|
||||
$ignoretimelimits = has_capability('mod/quiz:ignoretimelimits', $context, null, false);
|
||||
$timenow = time();
|
||||
$accessmanager = new quiz_access_manager($quizobj, $timenow, $ignoretimelimits);
|
||||
$accessmanager = new access_manager($quizobj, $timenow, $ignoretimelimits);
|
||||
|
||||
$attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
|
||||
$lastfinishedattempt = end($attempts);
|
||||
@ -1913,7 +1904,7 @@ class mod_quiz_external extends external_api {
|
||||
$numattempts = count($attempts);
|
||||
|
||||
if (!$attempttocheck) {
|
||||
$attempttocheck = $unfinishedattempt ? $unfinishedattempt : $lastfinishedattempt;
|
||||
$attempttocheck = $unfinishedattempt ?: $lastfinishedattempt;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
@ -1974,7 +1965,6 @@ class mod_quiz_external extends external_api {
|
||||
* @param int $quizid quiz instance id
|
||||
* @return array of warnings and the access information
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_quiz_exception
|
||||
*/
|
||||
public static function get_quiz_required_qtypes($quizid) {
|
||||
global $DB, $USER;
|
||||
@ -1988,7 +1978,7 @@ class mod_quiz_external extends external_api {
|
||||
|
||||
list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']);
|
||||
|
||||
$quizobj = quiz::create($cm->instance, $USER->id);
|
||||
$quizobj = quiz_settings::create($cm->instance, $USER->id);
|
||||
$quizobj->preload_questions();
|
||||
$quizobj->load_questions();
|
||||
|
||||
|
145
mod/quiz/classes/form/add_random_form.php
Normal file
145
mod/quiz/classes/form/add_random_form.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\form;
|
||||
|
||||
use core_tag_tag;
|
||||
use moodleform;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* The add random questions form.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class add_random_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
global $OUTPUT, $PAGE, $CFG;
|
||||
|
||||
$mform = $this->_form;
|
||||
$mform->setDisableShortforms();
|
||||
|
||||
$contexts = $this->_customdata['contexts'];
|
||||
$usablecontexts = $contexts->having_cap('moodle/question:useall');
|
||||
|
||||
// Random from existing category section.
|
||||
$mform->addElement('header', 'existingcategoryheader',
|
||||
get_string('randomfromexistingcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category'),
|
||||
array('contexts' => $usablecontexts, 'top' => true));
|
||||
$mform->setDefault('category', $this->_customdata['cat']);
|
||||
|
||||
$mform->addElement('checkbox', 'includesubcategories', '', get_string('recurse', 'quiz'));
|
||||
|
||||
$tops = question_get_top_categories_for_contexts(array_column($contexts->all(), 'id'));
|
||||
$mform->hideIf('includesubcategories', 'category', 'in', $tops);
|
||||
|
||||
if ($CFG->usetags) {
|
||||
$tagstrings = array();
|
||||
$tags = core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $usablecontexts);
|
||||
foreach ($tags as $tag) {
|
||||
$tagstrings["{$tag->id},{$tag->name}"] = $tag->name;
|
||||
}
|
||||
$options = array(
|
||||
'multiple' => true,
|
||||
'noselectionstring' => get_string('anytags', 'quiz'),
|
||||
);
|
||||
$mform->addElement('autocomplete', 'fromtags', get_string('randomquestiontags', 'mod_quiz'), $tagstrings, $options);
|
||||
$mform->addHelpButton('fromtags', 'randomquestiontags', 'mod_quiz');
|
||||
}
|
||||
|
||||
// TODO: in the past, the drop-down used to only show sensible choices for
|
||||
// number of questions to add. That is, if the currently selected filter
|
||||
// only matched 9 questions (not already in the quiz), then the drop-down would
|
||||
// only offer choices 1..9. This nice UI hint got lost when the UI became Ajax-y.
|
||||
// We should add it back.
|
||||
$mform->addElement('select', 'numbertoadd', get_string('randomnumber', 'quiz'),
|
||||
$this->get_number_of_questions_to_add_choices());
|
||||
|
||||
$previewhtml = $OUTPUT->render_from_template('mod_quiz/random_question_form_preview', []);
|
||||
$mform->addElement('html', $previewhtml);
|
||||
|
||||
$mform->addElement('submit', 'existingcategory', get_string('addrandomquestion', 'quiz'));
|
||||
|
||||
// If the manage categories plugins is enabled, add the elements to create a new category in the form.
|
||||
if (\core\plugininfo\qbank::is_plugin_enabled(\qbank_managecategories\helper::PLUGINNAME)) {
|
||||
// Random from a new category section.
|
||||
$mform->addElement('header', 'newcategoryheader',
|
||||
get_string('randomquestionusinganewcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('text', 'name', get_string('name'), 'maxlength="254" size="50"');
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
$mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'question'),
|
||||
array('contexts' => $usablecontexts, 'top' => true));
|
||||
$mform->addHelpButton('parent', 'parentcategory', 'question');
|
||||
|
||||
$mform->addElement('submit', 'newcategory',
|
||||
get_string('createcategoryandaddrandomquestion', 'quiz'));
|
||||
}
|
||||
|
||||
// Cancel button.
|
||||
$mform->addElement('cancel');
|
||||
$mform->closeHeaderBefore('cancel');
|
||||
|
||||
$mform->addElement('hidden', 'addonpage', 0, 'id="rform_qpage"');
|
||||
$mform->setType('addonpage', PARAM_SEQUENCE);
|
||||
$mform->addElement('hidden', 'cmid', 0);
|
||||
$mform->setType('cmid', PARAM_INT);
|
||||
$mform->addElement('hidden', 'returnurl', 0);
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
|
||||
// Add the javascript required to enhance this mform.
|
||||
$PAGE->requires->js_call_amd('mod_quiz/add_random_form', 'init', [
|
||||
$mform->getAttribute('id'),
|
||||
$contexts->lowest()->id,
|
||||
$tops,
|
||||
$CFG->usetags
|
||||
]);
|
||||
}
|
||||
|
||||
public function validation($fromform, $files) {
|
||||
$errors = parent::validation($fromform, $files);
|
||||
|
||||
if (!empty($fromform['newcategory']) && trim($fromform['name']) == '') {
|
||||
$errors['name'] = get_string('categorynamecantbeblank', 'question');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an arbitrary array for the dropdown menu
|
||||
*
|
||||
* @param int $maxrand
|
||||
* @return array of integers [1, 2, ..., 100] (or to the smaller of $maxrand and 100.)
|
||||
*/
|
||||
private function get_number_of_questions_to_add_choices($maxrand = 100) {
|
||||
$randomcount = array();
|
||||
for ($i = 1; $i <= min(100, $maxrand); $i++) {
|
||||
$randomcount[$i] = $i;
|
||||
}
|
||||
return $randomcount;
|
||||
}
|
||||
}
|
301
mod/quiz/classes/form/edit_override_form.php
Normal file
301
mod/quiz/classes/form/edit_override_form.php
Normal file
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\form;
|
||||
|
||||
use cm_info;
|
||||
use context;
|
||||
use context_module;
|
||||
use mod_quiz_mod_form;
|
||||
use moodle_url;
|
||||
use moodleform;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/mod_form.php');
|
||||
|
||||
/**
|
||||
* Form for editing quiz settings overrides.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2010 Matt Petro
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class edit_override_form extends moodleform {
|
||||
|
||||
/** @var cm_info course module object. */
|
||||
protected $cm;
|
||||
|
||||
/** @var stdClass the quiz settings object. */
|
||||
protected $quiz;
|
||||
|
||||
/** @var context_module the quiz context. */
|
||||
protected $context;
|
||||
|
||||
/** @var bool editing group override (true) or user override (false). */
|
||||
protected $groupmode;
|
||||
|
||||
/** @var int groupid, if provided. */
|
||||
protected $groupid;
|
||||
|
||||
/** @var int userid, if provided. */
|
||||
protected $userid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moodle_url $submiturl the form action URL.
|
||||
* @param cm_info $cm course module object.
|
||||
* @param stdClass $quiz the quiz settings object.
|
||||
* @param context_module $context the quiz context.
|
||||
* @param bool $groupmode editing group override (true) or user override (false).
|
||||
* @param stdClass|null $override the override being edited, if it already exists.
|
||||
*/
|
||||
public function __construct(moodle_url $submiturl,
|
||||
cm_info $cm, stdClass $quiz, context_module $context,
|
||||
bool $groupmode, ?stdClass $override) {
|
||||
|
||||
$this->cm = $cm;
|
||||
$this->quiz = $quiz;
|
||||
$this->context = $context;
|
||||
$this->groupmode = $groupmode;
|
||||
$this->groupid = empty($override->groupid) ? 0 : $override->groupid;
|
||||
$this->userid = empty($override->userid) ? 0 : $override->userid;
|
||||
|
||||
parent::__construct($submiturl);
|
||||
}
|
||||
|
||||
protected function definition() {
|
||||
global $DB;
|
||||
|
||||
$cm = $this->cm;
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('header', 'override', get_string('override', 'quiz'));
|
||||
|
||||
$quizgroupmode = groups_get_activity_groupmode($cm);
|
||||
$accessallgroups = ($quizgroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context);
|
||||
|
||||
if ($this->groupmode) {
|
||||
// Group override.
|
||||
if ($this->groupid) {
|
||||
// There is already a groupid, so freeze the selector.
|
||||
$groupchoices = [];
|
||||
$groupchoices[$this->groupid] = groups_get_group_name($this->groupid);
|
||||
$mform->addElement('select', 'groupid',
|
||||
get_string('overridegroup', 'quiz'), $groupchoices);
|
||||
$mform->freeze('groupid');
|
||||
} else {
|
||||
// Prepare the list of groups.
|
||||
// Only include the groups the current can access.
|
||||
$groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm);
|
||||
if (empty($groups)) {
|
||||
// Generate an error.
|
||||
$link = new moodle_url('/mod/quiz/overrides.php', ['cmid' => $cm->id]);
|
||||
throw new \moodle_exception('groupsnone', 'quiz', $link);
|
||||
}
|
||||
|
||||
$groupchoices = [];
|
||||
foreach ($groups as $group) {
|
||||
$groupchoices[$group->id] = $group->name;
|
||||
}
|
||||
unset($groups);
|
||||
|
||||
if (count($groupchoices) == 0) {
|
||||
$groupchoices[0] = get_string('none');
|
||||
}
|
||||
|
||||
$mform->addElement('select', 'groupid',
|
||||
get_string('overridegroup', 'quiz'), $groupchoices);
|
||||
$mform->addRule('groupid', get_string('required'), 'required', null, 'client');
|
||||
}
|
||||
} else {
|
||||
// User override.
|
||||
$userfieldsapi = \core_user\fields::for_identity($this->context)->with_userpic()->with_name();
|
||||
$extrauserfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
|
||||
if ($this->userid) {
|
||||
// There is already a userid, so freeze the selector.
|
||||
$user = $DB->get_record('user', ['id' => $this->userid]);
|
||||
profile_load_custom_fields($user);
|
||||
$userchoices = [];
|
||||
$userchoices[$this->userid] = self::display_user_name($user, $extrauserfields);
|
||||
$mform->addElement('select', 'userid',
|
||||
get_string('overrideuser', 'quiz'), $userchoices);
|
||||
$mform->freeze('userid');
|
||||
} else {
|
||||
// Prepare the list of users.
|
||||
$groupids = 0;
|
||||
if (!$accessallgroups) {
|
||||
$groups = groups_get_activity_allowed_groups($cm);
|
||||
$groupids = array_keys($groups);
|
||||
}
|
||||
$enrolledjoin = get_enrolled_with_capabilities_join(
|
||||
$this->context, '', 'mod/quiz:attempt', $groupids, true);
|
||||
$userfieldsql = $userfieldsapi->get_sql('u', true, '', '', false);
|
||||
list($sort, $sortparams) = users_order_by_sql('u', null,
|
||||
$this->context, $userfieldsql->mappings);
|
||||
|
||||
$users = $DB->get_records_sql("
|
||||
SELECT $userfieldsql->selects
|
||||
FROM {user} u
|
||||
$enrolledjoin->joins
|
||||
$userfieldsql->joins
|
||||
LEFT JOIN {quiz_overrides} existingoverride ON
|
||||
existingoverride.userid = u.id AND existingoverride.quiz = :quizid
|
||||
WHERE existingoverride.id IS NULL
|
||||
AND $enrolledjoin->wheres
|
||||
ORDER BY $sort
|
||||
", array_merge(['quizid' => $this->quiz->id], $userfieldsql->params, $enrolledjoin->params, $sortparams));
|
||||
|
||||
// Filter users based on any fixed restrictions (groups, profile).
|
||||
$info = new \core_availability\info_module($cm);
|
||||
$users = $info->filter_user_list($users);
|
||||
|
||||
if (empty($users)) {
|
||||
// Generate an error.
|
||||
$link = new moodle_url('/mod/quiz/overrides.php', ['cmid' => $cm->id]);
|
||||
throw new \moodle_exception('usersnone', 'quiz', $link);
|
||||
}
|
||||
|
||||
$userchoices = [];
|
||||
foreach ($users as $id => $user) {
|
||||
$userchoices[$id] = self::display_user_name($user, $extrauserfields);
|
||||
}
|
||||
unset($users);
|
||||
|
||||
$mform->addElement('searchableselector', 'userid',
|
||||
get_string('overrideuser', 'quiz'), $userchoices);
|
||||
$mform->addRule('userid', get_string('required'), 'required', null, 'client');
|
||||
}
|
||||
}
|
||||
|
||||
// Password.
|
||||
// This field has to be above the date and timelimit fields,
|
||||
// otherwise browsers will clear it when those fields are changed.
|
||||
$mform->addElement('passwordunmask', 'password', get_string('requirepassword', 'quiz'));
|
||||
$mform->setType('password', PARAM_TEXT);
|
||||
$mform->addHelpButton('password', 'requirepassword', 'quiz');
|
||||
$mform->setDefault('password', $this->quiz->password);
|
||||
|
||||
// Open and close dates.
|
||||
$mform->addElement('date_time_selector', 'timeopen',
|
||||
get_string('quizopen', 'quiz'), mod_quiz_mod_form::$datefieldoptions);
|
||||
$mform->setDefault('timeopen', $this->quiz->timeopen);
|
||||
|
||||
$mform->addElement('date_time_selector', 'timeclose',
|
||||
get_string('quizclose', 'quiz'), mod_quiz_mod_form::$datefieldoptions);
|
||||
$mform->setDefault('timeclose', $this->quiz->timeclose);
|
||||
|
||||
// Time limit.
|
||||
$mform->addElement('duration', 'timelimit',
|
||||
get_string('timelimit', 'quiz'), ['optional' => true]);
|
||||
$mform->addHelpButton('timelimit', 'timelimit', 'quiz');
|
||||
$mform->setDefault('timelimit', $this->quiz->timelimit);
|
||||
|
||||
// Number of attempts.
|
||||
$attemptoptions = ['0' => get_string('unlimited')];
|
||||
for ($i = 1; $i <= QUIZ_MAX_ATTEMPT_OPTION; $i++) {
|
||||
$attemptoptions[$i] = $i;
|
||||
}
|
||||
$mform->addElement('select', 'attempts',
|
||||
get_string('attemptsallowed', 'quiz'), $attemptoptions);
|
||||
$mform->addHelpButton('attempts', 'attempts', 'quiz');
|
||||
$mform->setDefault('attempts', $this->quiz->attempts);
|
||||
|
||||
// Submit buttons.
|
||||
$mform->addElement('submit', 'resetbutton',
|
||||
get_string('reverttodefaults', 'quiz'));
|
||||
|
||||
$buttonarray = [];
|
||||
$buttonarray[] = $mform->createElement('submit', 'submitbutton',
|
||||
get_string('save', 'quiz'));
|
||||
$buttonarray[] = $mform->createElement('submit', 'againbutton',
|
||||
get_string('saveoverrideandstay', 'quiz'));
|
||||
$buttonarray[] = $mform->createElement('cancel');
|
||||
|
||||
$mform->addGroup($buttonarray, 'buttonbar', '', [' '], false);
|
||||
$mform->closeHeaderBefore('buttonbar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user's name and identity ready to display.
|
||||
*
|
||||
* @param stdClass $user a user object.
|
||||
* @param array $extrauserfields (identity fields in user table only from the user_fields API)
|
||||
* @return string User's name, with extra info, for display.
|
||||
*/
|
||||
public static function display_user_name(stdClass $user, array $extrauserfields): string {
|
||||
$username = fullname($user);
|
||||
$namefields = [];
|
||||
foreach ($extrauserfields as $field) {
|
||||
if (isset($user->$field) && $user->$field !== '') {
|
||||
$namefields[] = s($user->$field);
|
||||
} else if (strpos($field, 'profile_field_') === 0) {
|
||||
$field = substr($field, 14);
|
||||
if (isset($user->profile[$field]) && $user->profile[$field] !== '') {
|
||||
$namefields[] = s($user->profile[$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($namefields) {
|
||||
$username .= ' (' . implode(', ', $namefields) . ')';
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
public function validation($data, $files): array {
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
$mform =& $this->_form;
|
||||
$quiz = $this->quiz;
|
||||
|
||||
if ($mform->elementExists('userid')) {
|
||||
if (empty($data['userid'])) {
|
||||
$errors['userid'] = get_string('required');
|
||||
}
|
||||
}
|
||||
|
||||
if ($mform->elementExists('groupid')) {
|
||||
if (empty($data['groupid'])) {
|
||||
$errors['groupid'] = get_string('required');
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the dates make sense.
|
||||
if (!empty($data['timeopen']) && !empty($data['timeclose'])) {
|
||||
if ($data['timeclose'] < $data['timeopen'] ) {
|
||||
$errors['timeclose'] = get_string('closebeforeopen', 'quiz');
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that at least one quiz setting was changed.
|
||||
$changed = false;
|
||||
$keys = ['timeopen', 'timeclose', 'timelimit', 'attempts', 'password'];
|
||||
foreach ($keys as $key) {
|
||||
if ($data[$key] != $quiz->{$key}) {
|
||||
$changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$changed) {
|
||||
$errors['timeopen'] = get_string('nooverridedata', 'quiz');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
64
mod/quiz/classes/form/preflight_check_form.php
Normal file
64
mod/quiz/classes/form/preflight_check_form.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\form;
|
||||
|
||||
use moodleform;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
/**
|
||||
* A form that limits student's access to attempt a quiz.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class preflight_check_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
$mform = $this->_form;
|
||||
$this->_form->updateAttributes(array('id' => 'mod_quiz_preflight_form'));
|
||||
|
||||
foreach ($this->_customdata['hidden'] as $name => $value) {
|
||||
if ($name === 'sesskey') {
|
||||
continue;
|
||||
}
|
||||
$mform->addElement('hidden', $name, $value);
|
||||
$mform->setType($name, PARAM_INT);
|
||||
}
|
||||
|
||||
foreach ($this->_customdata['rules'] as $rule) {
|
||||
if ($rule->is_preflight_check_required($this->_customdata['attemptid'])) {
|
||||
$rule->add_preflight_check_form_fields($this, $mform,
|
||||
$this->_customdata['attemptid']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->add_action_buttons(true, get_string('startattempt', 'quiz'));
|
||||
$this->set_display_vertical();
|
||||
$mform->setDisableShortforms();
|
||||
}
|
||||
|
||||
public function validation($data, $files): array {
|
||||
$errors = parent::validation($data, $files);
|
||||
$accessmanager = $this->_customdata['quizobj']->get_access_manager(time());
|
||||
return array_merge($errors, $accessmanager->validate_preflight_check(
|
||||
$data, $files, $this->_customdata['attemptid']));
|
||||
}
|
||||
}
|
356
mod/quiz/classes/local/access_rule_base.php
Normal file
356
mod/quiz/classes/local/access_rule_base.php
Normal file
@ -0,0 +1,356 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\local;
|
||||
|
||||
use mod_quiz\form\preflight_check_form;
|
||||
use mod_quiz_mod_form;
|
||||
use moodle_page;
|
||||
use MoodleQuickForm;
|
||||
use mod_quiz\quiz_settings;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Base class for rules that restrict the ability to attempt a quiz.
|
||||
*
|
||||
* Quiz access rule plugins must sublclass this one to form their main 'rule' class.
|
||||
* Most of the methods are defined in a slightly unnatural way because we either
|
||||
* want to say that access is allowed, or explain the reason why it is block.
|
||||
* Therefore instead of is_access_allowed(...) we have prevent_access(...) that
|
||||
* return false if access is permitted, or a string explanation (which is treated
|
||||
* as true) if access should be blocked. Slighly unnatural, but actually the easiest
|
||||
* way to implement this.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.2
|
||||
*/
|
||||
abstract class access_rule_base {
|
||||
/** @var stdClass the quiz settings. */
|
||||
protected $quiz;
|
||||
/** @var quiz_settings the quiz object. */
|
||||
protected $quizobj;
|
||||
/** @var int the time to use as 'now'. */
|
||||
protected $timenow;
|
||||
|
||||
/**
|
||||
* Create an instance of this rule for a particular quiz.
|
||||
*
|
||||
* @param quiz_settings $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
*/
|
||||
public function __construct($quizobj, $timenow) {
|
||||
$this->quizobj = $quizobj;
|
||||
$this->quiz = $quizobj->get_quiz();
|
||||
$this->timenow = $timenow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an appropriately configured instance of this rule, if it is applicable
|
||||
* to the given quiz, otherwise return null.
|
||||
*
|
||||
* @param quiz_settings $quizobj information about the quiz in question.
|
||||
* @param int $timenow the time that should be considered as 'now'.
|
||||
* @param bool $canignoretimelimits whether the current user is exempt from
|
||||
* time limits by the mod/quiz:ignoretimelimits capability.
|
||||
* @return self|null the rule, if applicable, else null.
|
||||
*/
|
||||
public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a user should be allowed to start a new attempt at this quiz now.
|
||||
*
|
||||
* @param int $numprevattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return string false if access should be allowed, a message explaining the
|
||||
* reason if access should be prevented.
|
||||
*/
|
||||
public function prevent_new_attempt($numprevattempts, $lastattempt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user should be blocked from starting a new attempt or continuing
|
||||
* an attempt now.
|
||||
* @return string false if access should be allowed, a message explaining the
|
||||
* reason if access should be prevented.
|
||||
*/
|
||||
public function prevent_access() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this rule require a UI check with the user before an attempt is started?
|
||||
*
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return bool whether a check is required before the user starts/continues
|
||||
* their attempt.
|
||||
*/
|
||||
public function is_preflight_check_required($attemptid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any field you want to pre-flight check form. You should only do
|
||||
* something here if {@see is_preflight_check_required()} returned true.
|
||||
*
|
||||
* @param preflight_check_form $quizform the form being built.
|
||||
* @param MoodleQuickForm $mform The wrapped MoodleQuickForm.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
*/
|
||||
public function add_preflight_check_form_fields(preflight_check_form $quizform,
|
||||
MoodleQuickForm $mform, $attemptid) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the pre-flight check form submission. You should only do
|
||||
* something here if {@see is_preflight_check_required()} returned true.
|
||||
*
|
||||
* If the form validates, the user will be allowed to continue.
|
||||
*
|
||||
* @param array $data the submitted form data.
|
||||
* @param array $files any files in the submission.
|
||||
* @param array $errors the list of validation errors that is being built up.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
* @return array the update $errors array;
|
||||
*/
|
||||
public function validate_preflight_check($data, $files, $errors, $attemptid) {
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* The pre-flight check has passed. This is a chance to record that fact in
|
||||
* some way.
|
||||
* @param int|null $attemptid the id of the current attempt, if there is one,
|
||||
* otherwise null.
|
||||
*/
|
||||
public function notify_preflight_check_passed($attemptid) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the current attempt at the quiz is finished. This is
|
||||
* used, for example by the password rule, to clear the flag in the session.
|
||||
*/
|
||||
public function current_attempt_finished() {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a brief summary of this rule, to show to users, if required.
|
||||
*
|
||||
* This information is show shown, for example, on the quiz view page, to explain this
|
||||
* restriction. There is no obligation to return anything. If it is not appropriate to
|
||||
* tell students about this rule, then just return ''.
|
||||
*
|
||||
* @return string a message, or array of messages, explaining the restriction
|
||||
* (may be '' if no message is appropriate).
|
||||
*/
|
||||
public function description() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the current user unable to start any more attempts in future, because of this rule?
|
||||
*
|
||||
* If this rule can determine that this user will never be allowed another attempt at
|
||||
* this quiz, for example because the last possible start time is past, or all attempts
|
||||
* have been used up, then return true. This is used to know whether to display a
|
||||
* final grade on the view page. This will only be called if there is not a currently
|
||||
* active attempt for this user.
|
||||
*
|
||||
* @param int $numprevattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return bool true if this rule means that this user will never be allowed another
|
||||
* attempt at this quiz.
|
||||
*/
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time by which, according to this rule, the user has to finish their attempt.
|
||||
*
|
||||
* @param stdClass $attempt the current attempt
|
||||
* @return int|false the attempt close time, or false if there is no close time.
|
||||
*/
|
||||
public function end_time($attempt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user should be shown a different amount of time than $timenow - $this->end_time(), then
|
||||
* override this method. This is useful if the time remaining is large enough to be omitted.
|
||||
* @param object $attempt the current attempt
|
||||
* @param int $timenow the time now. We don't use $this->timenow, so we can
|
||||
* give the user a more accurate indication of how much time is left.
|
||||
* @return mixed the time left in seconds (can be negative) or false if there is no limit.
|
||||
*/
|
||||
public function time_left_display($attempt, $timenow) {
|
||||
$endtime = $this->end_time($attempt);
|
||||
if ($endtime === false) {
|
||||
return false;
|
||||
}
|
||||
return $endtime - $timenow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this rule requires the attempt (and review) to be displayed in a pop-up window?
|
||||
*
|
||||
* @return bool true if it does.
|
||||
*/
|
||||
public function attempt_must_be_in_popup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Any options required when showing the attempt in a pop-up.
|
||||
*
|
||||
* @return array any options that are required for showing the attempt page
|
||||
* in a popup window.
|
||||
*/
|
||||
public function get_popup_options() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the attempt (review or summary) page with any special extra
|
||||
* properties required by this rule. securewindow rule is an example of where
|
||||
* this is used.
|
||||
*
|
||||
* @param moodle_page $page the page object to initialise.
|
||||
*/
|
||||
public function setup_attempt_page($page) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible for one rule to override other rules.
|
||||
*
|
||||
* The aim is that third-party rules should be able to replace sandard rules
|
||||
* if they want. See, for example MDL-13592.
|
||||
*
|
||||
* @return array plugin names of other rules that this one replaces.
|
||||
* For example ['ipaddress', 'password'].
|
||||
*/
|
||||
public function get_superceded_rules() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any fields that this rule requires to the quiz settings form. This
|
||||
* method is called from {@see mod_quiz_mod_form::definition()}, while the
|
||||
* security seciton is being built.
|
||||
* @param mod_quiz_mod_form $quizform the quiz settings form that is being built.
|
||||
* @param MoodleQuickForm $mform the wrapped MoodleQuickForm.
|
||||
*/
|
||||
public static function add_settings_form_fields(
|
||||
mod_quiz_mod_form $quizform, MoodleQuickForm $mform) {
|
||||
// By default do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the data from any form fields added using {@see add_settings_form_fields()}.
|
||||
* @param array $errors the errors found so far.
|
||||
* @param array $data the submitted form data.
|
||||
* @param array $files information about any uploaded files.
|
||||
* @param mod_quiz_mod_form $quizform the quiz form object.
|
||||
* @return array $errors the updated $errors array.
|
||||
*/
|
||||
public static function validate_settings_form_fields(array $errors,
|
||||
array $data, $files, mod_quiz_mod_form $quizform) {
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any options this rule adds to the 'Browser security' quiz setting.
|
||||
*
|
||||
* @return array key => lang string any choices to add to the quiz Browser
|
||||
* security settings menu.
|
||||
*/
|
||||
public static function get_browser_security_choices() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any submitted settings when the quiz settings form is submitted. This
|
||||
* is called from {@see quiz_after_add_or_update()} in lib.php.
|
||||
* @param object $quiz the data from the quiz form, including $quiz->id
|
||||
* which is the id of the quiz being saved.
|
||||
*/
|
||||
public static function save_settings($quiz) {
|
||||
// By default do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete any rule-specific settings when the quiz is deleted. This is called
|
||||
* from {@see quiz_delete_instance()} in lib.php.
|
||||
* @param object $quiz the data from the database, including $quiz->id
|
||||
* which is the id of the quiz being deleted.
|
||||
* @since Moodle 2.7.1, 2.6.4, 2.5.7
|
||||
*/
|
||||
public static function delete_settings($quiz) {
|
||||
// By default do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bits of SQL needed to load all the settings from all the access
|
||||
* plugins in one DB query. The easiest way to understand what you need to do
|
||||
* here is probably to read the code of {@see access_manager::load_settings()}.
|
||||
*
|
||||
* If you have some settings that cannot be loaded in this way, then you can
|
||||
* use the {@see get_extra_settings()} method instead, but that has
|
||||
* performance implications.
|
||||
*
|
||||
* @param int $quizid the id of the quiz we are loading settings for. This
|
||||
* can also be accessed as quiz.id in the SQL. (quiz is a table alisas for {quiz}.)
|
||||
* @return array with three elements:
|
||||
* 1. fields: any fields to add to the select list. These should be alised
|
||||
* if neccessary so that the field name starts the name of the plugin.
|
||||
* 2. joins: any joins (should probably be LEFT JOINS) with other tables that
|
||||
* are needed.
|
||||
* 3. params: array of placeholder values that are needed by the SQL. You must
|
||||
* used named placeholders, and the placeholder names should start with the
|
||||
* plugin name, to avoid collisions.
|
||||
*/
|
||||
public static function get_settings_sql($quizid) {
|
||||
return ['', '', []];
|
||||
}
|
||||
|
||||
/**
|
||||
* You can use this method to load any extra settings your plugin has that
|
||||
* cannot be loaded efficiently with get_settings_sql().
|
||||
* @param int $quizid the quiz id.
|
||||
* @return array setting value name => value. The value names should all
|
||||
* start with the name of your plugin to avoid collisions.
|
||||
*/
|
||||
public static function get_extra_settings($quizid) {
|
||||
return [];
|
||||
}
|
||||
}
|
@ -17,8 +17,8 @@
|
||||
namespace mod_quiz\local\reports;
|
||||
|
||||
use context_module;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use moodle_url;
|
||||
use quiz_attempt;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@ require_once($CFG->libdir.'/tablelib.php');
|
||||
use coding_exception;
|
||||
use context_module;
|
||||
use html_writer;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use moodle_url;
|
||||
use popup_action;
|
||||
use question_state;
|
||||
@ -30,7 +31,6 @@ use qubaid_condition;
|
||||
use qubaid_join;
|
||||
use qubaid_list;
|
||||
use question_engine_data_mapper;
|
||||
use quiz_attempt;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -44,14 +44,14 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
/**
|
||||
* Render the edit page
|
||||
*
|
||||
* @param \quiz $quizobj object containing all the quiz settings information.
|
||||
* @param \mod_quiz\quiz_settings $quizobj object containing all the quiz settings information.
|
||||
* @param structure $structure object containing the structure of the quiz.
|
||||
* @param \core_question\local\bank\question_edit_contexts $contexts the relevant question bank contexts.
|
||||
* @param \moodle_url $pageurl the canonical URL of this page.
|
||||
* @param array $pagevars the variables from {@link question_edit_setup()}.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function edit_page(\quiz $quizobj, structure $structure,
|
||||
public function edit_page(\mod_quiz\quiz_settings $quizobj, structure $structure,
|
||||
\core_question\local\bank\question_edit_contexts $contexts, \moodle_url $pageurl, array $pagevars) {
|
||||
$output = '';
|
||||
|
||||
|
38
mod/quiz/classes/output/links_to_other_attempts.php
Normal file
38
mod/quiz/classes/output/links_to_other_attempts.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use renderable;
|
||||
|
||||
/**
|
||||
* Represents the list of links to other attempts
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class links_to_other_attempts implements renderable {
|
||||
/**
|
||||
* @var array The list of links. string attempt number => one of three things:
|
||||
* - null if this is the current attempt, and so should not be linked. (Just the number is output.)
|
||||
* - moodle_url if this is a different attempt. (Output as a link to the URL with the number as link text.)
|
||||
* - a renderable, in which case the results of rendering the renderable is output.
|
||||
* (The third option is used by {@see quiz_attempt::links_to_other_redos()}.)
|
||||
*/
|
||||
public $links = [];
|
||||
}
|
55
mod/quiz/classes/output/navigation_panel_attempt.php
Normal file
55
mod/quiz/classes/output/navigation_panel_attempt.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use html_writer;
|
||||
|
||||
/**
|
||||
* Specialisation of {@see navigation_panel_base} for the attempt quiz page.
|
||||
*
|
||||
* This class is not currently renderable or templatable, but it probably should be in the future,
|
||||
* which is why it is already in the output namespace.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class navigation_panel_attempt extends navigation_panel_base {
|
||||
public function get_question_url($slot) {
|
||||
if ($this->attemptobj->can_navigate_to($slot)) {
|
||||
return $this->attemptobj->attempt_url($slot, -1, $this->page);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function render_before_button_bits(renderer $output) {
|
||||
return html_writer::tag('div', get_string('navnojswarning', 'quiz'),
|
||||
array('id' => 'quiznojswarning'));
|
||||
}
|
||||
|
||||
public function render_end_bits(renderer $output) {
|
||||
if ($this->page == -1) {
|
||||
// Don't link from the summary page to itself.
|
||||
return '';
|
||||
}
|
||||
return html_writer::link($this->attemptobj->summary_url(),
|
||||
get_string('endtest', 'quiz'), array('class' => 'endtestlink aalink')) .
|
||||
$this->render_restart_preview_link($output);
|
||||
}
|
||||
}
|
200
mod/quiz/classes/output/navigation_panel_base.php
Normal file
200
mod/quiz/classes/output/navigation_panel_base.php
Normal file
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
use moodle_url;
|
||||
use question_attempt;
|
||||
use question_display_options;
|
||||
use question_state;
|
||||
use renderable;
|
||||
use user_picture;
|
||||
|
||||
/**
|
||||
* Represents the navigation panel, and builds a {@see block_contents} to allow it to be output.
|
||||
*
|
||||
* This class is not currently renderable or templatable, but it probably should be in the future,
|
||||
* which is why it is already in the output namespace.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class navigation_panel_base {
|
||||
/** @var quiz_attempt */
|
||||
protected $attemptobj;
|
||||
/** @var question_display_options */
|
||||
protected $options;
|
||||
/** @var integer */
|
||||
protected $page;
|
||||
/** @var boolean */
|
||||
protected $showall;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param quiz_attempt $attemptobj construct the panel for this attempt.
|
||||
* @param question_display_options $options display options in force.
|
||||
* @param int $page which page of the quiz attempt is being shown, -1 if all.
|
||||
* @param bool $showall whether all pages are being shown at once.
|
||||
*/
|
||||
public function __construct(quiz_attempt $attemptobj,
|
||||
question_display_options $options, $page, $showall) {
|
||||
$this->attemptobj = $attemptobj;
|
||||
$this->options = $options;
|
||||
$this->page = $page;
|
||||
$this->showall = $showall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the buttons and section headings to go in the quiz navigation block.
|
||||
*
|
||||
* @return renderable[] the buttons, possibly interleaved with section headings.
|
||||
*/
|
||||
public function get_question_buttons() {
|
||||
$buttons = array();
|
||||
foreach ($this->attemptobj->get_slots() as $slot) {
|
||||
$heading = $this->attemptobj->get_heading_before_slot($slot);
|
||||
if (!is_null($heading)) {
|
||||
$sections = $this->attemptobj->get_quizobj()->get_sections();
|
||||
if (!(empty($heading) && count($sections) == 1)) {
|
||||
$buttons[] = new navigation_section_heading(format_string($heading));
|
||||
}
|
||||
}
|
||||
|
||||
$qa = $this->attemptobj->get_question_attempt($slot);
|
||||
$showcorrectness = $this->options->correctness && $qa->has_marks();
|
||||
|
||||
$button = new navigation_question_button();
|
||||
$button->id = 'quiznavbutton' . $slot;
|
||||
$button->number = $this->attemptobj->get_question_number($slot);
|
||||
$button->stateclass = $qa->get_state_class($showcorrectness);
|
||||
$button->navmethod = $this->attemptobj->get_navigation_method();
|
||||
if (!$showcorrectness && $button->stateclass === 'notanswered') {
|
||||
$button->stateclass = 'complete';
|
||||
}
|
||||
$button->statestring = $this->get_state_string($qa, $showcorrectness);
|
||||
$button->page = $this->attemptobj->get_question_page($slot);
|
||||
$button->currentpage = $this->showall || $button->page == $this->page;
|
||||
$button->flagged = $qa->is_flagged();
|
||||
$button->url = $this->get_question_url($slot);
|
||||
if ($this->attemptobj->is_blocked_by_previous_question($slot)) {
|
||||
$button->url = null;
|
||||
$button->stateclass = 'blocked';
|
||||
$button->statestring = get_string('questiondependsonprevious', 'quiz');
|
||||
}
|
||||
$buttons[] = $button;
|
||||
}
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable description of the current state of a particular question.
|
||||
*
|
||||
* @param question_attempt $qa the attempt at the question of interest.
|
||||
* @param bool $showcorrectness whether the current use is allowed to see if they have got the question right.
|
||||
* @return string Human-readable description of the state.
|
||||
*/
|
||||
protected function get_state_string(question_attempt $qa, $showcorrectness) {
|
||||
if ($qa->get_question(false)->length > 0) {
|
||||
return $qa->get_state_string($showcorrectness);
|
||||
}
|
||||
|
||||
// Special case handling for 'information' items.
|
||||
if ($qa->get_state() == question_state::$todo) {
|
||||
return get_string('notyetviewed', 'quiz');
|
||||
} else {
|
||||
return get_string('viewed', 'quiz');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to override to do output above the question buttons.
|
||||
*
|
||||
* @param renderer $output the quiz renderer to use.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function render_before_button_bits(renderer $output) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that subclasses must override to do output after the question buttons.
|
||||
*
|
||||
* @param renderer $output the quiz renderer to use.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
abstract public function render_end_bits(renderer $output);
|
||||
|
||||
/**
|
||||
* Render the restart preview button.
|
||||
*
|
||||
* @param renderer $output the quiz renderer to use.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
protected function render_restart_preview_link($output) {
|
||||
if (!$this->attemptobj->is_own_preview()) {
|
||||
return '';
|
||||
}
|
||||
return $output->restart_preview_button(new moodle_url(
|
||||
$this->attemptobj->start_attempt_url(), array('forcenew' => true)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to navigate to a particular question.
|
||||
*
|
||||
* @param int $slot slot number, to identify the question.
|
||||
* @return moodle_url|null URL if the user can navigate there, or null if they cannot.
|
||||
*/
|
||||
abstract protected function get_question_url($slot);
|
||||
|
||||
/**
|
||||
* Get the user picture which should be displayed, if required.
|
||||
*
|
||||
* @return user_picture|null
|
||||
*/
|
||||
public function user_picture() {
|
||||
global $DB;
|
||||
if ($this->attemptobj->get_quiz()->showuserpicture == QUIZ_SHOWIMAGE_NONE) {
|
||||
return null;
|
||||
}
|
||||
$user = $DB->get_record('user', array('id' => $this->attemptobj->get_userid()));
|
||||
$userpicture = new user_picture($user);
|
||||
$userpicture->courseid = $this->attemptobj->get_courseid();
|
||||
if ($this->attemptobj->get_quiz()->showuserpicture == QUIZ_SHOWIMAGE_LARGE) {
|
||||
$userpicture->size = true;
|
||||
}
|
||||
return $userpicture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 'allquestionsononepage' as CSS class name when $showall is set,
|
||||
* otherwise, return 'multipages' as CSS class name.
|
||||
*
|
||||
* @return string, CSS class name
|
||||
*/
|
||||
public function get_button_container_class() {
|
||||
// Quiz navigation is set on 'Show all questions on one page'.
|
||||
if ($this->showall) {
|
||||
return 'allquestionsononepage';
|
||||
}
|
||||
// Quiz navigation is set on 'Show one page at a time'.
|
||||
return 'multipages';
|
||||
}
|
||||
}
|
52
mod/quiz/classes/output/navigation_panel_review.php
Normal file
52
mod/quiz/classes/output/navigation_panel_review.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use html_writer;
|
||||
|
||||
/**
|
||||
* Specialisation of {@see navigation_panel_base} for the review quiz page.
|
||||
*
|
||||
* This class is not currently renderable or templatable, but it probably should be in the future,
|
||||
* which is why it is already in the output namespace.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class navigation_panel_review extends navigation_panel_base {
|
||||
public function get_question_url($slot) {
|
||||
return $this->attemptobj->review_url($slot, -1, $this->showall, $this->page);
|
||||
}
|
||||
|
||||
public function render_end_bits(renderer $output) {
|
||||
$html = '';
|
||||
if ($this->attemptobj->get_num_pages() > 1) {
|
||||
if ($this->showall) {
|
||||
$html .= html_writer::link($this->attemptobj->review_url(null, 0, false),
|
||||
get_string('showeachpage', 'quiz'));
|
||||
} else {
|
||||
$html .= html_writer::link($this->attemptobj->review_url(null, 0, true),
|
||||
get_string('showall', 'quiz'));
|
||||
}
|
||||
}
|
||||
$html .= $output->finish_review_link($this->attemptobj);
|
||||
$html .= $this->render_restart_preview_link($output);
|
||||
return $html;
|
||||
}
|
||||
}
|
49
mod/quiz/classes/output/navigation_question_button.php
Normal file
49
mod/quiz/classes/output/navigation_question_button.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use moodle_url;
|
||||
use renderable;
|
||||
|
||||
/**
|
||||
* Represents a single link in the navigation panel.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class navigation_question_button implements renderable {
|
||||
/** @var string id="..." to add to the HTML for this button. */
|
||||
public $id;
|
||||
/** @var string number to display in this button. Either the question number of 'i'. */
|
||||
public $number;
|
||||
/** @var string class to add to the class="" attribute to represnt the question state. */
|
||||
public $stateclass;
|
||||
/** @var string Textual description of the question state, e.g. to use as a tool tip. */
|
||||
public $statestring;
|
||||
/** @var int the page number this question is on. */
|
||||
public $page;
|
||||
/** @var bool true if this question is on the current page. */
|
||||
public $currentpage;
|
||||
/** @var bool true if this question has been flagged. */
|
||||
public $flagged;
|
||||
/** @var moodle_url the link this button goes to, or null if there should not be a link. */
|
||||
public $url;
|
||||
/** @var int QUIZ_NAVMETHOD_FREE or QUIZ_NAVMETHOD_SEQ. */
|
||||
public $navmethod;
|
||||
}
|
40
mod/quiz/classes/output/navigation_section_heading.php
Normal file
40
mod/quiz/classes/output/navigation_section_heading.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use renderable;
|
||||
|
||||
/**
|
||||
* Represents a heading in the navigation panel.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2015 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class navigation_section_heading implements renderable {
|
||||
/** @var string the heading text. */
|
||||
public $heading;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param string $heading the heading text
|
||||
*/
|
||||
public function __construct($heading) {
|
||||
$this->heading = $heading;
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
namespace mod_quiz\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The question_chooser renderable class.
|
||||
|
1468
mod/quiz/classes/output/renderer.php
Normal file
1468
mod/quiz/classes/output/renderer.php
Normal file
File diff suppressed because it is too large
Load Diff
98
mod/quiz/classes/output/view_page.php
Normal file
98
mod/quiz/classes/output/view_page.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use mod_quiz\access_manager;
|
||||
use mod_quiz\form\preflight_check_form;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* This class captures all the various information to render the front page of the quiz activity.
|
||||
*
|
||||
* This class is not currently renderable or templatable, but it very nearly could be,
|
||||
* which is why it is in the output namespace. It is used to send data to the renderer.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category output
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class view_page {
|
||||
/** @var array $infomessages of messages with information to display about the quiz. */
|
||||
public $infomessages;
|
||||
/** @var array $attempts contains all the user's attempts at this quiz. */
|
||||
public $attempts;
|
||||
/** @var quiz_attempt[] $attemptobjs objects corresponding to $attempts. */
|
||||
public $attemptobjs;
|
||||
/** @var access_manager $accessmanager contains various access rules. */
|
||||
public $accessmanager;
|
||||
/** @var bool $canreviewmine whether the current user has the capability to
|
||||
* review their own attempts. */
|
||||
public $canreviewmine;
|
||||
/** @var bool $canedit whether the current user has the capability to edit the quiz. */
|
||||
public $canedit;
|
||||
/** @var moodle_url $editurl the URL for editing this quiz. */
|
||||
public $editurl;
|
||||
/** @var int $attemptcolumn contains the number of attempts done. */
|
||||
public $attemptcolumn;
|
||||
/** @var int $gradecolumn contains the grades of any attempts. */
|
||||
public $gradecolumn;
|
||||
/** @var int $markcolumn contains the marks of any attempt. */
|
||||
public $markcolumn;
|
||||
/** @var int $overallstats contains all marks for any attempt. */
|
||||
public $overallstats;
|
||||
/** @var string $feedbackcolumn contains any feedback for and attempt. */
|
||||
public $feedbackcolumn;
|
||||
/** @var string $timenow contains a timestamp in string format. */
|
||||
public $timenow;
|
||||
/** @var int $numattempts contains the total number of attempts. */
|
||||
public $numattempts;
|
||||
/** @var float $mygrade contains the user's final grade for a quiz. */
|
||||
public $mygrade;
|
||||
/** @var bool $moreattempts whether this user is allowed more attempts. */
|
||||
public $moreattempts;
|
||||
/** @var int $mygradeoverridden contains an overriden grade. */
|
||||
public $mygradeoverridden;
|
||||
/** @var string $gradebookfeedback contains any feedback for a gradebook. */
|
||||
public $gradebookfeedback;
|
||||
/** @var bool $unfinished contains 1 if an attempt is unfinished. */
|
||||
public $unfinished;
|
||||
/** @var object $lastfinishedattempt the last attempt from the attempts array. */
|
||||
public $lastfinishedattempt;
|
||||
/** @var array $preventmessages of messages telling the user why they can't
|
||||
* attempt the quiz now. */
|
||||
public $preventmessages;
|
||||
/** @var string $buttontext caption for the start attempt button. If this is null, show no
|
||||
* button, or if it is '' show a back to the course button. */
|
||||
public $buttontext;
|
||||
/** @var moodle_url $startattempturl URL to start an attempt. */
|
||||
public $startattempturl;
|
||||
/** @var preflight_check_form|null $preflightcheckform confirmation form that must be
|
||||
* submitted before an attempt is started, if required. */
|
||||
public $preflightcheckform;
|
||||
/** @var moodle_url $startattempturl URL for any Back to the course button. */
|
||||
public $backtocourseurl;
|
||||
/** @var bool $showbacktocourse should we show a back to the course button? */
|
||||
public $showbacktocourse;
|
||||
/** @var bool whether the attempt must take place in a popup window. */
|
||||
public $popuprequired;
|
||||
/** @var array options to use for the popup window, if required. */
|
||||
public $popupoptions;
|
||||
/** @var bool $quizhasquestions whether the quiz has any questions. */
|
||||
public $quizhasquestions;
|
||||
}
|
@ -39,30 +39,30 @@ trait legacy_quizaccess_polyfill {
|
||||
/**
|
||||
* Export all user data for the specified user, for the specified quiz.
|
||||
*
|
||||
* @param \quiz $quiz The quiz being exported
|
||||
* @param \mod_quiz\quiz_settings $quiz The quiz being exported
|
||||
* @param \stdClass $user The user to export data for
|
||||
* @return \stdClass The data to be exported for this access rule.
|
||||
*/
|
||||
public static function export_quizaccess_user_data(\quiz $quiz, \stdClass $user) : \stdClass {
|
||||
public static function export_quizaccess_user_data(\mod_quiz\quiz_settings $quiz, \stdClass $user) : \stdClass {
|
||||
return static::_export_quizaccess_user_data($quiz, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all data for all users in the specified quiz.
|
||||
*
|
||||
* @param \quiz $quiz The quiz being deleted
|
||||
* @param \mod_quiz\quiz_settings $quiz The quiz being deleted
|
||||
*/
|
||||
public static function delete_quizaccess_data_for_all_users_in_context(\quiz $quiz) {
|
||||
public static function delete_quizaccess_data_for_all_users_in_context(\mod_quiz\quiz_settings $quiz) {
|
||||
static::_delete_quizaccess_data_for_all_users_in_context($quiz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all user data for the specified user, in the specified quiz.
|
||||
*
|
||||
* @param \quiz $quiz The quiz being deleted
|
||||
* @param \mod_quiz\quiz_settings $quiz The quiz being deleted
|
||||
* @param \stdClass $user The user to export data for
|
||||
*/
|
||||
public static function delete_quizaccess_data_for_user(\quiz $quiz, \stdClass $user) {
|
||||
public static function delete_quizaccess_data_for_user(\mod_quiz\quiz_settings $quiz, \stdClass $user) {
|
||||
static::_delete_quizaccess_data_for_user($quiz, $user);
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ use core_privacy\local\metadata\collection;
|
||||
use core_privacy\local\request\userlist;
|
||||
use core_privacy\local\request\writer;
|
||||
use core_privacy\manager;
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -276,7 +277,7 @@ class provider implements
|
||||
$quizzes = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($quizzes as $quiz) {
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($quiz->cmid, 'quiz');
|
||||
$quizobj = new \quiz($quiz, $cm, $course);
|
||||
$quizobj = new \mod_quiz\quiz_settings($quiz, $cm, $course);
|
||||
$context = $quizobj->get_context();
|
||||
|
||||
$quizdata = \core_privacy\local\request\helper::get_context_data($context, $contextlist->get_user());
|
||||
@ -353,7 +354,7 @@ class provider implements
|
||||
return;
|
||||
}
|
||||
|
||||
$quizobj = \quiz::create($cm->instance);
|
||||
$quizobj = \mod_quiz\quiz_settings::create($cm->instance);
|
||||
$quiz = $quizobj->get_quiz();
|
||||
|
||||
// Handle the 'quizaccess' subplugin.
|
||||
@ -392,7 +393,7 @@ class provider implements
|
||||
}
|
||||
|
||||
// Fetch the details of the data to be removed.
|
||||
$quizobj = \quiz::create($cm->instance);
|
||||
$quizobj = \mod_quiz\quiz_settings::create($cm->instance);
|
||||
$quiz = $quizobj->get_quiz();
|
||||
$user = $contextlist->get_user();
|
||||
|
||||
@ -440,7 +441,7 @@ class provider implements
|
||||
return;
|
||||
}
|
||||
|
||||
$quizobj = \quiz::create($cm->instance);
|
||||
$quizobj = \mod_quiz\quiz_settings::create($cm->instance);
|
||||
$quiz = $quizobj->get_quiz();
|
||||
|
||||
$userids = $userlist->get_userids();
|
||||
@ -526,7 +527,7 @@ class provider implements
|
||||
|
||||
// Store the quiz attempt data.
|
||||
$data = (object) [
|
||||
'state' => \quiz_attempt::state_name($attempt->state),
|
||||
'state' => quiz_attempt::state_name($attempt->state),
|
||||
];
|
||||
|
||||
if (!empty($attempt->timestart)) {
|
||||
|
@ -40,24 +40,24 @@ interface quizaccess_provider extends \core_privacy\local\request\plugin\subplug
|
||||
/**
|
||||
* Export all user data for the specified user, for the specified quiz.
|
||||
*
|
||||
* @param \quiz $quiz The quiz being exported
|
||||
* @param \mod_quiz\quiz_settings $quiz The quiz being exported
|
||||
* @param \stdClass $user The user to export data for
|
||||
* @return \stdClass The data to be exported for this access rule.
|
||||
*/
|
||||
public static function export_quizaccess_user_data(\quiz $quiz, \stdClass $user) : \stdClass;
|
||||
public static function export_quizaccess_user_data(\mod_quiz\quiz_settings $quiz, \stdClass $user) : \stdClass;
|
||||
|
||||
/**
|
||||
* Delete all data for all users in the specified quiz.
|
||||
*
|
||||
* @param \quiz $quiz The quiz being deleted
|
||||
* @param \mod_quiz\quiz_settings $quiz The quiz being deleted
|
||||
*/
|
||||
public static function delete_quizaccess_data_for_all_users_in_context(\quiz $quiz);
|
||||
public static function delete_quizaccess_data_for_all_users_in_context(\mod_quiz\quiz_settings $quiz);
|
||||
|
||||
/**
|
||||
* Delete all user data for the specified user, in the specified quiz.
|
||||
*
|
||||
* @param \quiz $quiz The quiz being deleted
|
||||
* @param \mod_quiz\quiz_settings $quiz The quiz being deleted
|
||||
* @param \stdClass $user The user to export data for
|
||||
*/
|
||||
public static function delete_quizaccess_data_for_user(\quiz $quiz, \stdClass $user);
|
||||
public static function delete_quizaccess_data_for_user(\mod_quiz\quiz_settings $quiz, \stdClass $user);
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ use qubaid_condition;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/engine/bank.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessmanager.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
|
||||
|
||||
/**
|
||||
* Helper class for question bank and its associated data.
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
namespace mod_quiz\question;
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/engine/datalib.php');
|
||||
@ -47,7 +49,7 @@ class qubaids_for_quiz extends \qubaid_join {
|
||||
|
||||
if ($onlyfinished) {
|
||||
$where .= ' AND state = :statefinished';
|
||||
$params['statefinished'] = \quiz_attempt::FINISHED;
|
||||
$params['statefinished'] = quiz_attempt::FINISHED;
|
||||
}
|
||||
|
||||
parent::__construct('{quiz_attempts} quiza', 'quiza.uniqueid', $where, $params);
|
||||
|
@ -16,10 +16,11 @@
|
||||
|
||||
namespace mod_quiz\question;
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/engine/datalib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/attemptlib.php');
|
||||
|
||||
/**
|
||||
* A {@see qubaid_condition} representing all the attempts by one user at a given quiz.
|
||||
@ -54,14 +55,14 @@ class qubaids_for_users_attempts extends \qubaid_join {
|
||||
|
||||
case 'finished':
|
||||
$where .= ' AND state IN (:state1, :state2)';
|
||||
$params['state1'] = \quiz_attempt::FINISHED;
|
||||
$params['state2'] = \quiz_attempt::ABANDONED;
|
||||
$params['state1'] = quiz_attempt::FINISHED;
|
||||
$params['state2'] = quiz_attempt::ABANDONED;
|
||||
break;
|
||||
|
||||
case 'unfinished':
|
||||
$where .= ' AND state IN (:state1, :state2)';
|
||||
$params['state1'] = \quiz_attempt::IN_PROGRESS;
|
||||
$params['state2'] = \quiz_attempt::OVERDUE;
|
||||
$params['state1'] = quiz_attempt::IN_PROGRESS;
|
||||
$params['state2'] = quiz_attempt::OVERDUE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
2283
mod/quiz/classes/quiz_attempt.php
Normal file
2283
mod/quiz/classes/quiz_attempt.php
Normal file
File diff suppressed because it is too large
Load Diff
562
mod/quiz/classes/quiz_settings.php
Normal file
562
mod/quiz/classes/quiz_settings.php
Normal file
@ -0,0 +1,562 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz;
|
||||
|
||||
use coding_exception;
|
||||
use context;
|
||||
use context_module;
|
||||
use mod_quiz\question\bank\qbank_helper;
|
||||
use mod_quiz\question\display_options;
|
||||
use moodle_exception;
|
||||
use moodle_url;
|
||||
use question_bank;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* A class encapsulating the settings for a quiz.
|
||||
*
|
||||
* When this class is initialised, it may have the settings adjusted to account
|
||||
* for the overrides for a particular user. See the create methods.
|
||||
*
|
||||
* Initially, it only loads a minimal amount of information about each question - loading
|
||||
* extra information only when necessary or when asked. The class tracks which questions
|
||||
* are loaded.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_settings {
|
||||
/** @var stdClass the course settings from the database. */
|
||||
protected $course;
|
||||
/** @var stdClass the course_module settings from the database. */
|
||||
protected $cm;
|
||||
/** @var stdClass the quiz settings from the database. */
|
||||
protected $quiz;
|
||||
/** @var context the quiz context. */
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* @var stdClass[] of questions augmented with slot information. For non-random
|
||||
* questions, the array key is question id. For random quesions it is 's' . $slotid.
|
||||
* probalby best to use ->questionid field of the object instead.
|
||||
*/
|
||||
protected $questions = null;
|
||||
/** @var stdClass[] of quiz_section rows. */
|
||||
protected $sections = null;
|
||||
/** @var access_manager the access manager for this quiz. */
|
||||
protected $accessmanager = null;
|
||||
/** @var bool whether the current user has capability mod/quiz:preview. */
|
||||
protected $ispreviewuser = null;
|
||||
|
||||
// Constructor =============================================================.
|
||||
|
||||
/**
|
||||
* Constructor, assuming we already have the necessary data loaded.
|
||||
*
|
||||
* @param object $quiz the row from the quiz table.
|
||||
* @param object $cm the course_module object for this quiz.
|
||||
* @param object $course the row from the course table for the course we belong to.
|
||||
* @param bool $getcontext intended for testing - stops the constructor getting the context.
|
||||
*/
|
||||
public function __construct($quiz, $cm, $course, $getcontext = true) {
|
||||
$this->quiz = $quiz;
|
||||
$this->cm = $cm;
|
||||
$this->quiz->cmid = $this->cm->id;
|
||||
$this->course = $course;
|
||||
if ($getcontext && !empty($cm->id)) {
|
||||
$this->context = context_module::instance($cm->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to create a new quiz object for a specific user.
|
||||
*
|
||||
* @param int $quizid the the quiz id.
|
||||
* @param int|null $userid the the userid (optional). If passed, relevant overrides are applied.
|
||||
* @return quiz_settings the new quiz object.
|
||||
*/
|
||||
public static function create($quizid, $userid = null) {
|
||||
global $DB;
|
||||
|
||||
$quiz = access_manager::load_quiz_and_settings($quizid);
|
||||
$course = $DB->get_record('course', ['id' => $quiz->course], '*', MUST_EXIST);
|
||||
$cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id, false, MUST_EXIST);
|
||||
|
||||
// Update quiz with override information.
|
||||
if ($userid) {
|
||||
$quiz = quiz_update_effective_access($quiz, $userid);
|
||||
}
|
||||
|
||||
return new quiz_settings($quiz, $cm, $course);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@see quiz_attempt} for an attempt at this quiz.
|
||||
*
|
||||
* @param object $attemptdata row from the quiz_attempts table.
|
||||
* @return quiz_attempt the new quiz_attempt object.
|
||||
*/
|
||||
public function create_attempt_object($attemptdata) {
|
||||
return new quiz_attempt($attemptdata, $this->quiz, $this->cm, $this->course);
|
||||
}
|
||||
|
||||
// Functions for loading more data =========================================.
|
||||
|
||||
/**
|
||||
* Load just basic information about all the questions in this quiz.
|
||||
*/
|
||||
public function preload_questions() {
|
||||
$slots = qbank_helper::get_question_structure($this->quiz->id, $this->context);
|
||||
$this->questions = [];
|
||||
foreach ($slots as $slot) {
|
||||
$this->questions[$slot->questionid] = $slot;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully load some or all of the questions for this quiz. You must call
|
||||
* {@see preload_questions()} first.
|
||||
*
|
||||
* @param array|null $deprecated no longer supported (it was not used).
|
||||
*/
|
||||
public function load_questions($deprecated = null) {
|
||||
if ($deprecated !== null) {
|
||||
debugging('The argument to quiz::load_questions is no longer supported. ' .
|
||||
'All questions are always loaded.', DEBUG_DEVELOPER);
|
||||
}
|
||||
if ($this->questions === null) {
|
||||
throw new coding_exception('You must call preload_questions before calling load_questions.');
|
||||
}
|
||||
|
||||
$questionstoprocess = [];
|
||||
foreach ($this->questions as $question) {
|
||||
if (is_number($question->questionid)) {
|
||||
$question->id = $question->questionid;
|
||||
$questionstoprocess[$question->questionid] = $question;
|
||||
}
|
||||
}
|
||||
get_question_options($questionstoprocess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the {@see \mod_quiz\structure} class for this quiz.
|
||||
*
|
||||
* @return structure describes the questions in the quiz.
|
||||
*/
|
||||
public function get_structure() {
|
||||
return structure::create_for_quiz($this);
|
||||
}
|
||||
|
||||
// Simple getters ==========================================================.
|
||||
|
||||
/**
|
||||
* Get the id of the course this quiz belongs to.
|
||||
*
|
||||
* @return int the course id.
|
||||
*/
|
||||
public function get_courseid() {
|
||||
return $this->course->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course settings object that this quiz belongs to.
|
||||
*
|
||||
* @return object the row of the course table.
|
||||
*/
|
||||
public function get_course() {
|
||||
return $this->course;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this quiz's id (in the quiz table).
|
||||
*
|
||||
* @return int the quiz id.
|
||||
*/
|
||||
public function get_quizid() {
|
||||
return $this->quiz->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the quiz settings object.
|
||||
*
|
||||
* @return stdClass the row of the quiz table.
|
||||
*/
|
||||
public function get_quiz() {
|
||||
return $this->quiz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the quiz name.
|
||||
*
|
||||
* @return string the name of this quiz.
|
||||
*/
|
||||
public function get_quiz_name() {
|
||||
return $this->quiz->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the navigation method in use.
|
||||
*
|
||||
* @return int QUIZ_NAVMETHOD_FREE or QUIZ_NAVMETHOD_SEQ.
|
||||
*/
|
||||
public function get_navigation_method() {
|
||||
return $this->quiz->navmethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* How many attepts is the user allowed at this quiz?
|
||||
*
|
||||
* @return int the number of attempts allowed at this quiz (0 = infinite).
|
||||
*/
|
||||
public function get_num_attempts_allowed() {
|
||||
return $this->quiz->attempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course-module id for this quiz.
|
||||
*
|
||||
* @return int the course_module id.
|
||||
*/
|
||||
public function get_cmid() {
|
||||
return $this->cm->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course-module object for this quiz.
|
||||
*
|
||||
* @return object the course_module object.
|
||||
*/
|
||||
public function get_cm() {
|
||||
return $this->cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the quiz context.
|
||||
*
|
||||
* @return context_module the module context for this quiz.
|
||||
*/
|
||||
public function get_context() {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the current user is someone who previews the quiz, rather than attempting it?
|
||||
*
|
||||
* @return bool true user is a preview user. False, if they can do real attempts.
|
||||
*/
|
||||
public function is_preview_user() {
|
||||
if (is_null($this->ispreviewuser)) {
|
||||
$this->ispreviewuser = has_capability('mod/quiz:preview', $this->context);
|
||||
}
|
||||
return $this->ispreviewuser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks user enrollment in the current course.
|
||||
*
|
||||
* @param int $userid the id of the user to check.
|
||||
* @return bool whether the user is enrolled.
|
||||
*/
|
||||
public function is_participant($userid) {
|
||||
return is_enrolled($this->get_context(), $userid, 'mod/quiz:attempt', $this->show_only_active_users());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is only active users in course should be shown.
|
||||
*
|
||||
* @return bool true if only active users should be shown.
|
||||
*/
|
||||
public function show_only_active_users() {
|
||||
return !has_capability('moodle/course:viewsuspendedusers', $this->get_context());
|
||||
}
|
||||
|
||||
/**
|
||||
* Have any questions been added to this quiz yet?
|
||||
*
|
||||
* @return bool whether any questions have been added to this quiz.
|
||||
*/
|
||||
public function has_questions() {
|
||||
if ($this->questions === null) {
|
||||
$this->preload_questions();
|
||||
}
|
||||
return !empty($this->questions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a particular question in this quiz, by its id.
|
||||
*
|
||||
* @param int $id the question id.
|
||||
* @return stdClass the question object with that id.
|
||||
*/
|
||||
public function get_question($id) {
|
||||
return $this->questions[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get some of the question in this quiz.
|
||||
*
|
||||
* @param array|null $questionids question ids of the questions to load. null for all.
|
||||
* @return stdClass[] the question data objects.
|
||||
*/
|
||||
public function get_questions($questionids = null) {
|
||||
if (is_null($questionids)) {
|
||||
$questionids = array_keys($this->questions);
|
||||
}
|
||||
$questions = [];
|
||||
foreach ($questionids as $id) {
|
||||
if (!array_key_exists($id, $this->questions)) {
|
||||
throw new moodle_exception('cannotstartmissingquestion', 'quiz', $this->view_url());
|
||||
}
|
||||
$questions[$id] = $this->questions[$id];
|
||||
$this->ensure_question_loaded($id);
|
||||
}
|
||||
return $questions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the sections in this quiz.
|
||||
*
|
||||
* @return array 0, 1, 2, ... => quiz_sections row from the database.
|
||||
*/
|
||||
public function get_sections() {
|
||||
global $DB;
|
||||
if ($this->sections === null) {
|
||||
$this->sections = array_values($DB->get_records('quiz_sections',
|
||||
['quizid' => $this->get_quizid()], 'firstslot'));
|
||||
}
|
||||
return $this->sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return access_manager and instance of the access_manager class
|
||||
* for this quiz at this time.
|
||||
*
|
||||
* @param int $timenow the current time as a unix timestamp.
|
||||
* @return access_manager and instance of the access_manager class
|
||||
* for this quiz at this time.
|
||||
*/
|
||||
public function get_access_manager($timenow) {
|
||||
if (is_null($this->accessmanager)) {
|
||||
$this->accessmanager = new access_manager($this, $timenow,
|
||||
has_capability('mod/quiz:ignoretimelimits', $this->context, null, false));
|
||||
}
|
||||
return $this->accessmanager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper round the has_capability funciton that automatically passes in the quiz context.
|
||||
*
|
||||
* @param string $capability the name of the capability to check. For example mod/quiz:view.
|
||||
* @param int|null $userid A user id. By default (null) checks the permissions of the current user.
|
||||
* @param bool $doanything If false, ignore effect of admin role assignment.
|
||||
* @return boolean true if the user has this capability. Otherwise false.
|
||||
*/
|
||||
public function has_capability($capability, $userid = null, $doanything = true) {
|
||||
return has_capability($capability, $this->context, $userid, $doanything);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper round the require_capability function that automatically passes in the quiz context.
|
||||
*
|
||||
* @param string $capability the name of the capability to check. For example mod/quiz:view.
|
||||
* @param int|null $userid A user id. By default (null) checks the permissions of the current user.
|
||||
* @param bool $doanything If false, ignore effect of admin role assignment.
|
||||
*/
|
||||
public function require_capability($capability, $userid = null, $doanything = true) {
|
||||
require_capability($capability, $this->context, $userid, $doanything);
|
||||
}
|
||||
|
||||
// URLs related to this attempt ============================================.
|
||||
|
||||
/**
|
||||
* Get the URL of this quiz's view.php page.
|
||||
*
|
||||
* @return moodle_url the URL of this quiz's view page.
|
||||
*/
|
||||
public function view_url() {
|
||||
return new moodle_url('/mod/quiz/view.php', ['id' => $this->cm->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of this quiz's edit questions page.
|
||||
*
|
||||
* @return moodle_url the URL of this quiz's edit page.
|
||||
*/
|
||||
public function edit_url() {
|
||||
return new moodle_url('/mod/quiz/edit.php', ['cmid' => $this->cm->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of a particular page within an attempt.
|
||||
*
|
||||
* @param int $attemptid the id of an attempt.
|
||||
* @param int $page optional page number to go to in the attempt.
|
||||
* @return moodle_url the URL of that attempt.
|
||||
*/
|
||||
public function attempt_url($attemptid, $page = 0) {
|
||||
$params = ['attempt' => $attemptid, 'cmid' => $this->get_cmid()];
|
||||
if ($page) {
|
||||
$params['page'] = $page;
|
||||
}
|
||||
return new moodle_url('/mod/quiz/attempt.php', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to start/continue an attempt.
|
||||
*
|
||||
* @param int $page page in the attempt to start on (optional).
|
||||
* @return moodle_url the URL of this quiz's edit page. Needs to be POSTed to with a cmid parameter.
|
||||
*/
|
||||
public function start_attempt_url($page = 0) {
|
||||
$params = ['cmid' => $this->cm->id, 'sesskey' => sesskey()];
|
||||
if ($page) {
|
||||
$params['page'] = $page;
|
||||
}
|
||||
return new moodle_url('/mod/quiz/startattempt.php', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to review a particular quiz attempt.
|
||||
*
|
||||
* @param int $attemptid the id of an attempt.
|
||||
* @return string the URL of the review of that attempt.
|
||||
*/
|
||||
public function review_url($attemptid) {
|
||||
return new moodle_url('/mod/quiz/review.php', ['attempt' => $attemptid, 'cmid' => $this->get_cmid()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL for the summary page for a particular attempt.
|
||||
*
|
||||
* @param int $attemptid the id of an attempt.
|
||||
* @return string the URL of the review of that attempt.
|
||||
*/
|
||||
public function summary_url($attemptid) {
|
||||
return new moodle_url('/mod/quiz/summary.php', ['attempt' => $attemptid, 'cmid' => $this->get_cmid()]);
|
||||
}
|
||||
|
||||
// Bits of content =========================================================.
|
||||
|
||||
/**
|
||||
* If $reviewoptions->attempt is false, meaning that students can't review this
|
||||
* attempt at the moment, return an appropriate string explaining why.
|
||||
*
|
||||
* @param int $when One of the display_options::DURING,
|
||||
* IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants.
|
||||
* @param bool $short if true, return a shorter string.
|
||||
* @return string an appropraite message.
|
||||
*/
|
||||
public function cannot_review_message($when, $short = false) {
|
||||
|
||||
if ($short) {
|
||||
$langstrsuffix = 'short';
|
||||
$dateformat = get_string('strftimedatetimeshort', 'langconfig');
|
||||
} else {
|
||||
$langstrsuffix = '';
|
||||
$dateformat = '';
|
||||
}
|
||||
|
||||
if ($when == display_options::DURING ||
|
||||
$when == display_options::IMMEDIATELY_AFTER) {
|
||||
return '';
|
||||
} else {
|
||||
if ($when == display_options::LATER_WHILE_OPEN && $this->quiz->timeclose &&
|
||||
$this->quiz->reviewattempt & display_options::AFTER_CLOSE) {
|
||||
return get_string('noreviewuntil' . $langstrsuffix, 'quiz',
|
||||
userdate($this->quiz->timeclose, $dateformat));
|
||||
} else {
|
||||
return get_string('noreview' . $langstrsuffix, 'quiz');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Probably not used any more, but left for backwards compatibility.
|
||||
*
|
||||
* @param string $title the name of this particular quiz page.
|
||||
* @return string always returns ''.
|
||||
*/
|
||||
public function navigation($title) {
|
||||
global $PAGE;
|
||||
$PAGE->navbar->add($title);
|
||||
return '';
|
||||
}
|
||||
|
||||
// Private methods =========================================================.
|
||||
|
||||
/**
|
||||
* Check that the definition of a particular question is loaded, and if not throw an exception.
|
||||
*
|
||||
* @param int $id a question id.
|
||||
*/
|
||||
protected function ensure_question_loaded($id) {
|
||||
if (isset($this->questions[$id]->_partiallyloaded)) {
|
||||
throw new moodle_exception('questionnotloaded', 'quiz', $this->view_url(), $id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the question types used in this quiz.
|
||||
*
|
||||
* @param boolean $includepotential if the quiz include random questions,
|
||||
* setting this flag to true will make the function to return all the
|
||||
* possible question types in the random questions category.
|
||||
* @return array a sorted array including the different question types.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function get_all_question_types_used($includepotential = false) {
|
||||
$questiontypes = [];
|
||||
|
||||
// To control if we need to look in categories for questions.
|
||||
$qcategories = [];
|
||||
|
||||
foreach ($this->get_questions() as $questiondata) {
|
||||
if ($questiondata->qtype === 'random' && $includepotential) {
|
||||
if (!isset($qcategories[$questiondata->category])) {
|
||||
$qcategories[$questiondata->category] = false;
|
||||
}
|
||||
if (!empty($questiondata->filtercondition)) {
|
||||
$filtercondition = json_decode($questiondata->filtercondition);
|
||||
$qcategories[$questiondata->category] = !empty($filtercondition->includingsubcategories);
|
||||
}
|
||||
} else {
|
||||
if (!in_array($questiondata->qtype, $questiontypes)) {
|
||||
$questiontypes[] = $questiondata->qtype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($qcategories)) {
|
||||
// We have to look for all the question types in these categories.
|
||||
$categoriestolook = [];
|
||||
foreach ($qcategories as $cat => $includesubcats) {
|
||||
if ($includesubcats) {
|
||||
$categoriestolook = array_merge($categoriestolook, question_categorylist($cat));
|
||||
} else {
|
||||
$categoriestolook[] = $cat;
|
||||
}
|
||||
}
|
||||
$questiontypesincategories = question_bank::get_all_question_types_in_categories($categoriestolook);
|
||||
$questiontypes = array_merge($questiontypes, $questiontypesincategories);
|
||||
}
|
||||
$questiontypes = array_unique($questiontypes);
|
||||
sort($questiontypes);
|
||||
|
||||
return $questiontypes;
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ use mod_quiz\question\qubaids_for_quiz;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class structure {
|
||||
/** @var \quiz the quiz this is the structure of. */
|
||||
/** @var \mod_quiz\quiz_settings the quiz this is the structure of. */
|
||||
protected $quizobj = null;
|
||||
|
||||
/**
|
||||
@ -83,7 +83,7 @@ class structure {
|
||||
/**
|
||||
* Create an instance of this class representing the structure of a given quiz.
|
||||
*
|
||||
* @param \quiz $quizobj the quiz.
|
||||
* @param \mod_quiz\quiz_settings $quizobj the quiz.
|
||||
* @return structure
|
||||
*/
|
||||
public static function create_for_quiz($quizobj) {
|
||||
|
@ -20,10 +20,10 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use context_course;
|
||||
use core_user;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use moodle_recordset;
|
||||
use question_display_options;
|
||||
use mod_quiz\question\display_options;
|
||||
use quiz_attempt;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
|
@ -24,8 +24,13 @@
|
||||
*/
|
||||
namespace mod_quiz\task;
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
use moodle_exception;
|
||||
use moodle_recordset;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
/**
|
||||
@ -39,27 +44,112 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
*/
|
||||
class update_overdue_attempts extends \core\task\scheduled_task {
|
||||
|
||||
public function get_name() {
|
||||
public function get_name(): string {
|
||||
return get_string('updateoverdueattemptstask', 'mod_quiz');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Close off any overdue attempts.
|
||||
*/
|
||||
public function execute() {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/cronlib.php');
|
||||
$timenow = time();
|
||||
$overduehander = new \mod_quiz_overdue_attempt_updater();
|
||||
|
||||
$processto = $timenow - get_config('quiz', 'graceperiodmin');
|
||||
|
||||
mtrace(' Looking for quiz overdue quiz attempts...');
|
||||
|
||||
list($count, $quizcount) = $overduehander->update_overdue_attempts($timenow, $processto);
|
||||
list($count, $quizcount) = $this->update_all_overdue_attempts($timenow, $processto);
|
||||
|
||||
mtrace(' Considered ' . $count . ' attempts in ' . $quizcount . ' quizzes.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the processing required.
|
||||
*
|
||||
* @param int $timenow the time to consider as 'now' during the processing.
|
||||
* @param int $processto only process attempt with timecheckstate longer ago than this.
|
||||
* @return array with two elements, the number of attempt considered, and how many different quizzes that was.
|
||||
*/
|
||||
public function update_all_overdue_attempts(int $timenow, int $processto): array {
|
||||
global $DB;
|
||||
|
||||
$attemptstoprocess = $this->get_list_of_overdue_attempts($processto);
|
||||
|
||||
$course = null;
|
||||
$quiz = null;
|
||||
$cm = null;
|
||||
|
||||
$count = 0;
|
||||
$quizcount = 0;
|
||||
foreach ($attemptstoprocess as $attempt) {
|
||||
try {
|
||||
|
||||
// If we have moved on to a different quiz, fetch the new data.
|
||||
if (!$quiz || $attempt->quiz != $quiz->id) {
|
||||
$quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST);
|
||||
$cm = get_coursemodule_from_instance('quiz', $attempt->quiz);
|
||||
$quizcount += 1;
|
||||
}
|
||||
|
||||
// If we have moved on to a different course, fetch the new data.
|
||||
if (!$course || $course->id != $quiz->course) {
|
||||
$course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
// Make a specialised version of the quiz settings, with the relevant overrides.
|
||||
$quizforuser = clone($quiz);
|
||||
$quizforuser->timeclose = $attempt->usertimeclose;
|
||||
$quizforuser->timelimit = $attempt->usertimelimit;
|
||||
|
||||
// Trigger any transitions that are required.
|
||||
$attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course);
|
||||
$attemptobj->handle_if_time_expired($timenow, false);
|
||||
$count += 1;
|
||||
|
||||
} catch (moodle_exception $e) {
|
||||
// If an error occurs while processing one attempt, don't let that kill cron.
|
||||
mtrace("Error while processing attempt $attempt->id at $attempt->quiz quiz:");
|
||||
mtrace($e->getMessage());
|
||||
mtrace($e->getTraceAsString());
|
||||
// Close down any currently open transactions, otherwise one error
|
||||
// will stop following DB changes from being committed.
|
||||
$DB->force_transaction_rollback();
|
||||
}
|
||||
}
|
||||
|
||||
$attemptstoprocess->close();
|
||||
return array($count, $quizcount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a recordset of all the attempts that need to be processed now.
|
||||
*
|
||||
* (Only public to allow unit testing. Do not use!)
|
||||
*
|
||||
* @param int $processto timestamp to process up to.
|
||||
* @return moodle_recordset of quiz_attempts that need to be processed because time has
|
||||
* passed, sorted by courseid then quizid.
|
||||
*/
|
||||
public function get_list_of_overdue_attempts(int $processto): moodle_recordset {
|
||||
global $DB;
|
||||
|
||||
// SQL to compute timeclose and timelimit for each attempt.
|
||||
$quizausersql = quiz_get_attempt_usertime_sql(
|
||||
"iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
|
||||
|
||||
// This query should have all the quiz_attempts columns.
|
||||
return $DB->get_recordset_sql("
|
||||
SELECT quiza.*,
|
||||
quizauser.usertimeclose,
|
||||
quizauser.usertimelimit
|
||||
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {quiz} quiz ON quiz.id = quiza.quiz
|
||||
JOIN ( $quizausersql ) quizauser ON quizauser.id = quiza.id
|
||||
|
||||
WHERE quiza.state IN ('inprogress', 'overdue')
|
||||
AND quiza.timecheckstate <= :processto
|
||||
ORDER BY quiz.course, quiza.quiz",
|
||||
|
||||
array('processto' => $processto, 'iprocessto' => $processto));
|
||||
}
|
||||
}
|
||||
|
@ -20,106 +20,13 @@
|
||||
* @package mod_quiz
|
||||
* @copyright 2012 the Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-76612 delete this file as part of Moodle 4.6 development.
|
||||
* @deprecated This file is no longer required in Moodle 4.2+.
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER);
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
|
||||
/**
|
||||
* This class holds all the code for automatically updating all attempts that have
|
||||
* gone over their time limit.
|
||||
*
|
||||
* @copyright 2012 the Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_quiz_overdue_attempt_updater {
|
||||
|
||||
/**
|
||||
* Do the processing required.
|
||||
* @param int $timenow the time to consider as 'now' during the processing.
|
||||
* @param int $processto only process attempt with timecheckstate longer ago than this.
|
||||
* @return array with two elements, the number of attempt considered, and how many different quizzes that was.
|
||||
*/
|
||||
public function update_overdue_attempts($timenow, $processto) {
|
||||
global $DB;
|
||||
|
||||
$attemptstoprocess = $this->get_list_of_overdue_attempts($processto);
|
||||
|
||||
$course = null;
|
||||
$quiz = null;
|
||||
$cm = null;
|
||||
|
||||
$count = 0;
|
||||
$quizcount = 0;
|
||||
foreach ($attemptstoprocess as $attempt) {
|
||||
try {
|
||||
|
||||
// If we have moved on to a different quiz, fetch the new data.
|
||||
if (!$quiz || $attempt->quiz != $quiz->id) {
|
||||
$quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST);
|
||||
$cm = get_coursemodule_from_instance('quiz', $attempt->quiz);
|
||||
$quizcount += 1;
|
||||
}
|
||||
|
||||
// If we have moved on to a different course, fetch the new data.
|
||||
if (!$course || $course->id != $quiz->course) {
|
||||
$course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
// Make a specialised version of the quiz settings, with the relevant overrides.
|
||||
$quizforuser = clone($quiz);
|
||||
$quizforuser->timeclose = $attempt->usertimeclose;
|
||||
$quizforuser->timelimit = $attempt->usertimelimit;
|
||||
|
||||
// Trigger any transitions that are required.
|
||||
$attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course);
|
||||
$attemptobj->handle_if_time_expired($timenow, false);
|
||||
$count += 1;
|
||||
|
||||
} catch (moodle_exception $e) {
|
||||
// If an error occurs while processing one attempt, don't let that kill cron.
|
||||
mtrace("Error while processing attempt {$attempt->id} at {$attempt->quiz} quiz:");
|
||||
mtrace($e->getMessage());
|
||||
mtrace($e->getTraceAsString());
|
||||
// Close down any currently open transactions, otherwise one error
|
||||
// will stop following DB changes from being committed.
|
||||
$DB->force_transaction_rollback();
|
||||
}
|
||||
}
|
||||
|
||||
$attemptstoprocess->close();
|
||||
return array($count, $quizcount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return moodle_recordset of quiz_attempts that need to be processed because time has
|
||||
* passed. The array is sorted by courseid then quizid.
|
||||
*/
|
||||
public function get_list_of_overdue_attempts($processto) {
|
||||
global $DB;
|
||||
|
||||
|
||||
// SQL to compute timeclose and timelimit for each attempt:
|
||||
$quizausersql = quiz_get_attempt_usertime_sql(
|
||||
"iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
|
||||
|
||||
// This query should have all the quiz_attempts columns.
|
||||
return $DB->get_recordset_sql("
|
||||
SELECT quiza.*,
|
||||
quizauser.usertimeclose,
|
||||
quizauser.usertimelimit
|
||||
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {quiz} quiz ON quiz.id = quiza.quiz
|
||||
JOIN ( $quizausersql ) quizauser ON quizauser.id = quiza.id
|
||||
|
||||
WHERE quiza.state IN ('inprogress', 'overdue')
|
||||
AND quiza.timecheckstate <= :processto
|
||||
ORDER BY quiz.course, quiza.quiz",
|
||||
|
||||
array('processto' => $processto, 'iprocessto' => $processto));
|
||||
}
|
||||
}
|
||||
require_once($CFG->dirroot . '/mod/quiz/deprecatedlib.php');
|
||||
|
@ -51,4 +51,19 @@ $renamedclasses = [
|
||||
'mod_quiz_attempts_report_form' => 'mod_quiz\local\reports\attempts_report_options_form',
|
||||
'mod_quiz_attempts_report_options' => 'mod_quiz\local\reports\attempts_report_options',
|
||||
'quiz_attempts_report_table' => 'mod_quiz\local\reports\attempts_report_table',
|
||||
'quiz_access_manager' => 'mod_quiz\access_manager',
|
||||
'mod_quiz_preflight_check_form' => 'mod_quiz\form\preflight_check_form',
|
||||
'quiz_override_form' => 'mod_quiz\form\edit_override_form',
|
||||
'quiz_access_rule_base' => 'mod_quiz\local\access_rule_base',
|
||||
'quiz_add_random_form' => 'mod_quiz\form\add_random_form',
|
||||
'mod_quiz_links_to_other_attempts' => 'mod_quiz\output\links_to_other_attempts',
|
||||
'mod_quiz_view_object' => 'mod_quiz\output\view_page',
|
||||
'mod_quiz_renderer' => 'mod_quiz\output\renderer',
|
||||
'quiz_nav_question_button' => 'mod_quiz\output\navigation_question_button',
|
||||
'quiz_nav_section_heading' => 'mod_quiz\output\navigation_section_heading',
|
||||
'quiz_nav_panel_base' => 'mod_quiz\output\navigation_panel_base',
|
||||
'quiz_attempt_nav_panel' => 'mod_quiz\output\navigation_panel_attempt',
|
||||
'quiz_review_nav_panel' => 'mod_quiz\output\navigation_panel_review',
|
||||
'quiz_attempt' => 'mod_quiz\quiz_attempt',
|
||||
'quiz' => 'mod_quiz\quiz_settings',
|
||||
];
|
||||
|
@ -22,6 +22,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\access_manager;
|
||||
use mod_quiz\quiz_settings;
|
||||
use mod_quiz\task\update_overdue_attempts;
|
||||
|
||||
/**
|
||||
* Internal function used in quiz_get_completion_state. Check passing grade (or no attempts left) requirement for completion.
|
||||
*
|
||||
@ -68,8 +72,8 @@ function quiz_completion_check_passing_grade_or_all_attempts($course, $cm, $user
|
||||
}
|
||||
$lastfinishedattempt = end($attempts);
|
||||
$context = context_module::instance($cm->id);
|
||||
$quizobj = quiz::create($quiz->id, $userid);
|
||||
$accessmanager = new quiz_access_manager($quizobj, time(),
|
||||
$quizobj = quiz_settings::create($quiz->id, $userid);
|
||||
$accessmanager = new access_manager($quizobj, time(),
|
||||
has_capability('mod/quiz:ignoretimelimits', $context, $userid, false));
|
||||
|
||||
return $accessmanager->is_finished(count($attempts), $lastfinishedattempt);
|
||||
@ -132,3 +136,62 @@ function quiz_get_completion_state($course, $cm, $userid, $type) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @copyright 2012 the Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts.
|
||||
* @todo MDL-76612 Final deprecation in Moodle 4.6
|
||||
*/
|
||||
class mod_quiz_overdue_attempt_updater {
|
||||
|
||||
/**
|
||||
* @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts. that was.
|
||||
*/
|
||||
public function update_overdue_attempts($timenow, $processto) {
|
||||
debugging('mod_quiz_overdue_attempt_updater has been deprecated. The code wsa moved to ' .
|
||||
'mod_quiz\task\update_overdue_attempts.');
|
||||
return (new update_overdue_attempts())->update_all_overdue_attempts((int) $timenow, (int) $processto);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts.
|
||||
*/
|
||||
public function get_list_of_overdue_attempts($processto) {
|
||||
debugging('mod_quiz_overdue_attempt_updater has been deprecated. The code wsa moved to ' .
|
||||
'mod_quiz\task\update_overdue_attempts.');
|
||||
return (new update_overdue_attempts())->get_list_of_overdue_attempts((int) $processto);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for quiz exceptions. Just saves a couple of arguments on the
|
||||
* constructor for a moodle_exception.
|
||||
*
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.0
|
||||
* @deprecated since Moodle 4.2. Please just use moodle_exception.
|
||||
* @todo MDL-76612 Final deprecation in Moodle 4.6
|
||||
*/
|
||||
class moodle_quiz_exception extends moodle_exception {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param quiz_settings $quizobj the quiz the error relates to.
|
||||
* @param string $errorcode The name of the string from error.php to print.
|
||||
* @param mixed $a Extra words and phrases that might be required in the error string.
|
||||
* @param string $link The url where the user will be prompted to continue.
|
||||
* If no url is provided the user will be directed to the site index page.
|
||||
* @param string|null $debuginfo optional debugging information.
|
||||
* @deprecated since Moodle 4.2. Please just use moodle_exception.
|
||||
*/
|
||||
public function __construct($quizobj, $errorcode, $a = null, $link = '', $debuginfo = null) {
|
||||
debugging('Class moodle_quiz_exception is deprecated. ' .
|
||||
'Please use a standard moodle_exception instead.', DEBUG_DEVELOPER);
|
||||
if (!$link) {
|
||||
$link = $quizobj->view_url();
|
||||
}
|
||||
parent::__construct($errorcode, 'quiz', $link, $a, $debuginfo);
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +40,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/addrandomform.php');
|
||||
require_once($CFG->dirroot . '/question/editlib.php');
|
||||
|
||||
// These params are only passed from page request to request while we stay on
|
||||
@ -63,7 +63,7 @@ $PAGE->set_secondary_active_tab("mod_quiz_edit");
|
||||
|
||||
// Get the course object and related bits.
|
||||
$course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
|
||||
$quizobj = new quiz($quiz, $cm, $course);
|
||||
$quizobj = new quiz_settings($quiz, $cm, $course);
|
||||
$structure = $quizobj->get_structure();
|
||||
|
||||
// You need mod/quiz:manage in addition to question capabilities to access this page.
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
if (!defined('AJAX_SCRIPT')) {
|
||||
define('AJAX_SCRIPT', true);
|
||||
}
|
||||
@ -57,7 +59,7 @@ $cm = get_coursemodule_from_instance('quiz', $quiz->id, $quiz->course);
|
||||
$course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
|
||||
require_login($course, false, $cm);
|
||||
|
||||
$quizobj = new quiz($quiz, $cm, $course);
|
||||
$quizobj = new quiz_settings($quiz, $cm, $course);
|
||||
$structure = $quizobj->get_structure();
|
||||
$modcontext = context_module::instance($cm->id);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
@ -28,14 +28,17 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_quiz\access_manager;
|
||||
use mod_quiz\form\add_random_form;
|
||||
use mod_quiz\question\bank\custom_view;
|
||||
use mod_quiz\question\display_options;
|
||||
use mod_quiz\question\qubaids_for_quiz;
|
||||
use mod_quiz\question\qubaids_for_users_attempts;
|
||||
use core_question\statistics\questions\all_calculated_for_qubaid_condition;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
require_once($CFG->dirroot . '/calendar/lib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
|
||||
|
||||
/**#@+
|
||||
* Option controlling what options are offered on the quiz settings form.
|
||||
@ -190,7 +193,7 @@ function quiz_delete_instance($id) {
|
||||
|
||||
$DB->delete_records('quiz_feedback', array('quizid' => $quiz->id));
|
||||
|
||||
quiz_access_manager::delete_settings($quiz);
|
||||
access_manager::delete_settings($quiz);
|
||||
|
||||
$events = $DB->get_records('event', array('modulename' => 'quiz', 'instance' => $quiz->id));
|
||||
foreach ($events as $event) {
|
||||
@ -581,12 +584,7 @@ function quiz_user_complete($course, $user, $mod, $quiz) {
|
||||
* array if there are none.
|
||||
*/
|
||||
function quiz_get_user_attempts($quizids, $userid, $status = 'finished', $includepreviews = false) {
|
||||
global $DB, $CFG;
|
||||
// TODO MDL-33071 it is very annoying to have to included all of locallib.php
|
||||
// just to get the quiz_attempt::FINISHED constants, but I will try to sort
|
||||
// that out properly for Moodle 2.4. For now, I will just do a quick fix for
|
||||
// MDL-33048.
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
global $DB;
|
||||
|
||||
$params = array();
|
||||
switch ($status) {
|
||||
@ -659,7 +657,7 @@ function quiz_get_user_grades($quiz, $userid = 0) {
|
||||
/**
|
||||
* Round a grade to to the correct number of decimal places, and format it for display.
|
||||
*
|
||||
* @param object $quiz The quiz table row, only $quiz->decimalpoints is used.
|
||||
* @param stdClass $quiz The quiz table row, only $quiz->decimalpoints is used.
|
||||
* @param float $grade The grade to round.
|
||||
* @return float
|
||||
*/
|
||||
@ -691,9 +689,9 @@ function quiz_get_grade_format($quiz) {
|
||||
/**
|
||||
* Round a grade to the correct number of decimal places, and format it for display.
|
||||
*
|
||||
* @param object $quiz The quiz table row, only $quiz->decimalpoints is used.
|
||||
* @param stdClass $quiz The quiz table row, only $quiz->decimalpoints is used.
|
||||
* @param float $grade The grade to round.
|
||||
* @return float
|
||||
* @return string
|
||||
*/
|
||||
function quiz_format_question_grade($quiz, $grade) {
|
||||
return format_float($grade, quiz_get_grade_format($quiz));
|
||||
@ -1185,7 +1183,7 @@ function mod_quiz_inplace_editable(string $itemtype, int $itemid, string $newval
|
||||
// Check permission of the user to update this item (customise question number).
|
||||
require_capability('mod/quiz:manage', $context);
|
||||
|
||||
$quizobj = new quiz($quiz, $cm, $course);
|
||||
$quizobj = new quiz_settings($quiz, $cm, $course);
|
||||
$structure = $quizobj->get_structure();
|
||||
$warning = false;
|
||||
// Clean input and update the record.
|
||||
@ -1236,7 +1234,7 @@ function quiz_after_add_or_update($quiz) {
|
||||
}
|
||||
|
||||
// Store any settings belonging to the access rules.
|
||||
quiz_access_manager::save_settings($quiz);
|
||||
access_manager::save_settings($quiz);
|
||||
|
||||
// Update the events relating to this quiz.
|
||||
quiz_update_events($quiz);
|
||||
@ -1965,7 +1963,7 @@ function quiz_check_updates_since(cm_info $cm, $from, $filter = array()) {
|
||||
|
||||
// Check if questions were updated.
|
||||
$updates->questions = (object) array('updated' => false);
|
||||
$quizobj = quiz::create($cm->instance, $USER->id);
|
||||
$quizobj = quiz_settings::create($cm->instance, $USER->id);
|
||||
$quizobj->preload_questions();
|
||||
$quizobj->load_questions();
|
||||
$questionids = array_keys($quizobj->get_questions());
|
||||
@ -2062,7 +2060,7 @@ function mod_quiz_core_calendar_provide_event_action(calendar_event $event,
|
||||
}
|
||||
|
||||
$cm = get_fast_modinfo($event->courseid, $userid)->instances['quiz'][$event->instance];
|
||||
$quizobj = quiz::create($cm->instance, $userid);
|
||||
$quizobj = quiz_settings::create($cm->instance, $userid);
|
||||
$quiz = $quizobj->get_quiz();
|
||||
|
||||
// Check they have capabilities allowing them to view the quiz.
|
||||
@ -2459,7 +2457,6 @@ function mod_quiz_output_fragment_quiz_question_bank($args) {
|
||||
*/
|
||||
function mod_quiz_output_fragment_add_random_question_form($args) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/quiz/addrandomform.php');
|
||||
|
||||
$contexts = new \core_question\local\bank\question_edit_contexts($args['context']);
|
||||
$formoptions = [
|
||||
@ -2473,7 +2470,7 @@ function mod_quiz_output_fragment_add_random_question_form($args) {
|
||||
'cmid' => $args['cmid']
|
||||
];
|
||||
|
||||
$form = new quiz_add_random_form(
|
||||
$form = new add_random_form(
|
||||
new \moodle_url('/mod/quiz/addrandom.php'),
|
||||
$formoptions,
|
||||
'post',
|
||||
|
@ -31,16 +31,15 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/lib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessmanager.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/accessmanager_form.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/renderer.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
|
||||
require_once($CFG->libdir . '/completionlib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
|
||||
use mod_quiz\access_manager;
|
||||
use mod_quiz\question\bank\qbank_helper;
|
||||
use mod_quiz\question\display_options;
|
||||
use mod_quiz\quiz_attempt;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
/**
|
||||
* @var int We show the countdown timer if there is less than this amount of time left before the
|
||||
@ -82,7 +81,7 @@ define('QUIZ_SHOWIMAGE_LARGE', 2);
|
||||
*
|
||||
* @param object $quizobj the quiz object to create an attempt for.
|
||||
* @param int $attemptnumber the sequence number for the attempt.
|
||||
* @param stdClass|null $lastattempt the previous attempt by this user, if any. Only needed
|
||||
* @param stdClass|false $lastattempt the previous attempt by this user, if any. Only needed
|
||||
* if $attemptnumber > 1 and $quiz->attemptonlast is true.
|
||||
* @param int $timenow the time the attempt was started at.
|
||||
* @param bool $ispreview whether this new attempt is a preview.
|
||||
@ -90,7 +89,7 @@ define('QUIZ_SHOWIMAGE_LARGE', 2);
|
||||
*
|
||||
* @return object the newly created attempt object.
|
||||
*/
|
||||
function quiz_create_attempt(quiz $quizobj, $attemptnumber, $lastattempt, $timenow, $ispreview = false, $userid = null) {
|
||||
function quiz_create_attempt(quiz_settings $quizobj, $attemptnumber, $lastattempt, $timenow, $ispreview = false, $userid = null) {
|
||||
global $USER;
|
||||
|
||||
if ($userid === null) {
|
||||
@ -146,17 +145,16 @@ function quiz_create_attempt(quiz $quizobj, $attemptnumber, $lastattempt, $timen
|
||||
/**
|
||||
* Start a normal, new, quiz attempt.
|
||||
*
|
||||
* @param quiz $quizobj the quiz object to start an attempt for.
|
||||
* @param quiz_settings $quizobj the quiz object to start an attempt for.
|
||||
* @param question_usage_by_activity $quba
|
||||
* @param object $attempt
|
||||
* @param integer $attemptnumber starting from 1
|
||||
* @param integer $timenow the attempt start time
|
||||
* @param array $questionids slot number => question id. Used for random questions, to force the choice
|
||||
* of a particular actual question. Intended for testing purposes only.
|
||||
* of a particular actual question. Intended for testing purposes only.
|
||||
* @param array $forcedvariantsbyslot slot number => variant. Used for questions with variants,
|
||||
* to force the choice of a particular variant. Intended for testing
|
||||
* purposes only.
|
||||
* @throws moodle_exception
|
||||
* to force the choice of a particular variant. Intended for testing
|
||||
* purposes only.
|
||||
* @return object modified attempt object
|
||||
*/
|
||||
function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow,
|
||||
@ -341,7 +339,7 @@ function quiz_start_attempt_built_on_last($quba, $attempt, $lastattempt) {
|
||||
/**
|
||||
* The save started question usage and quiz attempt in db and log the started attempt.
|
||||
*
|
||||
* @param quiz $quizobj
|
||||
* @param quiz_settings $quizobj
|
||||
* @param question_usage_by_activity $quba
|
||||
* @param object $attempt
|
||||
* @return object attempt object with uniqueid and id set.
|
||||
@ -586,8 +584,8 @@ function quiz_feedback_record_for_grade($grade, $quiz) {
|
||||
* got this grade on this quiz. The feedback is processed ready for diplay.
|
||||
*
|
||||
* @param float $grade a grade on this quiz.
|
||||
* @param object $quiz the quiz settings.
|
||||
* @param object $context the quiz context.
|
||||
* @param stdClass $quiz the quiz settings.
|
||||
* @param context_module $context the quiz context.
|
||||
* @return string the comment that corresponds to this grade (empty string if there is not one.
|
||||
*/
|
||||
function quiz_feedback_for_grade($grade, $quiz, $context) {
|
||||
@ -1355,7 +1353,7 @@ function quiz_questions_per_page_options() {
|
||||
|
||||
/**
|
||||
* Get the human-readable name for a quiz attempt state.
|
||||
* @param string $state one of the state constants like {@link quiz_attempt::IN_PROGRESS}.
|
||||
* @param string $state one of the state constants like {@see quiz_attempt::IN_PROGRESS}.
|
||||
* @return string The lang string to describe that state.
|
||||
*/
|
||||
function quiz_attempt_state_name($state) {
|
||||
@ -2437,16 +2435,15 @@ function quiz_view($quiz, $course, $cm, $context) {
|
||||
/**
|
||||
* 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 quiz_settings $quizobj quiz object
|
||||
* @param 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) {
|
||||
function quiz_validate_new_attempt(quiz_settings $quizobj, access_manager $accessmanager, $forcenew, $page, $redirect) {
|
||||
global $DB, $USER;
|
||||
$timenow = time();
|
||||
|
||||
@ -2486,7 +2483,7 @@ function quiz_validate_new_attempt(quiz $quizobj, quiz_access_manager $accessman
|
||||
if ($redirect) {
|
||||
redirect($quizobj->review_url($lastattempt->id));
|
||||
} else {
|
||||
throw new moodle_quiz_exception($quizobj, 'attemptalreadyclosed');
|
||||
throw new moodle_exception('attemptalreadyclosed', 'quiz', $quizobj->view_url());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2522,7 +2519,7 @@ function quiz_validate_new_attempt(quiz $quizobj, quiz_access_manager $accessman
|
||||
/**
|
||||
* Prepare and start a new attempt deleting the previous preview attempts.
|
||||
*
|
||||
* @param quiz $quizobj quiz object
|
||||
* @param quiz_settings $quizobj quiz object
|
||||
* @param int $attemptnumber the attempt number
|
||||
* @param object $lastattempt last attempt object
|
||||
* @param bool $offlineattempt whether is an offline attempt or not
|
||||
@ -2534,7 +2531,7 @@ function quiz_validate_new_attempt(quiz $quizobj, quiz_access_manager $accessman
|
||||
* @return object the new attempt
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function quiz_prepare_and_start_new_attempt(quiz $quizobj, $attemptnumber, $lastattempt,
|
||||
function quiz_prepare_and_start_new_attempt(quiz_settings $quizobj, $attemptnumber, $lastattempt,
|
||||
$offlineattempt = false, $forcedrandomquestions = [], $forcedvariants = [], $userid = null) {
|
||||
global $DB, $USER;
|
||||
|
||||
@ -2695,8 +2692,7 @@ function quiz_retrieve_tags_for_slot_ids($slotids) {
|
||||
*
|
||||
* @param int $attemptid the id of the current attempt.
|
||||
* @param int|null $cmid the course_module id for this quiz.
|
||||
* @return quiz_attempt $attemptobj all the data about the quiz attempt.
|
||||
* @throws moodle_exception
|
||||
* @return quiz_attempt all the data about the quiz attempt.
|
||||
*/
|
||||
function quiz_create_attempt_handling_errors($attemptid, $cmid = null) {
|
||||
try {
|
||||
|
@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->dirroot . '/course/moodleform_mod.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
use mod_quiz\access_manager;
|
||||
use mod_quiz\question\display_options;
|
||||
|
||||
/**
|
||||
@ -289,11 +290,11 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
|
||||
// Browser security choices.
|
||||
$mform->addElement('select', 'browsersecurity', get_string('browsersecurity', 'quiz'),
|
||||
quiz_access_manager::get_browser_security_choices());
|
||||
access_manager::get_browser_security_choices());
|
||||
$mform->addHelpButton('browsersecurity', 'browsersecurity', 'quiz');
|
||||
|
||||
// Any other rule plugins.
|
||||
quiz_access_manager::add_settings_form_fields($this, $mform);
|
||||
access_manager::add_settings_form_fields($this, $mform);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'quiz'));
|
||||
@ -479,7 +480,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
|
||||
// Load any settings belonging to the access rules.
|
||||
if (!empty($toform['instance'])) {
|
||||
$accesssettings = quiz_access_manager::load_settings($toform['instance']);
|
||||
$accesssettings = access_manager::load_settings($toform['instance']);
|
||||
foreach ($accesssettings as $name => $value) {
|
||||
$toform[$name] = $value;
|
||||
}
|
||||
@ -589,7 +590,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
unset($errors['gradepass']);
|
||||
}
|
||||
// Any other rule plugins.
|
||||
$errors = quiz_access_manager::validate_settings_form_fields($errors, $data, $files, $this);
|
||||
$errors = access_manager::validate_settings_form_fields($errors, $data, $files, $this);
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
@ -20,278 +20,10 @@
|
||||
* @package mod_quiz
|
||||
* @copyright 2010 Matt Petro
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-76612 delete this file as part of Moodle 4.6 development.
|
||||
* @deprecated This file is no longer required in Moodle 4.2+.
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/mod_form.php');
|
||||
|
||||
|
||||
/**
|
||||
* Form for editing settings overrides.
|
||||
*
|
||||
* @copyright 2010 Matt Petro
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_override_form extends moodleform {
|
||||
|
||||
/** @var cm_info course module object. */
|
||||
protected $cm;
|
||||
|
||||
/** @var stdClass the quiz settings object. */
|
||||
protected $quiz;
|
||||
|
||||
/** @var context the quiz context. */
|
||||
protected $context;
|
||||
|
||||
/** @var bool editing group override (true) or user override (false). */
|
||||
protected $groupmode;
|
||||
|
||||
/** @var int groupid, if provided. */
|
||||
protected $groupid;
|
||||
|
||||
/** @var int userid, if provided. */
|
||||
protected $userid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param moodle_url $submiturl the form action URL.
|
||||
* @param object course module object.
|
||||
* @param object the quiz settings object.
|
||||
* @param context the quiz context.
|
||||
* @param bool editing group override (true) or user override (false).
|
||||
* @param object $override the override being edited, if it already exists.
|
||||
*/
|
||||
public function __construct($submiturl, $cm, $quiz, $context, $groupmode, $override) {
|
||||
|
||||
$this->cm = $cm;
|
||||
$this->quiz = $quiz;
|
||||
$this->context = $context;
|
||||
$this->groupmode = $groupmode;
|
||||
$this->groupid = empty($override->groupid) ? 0 : $override->groupid;
|
||||
$this->userid = empty($override->userid) ? 0 : $override->userid;
|
||||
|
||||
parent::__construct($submiturl);
|
||||
}
|
||||
|
||||
protected function definition() {
|
||||
global $DB;
|
||||
|
||||
$cm = $this->cm;
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('header', 'override', get_string('override', 'quiz'));
|
||||
|
||||
$quizgroupmode = groups_get_activity_groupmode($cm);
|
||||
$accessallgroups = ($quizgroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context);
|
||||
|
||||
if ($this->groupmode) {
|
||||
// Group override.
|
||||
if ($this->groupid) {
|
||||
// There is already a groupid, so freeze the selector.
|
||||
$groupchoices = array();
|
||||
$groupchoices[$this->groupid] = groups_get_group_name($this->groupid);
|
||||
$mform->addElement('select', 'groupid',
|
||||
get_string('overridegroup', 'quiz'), $groupchoices);
|
||||
$mform->freeze('groupid');
|
||||
} else {
|
||||
// Prepare the list of groups.
|
||||
// Only include the groups the current can access.
|
||||
$groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm);
|
||||
if (empty($groups)) {
|
||||
// Generate an error.
|
||||
$link = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id));
|
||||
throw new \moodle_exception('groupsnone', 'quiz', $link);
|
||||
}
|
||||
|
||||
$groupchoices = array();
|
||||
foreach ($groups as $group) {
|
||||
$groupchoices[$group->id] = $group->name;
|
||||
}
|
||||
unset($groups);
|
||||
|
||||
if (count($groupchoices) == 0) {
|
||||
$groupchoices[0] = get_string('none');
|
||||
}
|
||||
|
||||
$mform->addElement('select', 'groupid',
|
||||
get_string('overridegroup', 'quiz'), $groupchoices);
|
||||
$mform->addRule('groupid', get_string('required'), 'required', null, 'client');
|
||||
}
|
||||
} else {
|
||||
// User override.
|
||||
$userfieldsapi = \core_user\fields::for_identity($this->context)->with_userpic()->with_name();
|
||||
$extrauserfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
|
||||
if ($this->userid) {
|
||||
// There is already a userid, so freeze the selector.
|
||||
$user = $DB->get_record('user', ['id' => $this->userid]);
|
||||
profile_load_custom_fields($user);
|
||||
$userchoices = array();
|
||||
$userchoices[$this->userid] = self::display_user_name($user, $extrauserfields);
|
||||
$mform->addElement('select', 'userid',
|
||||
get_string('overrideuser', 'quiz'), $userchoices);
|
||||
$mform->freeze('userid');
|
||||
} else {
|
||||
// Prepare the list of users.
|
||||
$groupids = 0;
|
||||
if (!$accessallgroups) {
|
||||
$groups = groups_get_activity_allowed_groups($cm);
|
||||
$groupids = array_keys($groups);
|
||||
}
|
||||
$enrolledjoin = get_enrolled_with_capabilities_join(
|
||||
$this->context, '', 'mod/quiz:attempt', $groupids, true);
|
||||
$userfieldsql = $userfieldsapi->get_sql('u', true, '', '', false);
|
||||
list($sort, $sortparams) = users_order_by_sql('u', null,
|
||||
$this->context, $userfieldsql->mappings);
|
||||
|
||||
$users = $DB->get_records_sql("
|
||||
SELECT $userfieldsql->selects
|
||||
FROM {user} u
|
||||
$enrolledjoin->joins
|
||||
$userfieldsql->joins
|
||||
LEFT JOIN {quiz_overrides} existingoverride ON
|
||||
existingoverride.userid = u.id AND existingoverride.quiz = :quizid
|
||||
WHERE existingoverride.id IS NULL
|
||||
AND $enrolledjoin->wheres
|
||||
ORDER BY $sort
|
||||
", array_merge(['quizid' => $this->quiz->id], $userfieldsql->params, $enrolledjoin->params, $sortparams));
|
||||
|
||||
// Filter users based on any fixed restrictions (groups, profile).
|
||||
$info = new \core_availability\info_module($cm);
|
||||
$users = $info->filter_user_list($users);
|
||||
|
||||
if (empty($users)) {
|
||||
// Generate an error.
|
||||
$link = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id));
|
||||
throw new \moodle_exception('usersnone', 'quiz', $link);
|
||||
}
|
||||
|
||||
$userchoices = [];
|
||||
foreach ($users as $id => $user) {
|
||||
$userchoices[$id] = self::display_user_name($user, $extrauserfields);
|
||||
}
|
||||
unset($users);
|
||||
|
||||
$mform->addElement('searchableselector', 'userid',
|
||||
get_string('overrideuser', 'quiz'), $userchoices);
|
||||
$mform->addRule('userid', get_string('required'), 'required', null, 'client');
|
||||
}
|
||||
}
|
||||
|
||||
// Password.
|
||||
// This field has to be above the date and timelimit fields,
|
||||
// otherwise browsers will clear it when those fields are changed.
|
||||
$mform->addElement('passwordunmask', 'password', get_string('requirepassword', 'quiz'));
|
||||
$mform->setType('password', PARAM_TEXT);
|
||||
$mform->addHelpButton('password', 'requirepassword', 'quiz');
|
||||
$mform->setDefault('password', $this->quiz->password);
|
||||
|
||||
// Open and close dates.
|
||||
$mform->addElement('date_time_selector', 'timeopen',
|
||||
get_string('quizopen', 'quiz'), mod_quiz_mod_form::$datefieldoptions);
|
||||
$mform->setDefault('timeopen', $this->quiz->timeopen);
|
||||
|
||||
$mform->addElement('date_time_selector', 'timeclose',
|
||||
get_string('quizclose', 'quiz'), mod_quiz_mod_form::$datefieldoptions);
|
||||
$mform->setDefault('timeclose', $this->quiz->timeclose);
|
||||
|
||||
// Time limit.
|
||||
$mform->addElement('duration', 'timelimit',
|
||||
get_string('timelimit', 'quiz'), array('optional' => true));
|
||||
$mform->addHelpButton('timelimit', 'timelimit', 'quiz');
|
||||
$mform->setDefault('timelimit', $this->quiz->timelimit);
|
||||
|
||||
// Number of attempts.
|
||||
$attemptoptions = array('0' => get_string('unlimited'));
|
||||
for ($i = 1; $i <= QUIZ_MAX_ATTEMPT_OPTION; $i++) {
|
||||
$attemptoptions[$i] = $i;
|
||||
}
|
||||
$mform->addElement('select', 'attempts',
|
||||
get_string('attemptsallowed', 'quiz'), $attemptoptions);
|
||||
$mform->addHelpButton('attempts', 'attempts', 'quiz');
|
||||
$mform->setDefault('attempts', $this->quiz->attempts);
|
||||
|
||||
// Submit buttons.
|
||||
$mform->addElement('submit', 'resetbutton',
|
||||
get_string('reverttodefaults', 'quiz'));
|
||||
|
||||
$buttonarray = array();
|
||||
$buttonarray[] = $mform->createElement('submit', 'submitbutton',
|
||||
get_string('save', 'quiz'));
|
||||
$buttonarray[] = $mform->createElement('submit', 'againbutton',
|
||||
get_string('saveoverrideandstay', 'quiz'));
|
||||
$buttonarray[] = $mform->createElement('cancel');
|
||||
|
||||
$mform->addGroup($buttonarray, 'buttonbar', '', array(' '), false);
|
||||
$mform->closeHeaderBefore('buttonbar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user's name and identity ready to display.
|
||||
*
|
||||
* @param stdClass $user a user object.
|
||||
* @param array $extrauserfields (identity fields in user table only from the user_fields API)
|
||||
* @return string User's name, with extra info, for display.
|
||||
*/
|
||||
public static function display_user_name(stdClass $user, array $extrauserfields): string {
|
||||
$username = fullname($user);
|
||||
$namefields = [];
|
||||
foreach ($extrauserfields as $field) {
|
||||
if (isset($user->$field) && $user->$field !== '') {
|
||||
$namefields[] = s($user->$field);
|
||||
} else if (strpos($field, 'profile_field_') === 0) {
|
||||
$field = substr($field, 14);
|
||||
if (isset($user->profile[$field]) && $user->profile[$field] !== '') {
|
||||
$namefields[] = s($user->profile[$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($namefields) {
|
||||
$username .= ' (' . implode(', ', $namefields) . ')';
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
public function validation($data, $files): array {
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
$mform =& $this->_form;
|
||||
$quiz = $this->quiz;
|
||||
|
||||
if ($mform->elementExists('userid')) {
|
||||
if (empty($data['userid'])) {
|
||||
$errors['userid'] = get_string('required');
|
||||
}
|
||||
}
|
||||
|
||||
if ($mform->elementExists('groupid')) {
|
||||
if (empty($data['groupid'])) {
|
||||
$errors['groupid'] = get_string('required');
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the dates make sense.
|
||||
if (!empty($data['timeopen']) && !empty($data['timeclose'])) {
|
||||
if ($data['timeclose'] < $data['timeopen'] ) {
|
||||
$errors['timeclose'] = get_string('closebeforeopen', 'quiz');
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that at least one quiz setting was changed.
|
||||
$changed = false;
|
||||
$keys = array('timeopen', 'timeclose', 'timelimit', 'attempts', 'password');
|
||||
foreach ($keys as $key) {
|
||||
if ($data[$key] != $quiz->{$key}) {
|
||||
$changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$changed) {
|
||||
$errors['timeopen'] = get_string('nooverridedata', 'quiz');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER);
|
||||
|
@ -22,11 +22,11 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\form\edit_override_form;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/lib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/override_form.php');
|
||||
|
||||
$overrideid = required_param('id', PARAM_INT);
|
||||
$confirm = optional_param('confirm', false, PARAM_BOOL);
|
||||
@ -103,7 +103,7 @@ if ($override->groupid) {
|
||||
profile_load_custom_fields($user);
|
||||
|
||||
$confirmstr = get_string('overridedeleteusersure', 'quiz',
|
||||
quiz_override_form::display_user_name($user,
|
||||
edit_override_form::display_user_name($user,
|
||||
\core_user\fields::get_identity_fields($context)));
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,11 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\form\edit_override_form;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/lib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/override_form.php');
|
||||
|
||||
|
||||
$cmid = optional_param('cmid', 0, PARAM_INT);
|
||||
$overrideid = optional_param('id', 0, PARAM_INT);
|
||||
@ -119,7 +118,7 @@ if (!$groupmode) {
|
||||
}
|
||||
|
||||
// Setup the form.
|
||||
$mform = new quiz_override_form($url, $cm, $quiz, $context, $groupmode, $override);
|
||||
$mform = new edit_override_form($url, $cm, $quiz, $context, $groupmode, $override);
|
||||
$mform->set_data($data);
|
||||
|
||||
if ($mform->is_cancelled()) {
|
||||
|
@ -25,8 +25,6 @@
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/lib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot.'/mod/quiz/override_form.php');
|
||||
|
||||
|
||||
$cmid = required_param('cmid', PARAM_INT);
|
||||
$mode = optional_param('mode', '', PARAM_ALPHA); // One of 'user' or 'group', default is 'group'.
|
||||
|
@ -28,6 +28,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
@ -71,7 +73,7 @@ require_sesskey();
|
||||
|
||||
// Check that this attempt belongs to this user.
|
||||
if ($attemptobj->get_userid() != $USER->id) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
|
||||
throw new moodle_exception('notyourattempt', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// Check capabilities.
|
||||
@ -81,8 +83,7 @@ if (!$attemptobj->is_preview_user()) {
|
||||
|
||||
// If the attempt is already closed, send them to the review page.
|
||||
if ($attemptobj->is_finished()) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(),
|
||||
'attemptalreadyclosed', null, $attemptobj->review_url());
|
||||
throw new moodle_exception('attemptalreadyclosed', 'quiz', $attemptobj->view_url());
|
||||
}
|
||||
|
||||
// Process the attempt, getting the new status for the attempt.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
@ -30,7 +32,7 @@ $slotnumber = required_param('slot', PARAM_INT);
|
||||
$repagtype = required_param('repag', PARAM_INT);
|
||||
|
||||
require_sesskey();
|
||||
$quizobj = quiz::create($quizid);
|
||||
$quizobj = quiz_settings::create($quizid);
|
||||
require_login($quizobj->get_course(), false, $quizobj->get_cm());
|
||||
require_capability('mod/quiz:manage', $quizobj->get_context());
|
||||
if (quiz_has_attempts($quizid)) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use mod_quiz\local\reports\report_base;
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use mod_quiz\local\reports\attempts_report_table;
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
/**
|
||||
* This is a table subclass for displaying the quiz grades report.
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
use mod_quiz\local\reports\attempts_report;
|
||||
use mod_quiz\question\bank\qbank_helper;
|
||||
use mod_quiz\quiz_attempt;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user