Commit 1d9e1a3c authored by Tim Hunt's avatar Tim Hunt
Browse files

MDL-29627 refactor the way the rules are constructed from the quiz.

parent d755b0f5
......@@ -53,41 +53,44 @@ class quiz_access_manager {
public function __construct($quizobj, $timenow, $canignoretimelimits) {
$this->quizobj = $quizobj;
$this->timenow = $timenow;
$this->create_standard_rules($canignoretimelimits);
$this->rules = $this->make_rules($quizobj, $timenow, $canignoretimelimits);
}
protected function create_standard_rules($canignoretimelimits) {
$rules = get_plugin_list_with_class('quizaccess', '', 'rule.php');
/**
* 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) {
$quiz = $this->quizobj->get_quiz();
if ($quiz->attempts > 0) {
$this->rules[] = new quizaccess_numattempts($this->quizobj, $this->timenow);
}
$this->rules[] = new quizaccess_openclosedate($this->quizobj, $this->timenow);
if (!empty($quiz->timelimit) && !$canignoretimelimits) {
$this->rules[] = new quizaccess_timelimit($this->quizobj, $this->timenow);
}
if (!empty($quiz->delay1) || !empty($quiz->delay2)) {
$this->rules[] = new quizaccess_delaybetweenattempts($this->quizobj, $this->timenow);
}
if (!empty($quiz->subnet)) {
$this->rules[] = new quizaccess_ipaddress($this->quizobj, $this->timenow);
$rules = array();
foreach (self::get_rule_classes() as $ruleclass) {
$rule = $ruleclass::make($quizobj, $timenow, $canignoretimelimits);
if ($rule) {
$rules[$ruleclass] = $rule;
}
}
if (!empty($quiz->password)) {
$this->passwordrule = new quizaccess_password($this->quizobj, $this->timenow);
$this->rules[] = $this->passwordrule;
$superceededrules = array();
foreach ($rules as $rule) {
$superceededrules += $rule->get_superceded_rules();
}
if (!empty($quiz->popup)) {
if ($quiz->popup == 1) {
$this->securewindowrule = new quizaccess_securewindow(
$this->quizobj, $this->timenow);
$this->rules[] = $this->securewindowrule;
} else if ($quiz->popup == 2) {
$this->safebrowserrule = new quizaccess_safebrowser(
$this->quizobj, $this->timenow);
$this->rules[] = $this->safebrowserrule;
}
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 get_plugin_list_with_class('quizaccess', '', 'rule.php');
}
/**
......@@ -101,12 +104,25 @@ class quiz_access_manager {
*/
public static function add_settings_form_fields(
mod_quiz_mod_form $quizform, MoodleQuickForm $mform) {
$rules = get_plugin_list_with_class('quizaccess', '', 'rule.php');
foreach ($rules as $rule) {
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(0 => get_string('none', 'quiz'));
foreach (self::get_rule_classes() as $rule) {
$options += $rule::get_browser_security_choices();
}
return $options;
}
/**
* Save any submitted settings when the quiz settings form is submitted.
*
......@@ -117,8 +133,8 @@ class quiz_access_manager {
* which is the is of the quiz being saved.
*/
public static function save_settings($quiz) {
$rules = get_plugin_list_with_class('quizaccess', '', 'rule.php');
foreach ($rules as $rule) {
foreach (self::get_rule_classes() as $rule) {
$rule::save_settings($quiz);
}
}
......@@ -167,7 +183,7 @@ class quiz_access_manager {
public static function load_settings($quizid) {
global $DB;
$rules = get_plugin_list_with_class('quizaccess', '', 'rule.php');
$rules = self::get_rule_classes();
list($sql, $params) = self::get_load_sql($quizid, $rules, '');
$data = (array) $DB->get_record_sql($sql, $params);
......@@ -191,7 +207,7 @@ class quiz_access_manager {
public static function load_quiz_and_settings($quizid) {
global $DB;
$rules = get_plugin_list_with_class('quizaccess', '', 'rule.php');
$rules = self::get_rule_classes();
list($sql, $params) = self::get_load_sql($quizid, $rules, 'quiz.*');
$quiz = $DB->get_record_sql($sql, $params, MUST_EXIST);
......@@ -204,6 +220,18 @@ class quiz_access_manager {
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;
}
protected function accumulate_messages(&$messages, $new) {
if (is_array($new)) {
$messages = array_merge($messages, $new);
......
......@@ -49,13 +49,28 @@ abstract class quiz_access_rule_base {
/**
* Create an instance of this rule for a particular quiz.
* @param object $quiz the quiz we will be controlling access to.
* @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.
......@@ -66,6 +81,7 @@ abstract class quiz_access_rule_base {
public function prevent_new_attempt($numprevattempts, $lastattempt) {
return false;
}
/**
* Whether or not a user should be allowed to start a new attempt at this quiz now.
* @return string false if access should be allowed, a message explaining the
......@@ -74,6 +90,7 @@ abstract class quiz_access_rule_base {
public function prevent_access() {
return false;
}
/**
* 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
......@@ -84,6 +101,7 @@ abstract class quiz_access_rule_base {
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
......@@ -137,6 +155,19 @@ abstract class quiz_access_rule_base {
// 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
......@@ -149,6 +180,14 @@ abstract class quiz_access_rule_base {
// By default do nothing.
}
/**
* @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.
......
......@@ -36,6 +36,15 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quizaccess_delaybetweenattempts extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if (empty($quizobj->get_quiz()->delay1) && empty($quizobj->get_quiz()->delay2)) {
return null;
}
$this->rules[] = new self($quizobj, $timenow);
}
public function prevent_new_attempt($numprevattempts, $lastattempt) {
if ($this->quiz->attempts > 0 && $numprevattempts >= $this->quiz->attempts) {
// No more attempts allowed anyway.
......
......@@ -30,12 +30,21 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
/**
* A rule implementing the ipaddress check against the ->submet setting.
* 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
*/
class quizaccess_ipaddress extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if (empty($quizobj->get_quiz()->subnet)) {
return null;
}
return new self($quizobj, $timenow);
}
public function prevent_access() {
if (address_in_subnet(getremoteaddr(), $this->quiz->subnet)) {
return false;
......
......@@ -36,15 +36,27 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quizaccess_numattempts extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if ($quizobj->get_num_attempts_allowed() == 0) {
return null;
}
return new self($quizobj, $timenow);
}
public function description() {
return get_string('attemptsallowedn', 'quiz', $this->quiz->attempts);
}
public function prevent_new_attempt($numprevattempts, $lastattempt) {
if ($numprevattempts >= $this->quiz->attempts) {
return get_string('nomoreattempts', 'quiz');
}
return false;
}
public function is_finished($numprevattempts, $lastattempt) {
return $numprevattempts >= $this->quiz->attempts;
}
......
......@@ -36,6 +36,12 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quizaccess_openclosedate extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
// This rule is always used, even if the quiz has no open or close date.
return new self($quizobj, $timenow);
}
public function description() {
$result = array();
if ($this->timenow < $this->quiz->timeopen) {
......
......@@ -37,6 +37,15 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quizaccess_password extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if (empty($quizobj->get_quiz()->password)) {
return null;
}
return new self($quizobj, $timenow);
}
public function description() {
return get_string('requirepasswordmessage', 'quiz');
}
......
......@@ -36,6 +36,16 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quizaccess_safebrowser extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if ($quizobj->get_quiz()->popup != 2) {
return null;
}
return new self($quizobj, $timenow);
}
public function prevent_access() {
if (!$this->check_safe_browser()) {
return get_string('safebrowsererror', 'quiz');
......@@ -45,7 +55,7 @@ class quizaccess_safebrowser extends quiz_access_rule_base {
}
public function description() {
return get_string("safebrowsernotice", "quiz");
return get_string('safebrowsernotice', 'quiz');
}
public function setup_attempt_page($page) {
......@@ -59,6 +69,20 @@ class quizaccess_safebrowser extends quiz_access_rule_base {
* @return true, if browser is safe browser else false
*/
function check_safe_browser() {
return strpos($_SERVER['HTTP_USER_AGENT'], "SEB") !== false;
return strpos($_SERVER['HTTP_USER_AGENT'], 'SEB') !== false;
}
/**
* @return array key => lang string any choices to add to the quiz Browser
* security settings menu.
*/
public static function get_browser_security_choices() {
global $CFG;
if (empty($CFG->enablesafebrowserintegration)) {
return array();
}
return array(2 => get_string('requiresafeexambrowser', 'quiz'));
}
}
......@@ -52,8 +52,17 @@ class quizaccess_securewindow extends quiz_access_rule_base {
'menubar' => false,
);
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if ($quizobj->get_quiz()->popup != 1) {
return null;
}
return new self($quizobj, $timenow);
}
public function attempt_must_be_in_popup() {
return true;
return !$this->quizobj->is_preview_user();
}
public function get_popup_options() {
......@@ -65,8 +74,21 @@ class quizaccess_securewindow extends quiz_access_rule_base {
$page->set_title($this->quizobj->get_course()->shortname . ': ' . $page->title);
$page->set_cacheable(false);
$page->set_pagelayout('popup');
if ($this->quizobj->is_preview_user()) {
return;
}
$page->add_body_class('quiz-secure-window');
$page->requires->js_init_call('M.mod_quiz.secure_window.init',
null, false, quiz_get_js_module());
}
/**
* @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(1 => get_string('popupwithjavascriptsupport', 'quiz'));
}
}
......@@ -37,6 +37,16 @@ require_once($CFG->dirroot . '/mod/quiz/accessrule/accessrulebase.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quizaccess_timelimit extends quiz_access_rule_base {
public static function make(quiz $quizobj, $timenow, $canignoretimelimits) {
if (empty($quizobj->get_quiz()->timelimit) || $canignoretimelimits) {
return null;
}
return new self($quizobj, $timenow);
}
public function description() {
return get_string('quiztimelimit', 'quiz', format_time($this->quiz->timelimit));
}
......
......@@ -282,13 +282,8 @@ class mod_quiz_mod_form extends moodleform_mod {
$mform->disabledIf('delay2', 'attempts', 'eq', 2);
// 'Secure' window.
$options = array(
0 => get_string('none', 'quiz'),
1 => get_string('popupwithjavascriptsupport', 'quiz'));
if (!empty($CFG->enablesafebrowserintegration)) {
$options[2] = get_string('requiresafeexambrowser', 'quiz');
}
$mform->addElement('select', 'popup', get_string('browsersecurity', 'quiz'), $options);
$mform->addElement('select', 'popup', get_string('browsersecurity', 'quiz'),
quiz_access_manager::get_browser_security_choices());
$mform->addHelpButton('popup', 'browsersecurity', 'quiz');
$mform->setAdvanced('popup', $quizconfig->popup_adv);
$mform->setDefault('popup', $quizconfig->popup);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment