Skip to content

Commit

Permalink
MDL-80945 quiz: Add SEB options to override settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Kotlyar committed Aug 19, 2024
1 parent 8a6e856 commit c6676fe
Show file tree
Hide file tree
Showing 14 changed files with 481 additions and 23 deletions.
111 changes: 96 additions & 15 deletions mod/quiz/accessrule/seb/classes/seb_quiz_settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use lang_string;
use moodle_exception;
use moodle_url;
use mod_quiz\quiz_settings;

defined('MOODLE_INTERNAL') || die();

Expand Down Expand Up @@ -196,11 +197,76 @@ protected static function define_properties(): array {
* @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)) {
return new static(0, $data);
global $USER;
// Skip cache if quiz has overrides for user.
if (!($hasoverrides = quiz_has_user_overrides($quizid))) {
if ($data = self::get_quiz_settings_cache()->get($quizid)) {
return new static(0, $data);
}
}

$sebquizsetting = self::get_record(['quizid' => $quizid]);

// Overwrite settings from override manager if available.
if ($hasoverrides) {
// Create blank seb_quiz_settings instance if none exists.
if (!$sebquizsetting) {
$record = new \stdClass();
$record->quizid = $quizid;
$record->cmid = get_coursemodule_from_instance('quiz', $quizid)->id;
$sebquizsetting = new self(0, $record);
}

$quizsetting = quiz_settings::create_for_cmid($sebquizsetting->get('cmid'), $USER->id)->get_quiz();
// If overriding enabled, overwrite seb settings.
if (isset($quizsetting->enableseboverride) && !!$quizsetting->enableseboverride) {
$prefix = 'seb_';
foreach (array_keys(self::properties_definition()) as $key) {
if (isset($quizsetting->{$prefix.$key})) {
$sebquizsetting->set($key, $quizsetting->{$prefix.$key});
}
}
}
}

return self::get_record(['quizid' => $quizid]);
return $sebquizsetting;
}

/**
* Get override record if there is for the current user.
*
* @return \stdClass|false
*/
protected function get_override() {
global $DB, $USER;
$userid = $USER->id;
$quizid = $this->get('quizid');

$override = false;

if (!($override = $DB->get_record('quiz_overrides', ['quiz' => $quizid, 'userid' => $userid]))) {
$quiz = $DB->get_record('quiz', ['id' => $quizid]);
$groupings = groups_get_user_groups($quiz->course, $userid);

if (!empty($groupings[0])) {
list($extra, $params) = $DB->get_in_or_equal(array_values($groupings[0]));
$sql = "SELECT * FROM {quiz_overrides}
WHERE groupid $extra AND quiz = ?";
$params[] = $quiz->id;
$override = $DB->get_record_sql($sql, $params);
}
}

return $override;
}

/**
* Get overridden sebdata if there is for the current user.
*
* @return array|false
*/
protected function get_override_data() {
return ($override = $this->get_override()) ? unserialize($override->sebdata) : false;
}

/**
Expand All @@ -210,16 +276,20 @@ public static function get_by_quiz_id(int $quizid) {
* @return string|null
*/
public static function get_config_by_quiz_id(int $quizid): ?string {
$config = self::get_config_cache()->get($quizid);

if ($config !== false) {
return $config;
// Skip cache if quiz has overrides for user.
if (!($hasoverrides = quiz_has_user_overrides($quizid))) {
$config = self::get_config_cache()->get($quizid);
if ($config !== false) {
return $config;
}
}

$config = null;
if ($settings = self::get_by_quiz_id($quizid)) {
$config = $settings->get_config();
self::get_config_cache()->set($quizid, $config);
if (!$hasoverrides) {
self::get_config_cache()->set($quizid, $config);
}
}

return $config;
Expand All @@ -232,16 +302,21 @@ public static function get_config_by_quiz_id(int $quizid): ?string {
* @return string|null
*/
public static function get_config_key_by_quiz_id(int $quizid): ?string {
$configkey = self::get_config_key_cache()->get($quizid);
// Skip cache if quiz has overrides for user.
if (!($hasoverrides = quiz_has_user_overrides($quizid))) {
$configkey = self::get_config_key_cache()->get($quizid);

if ($configkey !== false) {
return $configkey;
if ($configkey !== false) {
return $configkey;
}
}

$configkey = null;
if ($settings = self::get_by_quiz_id($quizid)) {
$configkey = $settings->get_config_key();
self::get_config_key_cache()->set($quizid, $configkey);
if (!$hasoverrides) {
self::get_config_key_cache()->set($quizid, $configkey);
}
}

return $configkey;
Expand Down Expand Up @@ -294,9 +369,12 @@ protected function after_update($result) {
* Helper method to execute common stuff after create and update.
*/
private function after_save() {
self::get_quiz_settings_cache()->set($this->get('quizid'), $this->to_record());
self::get_config_cache()->set($this->get('quizid'), $this->config);
self::get_config_key_cache()->set($this->get('quizid'), $this->configkey);
if (!$this->get_override()) {
$key = $this->get('quizid');
self::get_quiz_settings_cache()->set($key, $this->to_record());
self::get_config_cache()->set($key, $this->config);
self::get_config_key_cache()->set($key, $this->configkey);
}
}

/**
Expand Down Expand Up @@ -557,6 +635,7 @@ private function process_bool_setting(string $name) {
*/
private function process_quit_password_settings() {
$settings = $this->to_record();

if (!empty($settings->quitpassword) && is_string($settings->quitpassword)) {
// Hash quit password.
$hashedpassword = hash('SHA256', $settings->quitpassword);
Expand All @@ -571,6 +650,7 @@ private function process_quit_password_settings() {
*/
private function process_quit_url_from_settings() {
$settings = $this->to_record();

if (!empty($settings->linkquitseb) && is_string($settings->linkquitseb)) {
$this->plist->set_or_update_value('quitURL', new CFString($settings->linkquitseb));
}
Expand All @@ -592,6 +672,7 @@ private function process_quit_url_from_template_or_config() {
*/
private function process_url_filters() {
$settings = $this->to_record();

// Create rules to each expression provided and add to config.
$urlfilterrules = [];
// Get all rules separated by newlines and remove empty rules.
Expand Down
38 changes: 34 additions & 4 deletions mod/quiz/accessrule/seb/classes/settings_provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,17 @@ protected static function add_seb_header_element(\mod_quiz_mod_form $quizform, \
* @param \MoodleQuickForm $mform the wrapped MoodleQuickForm.
*/
protected static function add_seb_usage_options(\mod_quiz_mod_form $quizform, \MoodleQuickForm $mform) {
$options = self::get_requiresafeexambrowser_options($quizform->get_context());
$element = $mform->createElement(
'select',
'seb_requiresafeexambrowser',
get_string('seb_requiresafeexambrowser', 'quizaccess_seb'),
self::get_requiresafeexambrowser_options($quizform->get_context())
$options
);

self::insert_element($quizform, $mform, $element);
self::set_type($quizform, $mform, 'seb_requiresafeexambrowser', PARAM_INT);
self::set_default($quizform, $mform, 'seb_requiresafeexambrowser', self::USE_SEB_NO);
self::set_default($quizform, $mform, 'seb_requiresafeexambrowser', array_key_first($options));
self::add_help_button($quizform, $mform, 'seb_requiresafeexambrowser');

if (self::is_conflicting_permissions($quizform->get_context())) {
Expand Down Expand Up @@ -549,6 +550,11 @@ public static function is_conflicting_permissions(\context $context) {
return true;
}

if (!self::can_unrequire($context) &&
$settings->get('requiresafeexambrowser') == self::USE_SEB_NO) {
return true;
}

return false;
}

Expand All @@ -559,7 +565,11 @@ public static function is_conflicting_permissions(\context $context) {
* @return array
*/
public static function get_requiresafeexambrowser_options(\context $context): array {
$options[self::USE_SEB_NO] = get_string('no');
$options = [];

if (self::can_unrequire($context) || self::is_conflicting_permissions($context)) {
$options[self::USE_SEB_NO] = get_string('no');
}

if (self::can_configure_manually($context) || self::is_conflicting_permissions($context)) {
$options[self::USE_SEB_CONFIG_MANUALLY] = get_string('seb_use_manually', 'quizaccess_seb');
Expand All @@ -584,7 +594,7 @@ public static function get_requiresafeexambrowser_options(\context $context): ar
* Returns a list of templates.
* @return array
*/
protected static function get_template_options(): array {
public static function get_template_options(): array {
$templates = [];
$records = template::get_records(['enabled' => 1], 'name');
if ($records) {
Expand Down Expand Up @@ -785,6 +795,26 @@ public static function can_change_seb_allowedbrowserexamkeys(\context $context):
return has_capability('quizaccess/seb:manage_seb_allowedbrowserexamkeys', $context);
}

/**
* Check if the current user can unrequire SEB from quiz.
*
* @param \context $context Context to check access in.
* @return bool
*/
public static function can_unrequire(\context $context): bool {
return has_capability('quizaccess/seb:manage_seb_unrequiresafeexambrowser', $context);
}

/**
* Check if the current user can unrequire SEB from quiz in the override menu.
*
* @param \context $context Context to check access in.
* @return bool
*/
public static function can_override_unrequire(\context $context): bool {
return has_capability('quizaccess/seb:override_seb_unrequiresafeexambrowser', $context);
}

/**
* Check if the current user can config SEB manually.
*
Expand Down
16 changes: 16 additions & 0 deletions mod/quiz/accessrule/seb/db/access.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@
'editingteacher' => CAP_ALLOW
]
],
'quizaccess/seb:manage_seb_unrequiresafeexambrowser' => [
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => [
'manager' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
],
],
'quizaccess/seb:override_seb_unrequiresafeexambrowser' => [
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => [
'manager' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
],
],
'quizaccess/seb:manage_seb_templateid' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
Expand Down
2 changes: 2 additions & 0 deletions mod/quiz/accessrule/seb/lang/en/quizaccess_seb.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
$string['seb:manage_seb_regexallowed'] = 'Change SEB quiz setting: Regex expressions allowed';
$string['seb:manage_seb_regexblocked'] = 'Change SEB quiz setting: Regex expressions blocked';
$string['seb:manage_seb_requiresafeexambrowser'] = 'Change SEB quiz setting: Require Safe Exam Browser';
$string['seb:manage_seb_unrequiresafeexambrowser'] = 'Change SEB quiz setting: Do not require Safe Exam Browser';
$string['seb:override_seb_unrequiresafeexambrowser'] = 'Override SEB quiz setting: Do not require Safe Exam Browser';
$string['seb:manage_seb_showkeyboardlayout'] = 'Change SEB quiz setting: Show keyboard layout';
$string['seb:manage_seb_showreloadbutton'] = 'Change SEB quiz setting: Show reload button';
$string['seb:manage_seb_showsebtaskbar'] = 'Change SEB quiz setting: Show task bar';
Expand Down
9 changes: 9 additions & 0 deletions mod/quiz/accessrule/seb/tests/settings_provider_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,15 @@ public function test_get_requiresafeexambrowser_options($settingcapability): voi

$options = settings_provider::get_requiresafeexambrowser_options($this->context);

$this->assertCount(1, $options);
$this->assertFalse(array_key_exists(settings_provider::USE_SEB_CONFIG_MANUALLY, $options));
$this->assertFalse(array_key_exists(settings_provider::USE_SEB_TEMPLATE, $options));
$this->assertFalse(array_key_exists(settings_provider::USE_SEB_UPLOAD_CONFIG, $options));
$this->assertTrue(array_key_exists(settings_provider::USE_SEB_CLIENT_CONFIG, $options));
$this->assertFalse(array_key_exists(settings_provider::USE_SEB_NO, $options));

assign_capability('quizaccess/seb:manage_seb_unrequiresafeexambrowser', CAP_ALLOW, $this->roleid, $this->context->id);
$options = settings_provider::get_requiresafeexambrowser_options($this->context);
$this->assertCount(2, $options);
$this->assertFalse(array_key_exists(settings_provider::USE_SEB_CONFIG_MANUALLY, $options));
$this->assertFalse(array_key_exists(settings_provider::USE_SEB_TEMPLATE, $options));
Expand Down
2 changes: 1 addition & 1 deletion mod/quiz/accessrule/seb/version.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

defined('MOODLE_INTERNAL') || die();

$plugin->version = 2024042200;
$plugin->version = 2024073101;
$plugin->requires = 2024041600;
$plugin->component = 'quizaccess_seb';
$plugin->maturity = MATURITY_STABLE;
Loading

0 comments on commit c6676fe

Please sign in to comment.