Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Functions and classes used during installation, upgrades and for admin settings. 19 * 20 * ADMIN SETTINGS TREE INTRODUCTION 21 * 22 * This file performs the following tasks: 23 * -it defines the necessary objects and interfaces to build the Moodle 24 * admin hierarchy 25 * -it defines the admin_externalpage_setup() 26 * 27 * ADMIN_SETTING OBJECTS 28 * 29 * Moodle settings are represented by objects that inherit from the admin_setting 30 * class. These objects encapsulate how to read a setting, how to write a new value 31 * to a setting, and how to appropriately display the HTML to modify the setting. 32 * 33 * ADMIN_SETTINGPAGE OBJECTS 34 * 35 * The admin_setting objects are then grouped into admin_settingpages. The latter 36 * appear in the Moodle admin tree block. All interaction with admin_settingpage 37 * objects is handled by the admin/settings.php file. 38 * 39 * ADMIN_EXTERNALPAGE OBJECTS 40 * 41 * There are some settings in Moodle that are too complex to (efficiently) handle 42 * with admin_settingpages. (Consider, for example, user management and displaying 43 * lists of users.) In this case, we use the admin_externalpage object. This object 44 * places a link to an external PHP file in the admin tree block. 45 * 46 * If you're using an admin_externalpage object for some settings, you can take 47 * advantage of the admin_externalpage_* functions. For example, suppose you wanted 48 * to add a foo.php file into admin. First off, you add the following line to 49 * admin/settings/first.php (at the end of the file) or to some other file in 50 * admin/settings: 51 * <code> 52 * $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'), 53 * $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission')); 54 * </code> 55 * 56 * Next, in foo.php, your file structure would resemble the following: 57 * <code> 58 * require(__DIR__.'/../../config.php'); 59 * require_once($CFG->libdir.'/adminlib.php'); 60 * admin_externalpage_setup('foo'); 61 * // functionality like processing form submissions goes here 62 * echo $OUTPUT->header(); 63 * // your HTML goes here 64 * echo $OUTPUT->footer(); 65 * </code> 66 * 67 * The admin_externalpage_setup() function call ensures the user is logged in, 68 * and makes sure that they have the proper role permission to access the page. 69 * It also configures all $PAGE properties needed for navigation. 70 * 71 * ADMIN_CATEGORY OBJECTS 72 * 73 * Above and beyond all this, we have admin_category objects. These objects 74 * appear as folders in the admin tree block. They contain admin_settingpage's, 75 * admin_externalpage's, and other admin_category's. 76 * 77 * OTHER NOTES 78 * 79 * admin_settingpage's, admin_externalpage's, and admin_category's all inherit 80 * from part_of_admin_tree (a pseudointerface). This interface insists that 81 * a class has a check_access method for access permissions, a locate method 82 * used to find a specific node in the admin tree and find parent path. 83 * 84 * admin_category's inherit from parentable_part_of_admin_tree. This pseudo- 85 * interface ensures that the class implements a recursive add function which 86 * accepts a part_of_admin_tree object and searches for the proper place to 87 * put it. parentable_part_of_admin_tree implies part_of_admin_tree. 88 * 89 * Please note that the $this->name field of any part_of_admin_tree must be 90 * UNIQUE throughout the ENTIRE admin tree. 91 * 92 * The $this->name field of an admin_setting object (which is *not* part_of_ 93 * admin_tree) must be unique on the respective admin_settingpage where it is 94 * used. 95 * 96 * Original author: Vincenzo K. Marcovecchio 97 * Maintainer: Petr Skoda 98 * 99 * @package core 100 * @subpackage admin 101 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com 102 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 103 */ 104 105 defined('MOODLE_INTERNAL') || die(); 106 107 /// Add libraries 108 require_once($CFG->libdir.'/ddllib.php'); 109 require_once($CFG->libdir.'/xmlize.php'); 110 require_once($CFG->libdir.'/messagelib.php'); 111 112 define('INSECURE_DATAROOT_WARNING', 1); 113 define('INSECURE_DATAROOT_ERROR', 2); 114 115 /** 116 * Automatically clean-up all plugin data and remove the plugin DB tables 117 * 118 * NOTE: do not call directly, use new /admin/plugins.php?uninstall=component instead! 119 * 120 * @param string $type The plugin type, eg. 'mod', 'qtype', 'workshopgrading' etc. 121 * @param string $name The plugin name, eg. 'forum', 'multichoice', 'accumulative' etc. 122 * @uses global $OUTPUT to produce notices and other messages 123 * @return void 124 */ 125 function uninstall_plugin($type, $name) { 126 global $CFG, $DB, $OUTPUT; 127 128 // This may take a long time. 129 core_php_time_limit::raise(); 130 131 // Recursively uninstall all subplugins first. 132 $subplugintypes = core_component::get_plugin_types_with_subplugins(); 133 if (isset($subplugintypes[$type])) { 134 $base = core_component::get_plugin_directory($type, $name); 135 136 $subpluginsfile = "{$base}/db/subplugins.json"; 137 if (file_exists($subpluginsfile)) { 138 $subplugins = (array) json_decode(file_get_contents($subpluginsfile))->plugintypes; 139 } else if (file_exists("{$base}/db/subplugins.php")) { 140 debugging('Use of subplugins.php has been deprecated. ' . 141 'Please update your plugin to provide a subplugins.json file instead.', 142 DEBUG_DEVELOPER); 143 $subplugins = []; 144 include("{$base}/db/subplugins.php"); 145 } 146 147 if (!empty($subplugins)) { 148 foreach (array_keys($subplugins) as $subplugintype) { 149 $instances = core_component::get_plugin_list($subplugintype); 150 foreach ($instances as $subpluginname => $notusedpluginpath) { 151 uninstall_plugin($subplugintype, $subpluginname); 152 } 153 } 154 } 155 } 156 157 $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum' 158 159 if ($type === 'mod') { 160 $pluginname = $name; // eg. 'forum' 161 if (get_string_manager()->string_exists('modulename', $component)) { 162 $strpluginname = get_string('modulename', $component); 163 } else { 164 $strpluginname = $component; 165 } 166 167 } else { 168 $pluginname = $component; 169 if (get_string_manager()->string_exists('pluginname', $component)) { 170 $strpluginname = get_string('pluginname', $component); 171 } else { 172 $strpluginname = $component; 173 } 174 } 175 176 echo $OUTPUT->heading($pluginname); 177 178 // Delete all tag areas, collections and instances associated with this plugin. 179 core_tag_area::uninstall($component); 180 181 // Custom plugin uninstall. 182 $plugindirectory = core_component::get_plugin_directory($type, $name); 183 $uninstalllib = $plugindirectory . '/db/uninstall.php'; 184 if (file_exists($uninstalllib)) { 185 require_once($uninstalllib); 186 $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()' 187 if (function_exists($uninstallfunction)) { 188 // Do not verify result, let plugin complain if necessary. 189 $uninstallfunction(); 190 } 191 } 192 193 // Specific plugin type cleanup. 194 $plugininfo = core_plugin_manager::instance()->get_plugin_info($component); 195 if ($plugininfo) { 196 $plugininfo->uninstall_cleanup(); 197 core_plugin_manager::reset_caches(); 198 } 199 $plugininfo = null; 200 201 // perform clean-up task common for all the plugin/subplugin types 202 203 //delete the web service functions and pre-built services 204 require_once($CFG->dirroot.'/lib/externallib.php'); 205 external_delete_descriptions($component); 206 207 // delete calendar events 208 $DB->delete_records('event', array('modulename' => $pluginname)); 209 $DB->delete_records('event', ['component' => $component]); 210 211 // Delete scheduled tasks. 212 $DB->delete_records('task_adhoc', ['component' => $component]); 213 $DB->delete_records('task_scheduled', array('component' => $component)); 214 215 // Delete Inbound Message datakeys. 216 $DB->delete_records_select('messageinbound_datakeys', 217 'handler IN (SELECT id FROM {messageinbound_handlers} WHERE component = ?)', array($component)); 218 219 // Delete Inbound Message handlers. 220 $DB->delete_records('messageinbound_handlers', array('component' => $component)); 221 222 // delete all the logs 223 $DB->delete_records('log', array('module' => $pluginname)); 224 225 // delete log_display information 226 $DB->delete_records('log_display', array('component' => $component)); 227 228 // delete the module configuration records 229 unset_all_config_for_plugin($component); 230 if ($type === 'mod') { 231 unset_all_config_for_plugin($pluginname); 232 } 233 234 // delete message provider 235 message_provider_uninstall($component); 236 237 // delete the plugin tables 238 $xmldbfilepath = $plugindirectory . '/db/install.xml'; 239 drop_plugin_tables($component, $xmldbfilepath, false); 240 if ($type === 'mod' or $type === 'block') { 241 // non-frankenstyle table prefixes 242 drop_plugin_tables($name, $xmldbfilepath, false); 243 } 244 245 // delete the capabilities that were defined by this module 246 capabilities_cleanup($component); 247 248 // Delete all remaining files in the filepool owned by the component. 249 $fs = get_file_storage(); 250 $fs->delete_component_files($component); 251 252 // Finally purge all caches. 253 purge_all_caches(); 254 255 // Invalidate the hash used for upgrade detections. 256 set_config('allversionshash', ''); 257 258 echo $OUTPUT->notification(get_string('success'), 'notifysuccess'); 259 } 260 261 /** 262 * Returns the version of installed component 263 * 264 * @param string $component component name 265 * @param string $source either 'disk' or 'installed' - where to get the version information from 266 * @return string|bool version number or false if the component is not found 267 */ 268 function get_component_version($component, $source='installed') { 269 global $CFG, $DB; 270 271 list($type, $name) = core_component::normalize_component($component); 272 273 // moodle core or a core subsystem 274 if ($type === 'core') { 275 if ($source === 'installed') { 276 if (empty($CFG->version)) { 277 return false; 278 } else { 279 return $CFG->version; 280 } 281 } else { 282 if (!is_readable($CFG->dirroot.'/version.php')) { 283 return false; 284 } else { 285 $version = null; //initialize variable for IDEs 286 include($CFG->dirroot.'/version.php'); 287 return $version; 288 } 289 } 290 } 291 292 // activity module 293 if ($type === 'mod') { 294 if ($source === 'installed') { 295 if ($CFG->version < 2013092001.02) { 296 return $DB->get_field('modules', 'version', array('name'=>$name)); 297 } else { 298 return get_config('mod_'.$name, 'version'); 299 } 300 301 } else { 302 $mods = core_component::get_plugin_list('mod'); 303 if (empty($mods[$name]) or !is_readable($mods[$name].'/version.php')) { 304 return false; 305 } else { 306 $plugin = new stdClass(); 307 $plugin->version = null; 308 $module = $plugin; 309 include($mods[$name].'/version.php'); 310 return $plugin->version; 311 } 312 } 313 } 314 315 // block 316 if ($type === 'block') { 317 if ($source === 'installed') { 318 if ($CFG->version < 2013092001.02) { 319 return $DB->get_field('block', 'version', array('name'=>$name)); 320 } else { 321 return get_config('block_'.$name, 'version'); 322 } 323 } else { 324 $blocks = core_component::get_plugin_list('block'); 325 if (empty($blocks[$name]) or !is_readable($blocks[$name].'/version.php')) { 326 return false; 327 } else { 328 $plugin = new stdclass(); 329 include($blocks[$name].'/version.php'); 330 return $plugin->version; 331 } 332 } 333 } 334 335 // all other plugin types 336 if ($source === 'installed') { 337 return get_config($type.'_'.$name, 'version'); 338 } else { 339 $plugins = core_component::get_plugin_list($type); 340 if (empty($plugins[$name])) { 341 return false; 342 } else { 343 $plugin = new stdclass(); 344 include($plugins[$name].'/version.php'); 345 return $plugin->version; 346 } 347 } 348 } 349 350 /** 351 * Delete all plugin tables 352 * 353 * @param string $name Name of plugin, used as table prefix 354 * @param string $file Path to install.xml file 355 * @param bool $feedback defaults to true 356 * @return bool Always returns true 357 */ 358 function drop_plugin_tables($name, $file, $feedback=true) { 359 global $CFG, $DB; 360 361 // first try normal delete 362 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) { 363 return true; 364 } 365 366 // then try to find all tables that start with name and are not in any xml file 367 $used_tables = get_used_table_names(); 368 369 $tables = $DB->get_tables(); 370 371 /// Iterate over, fixing id fields as necessary 372 foreach ($tables as $table) { 373 if (in_array($table, $used_tables)) { 374 continue; 375 } 376 377 if (strpos($table, $name) !== 0) { 378 continue; 379 } 380 381 // found orphan table --> delete it 382 if ($DB->get_manager()->table_exists($table)) { 383 $xmldb_table = new xmldb_table($table); 384 $DB->get_manager()->drop_table($xmldb_table); 385 } 386 } 387 388 return true; 389 } 390 391 /** 392 * Returns names of all known tables == tables that moodle knows about. 393 * 394 * @return array Array of lowercase table names 395 */ 396 function get_used_table_names() { 397 $table_names = array(); 398 $dbdirs = get_db_directories(); 399 400 foreach ($dbdirs as $dbdir) { 401 $file = $dbdir.'/install.xml'; 402 403 $xmldb_file = new xmldb_file($file); 404 405 if (!$xmldb_file->fileExists()) { 406 continue; 407 } 408 409 $loaded = $xmldb_file->loadXMLStructure(); 410 $structure = $xmldb_file->getStructure(); 411 412 if ($loaded and $tables = $structure->getTables()) { 413 foreach($tables as $table) { 414 $table_names[] = strtolower($table->getName()); 415 } 416 } 417 } 418 419 return $table_names; 420 } 421 422 /** 423 * Returns list of all directories where we expect install.xml files 424 * @return array Array of paths 425 */ 426 function get_db_directories() { 427 global $CFG; 428 429 $dbdirs = array(); 430 431 /// First, the main one (lib/db) 432 $dbdirs[] = $CFG->libdir.'/db'; 433 434 /// Then, all the ones defined by core_component::get_plugin_types() 435 $plugintypes = core_component::get_plugin_types(); 436 foreach ($plugintypes as $plugintype => $pluginbasedir) { 437 if ($plugins = core_component::get_plugin_list($plugintype)) { 438 foreach ($plugins as $plugin => $plugindir) { 439 $dbdirs[] = $plugindir.'/db'; 440 } 441 } 442 } 443 444 return $dbdirs; 445 } 446 447 /** 448 * Try to obtain or release the cron lock. 449 * @param string $name name of lock 450 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionally 451 * @param bool $ignorecurrent ignore current lock state, usually extend previous lock, defaults to false 452 * @return bool true if lock obtained 453 */ 454 function set_cron_lock($name, $until, $ignorecurrent=false) { 455 global $DB; 456 if (empty($name)) { 457 debugging("Tried to get a cron lock for a null fieldname"); 458 return false; 459 } 460 461 // remove lock by force == remove from config table 462 if (is_null($until)) { 463 set_config($name, null); 464 return true; 465 } 466 467 if (!$ignorecurrent) { 468 // read value from db - other processes might have changed it 469 $value = $DB->get_field('config', 'value', array('name'=>$name)); 470 471 if ($value and $value > time()) { 472 //lock active 473 return false; 474 } 475 } 476 477 set_config($name, $until); 478 return true; 479 } 480 481 /** 482 * Test if and critical warnings are present 483 * @return bool 484 */ 485 function admin_critical_warnings_present() { 486 global $SESSION; 487 488 if (!has_capability('moodle/site:config', context_system::instance())) { 489 return 0; 490 } 491 492 if (!isset($SESSION->admin_critical_warning)) { 493 $SESSION->admin_critical_warning = 0; 494 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) { 495 $SESSION->admin_critical_warning = 1; 496 } 497 } 498 499 return $SESSION->admin_critical_warning; 500 } 501 502 /** 503 * Detects if float supports at least 10 decimal digits 504 * 505 * Detects if float supports at least 10 decimal digits 506 * and also if float-->string conversion works as expected. 507 * 508 * @return bool true if problem found 509 */ 510 function is_float_problem() { 511 $num1 = 2009010200.01; 512 $num2 = 2009010200.02; 513 514 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1); 515 } 516 517 /** 518 * Try to verify that dataroot is not accessible from web. 519 * 520 * Try to verify that dataroot is not accessible from web. 521 * It is not 100% correct but might help to reduce number of vulnerable sites. 522 * Protection from httpd.conf and .htaccess is not detected properly. 523 * 524 * @uses INSECURE_DATAROOT_WARNING 525 * @uses INSECURE_DATAROOT_ERROR 526 * @param bool $fetchtest try to test public access by fetching file, default false 527 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING might be problematic 528 */ 529 function is_dataroot_insecure($fetchtest=false) { 530 global $CFG; 531 532 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround 533 534 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1); 535 $rp = strrev(trim($rp, '/')); 536 $rp = explode('/', $rp); 537 foreach($rp as $r) { 538 if (strpos($siteroot, '/'.$r.'/') === 0) { 539 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory 540 } else { 541 break; // probably alias root 542 } 543 } 544 545 $siteroot = strrev($siteroot); 546 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/'); 547 548 if (strpos($dataroot, $siteroot) !== 0) { 549 return false; 550 } 551 552 if (!$fetchtest) { 553 return INSECURE_DATAROOT_WARNING; 554 } 555 556 // now try all methods to fetch a test file using http protocol 557 558 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); 559 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches); 560 $httpdocroot = $matches[1]; 561 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot)); 562 make_upload_directory('diag'); 563 $testfile = $CFG->dataroot.'/diag/public.txt'; 564 if (!file_exists($testfile)) { 565 file_put_contents($testfile, 'test file, do not delete'); 566 @chmod($testfile, $CFG->filepermissions); 567 } 568 $teststr = trim(file_get_contents($testfile)); 569 if (empty($teststr)) { 570 // hmm, strange 571 return INSECURE_DATAROOT_WARNING; 572 } 573 574 $testurl = $datarooturl.'/diag/public.txt'; 575 if (extension_loaded('curl') and 576 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and 577 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and 578 ($ch = @curl_init($testurl)) !== false) { 579 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 580 curl_setopt($ch, CURLOPT_HEADER, false); 581 $data = curl_exec($ch); 582 if (!curl_errno($ch)) { 583 $data = trim($data); 584 if ($data === $teststr) { 585 curl_close($ch); 586 return INSECURE_DATAROOT_ERROR; 587 } 588 } 589 curl_close($ch); 590 } 591 592 if ($data = @file_get_contents($testurl)) { 593 $data = trim($data); 594 if ($data === $teststr) { 595 return INSECURE_DATAROOT_ERROR; 596 } 597 } 598 599 preg_match('|https?://([^/]+)|i', $testurl, $matches); 600 $sitename = $matches[1]; 601 $error = 0; 602 if ($fp = @fsockopen($sitename, 80, $error)) { 603 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches); 604 $localurl = $matches[1]; 605 $out = "GET $localurl HTTP/1.1\r\n"; 606 $out .= "Host: $sitename\r\n"; 607 $out .= "Connection: Close\r\n\r\n"; 608 fwrite($fp, $out); 609 $data = ''; 610 $incoming = false; 611 while (!feof($fp)) { 612 if ($incoming) { 613 $data .= fgets($fp, 1024); 614 } else if (@fgets($fp, 1024) === "\r\n") { 615 $incoming = true; 616 } 617 } 618 fclose($fp); 619 $data = trim($data); 620 if ($data === $teststr) { 621 return INSECURE_DATAROOT_ERROR; 622 } 623 } 624 625 return INSECURE_DATAROOT_WARNING; 626 } 627 628 /** 629 * Enables CLI maintenance mode by creating new dataroot/climaintenance.html file. 630 */ 631 function enable_cli_maintenance_mode() { 632 global $CFG, $SITE; 633 634 if (file_exists("$CFG->dataroot/climaintenance.html")) { 635 unlink("$CFG->dataroot/climaintenance.html"); 636 } 637 638 if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) { 639 $data = $CFG->maintenance_message; 640 $data = bootstrap_renderer::early_error_content($data, null, null, null); 641 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data); 642 643 } else if (file_exists("$CFG->dataroot/climaintenance.template.html")) { 644 $data = file_get_contents("$CFG->dataroot/climaintenance.template.html"); 645 646 } else { 647 $data = get_string('sitemaintenance', 'admin'); 648 $data = bootstrap_renderer::early_error_content($data, null, null, null); 649 $data = bootstrap_renderer::plain_page(get_string('sitemaintenancetitle', 'admin', 650 format_string($SITE->fullname, true, ['context' => context_system::instance()])), $data); 651 } 652 653 file_put_contents("$CFG->dataroot/climaintenance.html", $data); 654 chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions); 655 } 656 657 /// CLASS DEFINITIONS ///////////////////////////////////////////////////////// 658 659 660 /** 661 * Interface for anything appearing in the admin tree 662 * 663 * The interface that is implemented by anything that appears in the admin tree 664 * block. It forces inheriting classes to define a method for checking user permissions 665 * and methods for finding something in the admin tree. 666 * 667 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 668 */ 669 interface part_of_admin_tree { 670 671 /** 672 * Finds a named part_of_admin_tree. 673 * 674 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree 675 * and not parentable_part_of_admin_tree, then this function should only check if 676 * $this->name matches $name. If it does, it should return a reference to $this, 677 * otherwise, it should return a reference to NULL. 678 * 679 * If a class inherits parentable_part_of_admin_tree, this method should be called 680 * recursively on all child objects (assuming, of course, the parent object's name 681 * doesn't match the search criterion). 682 * 683 * @param string $name The internal name of the part_of_admin_tree we're searching for. 684 * @return mixed An object reference or a NULL reference. 685 */ 686 public function locate($name); 687 688 /** 689 * Removes named part_of_admin_tree. 690 * 691 * @param string $name The internal name of the part_of_admin_tree we want to remove. 692 * @return bool success. 693 */ 694 public function prune($name); 695 696 /** 697 * Search using query 698 * @param string $query 699 * @return mixed array-object structure of found settings and pages 700 */ 701 public function search($query); 702 703 /** 704 * Verifies current user's access to this part_of_admin_tree. 705 * 706 * Used to check if the current user has access to this part of the admin tree or 707 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree, 708 * then this method is usually just a call to has_capability() in the site context. 709 * 710 * If a class inherits parentable_part_of_admin_tree, this method should return the 711 * logical OR of the return of check_access() on all child objects. 712 * 713 * @return bool True if the user has access, false if she doesn't. 714 */ 715 public function check_access(); 716 717 /** 718 * Mostly useful for removing of some parts of the tree in admin tree block. 719 * 720 * @return True is hidden from normal list view 721 */ 722 public function is_hidden(); 723 724 /** 725 * Show we display Save button at the page bottom? 726 * @return bool 727 */ 728 public function show_save(); 729 } 730 731 732 /** 733 * Interface implemented by any part_of_admin_tree that has children. 734 * 735 * The interface implemented by any part_of_admin_tree that can be a parent 736 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart 737 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods 738 * include an add method for adding other part_of_admin_tree objects as children. 739 * 740 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 741 */ 742 interface parentable_part_of_admin_tree extends part_of_admin_tree { 743 744 /** 745 * Adds a part_of_admin_tree object to the admin tree. 746 * 747 * Used to add a part_of_admin_tree object to this object or a child of this 748 * object. $something should only be added if $destinationname matches 749 * $this->name. If it doesn't, add should be called on child objects that are 750 * also parentable_part_of_admin_tree's. 751 * 752 * $something should be appended as the last child in the $destinationname. If the 753 * $beforesibling is specified, $something should be prepended to it. If the given 754 * sibling is not found, $something should be appended to the end of $destinationname 755 * and a developer debugging message should be displayed. 756 * 757 * @param string $destinationname The internal name of the new parent for $something. 758 * @param part_of_admin_tree $something The object to be added. 759 * @return bool True on success, false on failure. 760 */ 761 public function add($destinationname, $something, $beforesibling = null); 762 763 } 764 765 766 /** 767 * The object used to represent folders (a.k.a. categories) in the admin tree block. 768 * 769 * Each admin_category object contains a number of part_of_admin_tree objects. 770 * 771 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 772 */ 773 class admin_category implements parentable_part_of_admin_tree { 774 775 /** @var part_of_admin_tree[] An array of part_of_admin_tree objects that are this object's children */ 776 protected $children; 777 /** @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */ 778 public $name; 779 /** @var string The displayed name for this category. Usually obtained through get_string() */ 780 public $visiblename; 781 /** @var bool Should this category be hidden in admin tree block? */ 782 public $hidden; 783 /** @var mixed Either a string or an array or strings */ 784 public $path; 785 /** @var mixed Either a string or an array or strings */ 786 public $visiblepath; 787 788 /** @var array fast lookup category cache, all categories of one tree point to one cache */ 789 protected $category_cache; 790 791 /** @var bool If set to true children will be sorted when calling {@link admin_category::get_children()} */ 792 protected $sort = false; 793 /** @var bool If set to true children will be sorted in ascending order. */ 794 protected $sortasc = true; 795 /** @var bool If set to true sub categories and pages will be split and then sorted.. */ 796 protected $sortsplit = true; 797 /** @var bool $sorted True if the children have been sorted and don't need resorting */ 798 protected $sorted = false; 799 800 /** 801 * Constructor for an empty admin category 802 * 803 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects 804 * @param string $visiblename The displayed named for this category. Usually obtained through get_string() 805 * @param bool $hidden hide category in admin tree block, defaults to false 806 */ 807 public function __construct($name, $visiblename, $hidden=false) { 808 $this->children = array(); 809 $this->name = $name; 810 $this->visiblename = $visiblename; 811 $this->hidden = $hidden; 812 } 813 814 /** 815 * Get the URL to view this page. 816 * 817 * @return moodle_url 818 */ 819 public function get_settings_page_url(): moodle_url { 820 return new moodle_url( 821 '/admin/category.php', 822 [ 823 'category' => $this->name, 824 ] 825 ); 826 } 827 828 /** 829 * Returns a reference to the part_of_admin_tree object with internal name $name. 830 * 831 * @param string $name The internal name of the object we want. 832 * @param bool $findpath initialize path and visiblepath arrays 833 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL. 834 * defaults to false 835 */ 836 public function locate($name, $findpath=false) { 837 if (!isset($this->category_cache[$this->name])) { 838 // somebody much have purged the cache 839 $this->category_cache[$this->name] = $this; 840 } 841 842 if ($this->name == $name) { 843 if ($findpath) { 844 $this->visiblepath[] = $this->visiblename; 845 $this->path[] = $this->name; 846 } 847 return $this; 848 } 849 850 // quick category lookup 851 if (!$findpath and isset($this->category_cache[$name])) { 852 return $this->category_cache[$name]; 853 } 854 855 $return = NULL; 856 foreach($this->children as $childid=>$unused) { 857 if ($return = $this->children[$childid]->locate($name, $findpath)) { 858 break; 859 } 860 } 861 862 if (!is_null($return) and $findpath) { 863 $return->visiblepath[] = $this->visiblename; 864 $return->path[] = $this->name; 865 } 866 867 return $return; 868 } 869 870 /** 871 * Search using query 872 * 873 * @param string query 874 * @return mixed array-object structure of found settings and pages 875 */ 876 public function search($query) { 877 $result = array(); 878 foreach ($this->get_children() as $child) { 879 $subsearch = $child->search($query); 880 if (!is_array($subsearch)) { 881 debugging('Incorrect search result from '.$child->name); 882 continue; 883 } 884 $result = array_merge($result, $subsearch); 885 } 886 return $result; 887 } 888 889 /** 890 * Removes part_of_admin_tree object with internal name $name. 891 * 892 * @param string $name The internal name of the object we want to remove. 893 * @return bool success 894 */ 895 public function prune($name) { 896 897 if ($this->name == $name) { 898 return false; //can not remove itself 899 } 900 901 foreach($this->children as $precedence => $child) { 902 if ($child->name == $name) { 903 // clear cache and delete self 904 while($this->category_cache) { 905 // delete the cache, but keep the original array address 906 array_pop($this->category_cache); 907 } 908 unset($this->children[$precedence]); 909 return true; 910 } else if ($this->children[$precedence]->prune($name)) { 911 return true; 912 } 913 } 914 return false; 915 } 916 917 /** 918 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object. 919 * 920 * By default the new part of the tree is appended as the last child of the parent. You 921 * can specify a sibling node that the new part should be prepended to. If the given 922 * sibling is not found, the part is appended to the end (as it would be by default) and 923 * a developer debugging message is displayed. 924 * 925 * @throws coding_exception if the $beforesibling is empty string or is not string at all. 926 * @param string $destinationame The internal name of the immediate parent that we want for $something. 927 * @param mixed $something A part_of_admin_tree or setting instance to be added. 928 * @param string $beforesibling The name of the parent's child the $something should be prepended to. 929 * @return bool True if successfully added, false if $something can not be added. 930 */ 931 public function add($parentname, $something, $beforesibling = null) { 932 global $CFG; 933 934 $parent = $this->locate($parentname); 935 if (is_null($parent)) { 936 debugging('parent does not exist!'); 937 return false; 938 } 939 940 if ($something instanceof part_of_admin_tree) { 941 if (!($parent instanceof parentable_part_of_admin_tree)) { 942 debugging('error - parts of tree can be inserted only into parentable parts'); 943 return false; 944 } 945 if ($CFG->debugdeveloper && !is_null($this->locate($something->name))) { 946 // The name of the node is already used, simply warn the developer that this should not happen. 947 // It is intentional to check for the debug level before performing the check. 948 debugging('Duplicate admin page name: ' . $something->name, DEBUG_DEVELOPER); 949 } 950 if (is_null($beforesibling)) { 951 // Append $something as the parent's last child. 952 $parent->children[] = $something; 953 } else { 954 if (!is_string($beforesibling) or trim($beforesibling) === '') { 955 throw new coding_exception('Unexpected value of the beforesibling parameter'); 956 } 957 // Try to find the position of the sibling. 958 $siblingposition = null; 959 foreach ($parent->children as $childposition => $child) { 960 if ($child->name === $beforesibling) { 961 $siblingposition = $childposition; 962 break; 963 } 964 } 965 if (is_null($siblingposition)) { 966 debugging('Sibling '.$beforesibling.' not found', DEBUG_DEVELOPER); 967 $parent->children[] = $something; 968 } else { 969 $parent->children = array_merge( 970 array_slice($parent->children, 0, $siblingposition), 971 array($something), 972 array_slice($parent->children, $siblingposition) 973 ); 974 } 975 } 976 if ($something instanceof admin_category) { 977 if (isset($this->category_cache[$something->name])) { 978 debugging('Duplicate admin category name: '.$something->name); 979 } else { 980 $this->category_cache[$something->name] = $something; 981 $something->category_cache =& $this->category_cache; 982 foreach ($something->children as $child) { 983 // just in case somebody already added subcategories 984 if ($child instanceof admin_category) { 985 if (isset($this->category_cache[$child->name])) { 986 debugging('Duplicate admin category name: '.$child->name); 987 } else { 988 $this->category_cache[$child->name] = $child; 989 $child->category_cache =& $this->category_cache; 990 } 991 } 992 } 993 } 994 } 995 return true; 996 997 } else { 998 debugging('error - can not add this element'); 999 return false; 1000 } 1001 1002 } 1003 1004 /** 1005 * Checks if the user has access to anything in this category. 1006 * 1007 * @return bool True if the user has access to at least one child in this category, false otherwise. 1008 */ 1009 public function check_access() { 1010 foreach ($this->children as $child) { 1011 if ($child->check_access()) { 1012 return true; 1013 } 1014 } 1015 return false; 1016 } 1017 1018 /** 1019 * Is this category hidden in admin tree block? 1020 * 1021 * @return bool True if hidden 1022 */ 1023 public function is_hidden() { 1024 return $this->hidden; 1025 } 1026 1027 /** 1028 * Show we display Save button at the page bottom? 1029 * @return bool 1030 */ 1031 public function show_save() { 1032 foreach ($this->children as $child) { 1033 if ($child->show_save()) { 1034 return true; 1035 } 1036 } 1037 return false; 1038 } 1039 1040 /** 1041 * Sets sorting on this category. 1042 * 1043 * Please note this function doesn't actually do the sorting. 1044 * It can be called anytime. 1045 * Sorting occurs when the user calls get_children. 1046 * Code using the children array directly won't see the sorted results. 1047 * 1048 * @param bool $sort If set to true children will be sorted, if false they won't be. 1049 * @param bool $asc If true sorting will be ascending, otherwise descending. 1050 * @param bool $split If true we sort pages and sub categories separately. 1051 */ 1052 public function set_sorting($sort, $asc = true, $split = true) { 1053 $this->sort = (bool)$sort; 1054 $this->sortasc = (bool)$asc; 1055 $this->sortsplit = (bool)$split; 1056 } 1057 1058 /** 1059 * Returns the children associated with this category. 1060 * 1061 * @return part_of_admin_tree[] 1062 */ 1063 public function get_children() { 1064 // If we should sort and it hasn't already been sorted. 1065 if ($this->sort && !$this->sorted) { 1066 if ($this->sortsplit) { 1067 $categories = array(); 1068 $pages = array(); 1069 foreach ($this->children as $child) { 1070 if ($child instanceof admin_category) { 1071 $categories[] = $child; 1072 } else { 1073 $pages[] = $child; 1074 } 1075 } 1076 core_collator::asort_objects_by_property($categories, 'visiblename'); 1077 core_collator::asort_objects_by_property($pages, 'visiblename'); 1078 if (!$this->sortasc) { 1079 $categories = array_reverse($categories); 1080 $pages = array_reverse($pages); 1081 } 1082 $this->children = array_merge($pages, $categories); 1083 } else { 1084 core_collator::asort_objects_by_property($this->children, 'visiblename'); 1085 if (!$this->sortasc) { 1086 $this->children = array_reverse($this->children); 1087 } 1088 } 1089 $this->sorted = true; 1090 } 1091 return $this->children; 1092 } 1093 1094 /** 1095 * Magically gets a property from this object. 1096 * 1097 * @param $property 1098 * @return part_of_admin_tree[] 1099 * @throws coding_exception 1100 */ 1101 public function __get($property) { 1102 if ($property === 'children') { 1103 return $this->get_children(); 1104 } 1105 throw new coding_exception('Invalid property requested.'); 1106 } 1107 1108 /** 1109 * Magically sets a property against this object. 1110 * 1111 * @param string $property 1112 * @param mixed $value 1113 * @throws coding_exception 1114 */ 1115 public function __set($property, $value) { 1116 if ($property === 'children') { 1117 $this->sorted = false; 1118 $this->children = $value; 1119 } else { 1120 throw new coding_exception('Invalid property requested.'); 1121 } 1122 } 1123 1124 /** 1125 * Checks if an inaccessible property is set. 1126 * 1127 * @param string $property 1128 * @return bool 1129 * @throws coding_exception 1130 */ 1131 public function __isset($property) { 1132 if ($property === 'children') { 1133 return isset($this->children); 1134 } 1135 throw new coding_exception('Invalid property requested.'); 1136 } 1137 } 1138 1139 1140 /** 1141 * Root of admin settings tree, does not have any parent. 1142 * 1143 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1144 */ 1145 class admin_root extends admin_category { 1146 /** @var array List of errors */ 1147 public $errors; 1148 /** @var string search query */ 1149 public $search; 1150 /** @var bool full tree flag - true means all settings required, false only pages required */ 1151 public $fulltree; 1152 /** @var bool flag indicating loaded tree */ 1153 public $loaded; 1154 /** @var mixed site custom defaults overriding defaults in settings files*/ 1155 public $custom_defaults; 1156 1157 /** 1158 * @param bool $fulltree true means all settings required, 1159 * false only pages required 1160 */ 1161 public function __construct($fulltree) { 1162 global $CFG; 1163 1164 parent::__construct('root', get_string('administration'), false); 1165 $this->errors = array(); 1166 $this->search = ''; 1167 $this->fulltree = $fulltree; 1168 $this->loaded = false; 1169 1170 $this->category_cache = array(); 1171 1172 // load custom defaults if found 1173 $this->custom_defaults = null; 1174 $defaultsfile = "$CFG->dirroot/local/defaults.php"; 1175 if (is_readable($defaultsfile)) { 1176 $defaults = array(); 1177 include($defaultsfile); 1178 if (is_array($defaults) and count($defaults)) { 1179 $this->custom_defaults = $defaults; 1180 } 1181 } 1182 } 1183 1184 /** 1185 * Empties children array, and sets loaded to false 1186 * 1187 * @param bool $requirefulltree 1188 */ 1189 public function purge_children($requirefulltree) { 1190 $this->children = array(); 1191 $this->fulltree = ($requirefulltree || $this->fulltree); 1192 $this->loaded = false; 1193 //break circular dependencies - this helps PHP 5.2 1194 while($this->category_cache) { 1195 array_pop($this->category_cache); 1196 } 1197 $this->category_cache = array(); 1198 } 1199 } 1200 1201 1202 /** 1203 * Links external PHP pages into the admin tree. 1204 * 1205 * See detailed usage example at the top of this document (adminlib.php) 1206 * 1207 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1208 */ 1209 class admin_externalpage implements part_of_admin_tree { 1210 1211 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */ 1212 public $name; 1213 1214 /** @var string The displayed name for this external page. Usually obtained through get_string(). */ 1215 public $visiblename; 1216 1217 /** @var string The external URL that we should link to when someone requests this external page. */ 1218 public $url; 1219 1220 /** @var array The role capability/permission a user must have to access this external page. */ 1221 public $req_capability; 1222 1223 /** @var object The context in which capability/permission should be checked, default is site context. */ 1224 public $context; 1225 1226 /** @var bool hidden in admin tree block. */ 1227 public $hidden; 1228 1229 /** @var mixed either string or array of string */ 1230 public $path; 1231 1232 /** @var array list of visible names of page parents */ 1233 public $visiblepath; 1234 1235 /** 1236 * Constructor for adding an external page into the admin tree. 1237 * 1238 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects. 1239 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string(). 1240 * @param string $url The external URL that we should link to when someone requests this external page. 1241 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'. 1242 * @param boolean $hidden Is this external page hidden in admin tree block? Default false. 1243 * @param stdClass $context The context the page relates to. Not sure what happens 1244 * if you specify something other than system or front page. Defaults to system. 1245 */ 1246 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) { 1247 $this->name = $name; 1248 $this->visiblename = $visiblename; 1249 $this->url = $url; 1250 if (is_array($req_capability)) { 1251 $this->req_capability = $req_capability; 1252 } else { 1253 $this->req_capability = array($req_capability); 1254 } 1255 $this->hidden = $hidden; 1256 $this->context = $context; 1257 } 1258 1259 /** 1260 * Returns a reference to the part_of_admin_tree object with internal name $name. 1261 * 1262 * @param string $name The internal name of the object we want. 1263 * @param bool $findpath defaults to false 1264 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL. 1265 */ 1266 public function locate($name, $findpath=false) { 1267 if ($this->name == $name) { 1268 if ($findpath) { 1269 $this->visiblepath = array($this->visiblename); 1270 $this->path = array($this->name); 1271 } 1272 return $this; 1273 } else { 1274 $return = NULL; 1275 return $return; 1276 } 1277 } 1278 1279 /** 1280 * This function always returns false, required function by interface 1281 * 1282 * @param string $name 1283 * @return false 1284 */ 1285 public function prune($name) { 1286 return false; 1287 } 1288 1289 /** 1290 * Search using query 1291 * 1292 * @param string $query 1293 * @return mixed array-object structure of found settings and pages 1294 */ 1295 public function search($query) { 1296 $found = false; 1297 if (strpos(strtolower($this->name), $query) !== false) { 1298 $found = true; 1299 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) { 1300 $found = true; 1301 } 1302 if ($found) { 1303 $result = new stdClass(); 1304 $result->page = $this; 1305 $result->settings = array(); 1306 return array($this->name => $result); 1307 } else { 1308 return array(); 1309 } 1310 } 1311 1312 /** 1313 * Determines if the current user has access to this external page based on $this->req_capability. 1314 * 1315 * @return bool True if user has access, false otherwise. 1316 */ 1317 public function check_access() { 1318 global $CFG; 1319 $context = empty($this->context) ? context_system::instance() : $this->context; 1320 foreach($this->req_capability as $cap) { 1321 if (has_capability($cap, $context)) { 1322 return true; 1323 } 1324 } 1325 return false; 1326 } 1327 1328 /** 1329 * Is this external page hidden in admin tree block? 1330 * 1331 * @return bool True if hidden 1332 */ 1333 public function is_hidden() { 1334 return $this->hidden; 1335 } 1336 1337 /** 1338 * Show we display Save button at the page bottom? 1339 * @return bool 1340 */ 1341 public function show_save() { 1342 return false; 1343 } 1344 } 1345 1346 /** 1347 * Used to store details of the dependency between two settings elements. 1348 * 1349 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1350 * @copyright 2017 Davo Smith, Synergy Learning 1351 */ 1352 class admin_settingdependency { 1353 /** @var string the name of the setting to be shown/hidden */ 1354 public $settingname; 1355 /** @var string the setting this is dependent on */ 1356 public $dependenton; 1357 /** @var string the condition to show/hide the element */ 1358 public $condition; 1359 /** @var string the value to compare against */ 1360 public $value; 1361 1362 /** @var string[] list of valid conditions */ 1363 private static $validconditions = ['checked', 'notchecked', 'noitemselected', 'eq', 'neq', 'in']; 1364 1365 /** 1366 * admin_settingdependency constructor. 1367 * @param string $settingname 1368 * @param string $dependenton 1369 * @param string $condition 1370 * @param string $value 1371 * @throws \coding_exception 1372 */ 1373 public function __construct($settingname, $dependenton, $condition, $value) { 1374 $this->settingname = $this->parse_name($settingname); 1375 $this->dependenton = $this->parse_name($dependenton); 1376 $this->condition = $condition; 1377 $this->value = $value; 1378 1379 if (!in_array($this->condition, self::$validconditions)) { 1380 throw new coding_exception("Invalid condition '$condition'"); 1381 } 1382 } 1383 1384 /** 1385 * Convert the setting name into the form field name. 1386 * @param string $name 1387 * @return string 1388 */ 1389 private function parse_name($name) { 1390 $bits = explode('/', $name); 1391 $name = array_pop($bits); 1392 $plugin = ''; 1393 if ($bits) { 1394 $plugin = array_pop($bits); 1395 if ($plugin === 'moodle') { 1396 $plugin = ''; 1397 } 1398 } 1399 return 's_'.$plugin.'_'.$name; 1400 } 1401 1402 /** 1403 * Gather together all the dependencies in a format suitable for initialising javascript 1404 * @param admin_settingdependency[] $dependencies 1405 * @return array 1406 */ 1407 public static function prepare_for_javascript($dependencies) { 1408 $result = []; 1409 foreach ($dependencies as $d) { 1410 if (!isset($result[$d->dependenton])) { 1411 $result[$d->dependenton] = []; 1412 } 1413 if (!isset($result[$d->dependenton][$d->condition])) { 1414 $result[$d->dependenton][$d->condition] = []; 1415 } 1416 if (!isset($result[$d->dependenton][$d->condition][$d->value])) { 1417 $result[$d->dependenton][$d->condition][$d->value] = []; 1418 } 1419 $result[$d->dependenton][$d->condition][$d->value][] = $d->settingname; 1420 } 1421 return $result; 1422 } 1423 } 1424 1425 /** 1426 * Used to group a number of admin_setting objects into a page and add them to the admin tree. 1427 * 1428 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1429 */ 1430 class admin_settingpage implements part_of_admin_tree { 1431 1432 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */ 1433 public $name; 1434 1435 /** @var string The displayed name for this external page. Usually obtained through get_string(). */ 1436 public $visiblename; 1437 1438 /** @var mixed An array of admin_setting objects that are part of this setting page. */ 1439 public $settings; 1440 1441 /** @var admin_settingdependency[] list of settings to hide when certain conditions are met */ 1442 protected $dependencies = []; 1443 1444 /** @var array The role capability/permission a user must have to access this external page. */ 1445 public $req_capability; 1446 1447 /** @var object The context in which capability/permission should be checked, default is site context. */ 1448 public $context; 1449 1450 /** @var bool hidden in admin tree block. */ 1451 public $hidden; 1452 1453 /** @var mixed string of paths or array of strings of paths */ 1454 public $path; 1455 1456 /** @var array list of visible names of page parents */ 1457 public $visiblepath; 1458 1459 /** 1460 * see admin_settingpage for details of this function 1461 * 1462 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects. 1463 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string(). 1464 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'. 1465 * @param boolean $hidden Is this external page hidden in admin tree block? Default false. 1466 * @param stdClass $context The context the page relates to. Not sure what happens 1467 * if you specify something other than system or front page. Defaults to system. 1468 */ 1469 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) { 1470 $this->settings = new stdClass(); 1471 $this->name = $name; 1472 $this->visiblename = $visiblename; 1473 if (is_array($req_capability)) { 1474 $this->req_capability = $req_capability; 1475 } else { 1476 $this->req_capability = array($req_capability); 1477 } 1478 $this->hidden = $hidden; 1479 $this->context = $context; 1480 } 1481 1482 /** 1483 * see admin_category 1484 * 1485 * @param string $name 1486 * @param bool $findpath 1487 * @return mixed Object (this) if name == this->name, else returns null 1488 */ 1489 public function locate($name, $findpath=false) { 1490 if ($this->name == $name) { 1491 if ($findpath) { 1492 $this->visiblepath = array($this->visiblename); 1493 $this->path = array($this->name); 1494 } 1495 return $this; 1496 } else { 1497 $return = NULL; 1498 return $return; 1499 } 1500 } 1501 1502 /** 1503 * Search string in settings page. 1504 * 1505 * @param string $query 1506 * @return array 1507 */ 1508 public function search($query) { 1509 $found = array(); 1510 1511 foreach ($this->settings as $setting) { 1512 if ($setting->is_related($query)) { 1513 $found[] = $setting; 1514 } 1515 } 1516 1517 if ($found) { 1518 $result = new stdClass(); 1519 $result->page = $this; 1520 $result->settings = $found; 1521 return array($this->name => $result); 1522 } 1523 1524 $found = false; 1525 if (strpos(strtolower($this->name), $query) !== false) { 1526 $found = true; 1527 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) { 1528 $found = true; 1529 } 1530 if ($found) { 1531 $result = new stdClass(); 1532 $result->page = $this; 1533 $result->settings = array(); 1534 return array($this->name => $result); 1535 } else { 1536 return array(); 1537 } 1538 } 1539 1540 /** 1541 * This function always returns false, required by interface 1542 * 1543 * @param string $name 1544 * @return bool Always false 1545 */ 1546 public function prune($name) { 1547 return false; 1548 } 1549 1550 /** 1551 * adds an admin_setting to this admin_settingpage 1552 * 1553 * not the same as add for admin_category. adds an admin_setting to this admin_settingpage. settings appear (on the settingpage) in the order in which they're added 1554 * n.b. each admin_setting in an admin_settingpage must have a unique internal name 1555 * 1556 * @param object $setting is the admin_setting object you want to add 1557 * @return bool true if successful, false if not 1558 */ 1559 public function add($setting) { 1560 if (!($setting instanceof admin_setting)) { 1561 debugging('error - not a setting instance'); 1562 return false; 1563 } 1564 1565 $name = $setting->name; 1566 if ($setting->plugin) { 1567 $name = $setting->plugin . $name; 1568 } 1569 $this->settings->{$name} = $setting; 1570 return true; 1571 } 1572 1573 /** 1574 * Hide the named setting if the specified condition is matched. 1575 * 1576 * @param string $settingname 1577 * @param string $dependenton 1578 * @param string $condition 1579 * @param string $value 1580 */ 1581 public function hide_if($settingname, $dependenton, $condition = 'notchecked', $value = '1') { 1582 $this->dependencies[] = new admin_settingdependency($settingname, $dependenton, $condition, $value); 1583 1584 // Reformat the dependency name to the plugin | name format used in the display. 1585 $dependenton = str_replace('/', ' | ', $dependenton); 1586 1587 // Let the setting know, so it can be displayed underneath. 1588 $findname = str_replace('/', '', $settingname); 1589 foreach ($this->settings as $name => $setting) { 1590 if ($name === $findname) { 1591 $setting->add_dependent_on($dependenton); 1592 } 1593 } 1594 } 1595 1596 /** 1597 * see admin_externalpage 1598 * 1599 * @return bool Returns true for yes false for no 1600 */ 1601 public function check_access() { 1602 global $CFG; 1603 $context = empty($this->context) ? context_system::instance() : $this->context; 1604 foreach($this->req_capability as $cap) { 1605 if (has_capability($cap, $context)) { 1606 return true; 1607 } 1608 } 1609 return false; 1610 } 1611 1612 /** 1613 * outputs this page as html in a table (suitable for inclusion in an admin pagetype) 1614 * @return string Returns an XHTML string 1615 */ 1616 public function output_html() { 1617 $adminroot = admin_get_root(); 1618 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n"; 1619 foreach($this->settings as $setting) { 1620 $fullname = $setting->get_full_name(); 1621 if (array_key_exists($fullname, $adminroot->errors)) { 1622 $data = $adminroot->errors[$fullname]->data; 1623 } else { 1624 $data = $setting->get_setting(); 1625 // do not use defaults if settings not available - upgrade settings handles the defaults! 1626 } 1627 $return .= $setting->output_html($data); 1628 } 1629 $return .= '</fieldset>'; 1630 return $return; 1631 } 1632 1633 /** 1634 * Is this settings page hidden in admin tree block? 1635 * 1636 * @return bool True if hidden 1637 */ 1638 public function is_hidden() { 1639 return $this->hidden; 1640 } 1641 1642 /** 1643 * Show we display Save button at the page bottom? 1644 * @return bool 1645 */ 1646 public function show_save() { 1647 foreach($this->settings as $setting) { 1648 if (empty($setting->nosave)) { 1649 return true; 1650 } 1651 } 1652 return false; 1653 } 1654 1655 /** 1656 * Should any of the settings on this page be shown / hidden based on conditions? 1657 * @return bool 1658 */ 1659 public function has_dependencies() { 1660 return (bool)$this->dependencies; 1661 } 1662 1663 /** 1664 * Format the setting show/hide conditions ready to initialise the page javascript 1665 * @return array 1666 */ 1667 public function get_dependencies_for_javascript() { 1668 if (!$this->has_dependencies()) { 1669 return []; 1670 } 1671 return admin_settingdependency::prepare_for_javascript($this->dependencies); 1672 } 1673 } 1674 1675 1676 /** 1677 * Admin settings class. Only exists on setting pages. 1678 * Read & write happens at this level; no authentication. 1679 * 1680 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1681 */ 1682 abstract class admin_setting { 1683 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */ 1684 public $name; 1685 /** @var string localised name */ 1686 public $visiblename; 1687 /** @var string localised long description in Markdown format */ 1688 public $description; 1689 /** @var mixed Can be string or array of string */ 1690 public $defaultsetting; 1691 /** @var string */ 1692 public $updatedcallback; 1693 /** @var mixed can be String or Null. Null means main config table */ 1694 public $plugin; // null means main config table 1695 /** @var bool true indicates this setting does not actually save anything, just information */ 1696 public $nosave = false; 1697 /** @var bool if set, indicates that a change to this setting requires rebuild course cache */ 1698 public $affectsmodinfo = false; 1699 /** @var array of admin_setting_flag - These are extra checkboxes attached to a setting. */ 1700 private $flags = array(); 1701 /** @var bool Whether this field must be forced LTR. */ 1702 private $forceltr = null; 1703 /** @var array list of other settings that may cause this setting to be hidden */ 1704 private $dependenton = []; 1705 /** @var bool Whether this setting uses a custom form control */ 1706 protected $customcontrol = false; 1707 1708 /** 1709 * Constructor 1710 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 1711 * or 'myplugin/mysetting' for ones in config_plugins. 1712 * @param string $visiblename localised name 1713 * @param string $description localised long description 1714 * @param mixed $defaultsetting string or array depending on implementation 1715 */ 1716 public function __construct($name, $visiblename, $description, $defaultsetting) { 1717 $this->parse_setting_name($name); 1718 $this->visiblename = $visiblename; 1719 $this->description = $description; 1720 $this->defaultsetting = $defaultsetting; 1721 } 1722 1723 /** 1724 * Generic function to add a flag to this admin setting. 1725 * 1726 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1727 * @param bool $default - The default for the flag 1728 * @param string $shortname - The shortname for this flag. Used as a suffix for the setting name. 1729 * @param string $displayname - The display name for this flag. Used as a label next to the checkbox. 1730 */ 1731 protected function set_flag_options($enabled, $default, $shortname, $displayname) { 1732 if (empty($this->flags[$shortname])) { 1733 $this->flags[$shortname] = new admin_setting_flag($enabled, $default, $shortname, $displayname); 1734 } else { 1735 $this->flags[$shortname]->set_options($enabled, $default); 1736 } 1737 } 1738 1739 /** 1740 * Set the enabled options flag on this admin setting. 1741 * 1742 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1743 * @param bool $default - The default for the flag 1744 */ 1745 public function set_enabled_flag_options($enabled, $default) { 1746 $this->set_flag_options($enabled, $default, 'enabled', new lang_string('enabled', 'core_admin')); 1747 } 1748 1749 /** 1750 * Set the advanced options flag on this admin setting. 1751 * 1752 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1753 * @param bool $default - The default for the flag 1754 */ 1755 public function set_advanced_flag_options($enabled, $default) { 1756 $this->set_flag_options($enabled, $default, 'adv', new lang_string('advanced')); 1757 } 1758 1759 1760 /** 1761 * Set the locked options flag on this admin setting. 1762 * 1763 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1764 * @param bool $default - The default for the flag 1765 */ 1766 public function set_locked_flag_options($enabled, $default) { 1767 $this->set_flag_options($enabled, $default, 'locked', new lang_string('locked', 'core_admin')); 1768 } 1769 1770 /** 1771 * Set the required options flag on this admin setting. 1772 * 1773 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED. 1774 * @param bool $default - The default for the flag. 1775 */ 1776 public function set_required_flag_options($enabled, $default) { 1777 $this->set_flag_options($enabled, $default, 'required', new lang_string('required', 'core_admin')); 1778 } 1779 1780 /** 1781 * Is this option forced in config.php? 1782 * 1783 * @return bool 1784 */ 1785 public function is_readonly(): bool { 1786 global $CFG; 1787 1788 if (empty($this->plugin)) { 1789 if (array_key_exists($this->name, $CFG->config_php_settings)) { 1790 return true; 1791 } 1792 } else { 1793 if (array_key_exists($this->plugin, $CFG->forced_plugin_settings) 1794 and array_key_exists($this->name, $CFG->forced_plugin_settings[$this->plugin])) { 1795 return true; 1796 } 1797 } 1798 return false; 1799 } 1800 1801 /** 1802 * Get the currently saved value for a setting flag 1803 * 1804 * @param admin_setting_flag $flag - One of the admin_setting_flag for this admin_setting. 1805 * @return bool 1806 */ 1807 public function get_setting_flag_value(admin_setting_flag $flag) { 1808 $value = $this->config_read($this->name . '_' . $flag->get_shortname()); 1809 if (!isset($value)) { 1810 $value = $flag->get_default(); 1811 } 1812 1813 return !empty($value); 1814 } 1815 1816 /** 1817 * Get the list of defaults for the flags on this setting. 1818 * 1819 * @param array of strings describing the defaults for this setting. This is appended to by this function. 1820 */ 1821 public function get_setting_flag_defaults(& $defaults) { 1822 foreach ($this->flags as $flag) { 1823 if ($flag->is_enabled() && $flag->get_default()) { 1824 $defaults[] = $flag->get_displayname(); 1825 } 1826 } 1827 } 1828 1829 /** 1830 * Output the input fields for the advanced and locked flags on this setting. 1831 * 1832 * @param bool $adv - The current value of the advanced flag. 1833 * @param bool $locked - The current value of the locked flag. 1834 * @return string $output - The html for the flags. 1835 */ 1836 public function output_setting_flags() { 1837 $output = ''; 1838 1839 foreach ($this->flags as $flag) { 1840 if ($flag->is_enabled()) { 1841 $output .= $flag->output_setting_flag($this); 1842 } 1843 } 1844 1845 if (!empty($output)) { 1846 return html_writer::tag('span', $output, array('class' => 'adminsettingsflags')); 1847 } 1848 return $output; 1849 } 1850 1851 /** 1852 * Write the values of the flags for this admin setting. 1853 * 1854 * @param array $data - The data submitted from the form or null to set the default value for new installs. 1855 * @return bool - true if successful. 1856 */ 1857 public function write_setting_flags($data) { 1858 $result = true; 1859 foreach ($this->flags as $flag) { 1860 $result = $result && $flag->write_setting_flag($this, $data); 1861 } 1862 return $result; 1863 } 1864 1865 /** 1866 * Set up $this->name and potentially $this->plugin 1867 * 1868 * Set up $this->name and possibly $this->plugin based on whether $name looks 1869 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking 1870 * on the names, that is, output a developer debug warning if the name 1871 * contains anything other than [a-zA-Z0-9_]+. 1872 * 1873 * @param string $name the setting name passed in to the constructor. 1874 */ 1875 private function parse_setting_name($name) { 1876 $bits = explode('/', $name); 1877 if (count($bits) > 2) { 1878 throw new moodle_exception('invalidadminsettingname', '', '', $name); 1879 } 1880 $this->name = array_pop($bits); 1881 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) { 1882 throw new moodle_exception('invalidadminsettingname', '', '', $name); 1883 } 1884 if (!empty($bits)) { 1885 $this->plugin = array_pop($bits); 1886 if ($this->plugin === 'moodle') { 1887 $this->plugin = null; 1888 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) { 1889 throw new moodle_exception('invalidadminsettingname', '', '', $name); 1890 } 1891 } 1892 } 1893 1894 /** 1895 * Returns the fullname prefixed by the plugin 1896 * @return string 1897 */ 1898 public function get_full_name() { 1899 return 's_'.$this->plugin.'_'.$this->name; 1900 } 1901 1902 /** 1903 * Returns the ID string based on plugin and name 1904 * @return string 1905 */ 1906 public function get_id() { 1907 return 'id_s_'.$this->plugin.'_'.$this->name; 1908 } 1909 1910 /** 1911 * @param bool $affectsmodinfo If true, changes to this setting will 1912 * cause the course cache to be rebuilt 1913 */ 1914 public function set_affects_modinfo($affectsmodinfo) { 1915 $this->affectsmodinfo = $affectsmodinfo; 1916 } 1917 1918 /** 1919 * Returns the config if possible 1920 * 1921 * @return mixed returns config if successful else null 1922 */ 1923 public function config_read($name) { 1924 global $CFG; 1925 if (!empty($this->plugin)) { 1926 $value = get_config($this->plugin, $name); 1927 return $value === false ? NULL : $value; 1928 1929 } else { 1930 if (isset($CFG->$name)) { 1931 return $CFG->$name; 1932 } else { 1933 return NULL; 1934 } 1935 } 1936 } 1937 1938 /** 1939 * Used to set a config pair and log change 1940 * 1941 * @param string $name 1942 * @param mixed $value Gets converted to string if not null 1943 * @return bool Write setting to config table 1944 */ 1945 public function config_write($name, $value) { 1946 global $DB, $USER, $CFG; 1947 1948 if ($this->nosave) { 1949 return true; 1950 } 1951 1952 // make sure it is a real change 1953 $oldvalue = get_config($this->plugin, $name); 1954 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise 1955 $value = is_null($value) ? null : (string)$value; 1956 1957 if ($oldvalue === $value) { 1958 return true; 1959 } 1960 1961 // store change 1962 set_config($name, $value, $this->plugin); 1963 1964 // Some admin settings affect course modinfo 1965 if ($this->affectsmodinfo) { 1966 // Clear course cache for all courses 1967 rebuild_course_cache(0, true); 1968 } 1969 1970 $this->add_to_config_log($name, $oldvalue, $value); 1971 1972 return true; // BC only 1973 } 1974 1975 /** 1976 * Log config changes if necessary. 1977 * @param string $name 1978 * @param string $oldvalue 1979 * @param string $value 1980 */ 1981 protected function add_to_config_log($name, $oldvalue, $value) { 1982 add_to_config_log($name, $oldvalue, $value, $this->plugin); 1983 } 1984 1985 /** 1986 * Returns current value of this setting 1987 * @return mixed array or string depending on instance, NULL means not set yet 1988 */ 1989 public abstract function get_setting(); 1990 1991 /** 1992 * Returns default setting if exists 1993 * @return mixed array or string depending on instance; NULL means no default, user must supply 1994 */ 1995 public function get_defaultsetting() { 1996 $adminroot = admin_get_root(false, false); 1997 if (!empty($adminroot->custom_defaults)) { 1998 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin; 1999 if (isset($adminroot->custom_defaults[$plugin])) { 2000 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-) 2001 return $adminroot->custom_defaults[$plugin][$this->name]; 2002 } 2003 } 2004 } 2005 return $this->defaultsetting; 2006 } 2007 2008 /** 2009 * Store new setting 2010 * 2011 * @param mixed $data string or array, must not be NULL 2012 * @return string empty string if ok, string error message otherwise 2013 */ 2014 public abstract function write_setting($data); 2015 2016 /** 2017 * Return part of form with setting 2018 * This function should always be overwritten 2019 * 2020 * @param mixed $data array or string depending on setting 2021 * @param string $query 2022 * @return string 2023 */ 2024 public function output_html($data, $query='') { 2025 // should be overridden 2026 return; 2027 } 2028 2029 /** 2030 * Function called if setting updated - cleanup, cache reset, etc. 2031 * @param string $functionname Sets the function name 2032 * @return void 2033 */ 2034 public function set_updatedcallback($functionname) { 2035 $this->updatedcallback = $functionname; 2036 } 2037 2038 /** 2039 * Execute postupdatecallback if necessary. 2040 * @param mixed $original original value before write_setting() 2041 * @return bool true if changed, false if not. 2042 */ 2043 public function post_write_settings($original) { 2044 // Comparison must work for arrays too. 2045 if (serialize($original) === serialize($this->get_setting())) { 2046 return false; 2047 } 2048 2049 $callbackfunction = $this->updatedcallback; 2050 if (!empty($callbackfunction) and is_callable($callbackfunction)) { 2051 $callbackfunction($this->get_full_name()); 2052 } 2053 return true; 2054 } 2055 2056 /** 2057 * Is setting related to query text - used when searching 2058 * @param string $query 2059 * @return bool 2060 */ 2061 public function is_related($query) { 2062 if (strpos(strtolower($this->name), $query) !== false) { 2063 return true; 2064 } 2065 if (strpos(core_text::strtolower($this->visiblename), $query) !== false) { 2066 return true; 2067 } 2068 if (strpos(core_text::strtolower($this->description), $query) !== false) { 2069 return true; 2070 } 2071 $current = $this->get_setting(); 2072 if (!is_null($current)) { 2073 if (is_string($current)) { 2074 if (strpos(core_text::strtolower($current), $query) !== false) { 2075 return true; 2076 } 2077 } 2078 } 2079 $default = $this->get_defaultsetting(); 2080 if (!is_null($default)) { 2081 if (is_string($default)) { 2082 if (strpos(core_text::strtolower($default), $query) !== false) { 2083 return true; 2084 } 2085 } 2086 } 2087 return false; 2088 } 2089 2090 /** 2091 * Get whether this should be displayed in LTR mode. 2092 * 2093 * @return bool|null 2094 */ 2095 public function get_force_ltr() { 2096 return $this->forceltr; 2097 } 2098 2099 /** 2100 * Set whether to force LTR or not. 2101 * 2102 * @param bool $value True when forced, false when not force, null when unknown. 2103 */ 2104 public function set_force_ltr($value) { 2105 $this->forceltr = $value; 2106 } 2107 2108 /** 2109 * Add a setting to the list of those that could cause this one to be hidden 2110 * @param string $dependenton 2111 */ 2112 public function add_dependent_on($dependenton) { 2113 $this->dependenton[] = $dependenton; 2114 } 2115 2116 /** 2117 * Get a list of the settings that could cause this one to be hidden. 2118 * @return array 2119 */ 2120 public function get_dependent_on() { 2121 return $this->dependenton; 2122 } 2123 2124 /** 2125 * Whether this setting uses a custom form control. 2126 * This function is especially useful to decide if we should render a label element for this setting or not. 2127 * 2128 * @return bool 2129 */ 2130 public function has_custom_form_control(): bool { 2131 return $this->customcontrol; 2132 } 2133 } 2134 2135 /** 2136 * An additional option that can be applied to an admin setting. 2137 * The currently supported options are 'ADVANCED', 'LOCKED' and 'REQUIRED'. 2138 * 2139 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2140 */ 2141 class admin_setting_flag { 2142 /** @var bool Flag to indicate if this option can be toggled for this setting */ 2143 private $enabled = false; 2144 /** @var bool Flag to indicate if this option defaults to true or false */ 2145 private $default = false; 2146 /** @var string Short string used to create setting name - e.g. 'adv' */ 2147 private $shortname = ''; 2148 /** @var string String used as the label for this flag */ 2149 private $displayname = ''; 2150 /** @const Checkbox for this flag is displayed in admin page */ 2151 const ENABLED = true; 2152 /** @const Checkbox for this flag is not displayed in admin page */ 2153 const DISABLED = false; 2154 2155 /** 2156 * Constructor 2157 * 2158 * @param bool $enabled Can this option can be toggled. 2159 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED. 2160 * @param bool $default The default checked state for this setting option. 2161 * @param string $shortname The shortname of this flag. Currently supported flags are 'locked' and 'adv' 2162 * @param string $displayname The displayname of this flag. Used as a label for the flag. 2163 */ 2164 public function __construct($enabled, $default, $shortname, $displayname) { 2165 $this->shortname = $shortname; 2166 $this->displayname = $displayname; 2167 $this->set_options($enabled, $default); 2168 } 2169 2170 /** 2171 * Update the values of this setting options class 2172 * 2173 * @param bool $enabled Can this option can be toggled. 2174 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED. 2175 * @param bool $default The default checked state for this setting option. 2176 */ 2177 public function set_options($enabled, $default) { 2178 $this->enabled = $enabled; 2179 $this->default = $default; 2180 } 2181 2182 /** 2183 * Should this option appear in the interface and be toggleable? 2184 * 2185 * @return bool Is it enabled? 2186 */ 2187 public function is_enabled() { 2188 return $this->enabled; 2189 } 2190 2191 /** 2192 * Should this option be checked by default? 2193 * 2194 * @return bool Is it on by default? 2195 */ 2196 public function get_default() { 2197 return $this->default; 2198 } 2199 2200 /** 2201 * Return the short name for this flag. e.g. 'adv' or 'locked' 2202 * 2203 * @return string 2204 */ 2205 public function get_shortname() { 2206 return $this->shortname; 2207 } 2208 2209 /** 2210 * Return the display name for this flag. e.g. 'Advanced' or 'Locked' 2211 * 2212 * @return string 2213 */ 2214 public function get_displayname() { 2215 return $this->displayname; 2216 } 2217 2218 /** 2219 * Save the submitted data for this flag - or set it to the default if $data is null. 2220 * 2221 * @param admin_setting $setting - The admin setting for this flag 2222 * @param array $data - The data submitted from the form or null to set the default value for new installs. 2223 * @return bool 2224 */ 2225 public function write_setting_flag(admin_setting $setting, $data) { 2226 $result = true; 2227 if ($this->is_enabled()) { 2228 if (!isset($data)) { 2229 $value = $this->get_default(); 2230 } else { 2231 $value = !empty($data[$setting->get_full_name() . '_' . $this->get_shortname()]); 2232 } 2233 $result = $setting->config_write($setting->name . '_' . $this->get_shortname(), $value); 2234 } 2235 2236 return $result; 2237 2238 } 2239 2240 /** 2241 * Output the checkbox for this setting flag. Should only be called if the flag is enabled. 2242 * 2243 * @param admin_setting $setting - The admin setting for this flag 2244 * @return string - The html for the checkbox. 2245 */ 2246 public function output_setting_flag(admin_setting $setting) { 2247 global $OUTPUT; 2248 2249 $value = $setting->get_setting_flag_value($this); 2250 2251 $context = new stdClass(); 2252 $context->id = $setting->get_id() . '_' . $this->get_shortname(); 2253 $context->name = $setting->get_full_name() . '_' . $this->get_shortname(); 2254 $context->value = 1; 2255 $context->checked = $value ? true : false; 2256 $context->label = $this->get_displayname(); 2257 2258 return $OUTPUT->render_from_template('core_admin/setting_flag', $context); 2259 } 2260 } 2261 2262 2263 /** 2264 * No setting - just heading and text. 2265 * 2266 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2267 */ 2268 class admin_setting_heading extends admin_setting { 2269 2270 /** 2271 * not a setting, just text 2272 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2273 * @param string $heading heading 2274 * @param string $information text in box 2275 */ 2276 public function __construct($name, $heading, $information) { 2277 $this->nosave = true; 2278 parent::__construct($name, $heading, $information, ''); 2279 } 2280 2281 /** 2282 * Always returns true 2283 * @return bool Always returns true 2284 */ 2285 public function get_setting() { 2286 return true; 2287 } 2288 2289 /** 2290 * Always returns true 2291 * @return bool Always returns true 2292 */ 2293 public function get_defaultsetting() { 2294 return true; 2295 } 2296 2297 /** 2298 * Never write settings 2299 * @return string Always returns an empty string 2300 */ 2301 public function write_setting($data) { 2302 // do not write any setting 2303 return ''; 2304 } 2305 2306 /** 2307 * Returns an HTML string 2308 * @return string Returns an HTML string 2309 */ 2310 public function output_html($data, $query='') { 2311 global $OUTPUT; 2312 $context = new stdClass(); 2313 $context->title = $this->visiblename; 2314 $context->description = $this->description; 2315 $context->descriptionformatted = highlight($query, markdown_to_html($this->description)); 2316 return $OUTPUT->render_from_template('core_admin/setting_heading', $context); 2317 } 2318 } 2319 2320 /** 2321 * No setting - just name and description in same row. 2322 * 2323 * @copyright 2018 onwards Amaia Anabitarte 2324 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2325 */ 2326 class admin_setting_description extends admin_setting { 2327 2328 /** 2329 * Not a setting, just text 2330 * 2331 * @param string $name 2332 * @param string $visiblename 2333 * @param string $description 2334 */ 2335 public function __construct($name, $visiblename, $description) { 2336 $this->nosave = true; 2337 parent::__construct($name, $visiblename, $description, ''); 2338 } 2339 2340 /** 2341 * Always returns true 2342 * 2343 * @return bool Always returns true 2344 */ 2345 public function get_setting() { 2346 return true; 2347 } 2348 2349 /** 2350 * Always returns true 2351 * 2352 * @return bool Always returns true 2353 */ 2354 public function get_defaultsetting() { 2355 return true; 2356 } 2357 2358 /** 2359 * Never write settings 2360 * 2361 * @param mixed $data Gets converted to str for comparison against yes value 2362 * @return string Always returns an empty string 2363 */ 2364 public function write_setting($data) { 2365 // Do not write any setting. 2366 return ''; 2367 } 2368 2369 /** 2370 * Returns an HTML string 2371 * 2372 * @param string $data 2373 * @param string $query 2374 * @return string Returns an HTML string 2375 */ 2376 public function output_html($data, $query='') { 2377 global $OUTPUT; 2378 2379 $context = new stdClass(); 2380 $context->title = $this->visiblename; 2381 $context->description = $this->description; 2382 2383 return $OUTPUT->render_from_template('core_admin/setting_description', $context); 2384 } 2385 } 2386 2387 2388 2389 /** 2390 * The most flexible setting, the user enters text. 2391 * 2392 * This type of field should be used for config settings which are using 2393 * English words and are not localised (passwords, database name, list of values, ...). 2394 * 2395 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2396 */ 2397 class admin_setting_configtext extends admin_setting { 2398 2399 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */ 2400 public $paramtype; 2401 /** @var int default field size */ 2402 public $size; 2403 2404 /** 2405 * Config text constructor 2406 * 2407 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2408 * @param string $visiblename localised 2409 * @param string $description long localised info 2410 * @param string $defaultsetting 2411 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex 2412 * @param int $size default field size 2413 */ 2414 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) { 2415 $this->paramtype = $paramtype; 2416 if (!is_null($size)) { 2417 $this->size = $size; 2418 } else { 2419 $this->size = ($paramtype === PARAM_INT) ? 5 : 30; 2420 } 2421 parent::__construct($name, $visiblename, $description, $defaultsetting); 2422 } 2423 2424 /** 2425 * Get whether this should be displayed in LTR mode. 2426 * 2427 * Try to guess from the PARAM type unless specifically set. 2428 */ 2429 public function get_force_ltr() { 2430 $forceltr = parent::get_force_ltr(); 2431 if ($forceltr === null) { 2432 return !is_rtl_compatible($this->paramtype); 2433 } 2434 return $forceltr; 2435 } 2436 2437 /** 2438 * Return the setting 2439 * 2440 * @return mixed returns config if successful else null 2441 */ 2442 public function get_setting() { 2443 return $this->config_read($this->name); 2444 } 2445 2446 public function write_setting($data) { 2447 if ($this->paramtype === PARAM_INT and $data === '') { 2448 // do not complain if '' used instead of 0 2449 $data = 0; 2450 } 2451 // $data is a string 2452 $validated = $this->validate($data); 2453 if ($validated !== true) { 2454 return $validated; 2455 } 2456 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 2457 } 2458 2459 /** 2460 * Validate data before storage 2461 * @param string data 2462 * @return mixed true if ok string if error found 2463 */ 2464 public function validate($data) { 2465 // allow paramtype to be a custom regex if it is the form of /pattern/ 2466 if (preg_match('#^/.*/$#', $this->paramtype)) { 2467 if (preg_match($this->paramtype, $data)) { 2468 return true; 2469 } else { 2470 return get_string('validateerror', 'admin'); 2471 } 2472 2473 } else if ($this->paramtype === PARAM_RAW) { 2474 return true; 2475 2476 } else { 2477 $cleaned = clean_param($data, $this->paramtype); 2478 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison 2479 return true; 2480 } else { 2481 return get_string('validateerror', 'admin'); 2482 } 2483 } 2484 } 2485 2486 /** 2487 * Return an XHTML string for the setting 2488 * @return string Returns an XHTML string 2489 */ 2490 public function output_html($data, $query='') { 2491 global $OUTPUT; 2492 2493 $default = $this->get_defaultsetting(); 2494 $context = (object) [ 2495 'size' => $this->size, 2496 'id' => $this->get_id(), 2497 'name' => $this->get_full_name(), 2498 'value' => $data, 2499 'forceltr' => $this->get_force_ltr(), 2500 'readonly' => $this->is_readonly(), 2501 ]; 2502 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context); 2503 2504 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); 2505 } 2506 } 2507 2508 /** 2509 * Text input with a maximum length constraint. 2510 * 2511 * @copyright 2015 onwards Ankit Agarwal 2512 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2513 */ 2514 class admin_setting_configtext_with_maxlength extends admin_setting_configtext { 2515 2516 /** @var int maximum number of chars allowed. */ 2517 protected $maxlength; 2518 2519 /** 2520 * Config text constructor 2521 * 2522 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 2523 * or 'myplugin/mysetting' for ones in config_plugins. 2524 * @param string $visiblename localised 2525 * @param string $description long localised info 2526 * @param string $defaultsetting 2527 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex 2528 * @param int $size default field size 2529 * @param mixed $maxlength int maxlength allowed, 0 for infinite. 2530 */ 2531 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, 2532 $size=null, $maxlength = 0) { 2533 $this->maxlength = $maxlength; 2534 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size); 2535 } 2536 2537 /** 2538 * Validate data before storage 2539 * 2540 * @param string $data data 2541 * @return mixed true if ok string if error found 2542 */ 2543 public function validate($data) { 2544 $parentvalidation = parent::validate($data); 2545 if ($parentvalidation === true) { 2546 if ($this->maxlength > 0) { 2547 // Max length check. 2548 $length = core_text::strlen($data); 2549 if ($length > $this->maxlength) { 2550 return get_string('maximumchars', 'moodle', $this->maxlength); 2551 } 2552 return true; 2553 } else { 2554 return true; // No max length check needed. 2555 } 2556 } else { 2557 return $parentvalidation; 2558 } 2559 } 2560 } 2561 2562 /** 2563 * General text area without html editor. 2564 * 2565 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2566 */ 2567 class admin_setting_configtextarea extends admin_setting_configtext { 2568 private $rows; 2569 private $cols; 2570 2571 /** 2572 * @param string $name 2573 * @param string $visiblename 2574 * @param string $description 2575 * @param mixed $defaultsetting string or array 2576 * @param mixed $paramtype 2577 * @param string $cols The number of columns to make the editor 2578 * @param string $rows The number of rows to make the editor 2579 */ 2580 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') { 2581 $this->rows = $rows; 2582 $this->cols = $cols; 2583 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype); 2584 } 2585 2586 /** 2587 * Returns an XHTML string for the editor 2588 * 2589 * @param string $data 2590 * @param string $query 2591 * @return string XHTML string for the editor 2592 */ 2593 public function output_html($data, $query='') { 2594 global $OUTPUT; 2595 2596 $default = $this->get_defaultsetting(); 2597 $defaultinfo = $default; 2598 if (!is_null($default) and $default !== '') { 2599 $defaultinfo = "\n".$default; 2600 } 2601 2602 $context = (object) [ 2603 'cols' => $this->cols, 2604 'rows' => $this->rows, 2605 'id' => $this->get_id(), 2606 'name' => $this->get_full_name(), 2607 'value' => $data, 2608 'forceltr' => $this->get_force_ltr(), 2609 'readonly' => $this->is_readonly(), 2610 ]; 2611 $element = $OUTPUT->render_from_template('core_admin/setting_configtextarea', $context); 2612 2613 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query); 2614 } 2615 } 2616 2617 /** 2618 * General text area with html editor. 2619 */ 2620 class admin_setting_confightmleditor extends admin_setting_configtextarea { 2621 2622 /** 2623 * @param string $name 2624 * @param string $visiblename 2625 * @param string $description 2626 * @param mixed $defaultsetting string or array 2627 * @param mixed $paramtype 2628 */ 2629 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') { 2630 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows); 2631 $this->set_force_ltr(false); 2632 editors_head_setup(); 2633 } 2634 2635 /** 2636 * Returns an XHTML string for the editor 2637 * 2638 * @param string $data 2639 * @param string $query 2640 * @return string XHTML string for the editor 2641 */ 2642 public function output_html($data, $query='') { 2643 $editor = editors_get_preferred_editor(FORMAT_HTML); 2644 $editor->set_text($data); 2645 $editor->use_editor($this->get_id(), array('noclean'=>true)); 2646 return parent::output_html($data, $query); 2647 } 2648 2649 /** 2650 * Checks if data has empty html. 2651 * 2652 * @param string $data 2653 * @return string Empty when no errors. 2654 */ 2655 public function write_setting($data) { 2656 if (trim(html_to_text($data)) === '') { 2657 $data = ''; 2658 } 2659 return parent::write_setting($data); 2660 } 2661 } 2662 2663 2664 /** 2665 * Password field, allows unmasking of password 2666 * 2667 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2668 */ 2669 class admin_setting_configpasswordunmask extends admin_setting_configtext { 2670 2671 /** 2672 * Constructor 2673 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2674 * @param string $visiblename localised 2675 * @param string $description long localised info 2676 * @param string $defaultsetting default password 2677 */ 2678 public function __construct($name, $visiblename, $description, $defaultsetting) { 2679 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30); 2680 } 2681 2682 /** 2683 * Log config changes if necessary. 2684 * @param string $name 2685 * @param string $oldvalue 2686 * @param string $value 2687 */ 2688 protected function add_to_config_log($name, $oldvalue, $value) { 2689 if ($value !== '') { 2690 $value = '********'; 2691 } 2692 if ($oldvalue !== '' and $oldvalue !== null) { 2693 $oldvalue = '********'; 2694 } 2695 parent::add_to_config_log($name, $oldvalue, $value); 2696 } 2697 2698 /** 2699 * Returns HTML for the field. 2700 * 2701 * @param string $data Value for the field 2702 * @param string $query Passed as final argument for format_admin_setting 2703 * @return string Rendered HTML 2704 */ 2705 public function output_html($data, $query='') { 2706 global $OUTPUT; 2707 2708 $context = (object) [ 2709 'id' => $this->get_id(), 2710 'name' => $this->get_full_name(), 2711 'size' => $this->size, 2712 'value' => $this->is_readonly() ? null : $data, 2713 'forceltr' => $this->get_force_ltr(), 2714 'readonly' => $this->is_readonly(), 2715 ]; 2716 $element = $OUTPUT->render_from_template('core_admin/setting_configpasswordunmask', $context); 2717 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', null, $query); 2718 } 2719 } 2720 2721 /** 2722 * Password field, allows unmasking of password, with an advanced checkbox that controls an additional $name.'_adv' setting. 2723 * 2724 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2725 * @copyright 2018 Paul Holden (pholden@greenhead.ac.uk) 2726 */ 2727 class admin_setting_configpasswordunmask_with_advanced extends admin_setting_configpasswordunmask { 2728 2729 /** 2730 * Constructor 2731 * 2732 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2733 * @param string $visiblename localised 2734 * @param string $description long localised info 2735 * @param array $defaultsetting ('value'=>string, 'adv'=>bool) 2736 */ 2737 public function __construct($name, $visiblename, $description, $defaultsetting) { 2738 parent::__construct($name, $visiblename, $description, $defaultsetting['value']); 2739 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 2740 } 2741 } 2742 2743 /** 2744 * Admin setting class for encrypted values using secure encryption. 2745 * 2746 * @copyright 2019 The Open University 2747 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2748 */ 2749 class admin_setting_encryptedpassword extends admin_setting { 2750 2751 /** 2752 * Constructor. Same as parent except that the default value is always an empty string. 2753 * 2754 * @param string $name Internal name used in config table 2755 * @param string $visiblename Name shown on form 2756 * @param string $description Description that appears below field 2757 */ 2758 public function __construct(string $name, string $visiblename, string $description) { 2759 parent::__construct($name, $visiblename, $description, ''); 2760 } 2761 2762 public function get_setting() { 2763 return $this->config_read($this->name); 2764 } 2765 2766 public function write_setting($data) { 2767 $data = trim($data); 2768 if ($data === '') { 2769 // Value can really be set to nothing. 2770 $savedata = ''; 2771 } else { 2772 // Encrypt value before saving it. 2773 $savedata = \core\encryption::encrypt($data); 2774 } 2775 return ($this->config_write($this->name, $savedata) ? '' : get_string('errorsetting', 'admin')); 2776 } 2777 2778 public function output_html($data, $query='') { 2779 global $OUTPUT; 2780 2781 $default = $this->get_defaultsetting(); 2782 $context = (object) [ 2783 'id' => $this->get_id(), 2784 'name' => $this->get_full_name(), 2785 'set' => $data !== '', 2786 'novalue' => $this->get_setting() === null 2787 ]; 2788 $element = $OUTPUT->render_from_template('core_admin/setting_encryptedpassword', $context); 2789 2790 return format_admin_setting($this, $this->visiblename, $element, $this->description, 2791 true, '', $default, $query); 2792 } 2793 } 2794 2795 /** 2796 * Empty setting used to allow flags (advanced) on settings that can have no sensible default. 2797 * Note: Only advanced makes sense right now - locked does not. 2798 * 2799 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2800 */ 2801 class admin_setting_configempty extends admin_setting_configtext { 2802 2803 /** 2804 * @param string $name 2805 * @param string $visiblename 2806 * @param string $description 2807 */ 2808 public function __construct($name, $visiblename, $description) { 2809 parent::__construct($name, $visiblename, $description, '', PARAM_RAW); 2810 } 2811 2812 /** 2813 * Returns an XHTML string for the hidden field 2814 * 2815 * @param string $data 2816 * @param string $query 2817 * @return string XHTML string for the editor 2818 */ 2819 public function output_html($data, $query='') { 2820 global $OUTPUT; 2821 2822 $context = (object) [ 2823 'id' => $this->get_id(), 2824 'name' => $this->get_full_name() 2825 ]; 2826 $element = $OUTPUT->render_from_template('core_admin/setting_configempty', $context); 2827 2828 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', get_string('none'), $query); 2829 } 2830 } 2831 2832 2833 /** 2834 * Path to directory 2835 * 2836 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2837 */ 2838 class admin_setting_configfile extends admin_setting_configtext { 2839 /** 2840 * Constructor 2841 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2842 * @param string $visiblename localised 2843 * @param string $description long localised info 2844 * @param string $defaultdirectory default directory location 2845 */ 2846 public function __construct($name, $visiblename, $description, $defaultdirectory) { 2847 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50); 2848 } 2849 2850 /** 2851 * Returns XHTML for the field 2852 * 2853 * Returns XHTML for the field and also checks whether the file 2854 * specified in $data exists using file_exists() 2855 * 2856 * @param string $data File name and path to use in value attr 2857 * @param string $query 2858 * @return string XHTML field 2859 */ 2860 public function output_html($data, $query='') { 2861 global $CFG, $OUTPUT; 2862 2863 $default = $this->get_defaultsetting(); 2864 $context = (object) [ 2865 'id' => $this->get_id(), 2866 'name' => $this->get_full_name(), 2867 'size' => $this->size, 2868 'value' => $data, 2869 'showvalidity' => !empty($data), 2870 'valid' => $data && file_exists($data), 2871 'readonly' => !empty($CFG->preventexecpath) || $this->is_readonly(), 2872 'forceltr' => $this->get_force_ltr(), 2873 ]; 2874 2875 if ($context->readonly) { 2876 $this->visiblename .= '<div class="alert alert-info">'.get_string('execpathnotallowed', 'admin').'</div>'; 2877 } 2878 2879 $element = $OUTPUT->render_from_template('core_admin/setting_configfile', $context); 2880 2881 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); 2882 } 2883 2884 /** 2885 * Checks if execpatch has been disabled in config.php 2886 */ 2887 public function write_setting($data) { 2888 global $CFG; 2889 if (!empty($CFG->preventexecpath)) { 2890 if ($this->get_setting() === null) { 2891 // Use default during installation. 2892 $data = $this->get_defaultsetting(); 2893 if ($data === null) { 2894 $data = ''; 2895 } 2896 } else { 2897 return ''; 2898 } 2899 } 2900 return parent::write_setting($data); 2901 } 2902 2903 } 2904 2905 2906 /** 2907 * Path to executable file 2908 * 2909 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2910 */ 2911 class admin_setting_configexecutable extends admin_setting_configfile { 2912 2913 /** 2914 * Returns an XHTML field 2915 * 2916 * @param string $data This is the value for the field 2917 * @param string $query 2918 * @return string XHTML field 2919 */ 2920 public function output_html($data, $query='') { 2921 global $CFG, $OUTPUT; 2922 $default = $this->get_defaultsetting(); 2923 require_once("$CFG->libdir/filelib.php"); 2924 2925 $context = (object) [ 2926 'id' => $this->get_id(), 2927 'name' => $this->get_full_name(), 2928 'size' => $this->size, 2929 'value' => $data, 2930 'showvalidity' => !empty($data), 2931 'valid' => $data && file_exists($data) && !is_dir($data) && file_is_executable($data), 2932 'readonly' => !empty($CFG->preventexecpath), 2933 'forceltr' => $this->get_force_ltr() 2934 ]; 2935 2936 if (!empty($CFG->preventexecpath)) { 2937 $this->visiblename .= '<div class="alert alert-info">'.get_string('execpathnotallowed', 'admin').'</div>'; 2938 } 2939 2940 $element = $OUTPUT->render_from_template('core_admin/setting_configexecutable', $context); 2941 2942 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); 2943 } 2944 } 2945 2946 2947 /** 2948 * Path to directory 2949 * 2950 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2951 */ 2952 class admin_setting_configdirectory extends admin_setting_configfile { 2953 2954 /** 2955 * Returns an XHTML field 2956 * 2957 * @param string $data This is the value for the field 2958 * @param string $query 2959 * @return string XHTML 2960 */ 2961 public function output_html($data, $query='') { 2962 global $CFG, $OUTPUT; 2963 $default = $this->get_defaultsetting(); 2964 2965 $context = (object) [ 2966 'id' => $this->get_id(), 2967 'name' => $this->get_full_name(), 2968 'size' => $this->size, 2969 'value' => $data, 2970 'showvalidity' => !empty($data), 2971 'valid' => $data && file_exists($data) && is_dir($data), 2972 'readonly' => !empty($CFG->preventexecpath), 2973 'forceltr' => $this->get_force_ltr() 2974 ]; 2975 2976 if (!empty($CFG->preventexecpath)) { 2977 $this->visiblename .= '<div class="alert alert-info">'.get_string('execpathnotallowed', 'admin').'</div>'; 2978 } 2979 2980 $element = $OUTPUT->render_from_template('core_admin/setting_configdirectory', $context); 2981 2982 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); 2983 } 2984 } 2985 2986 2987 /** 2988 * Checkbox 2989 * 2990 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2991 */ 2992 class admin_setting_configcheckbox extends admin_setting { 2993 /** @var string Value used when checked */ 2994 public $yes; 2995 /** @var string Value used when not checked */ 2996 public $no; 2997 2998 /** 2999 * Constructor 3000 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 3001 * @param string $visiblename localised 3002 * @param string $description long localised info 3003 * @param string $defaultsetting 3004 * @param string $yes value used when checked 3005 * @param string $no value used when not checked 3006 */ 3007 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { 3008 parent::__construct($name, $visiblename, $description, $defaultsetting); 3009 $this->yes = (string)$yes; 3010 $this->no = (string)$no; 3011 } 3012 3013 /** 3014 * Retrieves the current setting using the objects name 3015 * 3016 * @return string 3017 */ 3018 public function get_setting() { 3019 return $this->config_read($this->name); 3020 } 3021 3022 /** 3023 * Sets the value for the setting 3024 * 3025 * Sets the value for the setting to either the yes or no values 3026 * of the object by comparing $data to yes 3027 * 3028 * @param mixed $data Gets converted to str for comparison against yes value 3029 * @return string empty string or error 3030 */ 3031 public function write_setting($data) { 3032 if ((string)$data === $this->yes) { // convert to strings before comparison 3033 $data = $this->yes; 3034 } else { 3035 $data = $this->no; 3036 } 3037 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 3038 } 3039 3040 /** 3041 * Returns an XHTML checkbox field 3042 * 3043 * @param string $data If $data matches yes then checkbox is checked 3044 * @param string $query 3045 * @return string XHTML field 3046 */ 3047 public function output_html($data, $query='') { 3048 global $OUTPUT; 3049 3050 $context = (object) [ 3051 'id' => $this->get_id(), 3052 'name' => $this->get_full_name(), 3053 'no' => $this->no, 3054 'value' => $this->yes, 3055 'checked' => (string) $data === $this->yes, 3056 'readonly' => $this->is_readonly(), 3057 ]; 3058 3059 $default = $this->get_defaultsetting(); 3060 if (!is_null($default)) { 3061 if ((string)$default === $this->yes) { 3062 $defaultinfo = get_string('checkboxyes', 'admin'); 3063 } else { 3064 $defaultinfo = get_string('checkboxno', 'admin'); 3065 } 3066 } else { 3067 $defaultinfo = NULL; 3068 } 3069 3070 $element = $OUTPUT->render_from_template('core_admin/setting_configcheckbox', $context); 3071 3072 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query); 3073 } 3074 } 3075 3076 3077 /** 3078 * Multiple checkboxes, each represents different value, stored in csv format 3079 * 3080 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3081 */ 3082 class admin_setting_configmulticheckbox extends admin_setting { 3083 /** @var array Array of choices value=>label */ 3084 public $choices; 3085 /** @var callable|null Loader function for choices */ 3086 protected $choiceloader = null; 3087 3088 /** 3089 * Constructor: uses parent::__construct 3090 * 3091 * The $choices parameter may be either an array of $value => $label format, 3092 * e.g. [1 => get_string('yes')], or a callback function which takes no parameters and 3093 * returns an array in that format. 3094 * 3095 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 3096 * @param string $visiblename localised 3097 * @param string $description long localised info 3098 * @param array $defaultsetting array of selected 3099 * @param array|callable $choices array of $value => $label for each checkbox, or a callback 3100 */ 3101 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 3102 if (is_array($choices)) { 3103 $this->choices = $choices; 3104 } 3105 if (is_callable($choices)) { 3106 $this->choiceloader = $choices; 3107 } 3108 parent::__construct($name, $visiblename, $description, $defaultsetting); 3109 } 3110 3111 /** 3112 * This function may be used in ancestors for lazy loading of choices 3113 * 3114 * Override this method if loading of choices is expensive, such 3115 * as when it requires multiple db requests. 3116 * 3117 * @return bool true if loaded, false if error 3118 */ 3119 public function load_choices() { 3120 if ($this->choiceloader) { 3121 if (!is_array($this->choices)) { 3122 $this->choices = call_user_func($this->choiceloader); 3123 } 3124 } 3125 return true; 3126 } 3127 3128 /** 3129 * Is setting related to query text - used when searching 3130 * 3131 * @param string $query 3132 * @return bool true on related, false on not or failure 3133 */ 3134 public function is_related($query) { 3135 if (!$this->load_choices() or empty($this->choices)) { 3136 return false; 3137 } 3138 if (parent::is_related($query)) { 3139 return true; 3140 } 3141 3142 foreach ($this->choices as $desc) { 3143 if (strpos(core_text::strtolower($desc), $query) !== false) { 3144 return true; 3145 } 3146 } 3147 return false; 3148 } 3149 3150 /** 3151 * Returns the current setting if it is set 3152 * 3153 * @return mixed null if null, else an array 3154 */ 3155 public function get_setting() { 3156 $result = $this->config_read($this->name); 3157 3158 if (is_null($result)) { 3159 return NULL; 3160 } 3161 if ($result === '') { 3162 return array(); 3163 } 3164 $enabled = explode(',', $result); 3165 $setting = array(); 3166 foreach ($enabled as $option) { 3167 $setting[$option] = 1; 3168 } 3169 return $setting; 3170 } 3171 3172 /** 3173 * Saves the setting(s) provided in $data 3174 * 3175 * @param array $data An array of data, if not array returns empty str 3176 * @return mixed empty string on useless data or bool true=success, false=failed 3177 */ 3178 public function write_setting($data) { 3179 if (!is_array($data)) { 3180 return ''; // ignore it 3181 } 3182 if (!$this->load_choices() or empty($this->choices)) { 3183 return ''; 3184 } 3185 unset($data['xxxxx']); 3186 $result = array(); 3187 foreach ($data as $key => $value) { 3188 if ($value and array_key_exists($key, $this->choices)) { 3189 $result[] = $key; 3190 } 3191 } 3192 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin'); 3193 } 3194 3195 /** 3196 * Returns XHTML field(s) as required by choices 3197 * 3198 * Relies on data being an array should data ever be another valid vartype with 3199 * acceptable value this may cause a warning/error 3200 * if (!is_array($data)) would fix the problem 3201 * 3202 * @todo Add vartype handling to ensure $data is an array 3203 * 3204 * @param array $data An array of checked values 3205 * @param string $query 3206 * @return string XHTML field 3207 */ 3208 public function output_html($data, $query='') { 3209 global $OUTPUT; 3210 3211 if (!$this->load_choices() or empty($this->choices)) { 3212 return ''; 3213 } 3214 3215 $default = $this->get_defaultsetting(); 3216 if (is_null($default)) { 3217 $default = array(); 3218 } 3219 if (is_null($data)) { 3220 $data = array(); 3221 } 3222 3223 $context = (object) [ 3224 'id' => $this->get_id(), 3225 'name' => $this->get_full_name(), 3226 ]; 3227 3228 $options = array(); 3229 $defaults = array(); 3230 foreach ($this->choices as $key => $description) { 3231 if (!empty($default[$key])) { 3232 $defaults[] = $description; 3233 } 3234 3235 $options[] = [ 3236 'key' => $key, 3237 'checked' => !empty($data[$key]), 3238 'label' => highlightfast($query, $description) 3239 ]; 3240 } 3241 3242 if (is_null($default)) { 3243 $defaultinfo = null; 3244 } else if (!empty($defaults)) { 3245 $defaultinfo = implode(', ', $defaults); 3246 } else { 3247 $defaultinfo = get_string('none'); 3248 } 3249 3250 $context->options = $options; 3251 $context->hasoptions = !empty($options); 3252 3253 $element = $OUTPUT->render_from_template('core_admin/setting_configmulticheckbox', $context); 3254 3255 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', $defaultinfo, $query); 3256 3257 } 3258 } 3259 3260 3261 /** 3262 * Multiple checkboxes 2, value stored as string 00101011 3263 * 3264 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3265 */ 3266 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox { 3267 3268 /** 3269 * Returns the setting if set 3270 * 3271 * @return mixed null if not set, else an array of set settings 3272 */ 3273 public function get_setting() { 3274 $result = $this->config_read($this->name); 3275 if (is_null($result)) { 3276 return NULL; 3277 } 3278 if (!$this->load_choices()) { 3279 return NULL; 3280 } 3281 $result = str_pad($result, count($this->choices), '0'); 3282 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY); 3283 $setting = array(); 3284 foreach ($this->choices as $key=>$unused) { 3285 $value = array_shift($result); 3286 if ($value) { 3287 $setting[$key] = 1; 3288 } 3289 } 3290 return $setting; 3291 } 3292 3293 /** 3294 * Save setting(s) provided in $data param 3295 * 3296 * @param array $data An array of settings to save 3297 * @return mixed empty string for bad data or bool true=>success, false=>error 3298 */ 3299 public function write_setting($data) { 3300 if (!is_array($data)) { 3301 return ''; // ignore it 3302 } 3303 if (!$this->load_choices() or empty($this->choices)) { 3304 return ''; 3305 } 3306 $result = ''; 3307 foreach ($this->choices as $key=>$unused) { 3308 if (!empty($data[$key])) { 3309 $result .= '1'; 3310 } else { 3311 $result .= '0'; 3312 } 3313 } 3314 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'); 3315 } 3316 } 3317 3318 3319 /** 3320 * Select one value from list 3321 * 3322 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3323 */ 3324 class admin_setting_configselect extends admin_setting { 3325 /** @var array Array of choices value=>label */ 3326 public $choices; 3327 /** @var array Array of choices grouped using optgroups */ 3328 public $optgroups; 3329 /** @var callable|null Loader function for choices */ 3330 protected $choiceloader = null; 3331 /** @var callable|null Validation function */ 3332 protected $validatefunction = null; 3333 3334 /** 3335 * Constructor. 3336 * 3337 * If you want to lazy-load the choices, pass a callback function that returns a choice 3338 * array for the $choices parameter. 3339 * 3340 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 3341 * @param string $visiblename localised 3342 * @param string $description long localised info 3343 * @param string|int $defaultsetting 3344 * @param array|callable|null $choices array of $value=>$label for each selection, or callback 3345 */ 3346 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 3347 // Look for optgroup and single options. 3348 if (is_array($choices)) { 3349 $this->choices = []; 3350 foreach ($choices as $key => $val) { 3351 if (is_array($val)) { 3352 $this->optgroups[$key] = $val; 3353 $this->choices = array_merge($this->choices, $val); 3354 } else { 3355 $this->choices[$key] = $val; 3356 } 3357 } 3358 } 3359 if (is_callable($choices)) { 3360 $this->choiceloader = $choices; 3361 } 3362 3363 parent::__construct($name, $visiblename, $description, $defaultsetting); 3364 } 3365 3366 /** 3367 * Sets a validate function. 3368 * 3369 * The callback will be passed one parameter, the new setting value, and should return either 3370 * an empty string '' if the value is OK, or an error message if not. 3371 * 3372 * @param callable|null $validatefunction Validate function or null to clear 3373 * @since Moodle 3.10 3374 */ 3375 public function set_validate_function(?callable $validatefunction = null) { 3376 $this->validatefunction = $validatefunction; 3377 } 3378 3379 /** 3380 * This function may be used in ancestors for lazy loading of choices 3381 * 3382 * Override this method if loading of choices is expensive, such 3383 * as when it requires multiple db requests. 3384 * 3385 * @return bool true if loaded, false if error 3386 */ 3387 public function load_choices() { 3388 if ($this->choiceloader) { 3389 if (!is_array($this->choices)) { 3390 $this->choices = call_user_func($this->choiceloader); 3391 } 3392 return true; 3393 } 3394 return true; 3395 } 3396 3397 /** 3398 * Check if this is $query is related to a choice 3399 * 3400 * @param string $query 3401 * @return bool true if related, false if not 3402 */ 3403 public function is_related($query) { 3404 if (parent::is_related($query)) { 3405 return true; 3406 } 3407 if (!$this->load_choices()) { 3408 return false; 3409 } 3410 foreach ($this->choices as $key=>$value) { 3411 if (strpos(core_text::strtolower($key), $query) !== false) { 3412 return true; 3413 } 3414 if (strpos(core_text::strtolower($value), $query) !== false) { 3415 return true; 3416 } 3417 } 3418 return false; 3419 } 3420 3421 /** 3422 * Return the setting 3423 * 3424 * @return mixed returns config if successful else null 3425 */ 3426 public function get_setting() { 3427 return $this->config_read($this->name); 3428 } 3429 3430 /** 3431 * Save a setting 3432 * 3433 * @param string $data 3434 * @return string empty of error string 3435 */ 3436 public function write_setting($data) { 3437 if (!$this->load_choices() or empty($this->choices)) { 3438 return ''; 3439 } 3440 if (!array_key_exists($data, $this->choices)) { 3441 return ''; // ignore it 3442 } 3443 3444 // Validate the new setting. 3445 $error = $this->validate_setting($data); 3446 if ($error) { 3447 return $error; 3448 } 3449 3450 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 3451 } 3452 3453 /** 3454 * Validate the setting. This uses the callback function if provided; subclasses could override 3455 * to carry out validation directly in the class. 3456 * 3457 * @param string $data New value being set 3458 * @return string Empty string if valid, or error message text 3459 * @since Moodle 3.10 3460 */ 3461 protected function validate_setting(string $data): string { 3462 // If validation function is specified, call it now. 3463 if ($this->validatefunction) { 3464 return call_user_func($this->validatefunction, $data); 3465 } else { 3466 return ''; 3467 } 3468 } 3469 3470 /** 3471 * Returns XHTML select field 3472 * 3473 * Ensure the options are loaded, and generate the XHTML for the select 3474 * element and any warning message. Separating this out from output_html 3475 * makes it easier to subclass this class. 3476 * 3477 * @param string $data the option to show as selected. 3478 * @param string $current the currently selected option in the database, null if none. 3479 * @param string $default the default selected option. 3480 * @return array the HTML for the select element, and a warning message. 3481 * @deprecated since Moodle 3.2 3482 */ 3483 public function output_select_html($data, $current, $default, $extraname = '') { 3484 debugging('The method admin_setting_configselect::output_select_html is depreacted, do not use any more.', DEBUG_DEVELOPER); 3485 } 3486 3487 /** 3488 * Returns XHTML select field and wrapping div(s) 3489 * 3490 * @see output_select_html() 3491 * 3492 * @param string $data the option to show as selected 3493 * @param string $query 3494 * @return string XHTML field and wrapping div 3495 */ 3496 public function output_html($data, $query='') { 3497 global $OUTPUT; 3498 3499 $default = $this->get_defaultsetting(); 3500 $current = $this->get_setting(); 3501 3502 if (!$this->load_choices() || empty($this->choices)) { 3503 return ''; 3504 } 3505 3506 $context = (object) [ 3507 'id' => $this->get_id(), 3508 'name' => $this->get_full_name(), 3509 ]; 3510 3511 if (!is_null($default) && array_key_exists($default, $this->choices)) { 3512 $defaultinfo = $this->choices[$default]; 3513 } else { 3514 $defaultinfo = NULL; 3515 } 3516 3517 // Warnings. 3518 $warning = ''; 3519 if ($current === null) { 3520 // First run. 3521 } else if (empty($current) && (array_key_exists('', $this->choices) || array_key_exists(0, $this->choices))) { 3522 // No warning. 3523 } else if (!array_key_exists($current, $this->choices)) { 3524 $warning = get_string('warningcurrentsetting', 'admin', $current); 3525 if (!is_null($default) && $data == $current) { 3526 $data = $default; // Use default instead of first value when showing the form. 3527 } 3528 } 3529 3530 $options = []; 3531 $template = 'core_admin/setting_configselect'; 3532 3533 if (!empty($this->optgroups)) { 3534 $optgroups = []; 3535 foreach ($this->optgroups as $label => $choices) { 3536 $optgroup = array('label' => $label, 'options' => []); 3537 foreach ($choices as $value => $name) { 3538 $optgroup['options'][] = [ 3539 'value' => $value, 3540 'name' => $name, 3541 'selected' => (string) $value == $data 3542 ]; 3543 unset($this->choices[$value]); 3544 } 3545 $optgroups[] = $optgroup; 3546 } 3547 $context->options = $options; 3548 $context->optgroups = $optgroups; 3549 $template = 'core_admin/setting_configselect_optgroup'; 3550 } 3551 3552 foreach ($this->choices as $value => $name) { 3553 $options[] = [ 3554 'value' => $value, 3555 'name' => $name, 3556 'selected' => (string) $value == $data 3557 ]; 3558 } 3559 $context->options = $options; 3560 $context->readonly = $this->is_readonly(); 3561 3562 $element = $OUTPUT->render_from_template($template, $context); 3563 3564 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, $warning, $defaultinfo, $query); 3565 } 3566 } 3567 3568 /** 3569 * Select multiple items from list 3570 * 3571 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3572 */ 3573 class admin_setting_configmultiselect extends admin_setting_configselect { 3574 /** 3575 * Constructor 3576 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 3577 * @param string $visiblename localised 3578 * @param string $description long localised info 3579 * @param array $defaultsetting array of selected items 3580 * @param array $choices array of $value=>$label for each list item 3581 */ 3582 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 3583 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); 3584 } 3585 3586 /** 3587 * Returns the select setting(s) 3588 * 3589 * @return mixed null or array. Null if no settings else array of setting(s) 3590 */ 3591 public function get_setting() { 3592 $result = $this->config_read($this->name); 3593 if (is_null($result)) { 3594 return NULL; 3595 } 3596 if ($result === '') { 3597 return array(); 3598 } 3599 return explode(',', $result); 3600 } 3601 3602 /** 3603 * Saves setting(s) provided through $data 3604 * 3605 * Potential bug in the works should anyone call with this function 3606 * using a vartype that is not an array 3607 * 3608 * @param array $data 3609 */ 3610 public function write_setting($data) { 3611 if (!is_array($data)) { 3612 return ''; //ignore it 3613 } 3614 if (!$this->load_choices() or empty($this->choices)) { 3615 return ''; 3616 } 3617 3618 unset($data['xxxxx']); 3619 3620 $save = array(); 3621 foreach ($data as $value) { 3622 if (!array_key_exists($value, $this->choices)) { 3623 continue; // ignore it 3624 } 3625 $save[] = $value; 3626 } 3627 3628 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin')); 3629 } 3630 3631 /** 3632 * Is setting related to query text - used when searching 3633 * 3634 * @param string $query 3635 * @return bool true if related, false if not 3636 */ 3637 public function is_related($query) { 3638 if (!$this->load_choices() or empty($this->choices)) { 3639 return false; 3640 } 3641 if (parent::is_related($query)) { 3642 return true; 3643 } 3644 3645 foreach ($this->choices as $desc) { 3646 if (strpos(core_text::strtolower($desc), $query) !== false) { 3647 return true; 3648 } 3649 } 3650 return false; 3651 } 3652 3653 /** 3654 * Returns XHTML multi-select field 3655 * 3656 * @todo Add vartype handling to ensure $data is an array 3657 * @param array $data Array of values to select by default 3658 * @param string $query 3659 * @return string XHTML multi-select field 3660 */ 3661 public function output_html($data, $query='') { 3662 global $OUTPUT; 3663 3664 if (!$this->load_choices() or empty($this->choices)) { 3665 return ''; 3666 } 3667 3668 $default = $this->get_defaultsetting(); 3669 if (is_null($default)) { 3670 $default = array(); 3671 } 3672 if (is_null($data)) { 3673 $data = array(); 3674 } 3675 3676 $context = (object) [ 3677 'id' => $this->get_id(), 3678 'name' => $this->get_full_name(), 3679 'size' => min(10, count($this->choices)) 3680 ]; 3681 3682 $defaults = []; 3683 $options = []; 3684 $template = 'core_admin/setting_configmultiselect'; 3685 3686 if (!empty($this->optgroups)) { 3687 $optgroups = []; 3688 foreach ($this->optgroups as $label => $choices) { 3689 $optgroup = array('label' => $label, 'options' => []); 3690 foreach ($choices as $value => $name) { 3691 if (in_array($value, $default)) { 3692 $defaults[] = $name; 3693 } 3694 $optgroup['options'][] = [ 3695 'value' => $value, 3696 'name' => $name, 3697 'selected' => in_array($value, $data) 3698 ]; 3699 unset($this->choices[$value]); 3700 } 3701 $optgroups[] = $optgroup; 3702 } 3703 $context->optgroups = $optgroups; 3704 $template = 'core_admin/setting_configmultiselect_optgroup'; 3705 } 3706 3707 foreach ($this->choices as $value => $name) { 3708 if (in_array($value, $default)) { 3709 $defaults[] = $name; 3710 } 3711 $options[] = [ 3712 'value' => $value, 3713 'name' => $name, 3714 'selected' => in_array($value, $data) 3715 ]; 3716 } 3717 $context->options = $options; 3718 $context->readonly = $this->is_readonly(); 3719 3720 if (is_null($default)) { 3721 $defaultinfo = NULL; 3722 } if (!empty($defaults)) { 3723 $defaultinfo = implode(', ', $defaults); 3724 } else { 3725 $defaultinfo = get_string('none'); 3726 } 3727 3728 $element = $OUTPUT->render_from_template($template, $context); 3729 3730 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query); 3731 } 3732 } 3733 3734 /** 3735 * Time selector 3736 * 3737 * This is a liiitle bit messy. we're using two selects, but we're returning 3738 * them as an array named after $name (so we only use $name2 internally for the setting) 3739 * 3740 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3741 */ 3742 class admin_setting_configtime extends admin_setting { 3743 /** @var string Used for setting second select (minutes) */ 3744 public $name2; 3745 3746 /** 3747 * Constructor 3748 * @param string $hoursname setting for hours 3749 * @param string $minutesname setting for hours 3750 * @param string $visiblename localised 3751 * @param string $description long localised info 3752 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes 3753 */ 3754 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) { 3755 $this->name2 = $minutesname; 3756 parent::__construct($hoursname, $visiblename, $description, $defaultsetting); 3757 } 3758 3759 /** 3760 * Get the selected time 3761 * 3762 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set 3763 */ 3764 public function get_setting() { 3765 $result1 = $this->config_read($this->name); 3766 $result2 = $this->config_read($this->name2); 3767 if (is_null($result1) or is_null($result2)) { 3768 return NULL; 3769 } 3770 3771 return array('h' => $result1, 'm' => $result2); 3772 } 3773 3774 /** 3775 * Store the time (hours and minutes) 3776 * 3777 * @param array $data Must be form 'h'=>xx, 'm'=>xx 3778 * @return bool true if success, false if not 3779 */ 3780 public function write_setting($data) { 3781 if (!is_array($data)) { 3782 return ''; 3783 } 3784 3785 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']); 3786 return ($result ? '' : get_string('errorsetting', 'admin')); 3787 } 3788 3789 /** 3790 * Returns XHTML time select fields 3791 * 3792 * @param array $data Must be form 'h'=>xx, 'm'=>xx 3793 * @param string $query 3794 * @return string XHTML time select fields and wrapping div(s) 3795 */ 3796 public function output_html($data, $query='') { 3797 global $OUTPUT; 3798 3799 $default = $this->get_defaultsetting(); 3800 if (is_array($default)) { 3801 $defaultinfo = $default['h'].':'.$default['m']; 3802 } else { 3803 $defaultinfo = NULL; 3804 } 3805 3806 $context = (object) [ 3807 'id' => $this->get_id(), 3808 'name' => $this->get_full_name(), 3809 'readonly' => $this->is_readonly(), 3810 'hours' => array_map(function($i) use ($data) { 3811 return [ 3812 'value' => $i, 3813 'name' => $i, 3814 'selected' => $i == $data['h'] 3815 ]; 3816 }, range(0, 23)), 3817 'minutes' => array_map(function($i) use ($data) { 3818 return [ 3819 'value' => $i, 3820 'name' => $i, 3821 'selected' => $i == $data['m'] 3822 ]; 3823 }, range(0, 59, 5)) 3824 ]; 3825 3826 $element = $OUTPUT->render_from_template('core_admin/setting_configtime', $context); 3827 3828 return format_admin_setting($this, $this->visiblename, $element, $this->description, 3829 $this->get_id() . 'h', '', $defaultinfo, $query); 3830 } 3831 3832 } 3833 3834 3835 /** 3836 * Seconds duration setting. 3837 * 3838 * @copyright 2012 Petr Skoda (http://skodak.org) 3839 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3840 */ 3841 class admin_setting_configduration extends admin_setting { 3842 3843 /** @var int default duration unit */ 3844 protected $defaultunit; 3845 /** @var callable|null Validation function */ 3846 protected $validatefunction = null; 3847 3848 /** 3849 * Constructor 3850 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 3851 * or 'myplugin/mysetting' for ones in config_plugins. 3852 * @param string $visiblename localised name 3853 * @param string $description localised long description 3854 * @param mixed $defaultsetting string or array depending on implementation 3855 * @param int $defaultunit - day, week, etc. (in seconds) 3856 */ 3857 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) { 3858 if (is_number($defaultsetting)) { 3859 $defaultsetting = self::parse_seconds($defaultsetting); 3860 } 3861 $units = self::get_units(); 3862 if (isset($units[$defaultunit])) { 3863 $this->defaultunit = $defaultunit; 3864 } else { 3865 $this->defaultunit = 86400; 3866 } 3867 parent::__construct($name, $visiblename, $description, $defaultsetting); 3868 } 3869 3870 /** 3871 * Sets a validate function. 3872 * 3873 * The callback will be passed one parameter, the new setting value, and should return either 3874 * an empty string '' if the value is OK, or an error message if not. 3875 * 3876 * @param callable|null $validatefunction Validate function or null to clear 3877 * @since Moodle 3.10 3878 */ 3879 public function set_validate_function(?callable $validatefunction = null) { 3880 $this->validatefunction = $validatefunction; 3881 } 3882 3883 /** 3884 * Validate the setting. This uses the callback function if provided; subclasses could override 3885 * to carry out validation directly in the class. 3886 * 3887 * @param int $data New value being set 3888 * @return string Empty string if valid, or error message text 3889 * @since Moodle 3.10 3890 */ 3891 protected function validate_setting(int $data): string { 3892 // If validation function is specified, call it now. 3893 if ($this->validatefunction) { 3894 return call_user_func($this->validatefunction, $data); 3895 } else { 3896 if ($data < 0) { 3897 return get_string('errorsetting', 'admin'); 3898 } 3899 return ''; 3900 } 3901 } 3902 3903 /** 3904 * Returns selectable units. 3905 * @static 3906 * @return array 3907 */ 3908 protected static function get_units() { 3909 return array( 3910 604800 => get_string('weeks'), 3911 86400 => get_string('days'), 3912 3600 => get_string('hours'), 3913 60 => get_string('minutes'), 3914 1 => get_string('seconds'), 3915 ); 3916 } 3917 3918 /** 3919 * Converts seconds to some more user friendly string. 3920 * @static 3921 * @param int $seconds 3922 * @return string 3923 */ 3924 protected static function get_duration_text($seconds) { 3925 if (empty($seconds)) { 3926 return get_string('none'); 3927 } 3928 $data = self::parse_seconds($seconds); 3929 switch ($data['u']) { 3930 case (60*60*24*7): 3931 return get_string('numweeks', '', $data['v']); 3932 case (60*60*24): 3933 return get_string('numdays', '', $data['v']); 3934 case (60*60): 3935 return get_string('numhours', '', $data['v']); 3936 case (60): 3937 return get_string('numminutes', '', $data['v']); 3938 default: 3939 return get_string('numseconds', '', $data['v']*$data['u']); 3940 } 3941 } 3942 3943 /** 3944 * Finds suitable units for given duration. 3945 * @static 3946 * @param int $seconds 3947 * @return array 3948 */ 3949 protected static function parse_seconds($seconds) { 3950 foreach (self::get_units() as $unit => $unused) { 3951 if ($seconds % $unit === 0) { 3952 return array('v'=>(int)($seconds/$unit), 'u'=>$unit); 3953 } 3954 } 3955 return array('v'=>(int)$seconds, 'u'=>1); 3956 } 3957 3958 /** 3959 * Get the selected duration as array. 3960 * 3961 * @return mixed An array containing 'v'=>xx, 'u'=>xx, or null if not set 3962 */ 3963 public function get_setting() { 3964 $seconds = $this->config_read($this->name); 3965 if (is_null($seconds)) { 3966 return null; 3967 } 3968 3969 return self::parse_seconds($seconds); 3970 } 3971 3972 /** 3973 * Store the duration as seconds. 3974 * 3975 * @param array $data Must be form 'h'=>xx, 'm'=>xx 3976 * @return bool true if success, false if not 3977 */ 3978 public function write_setting($data) { 3979 if (!is_array($data)) { 3980 return ''; 3981 } 3982 3983 $unit = (int)$data['u']; 3984 $value = (int)$data['v']; 3985 $seconds = $value * $unit; 3986 3987 // Validate the new setting. 3988 $error = $this->validate_setting($seconds); 3989 if ($error) { 3990 return $error; 3991 } 3992 3993 $result = $this->config_write($this->name, $seconds); 3994 return ($result ? '' : get_string('errorsetting', 'admin')); 3995 } 3996 3997 /** 3998 * Returns duration text+select fields. 3999 * 4000 * @param array $data Must be form 'v'=>xx, 'u'=>xx 4001 * @param string $query 4002 * @return string duration text+select fields and wrapping div(s) 4003 */ 4004 public function output_html($data, $query='') { 4005 global $OUTPUT; 4006 4007 $default = $this->get_defaultsetting(); 4008 if (is_number($default)) { 4009 $defaultinfo = self::get_duration_text($default); 4010 } else if (is_array($default)) { 4011 $defaultinfo = self::get_duration_text($default['v']*$default['u']); 4012 } else { 4013 $defaultinfo = null; 4014 } 4015 4016 $inputid = $this->get_id() . 'v'; 4017 $units = self::get_units(); 4018 $defaultunit = $this->defaultunit; 4019 4020 $context = (object) [ 4021 'id' => $this->get_id(), 4022 'name' => $this->get_full_name(), 4023 'value' => $data['v'], 4024 'readonly' => $this->is_readonly(), 4025 'options' => array_map(function($unit) use ($units, $data, $defaultunit) { 4026 return [ 4027 'value' => $unit, 4028 'name' => $units[$unit], 4029 'selected' => ($data['v'] == 0 && $unit == $defaultunit) || $unit == $data['u'] 4030 ]; 4031 }, array_keys($units)) 4032 ]; 4033 4034 $element = $OUTPUT->render_from_template('core_admin/setting_configduration', $context); 4035 4036 return format_admin_setting($this, $this->visiblename, $element, $this->description, $inputid, '', $defaultinfo, $query); 4037 } 4038 } 4039 4040 4041 /** 4042 * Seconds duration setting with an advanced checkbox, that controls a additional 4043 * $name.'_adv' setting. 4044 * 4045 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4046 * @copyright 2014 The Open University 4047 */ 4048 class admin_setting_configduration_with_advanced extends admin_setting_configduration { 4049 /** 4050 * Constructor 4051 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 4052 * or 'myplugin/mysetting' for ones in config_plugins. 4053 * @param string $visiblename localised name 4054 * @param string $description localised long description 4055 * @param array $defaultsetting array of int value, and bool whether it is 4056 * is advanced by default. 4057 * @param int $defaultunit - day, week, etc. (in seconds) 4058 */ 4059 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) { 4060 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $defaultunit); 4061 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 4062 } 4063 } 4064 4065 4066 /** 4067 * Used to validate a textarea used for ip addresses 4068 * 4069 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4070 * @copyright 2011 Petr Skoda (http://skodak.org) 4071 */ 4072 class admin_setting_configiplist extends admin_setting_configtextarea { 4073 4074 /** 4075 * Validate the contents of the textarea as IP addresses 4076 * 4077 * Used to validate a new line separated list of IP addresses collected from 4078 * a textarea control 4079 * 4080 * @param string $data A list of IP Addresses separated by new lines 4081 * @return mixed bool true for success or string:error on failure 4082 */ 4083 public function validate($data) { 4084 if(!empty($data)) { 4085 $lines = explode("\n", $data); 4086 } else { 4087 return true; 4088 } 4089 $result = true; 4090 $badips = array(); 4091 foreach ($lines as $line) { 4092 $tokens = explode('#', $line); 4093 $ip = trim($tokens[0]); 4094 if (empty($ip)) { 4095 continue; 4096 } 4097 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) || 4098 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) || 4099 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) { 4100 } else { 4101 $result = false; 4102 $badips[] = $ip; 4103 } 4104 } 4105 if($result) { 4106 return true; 4107 } else { 4108 return get_string('validateiperror', 'admin', join(', ', $badips)); 4109 } 4110 } 4111 } 4112 4113 /** 4114 * Used to validate a textarea used for domain names, wildcard domain names and IP addresses/ranges (both IPv4 and IPv6 format). 4115 * 4116 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4117 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com) 4118 */ 4119 class admin_setting_configmixedhostiplist extends admin_setting_configtextarea { 4120 4121 /** 4122 * Validate the contents of the textarea as either IP addresses, domain name or wildcard domain name (RFC 4592). 4123 * Used to validate a new line separated list of entries collected from a textarea control. 4124 * 4125 * This setting provides support for internationalised domain names (IDNs), however, such UTF-8 names will be converted to 4126 * their ascii-compatible encoding (punycode) on save, and converted back to their UTF-8 representation when fetched 4127 * via the get_setting() method, which has been overriden. 4128 * 4129 * @param string $data A list of FQDNs, DNS wildcard format domains, and IP addresses, separated by new lines. 4130 * @return mixed bool true for success or string:error on failure 4131 */ 4132 public function validate($data) { 4133 if (empty($data)) { 4134 return true; 4135 } 4136 $entries = explode("\n", $data); 4137 $badentries = []; 4138 4139 foreach ($entries as $key => $entry) { 4140 $entry = trim($entry); 4141 if (empty($entry)) { 4142 return get_string('validateemptylineerror', 'admin'); 4143 } 4144 4145 // Validate each string entry against the supported formats. 4146 if (\core\ip_utils::is_ip_address($entry) || \core\ip_utils::is_ipv6_range($entry) 4147 || \core\ip_utils::is_ipv4_range($entry) || \core\ip_utils::is_domain_name($entry) 4148 || \core\ip_utils::is_domain_matching_pattern($entry)) { 4149 continue; 4150 } 4151 4152 // Otherwise, the entry is invalid. 4153 $badentries[] = $entry; 4154 } 4155 4156 if ($badentries) { 4157 return get_string('validateerrorlist', 'admin', join(', ', $badentries)); 4158 } 4159 return true; 4160 } 4161 4162 /** 4163 * Convert any lines containing international domain names (IDNs) to their ascii-compatible encoding (ACE). 4164 * 4165 * @param string $data the setting data, as sent from the web form. 4166 * @return string $data the setting data, with all IDNs converted (using punycode) to their ascii encoded version. 4167 */ 4168 protected function ace_encode($data) { 4169 if (empty($data)) { 4170 return $data; 4171 } 4172 $entries = explode("\n", $data); 4173 foreach ($entries as $key => $entry) { 4174 $entry = trim($entry); 4175 // This regex matches any string that has non-ascii character. 4176 if (preg_match('/[^\x00-\x7f]/', $entry)) { 4177 // If we can convert the unicode string to an idn, do so. 4178 // Otherwise, leave the original unicode string alone and let the validation function handle it (it will fail). 4179 $val = idn_to_ascii($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); 4180 $entries[$key] = $val ? $val : $entry; 4181 } 4182 } 4183 return implode("\n", $entries); 4184 } 4185 4186 /** 4187 * Decode any ascii-encoded domain names back to their utf-8 representation for display. 4188 * 4189 * @param string $data the setting data, as found in the database. 4190 * @return string $data the setting data, with all ascii-encoded IDNs decoded back to their utf-8 representation. 4191 */ 4192 protected function ace_decode($data) { 4193 $entries = explode("\n", $data); 4194 foreach ($entries as $key => $entry) { 4195 $entry = trim($entry); 4196 if (strpos($entry, 'xn--') !== false) { 4197 $entries[$key] = idn_to_utf8($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); 4198 } 4199 } 4200 return implode("\n", $entries); 4201 } 4202 4203 /** 4204 * Override, providing utf8-decoding for ascii-encoded IDN strings. 4205 * 4206 * @return mixed returns punycode-converted setting string if successful, else null. 4207 */ 4208 public function get_setting() { 4209 // Here, we need to decode any ascii-encoded IDNs back to their native, utf-8 representation. 4210 $data = $this->config_read($this->name); 4211 if (function_exists('idn_to_utf8') && !is_null($data)) { 4212 $data = $this->ace_decode($data); 4213 } 4214 return $data; 4215 } 4216 4217 /** 4218 * Override, providing ascii-encoding for utf8 (native) IDN strings. 4219 * 4220 * @param string $data 4221 * @return string 4222 */ 4223 public function write_setting($data) { 4224 if ($this->paramtype === PARAM_INT and $data === '') { 4225 // Do not complain if '' used instead of 0. 4226 $data = 0; 4227 } 4228 4229 // Try to convert any non-ascii domains to ACE prior to validation - we can't modify anything in validate! 4230 if (function_exists('idn_to_ascii')) { 4231 $data = $this->ace_encode($data); 4232 } 4233 4234 $validated = $this->validate($data); 4235 if ($validated !== true) { 4236 return $validated; 4237 } 4238 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 4239 } 4240 } 4241 4242 /** 4243 * Used to validate a textarea used for port numbers. 4244 * 4245 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4246 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com) 4247 */ 4248 class admin_setting_configportlist extends admin_setting_configtextarea { 4249 4250 /** 4251 * Validate the contents of the textarea as port numbers. 4252 * Used to validate a new line separated list of ports collected from a textarea control. 4253 * 4254 * @param string $data A list of ports separated by new lines 4255 * @return mixed bool true for success or string:error on failure 4256 */ 4257 public function validate($data) { 4258 if (empty($data)) { 4259 return true; 4260 } 4261 $ports = explode("\n", $data); 4262 $badentries = []; 4263 foreach ($ports as $port) { 4264 $port = trim($port); 4265 if (empty($port)) { 4266 return get_string('validateemptylineerror', 'admin'); 4267 } 4268 4269 // Is the string a valid integer number? 4270 if (strval(intval($port)) !== $port || intval($port) <= 0) { 4271 $badentries[] = $port; 4272 } 4273 } 4274 if ($badentries) { 4275 return get_string('validateerrorlist', 'admin', $badentries); 4276 } 4277 return true; 4278 } 4279 } 4280 4281 4282 /** 4283 * An admin setting for selecting one or more users who have a capability 4284 * in the system context 4285 * 4286 * An admin setting for selecting one or more users, who have a particular capability 4287 * in the system context. Warning, make sure the list will never be too long. There is 4288 * no paging or searching of this list. 4289 * 4290 * To correctly get a list of users from this config setting, you need to call the 4291 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php. 4292 * 4293 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4294 */ 4295 class admin_setting_users_with_capability extends admin_setting_configmultiselect { 4296 /** @var string The capabilities name */ 4297 protected $capability; 4298 /** @var int include admin users too */ 4299 protected $includeadmins; 4300 4301 /** 4302 * Constructor. 4303 * 4304 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 4305 * @param string $visiblename localised name 4306 * @param string $description localised long description 4307 * @param array $defaultsetting array of usernames 4308 * @param string $capability string capability name. 4309 * @param bool $includeadmins include administrators 4310 */ 4311 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) { 4312 $this->capability = $capability; 4313 $this->includeadmins = $includeadmins; 4314 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL); 4315 } 4316 4317 /** 4318 * Load all of the uses who have the capability into choice array 4319 * 4320 * @return bool Always returns true 4321 */ 4322 function load_choices() { 4323 if (is_array($this->choices)) { 4324 return true; 4325 } 4326 list($sort, $sortparams) = users_order_by_sql('u'); 4327 if (!empty($sortparams)) { 4328 throw new coding_exception('users_order_by_sql returned some query parameters. ' . 4329 'This is unexpected, and a problem because there is no way to pass these ' . 4330 'parameters to get_users_by_capability. See MDL-34657.'); 4331 } 4332 $userfieldsapi = \core_user\fields::for_name(); 4333 $userfields = 'u.id, u.username, ' . $userfieldsapi->get_sql('u', false, '', '', false)->selects; 4334 $users = get_users_by_capability(context_system::instance(), $this->capability, $userfields, $sort); 4335 $this->choices = array( 4336 '$@NONE@$' => get_string('nobody'), 4337 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)), 4338 ); 4339 if ($this->includeadmins) { 4340 $admins = get_admins(); 4341 foreach ($admins as $user) { 4342 $this->choices[$user->id] = fullname($user); 4343 } 4344 } 4345 if (is_array($users)) { 4346 foreach ($users as $user) { 4347 $this->choices[$user->id] = fullname($user); 4348 } 4349 } 4350 return true; 4351 } 4352 4353 /** 4354 * Returns the default setting for class 4355 * 4356 * @return mixed Array, or string. Empty string if no default 4357 */ 4358 public function get_defaultsetting() { 4359 $this->load_choices(); 4360 $defaultsetting = parent::get_defaultsetting(); 4361 if (empty($defaultsetting)) { 4362 return array('$@NONE@$'); 4363 } else if (array_key_exists($defaultsetting, $this->choices)) { 4364 return $defaultsetting; 4365 } else { 4366 return ''; 4367 } 4368 } 4369 4370 /** 4371 * Returns the current setting 4372 * 4373 * @return mixed array or string 4374 */ 4375 public function get_setting() { 4376 $result = parent::get_setting(); 4377 if ($result === null) { 4378 // this is necessary for settings upgrade 4379 return null; 4380 } 4381 if (empty($result)) { 4382 $result = array('$@NONE@$'); 4383 } 4384 return $result; 4385 } 4386 4387 /** 4388 * Save the chosen setting provided as $data 4389 * 4390 * @param array $data 4391 * @return mixed string or array 4392 */ 4393 public function write_setting($data) { 4394 // If all is selected, remove any explicit options. 4395 if (in_array('$@ALL@$', $data)) { 4396 $data = array('$@ALL@$'); 4397 } 4398 // None never needs to be written to the DB. 4399 if (in_array('$@NONE@$', $data)) { 4400 unset($data[array_search('$@NONE@$', $data)]); 4401 } 4402 return parent::write_setting($data); 4403 } 4404 } 4405 4406 4407 /** 4408 * Special checkbox for calendar - resets SESSION vars. 4409 * 4410 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4411 */ 4412 class admin_setting_special_adminseesall extends admin_setting_configcheckbox { 4413 /** 4414 * Calls the parent::__construct with default values 4415 * 4416 * name => calendar_adminseesall 4417 * visiblename => get_string('adminseesall', 'admin') 4418 * description => get_string('helpadminseesall', 'admin') 4419 * defaultsetting => 0 4420 */ 4421 public function __construct() { 4422 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'), 4423 get_string('helpadminseesall', 'admin'), '0'); 4424 } 4425 4426 /** 4427 * Stores the setting passed in $data 4428 * 4429 * @param mixed gets converted to string for comparison 4430 * @return string empty string or error message 4431 */ 4432 public function write_setting($data) { 4433 global $SESSION; 4434 return parent::write_setting($data); 4435 } 4436 } 4437 4438 /** 4439 * Special select for settings that are altered in setup.php and can not be altered on the fly 4440 * 4441 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4442 */ 4443 class admin_setting_special_selectsetup extends admin_setting_configselect { 4444 /** 4445 * Reads the setting directly from the database 4446 * 4447 * @return mixed 4448 */ 4449 public function get_setting() { 4450 // read directly from db! 4451 return get_config(NULL, $this->name); 4452 } 4453 4454 /** 4455 * Save the setting passed in $data 4456 * 4457 * @param string $data The setting to save 4458 * @return string empty or error message 4459 */ 4460 public function write_setting($data) { 4461 global $CFG; 4462 // do not change active CFG setting! 4463 $current = $CFG->{$this->name}; 4464 $result = parent::write_setting($data); 4465 $CFG->{$this->name} = $current; 4466 return $result; 4467 } 4468 } 4469 4470 4471 /** 4472 * Special select for frontpage - stores data in course table 4473 * 4474 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4475 */ 4476 class admin_setting_sitesetselect extends admin_setting_configselect { 4477 /** 4478 * Returns the site name for the selected site 4479 * 4480 * @see get_site() 4481 * @return string The site name of the selected site 4482 */ 4483 public function get_setting() { 4484 $site = course_get_format(get_site())->get_course(); 4485 return $site->{$this->name}; 4486 } 4487 4488 /** 4489 * Updates the database and save the setting 4490 * 4491 * @param string data 4492 * @return string empty or error message 4493 */ 4494 public function write_setting($data) { 4495 global $DB, $SITE, $COURSE; 4496 if (!in_array($data, array_keys($this->choices))) { 4497 return get_string('errorsetting', 'admin'); 4498 } 4499 $record = new stdClass(); 4500 $record->id = SITEID; 4501 $temp = $this->name; 4502 $record->$temp = $data; 4503 $record->timemodified = time(); 4504 4505 course_get_format($SITE)->update_course_format_options($record); 4506 $DB->update_record('course', $record); 4507 4508 // Reset caches. 4509 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 4510 if ($SITE->id == $COURSE->id) { 4511 $COURSE = $SITE; 4512 } 4513 format_base::reset_course_cache($SITE->id); 4514 4515 return ''; 4516 4517 } 4518 } 4519 4520 4521 /** 4522 * Select for blog's bloglevel setting: if set to 0, will set blog_menu 4523 * block to hidden. 4524 * 4525 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4526 */ 4527 class admin_setting_bloglevel extends admin_setting_configselect { 4528 /** 4529 * Updates the database and save the setting 4530 * 4531 * @param string data 4532 * @return string empty or error message 4533 */ 4534 public function write_setting($data) { 4535 global $DB, $CFG; 4536 if ($data == 0) { 4537 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1"); 4538 foreach ($blogblocks as $block) { 4539 $DB->set_field('block', 'visible', 0, array('id' => $block->id)); 4540 } 4541 } else { 4542 // reenable all blocks only when switching from disabled blogs 4543 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) { 4544 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0"); 4545 foreach ($blogblocks as $block) { 4546 $DB->set_field('block', 'visible', 1, array('id' => $block->id)); 4547 } 4548 } 4549 } 4550 return parent::write_setting($data); 4551 } 4552 } 4553 4554 4555 /** 4556 * Special select - lists on the frontpage - hacky 4557 * 4558 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4559 */ 4560 class admin_setting_courselist_frontpage extends admin_setting { 4561 /** @var array Array of choices value=>label */ 4562 public $choices; 4563 4564 /** 4565 * Construct override, requires one param 4566 * 4567 * @param bool $loggedin Is the user logged in 4568 */ 4569 public function __construct($loggedin) { 4570 global $CFG; 4571 require_once($CFG->dirroot.'/course/lib.php'); 4572 $name = 'frontpage'.($loggedin ? 'loggedin' : ''); 4573 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin'); 4574 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin'); 4575 $defaults = array(FRONTPAGEALLCOURSELIST); 4576 parent::__construct($name, $visiblename, $description, $defaults); 4577 } 4578 4579 /** 4580 * Loads the choices available 4581 * 4582 * @return bool always returns true 4583 */ 4584 public function load_choices() { 4585 if (is_array($this->choices)) { 4586 return true; 4587 } 4588 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'), 4589 FRONTPAGEALLCOURSELIST => get_string('frontpagecourselist'), 4590 FRONTPAGEENROLLEDCOURSELIST => get_string('frontpageenrolledcourselist'), 4591 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'), 4592 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'), 4593 FRONTPAGECOURSESEARCH => get_string('frontpagecoursesearch'), 4594 'none' => get_string('none')); 4595 if ($this->name === 'frontpage') { 4596 unset($this->choices[FRONTPAGEENROLLEDCOURSELIST]); 4597 } 4598 return true; 4599 } 4600 4601 /** 4602 * Returns the selected settings 4603 * 4604 * @param mixed array or setting or null 4605 */ 4606 public function get_setting() { 4607 $result = $this->config_read($this->name); 4608 if (is_null($result)) { 4609 return NULL; 4610 } 4611 if ($result === '') { 4612 return array(); 4613 } 4614 return explode(',', $result); 4615 } 4616 4617 /** 4618 * Save the selected options 4619 * 4620 * @param array $data 4621 * @return mixed empty string (data is not an array) or bool true=success false=failure 4622 */ 4623 public function write_setting($data) { 4624 if (!is_array($data)) { 4625 return ''; 4626 } 4627 $this->load_choices(); 4628 $save = array(); 4629 foreach($data as $datum) { 4630 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) { 4631 continue; 4632 } 4633 $save[$datum] = $datum; // no duplicates 4634 } 4635 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin')); 4636 } 4637 4638 /** 4639 * Return XHTML select field and wrapping div 4640 * 4641 * @todo Add vartype handling to make sure $data is an array 4642 * @param array $data Array of elements to select by default 4643 * @return string XHTML select field and wrapping div 4644 */ 4645 public function output_html($data, $query='') { 4646 global $OUTPUT; 4647 4648 $this->load_choices(); 4649 $currentsetting = array(); 4650 foreach ($data as $key) { 4651 if ($key != 'none' and array_key_exists($key, $this->choices)) { 4652 $currentsetting[] = $key; // already selected first 4653 } 4654 } 4655 4656 $context = (object) [ 4657 'id' => $this->get_id(), 4658 'name' => $this->get_full_name(), 4659 ]; 4660 4661 $options = $this->choices; 4662 $selects = []; 4663 for ($i = 0; $i < count($this->choices) - 1; $i++) { 4664 if (!array_key_exists($i, $currentsetting)) { 4665 $currentsetting[$i] = 'none'; 4666 } 4667 $selects[] = [ 4668 'key' => $i, 4669 'options' => array_map(function($option) use ($options, $currentsetting, $i) { 4670 return [ 4671 'name' => $options[$option], 4672 'value' => $option, 4673 'selected' => $currentsetting[$i] == $option 4674 ]; 4675 }, array_keys($options)) 4676 ]; 4677 } 4678 $context->selects = $selects; 4679 4680 $element = $OUTPUT->render_from_template('core_admin/setting_courselist_frontpage', $context); 4681 4682 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query); 4683 } 4684 } 4685 4686 4687 /** 4688 * Special checkbox for frontpage - stores data in course table 4689 * 4690 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4691 */ 4692 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox { 4693 /** 4694 * Returns the current sites name 4695 * 4696 * @return string 4697 */ 4698 public function get_setting() { 4699 $site = course_get_format(get_site())->get_course(); 4700 return $site->{$this->name}; 4701 } 4702 4703 /** 4704 * Save the selected setting 4705 * 4706 * @param string $data The selected site 4707 * @return string empty string or error message 4708 */ 4709 public function write_setting($data) { 4710 global $DB, $SITE, $COURSE; 4711 $record = new stdClass(); 4712 $record->id = $SITE->id; 4713 $record->{$this->name} = ($data == '1' ? 1 : 0); 4714 $record->timemodified = time(); 4715 4716 course_get_format($SITE)->update_course_format_options($record); 4717 $DB->update_record('course', $record); 4718 4719 // Reset caches. 4720 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 4721 if ($SITE->id == $COURSE->id) { 4722 $COURSE = $SITE; 4723 } 4724 format_base::reset_course_cache($SITE->id); 4725 4726 return ''; 4727 } 4728 } 4729 4730 /** 4731 * Special text for frontpage - stores data in course table. 4732 * Empty string means not set here. Manual setting is required. 4733 * 4734 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4735 */ 4736 class admin_setting_sitesettext extends admin_setting_configtext { 4737 4738 /** 4739 * Constructor. 4740 */ 4741 public function __construct() { 4742 call_user_func_array(['parent', '__construct'], func_get_args()); 4743 $this->set_force_ltr(false); 4744 } 4745 4746 /** 4747 * Return the current setting 4748 * 4749 * @return mixed string or null 4750 */ 4751 public function get_setting() { 4752 $site = course_get_format(get_site())->get_course(); 4753 return $site->{$this->name} != '' ? $site->{$this->name} : NULL; 4754 } 4755 4756 /** 4757 * Validate the selected data 4758 * 4759 * @param string $data The selected value to validate 4760 * @return mixed true or message string 4761 */ 4762 public function validate($data) { 4763 global $DB, $SITE; 4764 $cleaned = clean_param($data, PARAM_TEXT); 4765 if ($cleaned === '') { 4766 return get_string('required'); 4767 } 4768 if ($this->name ==='shortname' && 4769 $DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data, $SITE->id))) { 4770 return get_string('shortnametaken', 'error', $data); 4771 } 4772 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison 4773 return true; 4774 } else { 4775 return get_string('validateerror', 'admin'); 4776 } 4777 } 4778 4779 /** 4780 * Save the selected setting 4781 * 4782 * @param string $data The selected value 4783 * @return string empty or error message 4784 */ 4785 public function write_setting($data) { 4786 global $DB, $SITE, $COURSE; 4787 $data = trim($data); 4788 $validated = $this->validate($data); 4789 if ($validated !== true) { 4790 return $validated; 4791 } 4792 4793 $record = new stdClass(); 4794 $record->id = $SITE->id; 4795 $record->{$this->name} = $data; 4796 $record->timemodified = time(); 4797 4798 course_get_format($SITE)->update_course_format_options($record); 4799 $DB->update_record('course', $record); 4800 4801 // Reset caches. 4802 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 4803 if ($SITE->id == $COURSE->id) { 4804 $COURSE = $SITE; 4805 } 4806 format_base::reset_course_cache($SITE->id); 4807 4808 return ''; 4809 } 4810 } 4811 4812 4813 /** 4814 * Special text editor for site description. 4815 * 4816 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4817 */ 4818 class admin_setting_special_frontpagedesc extends admin_setting_confightmleditor { 4819 4820 /** 4821 * Calls parent::__construct with specific arguments 4822 */ 4823 public function __construct() { 4824 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), null, 4825 PARAM_RAW, 60, 15); 4826 } 4827 4828 /** 4829 * Return the current setting 4830 * @return string The current setting 4831 */ 4832 public function get_setting() { 4833 $site = course_get_format(get_site())->get_course(); 4834 return $site->{$this->name}; 4835 } 4836 4837 /** 4838 * Save the new setting 4839 * 4840 * @param string $data The new value to save 4841 * @return string empty or error message 4842 */ 4843 public function write_setting($data) { 4844 global $DB, $SITE, $COURSE; 4845 $record = new stdClass(); 4846 $record->id = $SITE->id; 4847 $record->{$this->name} = $data; 4848 $record->timemodified = time(); 4849 4850 course_get_format($SITE)->update_course_format_options($record); 4851 $DB->update_record('course', $record); 4852 4853 // Reset caches. 4854 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 4855 if ($SITE->id == $COURSE->id) { 4856 $COURSE = $SITE; 4857 } 4858 format_base::reset_course_cache($SITE->id); 4859 4860 return ''; 4861 } 4862 } 4863 4864 4865 /** 4866 * Administration interface for emoticon_manager settings. 4867 * 4868 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4869 */ 4870 class admin_setting_emoticons extends admin_setting { 4871 4872 /** 4873 * Calls parent::__construct with specific args 4874 */ 4875 public function __construct() { 4876 global $CFG; 4877 4878 $manager = get_emoticon_manager(); 4879 $defaults = $this->prepare_form_data($manager->default_emoticons()); 4880 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults); 4881 } 4882 4883 /** 4884 * Return the current setting(s) 4885 * 4886 * @return array Current settings array 4887 */ 4888 public function get_setting() { 4889 global $CFG; 4890 4891 $manager = get_emoticon_manager(); 4892 4893 $config = $this->config_read($this->name); 4894 if (is_null($config)) { 4895 return null; 4896 } 4897 4898 $config = $manager->decode_stored_config($config); 4899 if (is_null($config)) { 4900 return null; 4901 } 4902 4903 return $this->prepare_form_data($config); 4904 } 4905 4906 /** 4907 * Save selected settings 4908 * 4909 * @param array $data Array of settings to save 4910 * @return bool 4911 */ 4912 public function write_setting($data) { 4913 4914 $manager = get_emoticon_manager(); 4915 $emoticons = $this->process_form_data($data); 4916 4917 if ($emoticons === false) { 4918 return false; 4919 } 4920 4921 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) { 4922 return ''; // success 4923 } else { 4924 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br'); 4925 } 4926 } 4927 4928 /** 4929 * Return XHTML field(s) for options 4930 * 4931 * @param array $data Array of options to set in HTML 4932 * @return string XHTML string for the fields and wrapping div(s) 4933 */ 4934 public function output_html($data, $query='') { 4935 global $OUTPUT; 4936 4937 $context = (object) [ 4938 'name' => $this->get_full_name(), 4939 'emoticons' => [], 4940 'forceltr' => true, 4941 ]; 4942 4943 $i = 0; 4944 foreach ($data as $field => $value) { 4945 4946 // When $i == 0: text. 4947 // When $i == 1: imagename. 4948 // When $i == 2: imagecomponent. 4949 // When $i == 3: altidentifier. 4950 // When $i == 4: altcomponent. 4951 $fields[$i] = (object) [ 4952 'field' => $field, 4953 'value' => $value, 4954 'index' => $i 4955 ]; 4956 $i++; 4957 4958 if ($i > 4) { 4959 $icon = null; 4960 if (!empty($fields[1]->value)) { 4961 if (get_string_manager()->string_exists($fields[3]->value, $fields[4]->value)) { 4962 $alt = get_string($fields[3]->value, $fields[4]->value); 4963 } else { 4964 $alt = $fields[0]->value; 4965 } 4966 $icon = new pix_emoticon($fields[1]->value, $alt, $fields[2]->value); 4967 } 4968 $context->emoticons[] = [ 4969 'fields' => $fields, 4970 'icon' => $icon ? $icon->export_for_template($OUTPUT) : null 4971 ]; 4972 $fields = []; 4973 $i = 0; 4974 } 4975 } 4976 4977 $context->reseturl = new moodle_url('/admin/resetemoticons.php'); 4978 $element = $OUTPUT->render_from_template('core_admin/setting_emoticons', $context); 4979 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query); 4980 } 4981 4982 /** 4983 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data 4984 * 4985 * @see self::process_form_data() 4986 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager} 4987 * @return array of form fields and their values 4988 */ 4989 protected function prepare_form_data(array $emoticons) { 4990 4991 $form = array(); 4992 $i = 0; 4993 foreach ($emoticons as $emoticon) { 4994 $form['text'.$i] = $emoticon->text; 4995 $form['imagename'.$i] = $emoticon->imagename; 4996 $form['imagecomponent'.$i] = $emoticon->imagecomponent; 4997 $form['altidentifier'.$i] = $emoticon->altidentifier; 4998 $form['altcomponent'.$i] = $emoticon->altcomponent; 4999 $i++; 5000 } 5001 // add one more blank field set for new object 5002 $form['text'.$i] = ''; 5003 $form['imagename'.$i] = ''; 5004 $form['imagecomponent'.$i] = ''; 5005 $form['altidentifier'.$i] = ''; 5006 $form['altcomponent'.$i] = ''; 5007 5008 return $form; 5009 } 5010 5011 /** 5012 * Converts the data from admin settings form into an array of emoticon objects 5013 * 5014 * @see self::prepare_form_data() 5015 * @param array $data array of admin form fields and values 5016 * @return false|array of emoticon objects 5017 */ 5018 protected function process_form_data(array $form) { 5019 5020 $count = count($form); // number of form field values 5021 5022 if ($count % 5) { 5023 // we must get five fields per emoticon object 5024 return false; 5025 } 5026 5027 $emoticons = array(); 5028 for ($i = 0; $i < $count / 5; $i++) { 5029 $emoticon = new stdClass(); 5030 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS); 5031 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH); 5032 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_COMPONENT); 5033 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID); 5034 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_COMPONENT); 5035 5036 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) { 5037 // prevent from breaking http://url.addresses by accident 5038 $emoticon->text = ''; 5039 } 5040 5041 if (strlen($emoticon->text) < 2) { 5042 // do not allow single character emoticons 5043 $emoticon->text = ''; 5044 } 5045 5046 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) { 5047 // emoticon text must contain some non-alphanumeric character to prevent 5048 // breaking HTML tags 5049 $emoticon->text = ''; 5050 } 5051 5052 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') { 5053 $emoticons[] = $emoticon; 5054 } 5055 } 5056 return $emoticons; 5057 } 5058 5059 } 5060 5061 5062 /** 5063 * Special setting for limiting of the list of available languages. 5064 * 5065 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5066 */ 5067 class admin_setting_langlist extends admin_setting_configtext { 5068 /** 5069 * Calls parent::__construct with specific arguments 5070 */ 5071 public function __construct() { 5072 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS); 5073 } 5074 5075 /** 5076 * Validate that each language identifier exists on the site 5077 * 5078 * @param string $data 5079 * @return bool|string True if validation successful, otherwise error string 5080 */ 5081 public function validate($data) { 5082 $parentcheck = parent::validate($data); 5083 if ($parentcheck !== true) { 5084 return $parentcheck; 5085 } 5086 5087 if ($data === '') { 5088 return true; 5089 } 5090 5091 // Normalize language identifiers. 5092 $langcodes = array_map('trim', explode(',', $data)); 5093 foreach ($langcodes as $langcode) { 5094 // If the langcode contains optional alias, split it out. 5095 [$langcode, ] = preg_split('/\s*\|\s*/', $langcode, 2); 5096 5097 if (!get_string_manager()->translation_exists($langcode)) { 5098 return get_string('invalidlanguagecode', 'error', $langcode); 5099 } 5100 } 5101 5102 return true; 5103 } 5104 5105 /** 5106 * Save the new setting 5107 * 5108 * @param string $data The new setting 5109 * @return bool 5110 */ 5111 public function write_setting($data) { 5112 $return = parent::write_setting($data); 5113 get_string_manager()->reset_caches(); 5114 return $return; 5115 } 5116 } 5117 5118 5119 /** 5120 * Allows to specify comma separated list of known country codes. 5121 * 5122 * This is a simple subclass of the plain input text field with added validation so that all the codes are actually 5123 * known codes. 5124 * 5125 * @package core 5126 * @category admin 5127 * @copyright 2020 David Mudrák <david@moodle.com> 5128 * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5129 */ 5130 class admin_setting_countrycodes extends admin_setting_configtext { 5131 5132 /** 5133 * Construct the instance of the setting. 5134 * 5135 * @param string $name Name of the admin setting such as 'allcountrycodes' or 'myplugin/countries'. 5136 * @param lang_string|string $visiblename Language string with the field label text. 5137 * @param lang_string|string $description Language string with the field description text. 5138 * @param string $defaultsetting Default value of the setting. 5139 * @param int $size Input text field size. 5140 */ 5141 public function __construct($name, $visiblename, $description, $defaultsetting = '', $size = null) { 5142 parent::__construct($name, $visiblename, $description, $defaultsetting, '/^(?:\w+(?:,\w+)*)?$/', $size); 5143 } 5144 5145 /** 5146 * Validate the setting value before storing it. 5147 * 5148 * The value is first validated through custom regex so that it is a word consisting of letters, numbers or underscore; or 5149 * a comma separated list of such words. 5150 * 5151 * @param string $data Value inserted into the setting field. 5152 * @return bool|string True if the value is OK, error string otherwise. 5153 */ 5154 public function validate($data) { 5155 5156 $parentcheck = parent::validate($data); 5157 5158 if ($parentcheck !== true) { 5159 return $parentcheck; 5160 } 5161 5162 if ($data === '') { 5163 return true; 5164 } 5165 5166 $allcountries = get_string_manager()->get_list_of_countries(true); 5167 5168 foreach (explode(',', $data) as $code) { 5169 if (!isset($allcountries[$code])) { 5170 return get_string('invalidcountrycode', 'core_error', $code); 5171 } 5172 } 5173 5174 return true; 5175 } 5176 } 5177 5178 5179 /** 5180 * Selection of one of the recognised countries using the list 5181 * returned by {@link get_list_of_countries()}. 5182 * 5183 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5184 */ 5185 class admin_settings_country_select extends admin_setting_configselect { 5186 protected $includeall; 5187 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) { 5188 $this->includeall = $includeall; 5189 parent::__construct($name, $visiblename, $description, $defaultsetting, null); 5190 } 5191 5192 /** 5193 * Lazy-load the available choices for the select box 5194 */ 5195 public function load_choices() { 5196 global $CFG; 5197 if (is_array($this->choices)) { 5198 return true; 5199 } 5200 $this->choices = array_merge( 5201 array('0' => get_string('choosedots')), 5202 get_string_manager()->get_list_of_countries($this->includeall)); 5203 return true; 5204 } 5205 } 5206 5207 5208 /** 5209 * admin_setting_configselect for the default number of sections in a course, 5210 * simply so we can lazy-load the choices. 5211 * 5212 * @copyright 2011 The Open University 5213 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5214 */ 5215 class admin_settings_num_course_sections extends admin_setting_configselect { 5216 public function __construct($name, $visiblename, $description, $defaultsetting) { 5217 parent::__construct($name, $visiblename, $description, $defaultsetting, array()); 5218 } 5219 5220 /** Lazy-load the available choices for the select box */ 5221 public function load_choices() { 5222 $max = get_config('moodlecourse', 'maxsections'); 5223 if (!isset($max) || !is_numeric($max)) { 5224 $max = 52; 5225 } 5226 for ($i = 0; $i <= $max; $i++) { 5227 $this->choices[$i] = "$i"; 5228 } 5229 return true; 5230 } 5231 } 5232 5233 5234 /** 5235 * Course category selection 5236 * 5237 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5238 */ 5239 class admin_settings_coursecat_select extends admin_setting_configselect_autocomplete { 5240 /** 5241 * Calls parent::__construct with specific arguments 5242 */ 5243 public function __construct($name, $visiblename, $description, $defaultsetting = 1) { 5244 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices = null); 5245 } 5246 5247 /** 5248 * Load the available choices for the select box 5249 * 5250 * @return bool 5251 */ 5252 public function load_choices() { 5253 if (is_array($this->choices)) { 5254 return true; 5255 } 5256 $this->choices = core_course_category::make_categories_list('', 0, ' / '); 5257 return true; 5258 } 5259 } 5260 5261 5262 /** 5263 * Special control for selecting days to backup 5264 * 5265 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5266 */ 5267 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 { 5268 /** 5269 * Calls parent::__construct with specific arguments 5270 */ 5271 public function __construct() { 5272 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL); 5273 $this->plugin = 'backup'; 5274 } 5275 5276 /** 5277 * Load the available choices for the select box 5278 * 5279 * @return bool Always returns true 5280 */ 5281 public function load_choices() { 5282 if (is_array($this->choices)) { 5283 return true; 5284 } 5285 $this->choices = array(); 5286 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); 5287 foreach ($days as $day) { 5288 $this->choices[$day] = get_string($day, 'calendar'); 5289 } 5290 return true; 5291 } 5292 } 5293 5294 /** 5295 * Special setting for backup auto destination. 5296 * 5297 * @package core 5298 * @subpackage admin 5299 * @copyright 2014 Frédéric Massart - FMCorz.net 5300 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5301 */ 5302 class admin_setting_special_backup_auto_destination extends admin_setting_configdirectory { 5303 5304 /** 5305 * Calls parent::__construct with specific arguments. 5306 */ 5307 public function __construct() { 5308 parent::__construct('backup/backup_auto_destination', new lang_string('saveto'), new lang_string('backupsavetohelp'), ''); 5309 } 5310 5311 /** 5312 * Check if the directory must be set, depending on backup/backup_auto_storage. 5313 * 5314 * Note: backup/backup_auto_storage must be specified BEFORE this setting otherwise 5315 * there will be conflicts if this validation happens before the other one. 5316 * 5317 * @param string $data Form data. 5318 * @return string Empty when no errors. 5319 */ 5320 public function write_setting($data) { 5321 $storage = (int) get_config('backup', 'backup_auto_storage'); 5322 if ($storage !== 0) { 5323 if (empty($data) || !file_exists($data) || !is_dir($data) || !is_writable($data) ) { 5324 // The directory must exist and be writable. 5325 return get_string('backuperrorinvaliddestination'); 5326 } 5327 } 5328 return parent::write_setting($data); 5329 } 5330 } 5331 5332 5333 /** 5334 * Special debug setting 5335 * 5336 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5337 */ 5338 class admin_setting_special_debug extends admin_setting_configselect { 5339 /** 5340 * Calls parent::__construct with specific arguments 5341 */ 5342 public function __construct() { 5343 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL); 5344 } 5345 5346 /** 5347 * Load the available choices for the select box 5348 * 5349 * @return bool 5350 */ 5351 public function load_choices() { 5352 if (is_array($this->choices)) { 5353 return true; 5354 } 5355 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'), 5356 DEBUG_MINIMAL => get_string('debugminimal', 'admin'), 5357 DEBUG_NORMAL => get_string('debugnormal', 'admin'), 5358 DEBUG_ALL => get_string('debugall', 'admin'), 5359 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')); 5360 return true; 5361 } 5362 } 5363 5364 5365 /** 5366 * Special admin control 5367 * 5368 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5369 */ 5370 class admin_setting_special_calendar_weekend extends admin_setting { 5371 /** 5372 * Calls parent::__construct with specific arguments 5373 */ 5374 public function __construct() { 5375 $name = 'calendar_weekend'; 5376 $visiblename = get_string('calendar_weekend', 'admin'); 5377 $description = get_string('helpweekenddays', 'admin'); 5378 $default = array ('0', '6'); // Saturdays and Sundays 5379 parent::__construct($name, $visiblename, $description, $default); 5380 } 5381 5382 /** 5383 * Gets the current settings as an array 5384 * 5385 * @return mixed Null if none, else array of settings 5386 */ 5387 public function get_setting() { 5388 $result = $this->config_read($this->name); 5389 if (is_null($result)) { 5390 return NULL; 5391 } 5392 if ($result === '') { 5393 return array(); 5394 } 5395 $settings = array(); 5396 for ($i=0; $i<7; $i++) { 5397 if ($result & (1 << $i)) { 5398 $settings[] = $i; 5399 } 5400 } 5401 return $settings; 5402 } 5403 5404 /** 5405 * Save the new settings 5406 * 5407 * @param array $data Array of new settings 5408 * @return bool 5409 */ 5410 public function write_setting($data) { 5411 if (!is_array($data)) { 5412 return ''; 5413 } 5414 unset($data['xxxxx']); 5415 $result = 0; 5416 foreach($data as $index) { 5417 $result |= 1 << $index; 5418 } 5419 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin')); 5420 } 5421 5422 /** 5423 * Return XHTML to display the control 5424 * 5425 * @param array $data array of selected days 5426 * @param string $query 5427 * @return string XHTML for display (field + wrapping div(s) 5428 */ 5429 public function output_html($data, $query='') { 5430 global $OUTPUT; 5431 5432 // The order matters very much because of the implied numeric keys. 5433 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); 5434 $context = (object) [ 5435 'name' => $this->get_full_name(), 5436 'id' => $this->get_id(), 5437 'days' => array_map(function($index) use ($days, $data) { 5438 return [ 5439 'index' => $index, 5440 'label' => get_string($days[$index], 'calendar'), 5441 'checked' => in_array($index, $data) 5442 ]; 5443 }, array_keys($days)) 5444 ]; 5445 5446 $element = $OUTPUT->render_from_template('core_admin/setting_special_calendar_weekend', $context); 5447 5448 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query); 5449 5450 } 5451 } 5452 5453 5454 /** 5455 * Admin setting that allows a user to pick a behaviour. 5456 * 5457 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5458 */ 5459 class admin_setting_question_behaviour extends admin_setting_configselect { 5460 /** 5461 * @param string $name name of config variable 5462 * @param string $visiblename display name 5463 * @param string $description description 5464 * @param string $default default. 5465 */ 5466 public function __construct($name, $visiblename, $description, $default) { 5467 parent::__construct($name, $visiblename, $description, $default, null); 5468 } 5469 5470 /** 5471 * Load list of behaviours as choices 5472 * @return bool true => success, false => error. 5473 */ 5474 public function load_choices() { 5475 global $CFG; 5476 require_once($CFG->dirroot . '/question/engine/lib.php'); 5477 $this->choices = question_engine::get_behaviour_options(''); 5478 return true; 5479 } 5480 } 5481 5482 5483 /** 5484 * Admin setting that allows a user to pick appropriate roles for something. 5485 * 5486 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5487 */ 5488 class admin_setting_pickroles extends admin_setting_configmulticheckbox { 5489 /** @var array Array of capabilities which identify roles */ 5490 private $types; 5491 5492 /** 5493 * @param string $name Name of config variable 5494 * @param string $visiblename Display name 5495 * @param string $description Description 5496 * @param array $types Array of archetypes which identify 5497 * roles that will be enabled by default. 5498 */ 5499 public function __construct($name, $visiblename, $description, $types) { 5500 parent::__construct($name, $visiblename, $description, NULL, NULL); 5501 $this->types = $types; 5502 } 5503 5504 /** 5505 * Load roles as choices 5506 * 5507 * @return bool true=>success, false=>error 5508 */ 5509 public function load_choices() { 5510 global $CFG, $DB; 5511 if (during_initial_install()) { 5512 return false; 5513 } 5514 if (is_array($this->choices)) { 5515 return true; 5516 } 5517 if ($roles = get_all_roles()) { 5518 $this->choices = role_fix_names($roles, null, ROLENAME_ORIGINAL, true); 5519 return true; 5520 } else { 5521 return false; 5522 } 5523 } 5524 5525 /** 5526 * Return the default setting for this control 5527 * 5528 * @return array Array of default settings 5529 */ 5530 public function get_defaultsetting() { 5531 global $CFG; 5532 5533 if (during_initial_install()) { 5534 return null; 5535 } 5536 $result = array(); 5537 foreach($this->types as $archetype) { 5538 if ($caproles = get_archetype_roles($archetype)) { 5539 foreach ($caproles as $caprole) { 5540 $result[$caprole->id] = 1; 5541 } 5542 } 5543 } 5544 return $result; 5545 } 5546 } 5547 5548 5549 /** 5550 * Admin setting that is a list of installed filter plugins. 5551 * 5552 * @copyright 2015 The Open University 5553 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5554 */ 5555 class admin_setting_pickfilters extends admin_setting_configmulticheckbox { 5556 5557 /** 5558 * Constructor 5559 * 5560 * @param string $name unique ascii name, either 'mysetting' for settings 5561 * that in config, or 'myplugin/mysetting' for ones in config_plugins. 5562 * @param string $visiblename localised name 5563 * @param string $description localised long description 5564 * @param array $default the default. E.g. array('urltolink' => 1, 'emoticons' => 1) 5565 */ 5566 public function __construct($name, $visiblename, $description, $default) { 5567 if (empty($default)) { 5568 $default = array(); 5569 } 5570 $this->load_choices(); 5571 foreach ($default as $plugin) { 5572 if (!isset($this->choices[$plugin])) { 5573 unset($default[$plugin]); 5574 } 5575 } 5576 parent::__construct($name, $visiblename, $description, $default, null); 5577 } 5578 5579 public function load_choices() { 5580 if (is_array($this->choices)) { 5581 return true; 5582 } 5583 $this->choices = array(); 5584 5585 foreach (core_component::get_plugin_list('filter') as $plugin => $unused) { 5586 $this->choices[$plugin] = filter_get_name($plugin); 5587 } 5588 return true; 5589 } 5590 } 5591 5592 5593 /** 5594 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting. 5595 * 5596 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5597 */ 5598 class admin_setting_configtext_with_advanced extends admin_setting_configtext { 5599 /** 5600 * Constructor 5601 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 5602 * @param string $visiblename localised 5603 * @param string $description long localised info 5604 * @param array $defaultsetting ('value'=>string, '__construct'=>bool) 5605 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex 5606 * @param int $size default field size 5607 */ 5608 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) { 5609 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $paramtype, $size); 5610 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 5611 } 5612 } 5613 5614 5615 /** 5616 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting. 5617 * 5618 * @copyright 2009 Petr Skoda (http://skodak.org) 5619 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5620 */ 5621 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox { 5622 5623 /** 5624 * Constructor 5625 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 5626 * @param string $visiblename localised 5627 * @param string $description long localised info 5628 * @param array $defaultsetting ('value'=>string, 'adv'=>bool) 5629 * @param string $yes value used when checked 5630 * @param string $no value used when not checked 5631 */ 5632 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { 5633 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no); 5634 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 5635 } 5636 5637 } 5638 5639 5640 /** 5641 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting. 5642 * 5643 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv 5644 * 5645 * @copyright 2010 Sam Hemelryk 5646 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5647 */ 5648 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox { 5649 /** 5650 * Constructor 5651 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 5652 * @param string $visiblename localised 5653 * @param string $description long localised info 5654 * @param array $defaultsetting ('value'=>string, 'locked'=>bool) 5655 * @param string $yes value used when checked 5656 * @param string $no value used when not checked 5657 */ 5658 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { 5659 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no); 5660 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked'])); 5661 } 5662 5663 } 5664 5665 /** 5666 * Autocomplete as you type form element. 5667 * 5668 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5669 */ 5670 class admin_setting_configselect_autocomplete extends admin_setting_configselect { 5671 /** @var boolean $tags Should we allow typing new entries to the field? */ 5672 protected $tags = false; 5673 /** @var string $ajax Name of an AMD module to send/process ajax requests. */ 5674 protected $ajax = ''; 5675 /** @var string $placeholder Placeholder text for an empty list. */ 5676 protected $placeholder = ''; 5677 /** @var bool $casesensitive Whether the search has to be case-sensitive. */ 5678 protected $casesensitive = false; 5679 /** @var bool $showsuggestions Show suggestions by default - but this can be turned off. */ 5680 protected $showsuggestions = true; 5681 /** @var string $noselectionstring String that is shown when there are no selections. */ 5682 protected $noselectionstring = ''; 5683 5684 /** 5685 * Returns XHTML select field and wrapping div(s) 5686 * 5687 * @see output_select_html() 5688 * 5689 * @param string $data the option to show as selected 5690 * @param string $query 5691 * @return string XHTML field and wrapping div 5692 */ 5693 public function output_html($data, $query='') { 5694 global $PAGE; 5695 5696 $html = parent::output_html($data, $query); 5697 5698 if ($html === '') { 5699 return $html; 5700 } 5701 5702 $this->placeholder = get_string('search'); 5703 5704 $params = array('#' . $this->get_id(), $this->tags, $this->ajax, 5705 $this->placeholder, $this->casesensitive, $this->showsuggestions, $this->noselectionstring); 5706 5707 // Load autocomplete wrapper for select2 library. 5708 $PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params); 5709 5710 return $html; 5711 } 5712 } 5713 5714 /** 5715 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting. 5716 * 5717 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5718 */ 5719 class admin_setting_configselect_with_advanced extends admin_setting_configselect { 5720 /** 5721 * Calls parent::__construct with specific arguments 5722 */ 5723 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 5724 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices); 5725 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 5726 } 5727 5728 } 5729 5730 /** 5731 * Select with an advanced checkbox that controls an additional $name.'_locked' config setting. 5732 * 5733 * @copyright 2017 Marina Glancy 5734 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5735 */ 5736 class admin_setting_configselect_with_lock extends admin_setting_configselect { 5737 /** 5738 * Constructor 5739 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 5740 * or 'myplugin/mysetting' for ones in config_plugins. 5741 * @param string $visiblename localised 5742 * @param string $description long localised info 5743 * @param array $defaultsetting ('value'=>string, 'locked'=>bool) 5744 * @param array $choices array of $value=>$label for each selection 5745 */ 5746 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 5747 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices); 5748 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked'])); 5749 } 5750 } 5751 5752 5753 /** 5754 * Graded roles in gradebook 5755 * 5756 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5757 */ 5758 class admin_setting_special_gradebookroles extends admin_setting_pickroles { 5759 /** 5760 * Calls parent::__construct with specific arguments 5761 */ 5762 public function __construct() { 5763 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'), 5764 get_string('configgradebookroles', 'admin'), 5765 array('student')); 5766 } 5767 } 5768 5769 5770 /** 5771 * 5772 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5773 */ 5774 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox { 5775 /** 5776 * Saves the new settings passed in $data 5777 * 5778 * @param string $data 5779 * @return mixed string or Array 5780 */ 5781 public function write_setting($data) { 5782 global $CFG, $DB; 5783 5784 $oldvalue = $this->config_read($this->name); 5785 $return = parent::write_setting($data); 5786 $newvalue = $this->config_read($this->name); 5787 5788 if ($oldvalue !== $newvalue) { 5789 // force full regrading 5790 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0)); 5791 } 5792 5793 return $return; 5794 } 5795 } 5796 5797 5798 /** 5799 * Which roles to show on course description page 5800 * 5801 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5802 */ 5803 class admin_setting_special_coursecontact extends admin_setting_pickroles { 5804 /** 5805 * Calls parent::__construct with specific arguments 5806 */ 5807 public function __construct() { 5808 parent::__construct('coursecontact', get_string('coursecontact', 'admin'), 5809 get_string('coursecontact_desc', 'admin'), 5810 array('editingteacher')); 5811 $this->set_updatedcallback(function (){ 5812 cache::make('core', 'coursecontacts')->purge(); 5813 }); 5814 } 5815 } 5816 5817 5818 /** 5819 * 5820 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5821 */ 5822 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox { 5823 /** 5824 * Calls parent::__construct with specific arguments 5825 */ 5826 public function __construct() { 5827 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'), 5828 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0'); 5829 } 5830 5831 /** 5832 * Old syntax of class constructor. Deprecated in PHP7. 5833 * 5834 * @deprecated since Moodle 3.1 5835 */ 5836 public function admin_setting_special_gradelimiting() { 5837 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER); 5838 self::__construct(); 5839 } 5840 5841 /** 5842 * Force site regrading 5843 */ 5844 function regrade_all() { 5845 global $CFG; 5846 require_once("$CFG->libdir/gradelib.php"); 5847 grade_force_site_regrading(); 5848 } 5849 5850 /** 5851 * Saves the new settings 5852 * 5853 * @param mixed $data 5854 * @return string empty string or error message 5855 */ 5856 function write_setting($data) { 5857 $previous = $this->get_setting(); 5858 5859 if ($previous === null) { 5860 if ($data) { 5861 $this->regrade_all(); 5862 } 5863 } else { 5864 if ($data != $previous) { 5865 $this->regrade_all(); 5866 } 5867 } 5868 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 5869 } 5870 5871 } 5872 5873 /** 5874 * Special setting for $CFG->grade_minmaxtouse. 5875 * 5876 * @package core 5877 * @copyright 2015 Frédéric Massart - FMCorz.net 5878 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5879 */ 5880 class admin_setting_special_grademinmaxtouse extends admin_setting_configselect { 5881 5882 /** 5883 * Constructor. 5884 */ 5885 public function __construct() { 5886 parent::__construct('grade_minmaxtouse', new lang_string('minmaxtouse', 'grades'), 5887 new lang_string('minmaxtouse_desc', 'grades'), GRADE_MIN_MAX_FROM_GRADE_ITEM, 5888 array( 5889 GRADE_MIN_MAX_FROM_GRADE_ITEM => get_string('gradeitemminmax', 'grades'), 5890 GRADE_MIN_MAX_FROM_GRADE_GRADE => get_string('gradegrademinmax', 'grades') 5891 ) 5892 ); 5893 } 5894 5895 /** 5896 * Saves the new setting. 5897 * 5898 * @param mixed $data 5899 * @return string empty string or error message 5900 */ 5901 function write_setting($data) { 5902 global $CFG; 5903 5904 $previous = $this->get_setting(); 5905 $result = parent::write_setting($data); 5906 5907 // If saved and the value has changed. 5908 if (empty($result) && $previous != $data) { 5909 require_once($CFG->libdir . '/gradelib.php'); 5910 grade_force_site_regrading(); 5911 } 5912 5913 return $result; 5914 } 5915 5916 } 5917 5918 5919 /** 5920 * Primary grade export plugin - has state tracking. 5921 * 5922 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5923 */ 5924 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox { 5925 /** 5926 * Calls parent::__construct with specific arguments 5927 */ 5928 public function __construct() { 5929 parent::__construct('gradeexport', get_string('gradeexport', 'admin'), 5930 get_string('configgradeexport', 'admin'), array(), NULL); 5931 } 5932 5933 /** 5934 * Load the available choices for the multicheckbox 5935 * 5936 * @return bool always returns true 5937 */ 5938 public function load_choices() { 5939 if (is_array($this->choices)) { 5940 return true; 5941 } 5942 $this->choices = array(); 5943 5944 if ($plugins = core_component::get_plugin_list('gradeexport')) { 5945 foreach($plugins as $plugin => $unused) { 5946 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin); 5947 } 5948 } 5949 return true; 5950 } 5951 } 5952 5953 5954 /** 5955 * A setting for setting the default grade point value. Must be an integer between 1 and $CFG->gradepointmax. 5956 * 5957 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5958 */ 5959 class admin_setting_special_gradepointdefault extends admin_setting_configtext { 5960 /** 5961 * Config gradepointmax constructor 5962 * 5963 * @param string $name Overidden by "gradepointmax" 5964 * @param string $visiblename Overridden by "gradepointmax" language string. 5965 * @param string $description Overridden by "gradepointmax_help" language string. 5966 * @param string $defaultsetting Not used, overridden by 100. 5967 * @param mixed $paramtype Overridden by PARAM_INT. 5968 * @param int $size Overridden by 5. 5969 */ 5970 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) { 5971 $name = 'gradepointdefault'; 5972 $visiblename = get_string('gradepointdefault', 'grades'); 5973 $description = get_string('gradepointdefault_help', 'grades'); 5974 $defaultsetting = 100; 5975 $paramtype = PARAM_INT; 5976 $size = 5; 5977 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size); 5978 } 5979 5980 /** 5981 * Validate data before storage 5982 * @param string $data The submitted data 5983 * @return bool|string true if ok, string if error found 5984 */ 5985 public function validate($data) { 5986 global $CFG; 5987 if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) { 5988 return true; 5989 } else { 5990 return get_string('gradepointdefault_validateerror', 'grades'); 5991 } 5992 } 5993 } 5994 5995 5996 /** 5997 * A setting for setting the maximum grade value. Must be an integer between 1 and 10000. 5998 * 5999 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6000 */ 6001 class admin_setting_special_gradepointmax extends admin_setting_configtext { 6002 6003 /** 6004 * Config gradepointmax constructor 6005 * 6006 * @param string $name Overidden by "gradepointmax" 6007 * @param string $visiblename Overridden by "gradepointmax" language string. 6008 * @param string $description Overridden by "gradepointmax_help" language string. 6009 * @param string $defaultsetting Not used, overridden by 100. 6010 * @param mixed $paramtype Overridden by PARAM_INT. 6011 * @param int $size Overridden by 5. 6012 */ 6013 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) { 6014 $name = 'gradepointmax'; 6015 $visiblename = get_string('gradepointmax', 'grades'); 6016 $description = get_string('gradepointmax_help', 'grades'); 6017 $defaultsetting = 100; 6018 $paramtype = PARAM_INT; 6019 $size = 5; 6020 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size); 6021 } 6022 6023 /** 6024 * Save the selected setting 6025 * 6026 * @param string $data The selected site 6027 * @return string empty string or error message 6028 */ 6029 public function write_setting($data) { 6030 if ($data === '') { 6031 $data = (int)$this->defaultsetting; 6032 } else { 6033 $data = $data; 6034 } 6035 return parent::write_setting($data); 6036 } 6037 6038 /** 6039 * Validate data before storage 6040 * @param string $data The submitted data 6041 * @return bool|string true if ok, string if error found 6042 */ 6043 public function validate($data) { 6044 if (((string)(int)$data === (string)$data && $data > 0 && $data <= 10000)) { 6045 return true; 6046 } else { 6047 return get_string('gradepointmax_validateerror', 'grades'); 6048 } 6049 } 6050 6051 /** 6052 * Return an XHTML string for the setting 6053 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx 6054 * @param string $query search query to be highlighted 6055 * @return string XHTML to display control 6056 */ 6057 public function output_html($data, $query = '') { 6058 global $OUTPUT; 6059 6060 $default = $this->get_defaultsetting(); 6061 $context = (object) [ 6062 'size' => $this->size, 6063 'id' => $this->get_id(), 6064 'name' => $this->get_full_name(), 6065 'value' => $data, 6066 'attributes' => [ 6067 'maxlength' => 5 6068 ], 6069 'forceltr' => $this->get_force_ltr() 6070 ]; 6071 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context); 6072 6073 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); 6074 } 6075 } 6076 6077 6078 /** 6079 * Grade category settings 6080 * 6081 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6082 */ 6083 class admin_setting_gradecat_combo extends admin_setting { 6084 /** @var array Array of choices */ 6085 public $choices; 6086 6087 /** 6088 * Sets choices and calls parent::__construct with passed arguments 6089 * @param string $name 6090 * @param string $visiblename 6091 * @param string $description 6092 * @param mixed $defaultsetting string or array depending on implementation 6093 * @param array $choices An array of choices for the control 6094 */ 6095 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 6096 $this->choices = $choices; 6097 parent::__construct($name, $visiblename, $description, $defaultsetting); 6098 } 6099 6100 /** 6101 * Return the current setting(s) array 6102 * 6103 * @return array Array of value=>xx, forced=>xx, adv=>xx 6104 */ 6105 public function get_setting() { 6106 global $CFG; 6107 6108 $value = $this->config_read($this->name); 6109 $flag = $this->config_read($this->name.'_flag'); 6110 6111 if (is_null($value) or is_null($flag)) { 6112 return NULL; 6113 } 6114 6115 $flag = (int)$flag; 6116 $forced = (boolean)(1 & $flag); // first bit 6117 $adv = (boolean)(2 & $flag); // second bit 6118 6119 return array('value' => $value, 'forced' => $forced, 'adv' => $adv); 6120 } 6121 6122 /** 6123 * Save the new settings passed in $data 6124 * 6125 * @todo Add vartype handling to ensure $data is array 6126 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx 6127 * @return string empty or error message 6128 */ 6129 public function write_setting($data) { 6130 global $CFG; 6131 6132 $value = $data['value']; 6133 $forced = empty($data['forced']) ? 0 : 1; 6134 $adv = empty($data['adv']) ? 0 : 2; 6135 $flag = ($forced | $adv); //bitwise or 6136 6137 if (!in_array($value, array_keys($this->choices))) { 6138 return 'Error setting '; 6139 } 6140 6141 $oldvalue = $this->config_read($this->name); 6142 $oldflag = (int)$this->config_read($this->name.'_flag'); 6143 $oldforced = (1 & $oldflag); // first bit 6144 6145 $result1 = $this->config_write($this->name, $value); 6146 $result2 = $this->config_write($this->name.'_flag', $flag); 6147 6148 // force regrade if needed 6149 if ($oldforced != $forced or ($forced and $value != $oldvalue)) { 6150 require_once($CFG->libdir.'/gradelib.php'); 6151 grade_category::updated_forced_settings(); 6152 } 6153 6154 if ($result1 and $result2) { 6155 return ''; 6156 } else { 6157 return get_string('errorsetting', 'admin'); 6158 } 6159 } 6160 6161 /** 6162 * Return XHTML to display the field and wrapping div 6163 * 6164 * @todo Add vartype handling to ensure $data is array 6165 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx 6166 * @param string $query 6167 * @return string XHTML to display control 6168 */ 6169 public function output_html($data, $query='') { 6170 global $OUTPUT; 6171 6172 $value = $data['value']; 6173 6174 $default = $this->get_defaultsetting(); 6175 if (!is_null($default)) { 6176 $defaultinfo = array(); 6177 if (isset($this->choices[$default['value']])) { 6178 $defaultinfo[] = $this->choices[$default['value']]; 6179 } 6180 if (!empty($default['forced'])) { 6181 $defaultinfo[] = get_string('force'); 6182 } 6183 if (!empty($default['adv'])) { 6184 $defaultinfo[] = get_string('advanced'); 6185 } 6186 $defaultinfo = implode(', ', $defaultinfo); 6187 6188 } else { 6189 $defaultinfo = NULL; 6190 } 6191 6192 $options = $this->choices; 6193 $context = (object) [ 6194 'id' => $this->get_id(), 6195 'name' => $this->get_full_name(), 6196 'forced' => !empty($data['forced']), 6197 'advanced' => !empty($data['adv']), 6198 'options' => array_map(function($option) use ($options, $value) { 6199 return [ 6200 'value' => $option, 6201 'name' => $options[$option], 6202 'selected' => $option == $value 6203 ]; 6204 }, array_keys($options)), 6205 ]; 6206 6207 $element = $OUTPUT->render_from_template('core_admin/setting_gradecat_combo', $context); 6208 6209 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query); 6210 } 6211 } 6212 6213 6214 /** 6215 * Selection of grade report in user profiles 6216 * 6217 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6218 */ 6219 class admin_setting_grade_profilereport extends admin_setting_configselect { 6220 /** 6221 * Calls parent::__construct with specific arguments 6222 */ 6223 public function __construct() { 6224 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null); 6225 } 6226 6227 /** 6228 * Loads an array of choices for the configselect control 6229 * 6230 * @return bool always return true 6231 */ 6232 public function load_choices() { 6233 if (is_array($this->choices)) { 6234 return true; 6235 } 6236 $this->choices = array(); 6237 6238 global $CFG; 6239 require_once($CFG->libdir.'/gradelib.php'); 6240 6241 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) { 6242 if (file_exists($plugindir.'/lib.php')) { 6243 require_once($plugindir.'/lib.php'); 6244 $functionname = 'grade_report_'.$plugin.'_profilereport'; 6245 if (function_exists($functionname)) { 6246 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin); 6247 } 6248 } 6249 } 6250 return true; 6251 } 6252 } 6253 6254 /** 6255 * Provides a selection of grade reports to be used for "grades". 6256 * 6257 * @copyright 2015 Adrian Greeve <adrian@moodle.com> 6258 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6259 */ 6260 class admin_setting_my_grades_report extends admin_setting_configselect { 6261 6262 /** 6263 * Calls parent::__construct with specific arguments. 6264 */ 6265 public function __construct() { 6266 parent::__construct('grade_mygrades_report', new lang_string('mygrades', 'grades'), 6267 new lang_string('mygrades_desc', 'grades'), 'overview', null); 6268 } 6269 6270 /** 6271 * Loads an array of choices for the configselect control. 6272 * 6273 * @return bool always returns true. 6274 */ 6275 public function load_choices() { 6276 global $CFG; // Remove this line and behold the horror of behat test failures! 6277 $this->choices = array(); 6278 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) { 6279 if (file_exists($plugindir . '/lib.php')) { 6280 require_once($plugindir . '/lib.php'); 6281 // Check to see if the class exists. Check the correct plugin convention first. 6282 if (class_exists('gradereport_' . $plugin)) { 6283 $classname = 'gradereport_' . $plugin; 6284 } else if (class_exists('grade_report_' . $plugin)) { 6285 // We are using the old plugin naming convention. 6286 $classname = 'grade_report_' . $plugin; 6287 } else { 6288 continue; 6289 } 6290 if ($classname::supports_mygrades()) { 6291 $this->choices[$plugin] = get_string('pluginname', 'gradereport_' . $plugin); 6292 } 6293 } 6294 } 6295 // Add an option to specify an external url. 6296 $this->choices['external'] = get_string('externalurl', 'grades'); 6297 return true; 6298 } 6299 } 6300 6301 /** 6302 * Special class for register auth selection 6303 * 6304 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6305 */ 6306 class admin_setting_special_registerauth extends admin_setting_configselect { 6307 /** 6308 * Calls parent::__construct with specific arguments 6309 */ 6310 public function __construct() { 6311 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null); 6312 } 6313 6314 /** 6315 * Returns the default option 6316 * 6317 * @return string empty or default option 6318 */ 6319 public function get_defaultsetting() { 6320 $this->load_choices(); 6321 $defaultsetting = parent::get_defaultsetting(); 6322 if (array_key_exists($defaultsetting, $this->choices)) { 6323 return $defaultsetting; 6324 } else { 6325 return ''; 6326 } 6327 } 6328 6329 /** 6330 * Loads the possible choices for the array 6331 * 6332 * @return bool always returns true 6333 */ 6334 public function load_choices() { 6335 global $CFG; 6336 6337 if (is_array($this->choices)) { 6338 return true; 6339 } 6340 $this->choices = array(); 6341 $this->choices[''] = get_string('disable'); 6342 6343 $authsenabled = get_enabled_auth_plugins(); 6344 6345 foreach ($authsenabled as $auth) { 6346 $authplugin = get_auth_plugin($auth); 6347 if (!$authplugin->can_signup()) { 6348 continue; 6349 } 6350 // Get the auth title (from core or own auth lang files) 6351 $authtitle = $authplugin->get_title(); 6352 $this->choices[$auth] = $authtitle; 6353 } 6354 return true; 6355 } 6356 } 6357 6358 6359 /** 6360 * General plugins manager 6361 */ 6362 class admin_page_pluginsoverview extends admin_externalpage { 6363 6364 /** 6365 * Sets basic information about the external page 6366 */ 6367 public function __construct() { 6368 global $CFG; 6369 parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'), 6370 "$CFG->wwwroot/$CFG->admin/plugins.php"); 6371 } 6372 } 6373 6374 /** 6375 * Module manage page 6376 * 6377 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6378 */ 6379 class admin_page_managemods extends admin_externalpage { 6380 /** 6381 * Calls parent::__construct with specific arguments 6382 */ 6383 public function __construct() { 6384 global $CFG; 6385 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php"); 6386 } 6387 6388 /** 6389 * Try to find the specified module 6390 * 6391 * @param string $query The module to search for 6392 * @return array 6393 */ 6394 public function search($query) { 6395 global $CFG, $DB; 6396 if ($result = parent::search($query)) { 6397 return $result; 6398 } 6399 6400 $found = false; 6401 if ($modules = $DB->get_records('modules')) { 6402 foreach ($modules as $module) { 6403 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) { 6404 continue; 6405 } 6406 if (strpos($module->name, $query) !== false) { 6407 $found = true; 6408 break; 6409 } 6410 $strmodulename = get_string('modulename', $module->name); 6411 if (strpos(core_text::strtolower($strmodulename), $query) !== false) { 6412 $found = true; 6413 break; 6414 } 6415 } 6416 } 6417 if ($found) { 6418 $result = new stdClass(); 6419 $result->page = $this; 6420 $result->settings = array(); 6421 return array($this->name => $result); 6422 } else { 6423 return array(); 6424 } 6425 } 6426 } 6427 6428 6429 /** 6430 * Special class for enrol plugins management. 6431 * 6432 * @copyright 2010 Petr Skoda {@link http://skodak.org} 6433 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6434 */ 6435 class admin_setting_manageenrols extends admin_setting { 6436 /** 6437 * Calls parent::__construct with specific arguments 6438 */ 6439 public function __construct() { 6440 $this->nosave = true; 6441 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', ''); 6442 } 6443 6444 /** 6445 * Always returns true, does nothing 6446 * 6447 * @return true 6448 */ 6449 public function get_setting() { 6450 return true; 6451 } 6452 6453 /** 6454 * Always returns true, does nothing 6455 * 6456 * @return true 6457 */ 6458 public function get_defaultsetting() { 6459 return true; 6460 } 6461 6462 /** 6463 * Always returns '', does not write anything 6464 * 6465 * @return string Always returns '' 6466 */ 6467 public function write_setting($data) { 6468 // do not write any setting 6469 return ''; 6470 } 6471 6472 /** 6473 * Checks if $query is one of the available enrol plugins 6474 * 6475 * @param string $query The string to search for 6476 * @return bool Returns true if found, false if not 6477 */ 6478 public function is_related($query) { 6479 if (parent::is_related($query)) { 6480 return true; 6481 } 6482 6483 $query = core_text::strtolower($query); 6484 $enrols = enrol_get_plugins(false); 6485 foreach ($enrols as $name=>$enrol) { 6486 $localised = get_string('pluginname', 'enrol_'.$name); 6487 if (strpos(core_text::strtolower($name), $query) !== false) { 6488 return true; 6489 } 6490 if (strpos(core_text::strtolower($localised), $query) !== false) { 6491 return true; 6492 } 6493 } 6494 return false; 6495 } 6496 6497 /** 6498 * Builds the XHTML to display the control 6499 * 6500 * @param string $data Unused 6501 * @param string $query 6502 * @return string 6503 */ 6504 public function output_html($data, $query='') { 6505 global $CFG, $OUTPUT, $DB, $PAGE; 6506 6507 // Display strings. 6508 $strup = get_string('up'); 6509 $strdown = get_string('down'); 6510 $strsettings = get_string('settings'); 6511 $strenable = get_string('enable'); 6512 $strdisable = get_string('disable'); 6513 $struninstall = get_string('uninstallplugin', 'core_admin'); 6514 $strusage = get_string('enrolusage', 'enrol'); 6515 $strversion = get_string('version'); 6516 $strtest = get_string('testsettings', 'core_enrol'); 6517 6518 $pluginmanager = core_plugin_manager::instance(); 6519 6520 $enrols_available = enrol_get_plugins(false); 6521 $active_enrols = enrol_get_plugins(true); 6522 6523 $allenrols = array(); 6524 foreach ($active_enrols as $key=>$enrol) { 6525 $allenrols[$key] = true; 6526 } 6527 foreach ($enrols_available as $key=>$enrol) { 6528 $allenrols[$key] = true; 6529 } 6530 // Now find all borked plugins and at least allow then to uninstall. 6531 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}"); 6532 foreach ($condidates as $candidate) { 6533 if (empty($allenrols[$candidate])) { 6534 $allenrols[$candidate] = true; 6535 } 6536 } 6537 6538 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true); 6539 $return .= $OUTPUT->box_start('generalbox enrolsui'); 6540 6541 $table = new html_table(); 6542 $table->head = array(get_string('name'), $strusage, $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $strtest, $struninstall); 6543 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 6544 $table->id = 'courseenrolmentplugins'; 6545 $table->attributes['class'] = 'admintable generaltable'; 6546 $table->data = array(); 6547 6548 // Iterate through enrol plugins and add to the display table. 6549 $updowncount = 1; 6550 $enrolcount = count($active_enrols); 6551 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey())); 6552 $printed = array(); 6553 foreach($allenrols as $enrol => $unused) { 6554 $plugininfo = $pluginmanager->get_plugin_info('enrol_'.$enrol); 6555 $version = get_config('enrol_'.$enrol, 'version'); 6556 if ($version === false) { 6557 $version = ''; 6558 } 6559 6560 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) { 6561 $name = get_string('pluginname', 'enrol_'.$enrol); 6562 } else { 6563 $name = $enrol; 6564 } 6565 // Usage. 6566 $ci = $DB->count_records('enrol', array('enrol'=>$enrol)); 6567 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol)); 6568 $usage = "$ci / $cp"; 6569 6570 // Hide/show links. 6571 $class = ''; 6572 if (isset($active_enrols[$enrol])) { 6573 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol)); 6574 $hideshow = "<a href=\"$aurl\">"; 6575 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>'; 6576 $enabled = true; 6577 $displayname = $name; 6578 } else if (isset($enrols_available[$enrol])) { 6579 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol)); 6580 $hideshow = "<a href=\"$aurl\">"; 6581 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>'; 6582 $enabled = false; 6583 $displayname = $name; 6584 $class = 'dimmed_text'; 6585 } else { 6586 $hideshow = ''; 6587 $enabled = false; 6588 $displayname = '<span class="notifyproblem">'.$name.'</span>'; 6589 } 6590 if ($PAGE->theme->resolve_image_location('icon', 'enrol_' . $name, false)) { 6591 $icon = $OUTPUT->pix_icon('icon', '', 'enrol_' . $name, array('class' => 'icon pluginicon')); 6592 } else { 6593 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon')); 6594 } 6595 6596 // Up/down link (only if enrol is enabled). 6597 $updown = ''; 6598 if ($enabled) { 6599 if ($updowncount > 1) { 6600 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol)); 6601 $updown .= "<a href=\"$aurl\">"; 6602 $updown .= $OUTPUT->pix_icon('t/up', $strup) . '</a> '; 6603 } else { 6604 $updown .= $OUTPUT->spacer() . ' '; 6605 } 6606 if ($updowncount < $enrolcount) { 6607 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol)); 6608 $updown .= "<a href=\"$aurl\">"; 6609 $updown .= $OUTPUT->pix_icon('t/down', $strdown) . '</a> '; 6610 } else { 6611 $updown .= $OUTPUT->spacer() . ' '; 6612 } 6613 ++$updowncount; 6614 } 6615 6616 // Add settings link. 6617 if (!$version) { 6618 $settings = ''; 6619 } else if ($surl = $plugininfo->get_settings_url()) { 6620 $settings = html_writer::link($surl, $strsettings); 6621 } else { 6622 $settings = ''; 6623 } 6624 6625 // Add uninstall info. 6626 $uninstall = ''; 6627 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('enrol_'.$enrol, 'manage')) { 6628 $uninstall = html_writer::link($uninstallurl, $struninstall); 6629 } 6630 6631 $test = ''; 6632 if (!empty($enrols_available[$enrol]) and method_exists($enrols_available[$enrol], 'test_settings')) { 6633 $testsettingsurl = new moodle_url('/enrol/test_settings.php', array('enrol'=>$enrol, 'sesskey'=>sesskey())); 6634 $test = html_writer::link($testsettingsurl, $strtest); 6635 } 6636 6637 // Add a row to the table. 6638 $row = new html_table_row(array($icon.$displayname, $usage, $version, $hideshow, $updown, $settings, $test, $uninstall)); 6639 if ($class) { 6640 $row->attributes['class'] = $class; 6641 } 6642 $table->data[] = $row; 6643 6644 $printed[$enrol] = true; 6645 } 6646 6647 $return .= html_writer::table($table); 6648 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin'); 6649 $return .= $OUTPUT->box_end(); 6650 return highlight($query, $return); 6651 } 6652 } 6653 6654 6655 /** 6656 * Blocks manage page 6657 * 6658 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6659 */ 6660 class admin_page_manageblocks extends admin_externalpage { 6661 /** 6662 * Calls parent::__construct with specific arguments 6663 */ 6664 public function __construct() { 6665 global $CFG; 6666 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php"); 6667 } 6668 6669 /** 6670 * Search for a specific block 6671 * 6672 * @param string $query The string to search for 6673 * @return array 6674 */ 6675 public function search($query) { 6676 global $CFG, $DB; 6677 if ($result = parent::search($query)) { 6678 return $result; 6679 } 6680 6681 $found = false; 6682 if ($blocks = $DB->get_records('block')) { 6683 foreach ($blocks as $block) { 6684 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) { 6685 continue; 6686 } 6687 if (strpos($block->name, $query) !== false) { 6688 $found = true; 6689 break; 6690 } 6691 $strblockname = get_string('pluginname', 'block_'.$block->name); 6692 if (strpos(core_text::strtolower($strblockname), $query) !== false) { 6693 $found = true; 6694 break; 6695 } 6696 } 6697 } 6698 if ($found) { 6699 $result = new stdClass(); 6700 $result->page = $this; 6701 $result->settings = array(); 6702 return array($this->name => $result); 6703 } else { 6704 return array(); 6705 } 6706 } 6707 } 6708 6709 /** 6710 * Message outputs configuration 6711 * 6712 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6713 */ 6714 class admin_page_managemessageoutputs extends admin_externalpage { 6715 /** 6716 * Calls parent::__construct with specific arguments 6717 */ 6718 public function __construct() { 6719 global $CFG; 6720 parent::__construct('managemessageoutputs', 6721 get_string('defaultmessageoutputs', 'message'), 6722 new moodle_url('/admin/message.php') 6723 ); 6724 } 6725 6726 /** 6727 * Search for a specific message processor 6728 * 6729 * @param string $query The string to search for 6730 * @return array 6731 */ 6732 public function search($query) { 6733 global $CFG, $DB; 6734 if ($result = parent::search($query)) { 6735 return $result; 6736 } 6737 6738 $found = false; 6739 if ($processors = get_message_processors()) { 6740 foreach ($processors as $processor) { 6741 if (!$processor->available) { 6742 continue; 6743 } 6744 if (strpos($processor->name, $query) !== false) { 6745 $found = true; 6746 break; 6747 } 6748 $strprocessorname = get_string('pluginname', 'message_'.$processor->name); 6749 if (strpos(core_text::strtolower($strprocessorname), $query) !== false) { 6750 $found = true; 6751 break; 6752 } 6753 } 6754 } 6755 if ($found) { 6756 $result = new stdClass(); 6757 $result->page = $this; 6758 $result->settings = array(); 6759 return array($this->name => $result); 6760 } else { 6761 return array(); 6762 } 6763 } 6764 } 6765 6766 /** 6767 * Manage question behaviours page 6768 * 6769 * @copyright 2011 The Open University 6770 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6771 */ 6772 class admin_page_manageqbehaviours extends admin_externalpage { 6773 /** 6774 * Constructor 6775 */ 6776 public function __construct() { 6777 global $CFG; 6778 parent::__construct('manageqbehaviours', get_string('manageqbehaviours', 'admin'), 6779 new moodle_url('/admin/qbehaviours.php')); 6780 } 6781 6782 /** 6783 * Search question behaviours for the specified string 6784 * 6785 * @param string $query The string to search for in question behaviours 6786 * @return array 6787 */ 6788 public function search($query) { 6789 global $CFG; 6790 if ($result = parent::search($query)) { 6791 return $result; 6792 } 6793 6794 $found = false; 6795 require_once($CFG->dirroot . '/question/engine/lib.php'); 6796 foreach (core_component::get_plugin_list('qbehaviour') as $behaviour => $notused) { 6797 if (strpos(core_text::strtolower(question_engine::get_behaviour_name($behaviour)), 6798 $query) !== false) { 6799 $found = true; 6800 break; 6801 } 6802 } 6803 if ($found) { 6804 $result = new stdClass(); 6805 $result->page = $this; 6806 $result->settings = array(); 6807 return array($this->name => $result); 6808 } else { 6809 return array(); 6810 } 6811 } 6812 } 6813 6814 6815 /** 6816 * Question type manage page 6817 * 6818 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6819 */ 6820 class admin_page_manageqtypes extends admin_externalpage { 6821 /** 6822 * Calls parent::__construct with specific arguments 6823 */ 6824 public function __construct() { 6825 global $CFG; 6826 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'), 6827 new moodle_url('/admin/qtypes.php')); 6828 } 6829 6830 /** 6831 * Search question types for the specified string 6832 * 6833 * @param string $query The string to search for in question types 6834 * @return array 6835 */ 6836 public function search($query) { 6837 global $CFG; 6838 if ($result = parent::search($query)) { 6839 return $result; 6840 } 6841 6842 $found = false; 6843 require_once($CFG->dirroot . '/question/engine/bank.php'); 6844 foreach (question_bank::get_all_qtypes() as $qtype) { 6845 if (strpos(core_text::strtolower($qtype->local_name()), $query) !== false) { 6846 $found = true; 6847 break; 6848 } 6849 } 6850 if ($found) { 6851 $result = new stdClass(); 6852 $result->page = $this; 6853 $result->settings = array(); 6854 return array($this->name => $result); 6855 } else { 6856 return array(); 6857 } 6858 } 6859 } 6860 6861 6862 class admin_page_manageportfolios extends admin_externalpage { 6863 /** 6864 * Calls parent::__construct with specific arguments 6865 */ 6866 public function __construct() { 6867 global $CFG; 6868 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'), 6869 "$CFG->wwwroot/$CFG->admin/portfolio.php"); 6870 } 6871 6872 /** 6873 * Searches page for the specified string. 6874 * @param string $query The string to search for 6875 * @return bool True if it is found on this page 6876 */ 6877 public function search($query) { 6878 global $CFG; 6879 if ($result = parent::search($query)) { 6880 return $result; 6881 } 6882 6883 $found = false; 6884 $portfolios = core_component::get_plugin_list('portfolio'); 6885 foreach ($portfolios as $p => $dir) { 6886 if (strpos($p, $query) !== false) { 6887 $found = true; 6888 break; 6889 } 6890 } 6891 if (!$found) { 6892 foreach (portfolio_instances(false, false) as $instance) { 6893 $title = $instance->get('name'); 6894 if (strpos(core_text::strtolower($title), $query) !== false) { 6895 $found = true; 6896 break; 6897 } 6898 } 6899 } 6900 6901 if ($found) { 6902 $result = new stdClass(); 6903 $result->page = $this; 6904 $result->settings = array(); 6905 return array($this->name => $result); 6906 } else { 6907 return array(); 6908 } 6909 } 6910 } 6911 6912 6913 class admin_page_managerepositories extends admin_externalpage { 6914 /** 6915 * Calls parent::__construct with specific arguments 6916 */ 6917 public function __construct() { 6918 global $CFG; 6919 parent::__construct('managerepositories', get_string('manage', 6920 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php"); 6921 } 6922 6923 /** 6924 * Searches page for the specified string. 6925 * @param string $query The string to search for 6926 * @return bool True if it is found on this page 6927 */ 6928 public function search($query) { 6929 global $CFG; 6930 if ($result = parent::search($query)) { 6931 return $result; 6932 } 6933 6934 $found = false; 6935 $repositories= core_component::get_plugin_list('repository'); 6936 foreach ($repositories as $p => $dir) { 6937 if (strpos($p, $query) !== false) { 6938 $found = true; 6939 break; 6940 } 6941 } 6942 if (!$found) { 6943 foreach (repository::get_types() as $instance) { 6944 $title = $instance->get_typename(); 6945 if (strpos(core_text::strtolower($title), $query) !== false) { 6946 $found = true; 6947 break; 6948 } 6949 } 6950 } 6951 6952 if ($found) { 6953 $result = new stdClass(); 6954 $result->page = $this; 6955 $result->settings = array(); 6956 return array($this->name => $result); 6957 } else { 6958 return array(); 6959 } 6960 } 6961 } 6962 6963 6964 /** 6965 * Special class for authentication administration. 6966 * 6967 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6968 */ 6969 class admin_setting_manageauths extends admin_setting { 6970 /** 6971 * Calls parent::__construct with specific arguments 6972 */ 6973 public function __construct() { 6974 $this->nosave = true; 6975 parent::__construct('authsui', get_string('authsettings', 'admin'), '', ''); 6976 } 6977 6978 /** 6979 * Always returns true 6980 * 6981 * @return true 6982 */ 6983 public function get_setting() { 6984 return true; 6985 } 6986 6987 /** 6988 * Always returns true 6989 * 6990 * @return true 6991 */ 6992 public function get_defaultsetting() { 6993 return true; 6994 } 6995 6996 /** 6997 * Always returns '' and doesn't write anything 6998 * 6999 * @return string Always returns '' 7000 */ 7001 public function write_setting($data) { 7002 // do not write any setting 7003 return ''; 7004 } 7005 7006 /** 7007 * Search to find if Query is related to auth plugin 7008 * 7009 * @param string $query The string to search for 7010 * @return bool true for related false for not 7011 */ 7012 public function is_related($query) { 7013 if (parent::is_related($query)) { 7014 return true; 7015 } 7016 7017 $authsavailable = core_component::get_plugin_list('auth'); 7018 foreach ($authsavailable as $auth => $dir) { 7019 if (strpos($auth, $query) !== false) { 7020 return true; 7021 } 7022 $authplugin = get_auth_plugin($auth); 7023 $authtitle = $authplugin->get_title(); 7024 if (strpos(core_text::strtolower($authtitle), $query) !== false) { 7025 return true; 7026 } 7027 } 7028 return false; 7029 } 7030 7031 /** 7032 * Return XHTML to display control 7033 * 7034 * @param mixed $data Unused 7035 * @param string $query 7036 * @return string highlight 7037 */ 7038 public function output_html($data, $query='') { 7039 global $CFG, $OUTPUT, $DB; 7040 7041 // display strings 7042 $txt = get_strings(array('authenticationplugins', 'users', 'administration', 7043 'settings', 'edit', 'name', 'enable', 'disable', 7044 'up', 'down', 'none', 'users')); 7045 $txt->updown = "$txt->up/$txt->down"; 7046 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 7047 $txt->testsettings = get_string('testsettings', 'core_auth'); 7048 7049 $authsavailable = core_component::get_plugin_list('auth'); 7050 get_enabled_auth_plugins(true); // fix the list of enabled auths 7051 if (empty($CFG->auth)) { 7052 $authsenabled = array(); 7053 } else { 7054 $authsenabled = explode(',', $CFG->auth); 7055 } 7056 7057 // construct the display array, with enabled auth plugins at the top, in order 7058 $displayauths = array(); 7059 $registrationauths = array(); 7060 $registrationauths[''] = $txt->disable; 7061 $authplugins = array(); 7062 foreach ($authsenabled as $auth) { 7063 $authplugin = get_auth_plugin($auth); 7064 $authplugins[$auth] = $authplugin; 7065 /// Get the auth title (from core or own auth lang files) 7066 $authtitle = $authplugin->get_title(); 7067 /// Apply titles 7068 $displayauths[$auth] = $authtitle; 7069 if ($authplugin->can_signup()) { 7070 $registrationauths[$auth] = $authtitle; 7071 } 7072 } 7073 7074 foreach ($authsavailable as $auth => $dir) { 7075 if (array_key_exists($auth, $displayauths)) { 7076 continue; //already in the list 7077 } 7078 $authplugin = get_auth_plugin($auth); 7079 $authplugins[$auth] = $authplugin; 7080 /// Get the auth title (from core or own auth lang files) 7081 $authtitle = $authplugin->get_title(); 7082 /// Apply titles 7083 $displayauths[$auth] = $authtitle; 7084 if ($authplugin->can_signup()) { 7085 $registrationauths[$auth] = $authtitle; 7086 } 7087 } 7088 7089 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main'); 7090 $return .= $OUTPUT->box_start('generalbox authsui'); 7091 7092 $table = new html_table(); 7093 $table->head = array($txt->name, $txt->users, $txt->enable, $txt->updown, $txt->settings, $txt->testsettings, $txt->uninstall); 7094 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 7095 $table->data = array(); 7096 $table->attributes['class'] = 'admintable generaltable'; 7097 $table->id = 'manageauthtable'; 7098 7099 //add always enabled plugins first 7100 $displayname = $displayauths['manual']; 7101 $settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>"; 7102 $usercount = $DB->count_records('user', array('auth'=>'manual', 'deleted'=>0)); 7103 $table->data[] = array($displayname, $usercount, '', '', $settings, '', ''); 7104 $displayname = $displayauths['nologin']; 7105 $usercount = $DB->count_records('user', array('auth'=>'nologin', 'deleted'=>0)); 7106 $table->data[] = array($displayname, $usercount, '', '', '', '', ''); 7107 7108 7109 // iterate through auth plugins and add to the display table 7110 $updowncount = 1; 7111 $authcount = count($authsenabled); 7112 $url = "auth.php?sesskey=" . sesskey(); 7113 foreach ($displayauths as $auth => $name) { 7114 if ($auth == 'manual' or $auth == 'nologin') { 7115 continue; 7116 } 7117 $class = ''; 7118 // hide/show link 7119 if (in_array($auth, $authsenabled)) { 7120 $hideshow = "<a href=\"$url&action=disable&auth=$auth\">"; 7121 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>'; 7122 $enabled = true; 7123 $displayname = $name; 7124 } 7125 else { 7126 $hideshow = "<a href=\"$url&action=enable&auth=$auth\">"; 7127 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>'; 7128 $enabled = false; 7129 $displayname = $name; 7130 $class = 'dimmed_text'; 7131 } 7132 7133 $usercount = $DB->count_records('user', array('auth'=>$auth, 'deleted'=>0)); 7134 7135 // up/down link (only if auth is enabled) 7136 $updown = ''; 7137 if ($enabled) { 7138 if ($updowncount > 1) { 7139 $updown .= "<a href=\"$url&action=up&auth=$auth\">"; 7140 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a> '; 7141 } 7142 else { 7143 $updown .= $OUTPUT->spacer() . ' '; 7144 } 7145 if ($updowncount < $authcount) { 7146 $updown .= "<a href=\"$url&action=down&auth=$auth\">"; 7147 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a> '; 7148 } 7149 else { 7150 $updown .= $OUTPUT->spacer() . ' '; 7151 } 7152 ++ $updowncount; 7153 } 7154 7155 // settings link 7156 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) { 7157 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>"; 7158 } else if (file_exists($CFG->dirroot.'/auth/'.$auth.'/config.html')) { 7159 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>"; 7160 } else { 7161 $settings = ''; 7162 } 7163 7164 // Uninstall link. 7165 $uninstall = ''; 7166 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('auth_'.$auth, 'manage')) { 7167 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 7168 } 7169 7170 $test = ''; 7171 if (!empty($authplugins[$auth]) and method_exists($authplugins[$auth], 'test_settings')) { 7172 $testurl = new moodle_url('/auth/test_settings.php', array('auth'=>$auth, 'sesskey'=>sesskey())); 7173 $test = html_writer::link($testurl, $txt->testsettings); 7174 } 7175 7176 // Add a row to the table. 7177 $row = new html_table_row(array($displayname, $usercount, $hideshow, $updown, $settings, $test, $uninstall)); 7178 if ($class) { 7179 $row->attributes['class'] = $class; 7180 } 7181 $table->data[] = $row; 7182 } 7183 $return .= html_writer::table($table); 7184 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters'); 7185 $return .= $OUTPUT->box_end(); 7186 return highlight($query, $return); 7187 } 7188 } 7189 7190 7191 /** 7192 * Special class for authentication administration. 7193 * 7194 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7195 */ 7196 class admin_setting_manageeditors extends admin_setting { 7197 /** 7198 * Calls parent::__construct with specific arguments 7199 */ 7200 public function __construct() { 7201 $this->nosave = true; 7202 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', ''); 7203 } 7204 7205 /** 7206 * Always returns true, does nothing 7207 * 7208 * @return true 7209 */ 7210 public function get_setting() { 7211 return true; 7212 } 7213 7214 /** 7215 * Always returns true, does nothing 7216 * 7217 * @return true 7218 */ 7219 public function get_defaultsetting() { 7220 return true; 7221 } 7222 7223 /** 7224 * Always returns '', does not write anything 7225 * 7226 * @return string Always returns '' 7227 */ 7228 public function write_setting($data) { 7229 // do not write any setting 7230 return ''; 7231 } 7232 7233 /** 7234 * Checks if $query is one of the available editors 7235 * 7236 * @param string $query The string to search for 7237 * @return bool Returns true if found, false if not 7238 */ 7239 public function is_related($query) { 7240 if (parent::is_related($query)) { 7241 return true; 7242 } 7243 7244 $editors_available = editors_get_available(); 7245 foreach ($editors_available as $editor=>$editorstr) { 7246 if (strpos($editor, $query) !== false) { 7247 return true; 7248 } 7249 if (strpos(core_text::strtolower($editorstr), $query) !== false) { 7250 return true; 7251 } 7252 } 7253 return false; 7254 } 7255 7256 /** 7257 * Builds the XHTML to display the control 7258 * 7259 * @param string $data Unused 7260 * @param string $query 7261 * @return string 7262 */ 7263 public function output_html($data, $query='') { 7264 global $CFG, $OUTPUT; 7265 7266 // display strings 7267 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable', 7268 'up', 'down', 'none')); 7269 $struninstall = get_string('uninstallplugin', 'core_admin'); 7270 7271 $txt->updown = "$txt->up/$txt->down"; 7272 7273 $editors_available = editors_get_available(); 7274 $active_editors = explode(',', $CFG->texteditors); 7275 7276 $active_editors = array_reverse($active_editors); 7277 foreach ($active_editors as $key=>$editor) { 7278 if (empty($editors_available[$editor])) { 7279 unset($active_editors[$key]); 7280 } else { 7281 $name = $editors_available[$editor]; 7282 unset($editors_available[$editor]); 7283 $editors_available[$editor] = $name; 7284 } 7285 } 7286 if (empty($active_editors)) { 7287 //$active_editors = array('textarea'); 7288 } 7289 $editors_available = array_reverse($editors_available, true); 7290 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true); 7291 $return .= $OUTPUT->box_start('generalbox editorsui'); 7292 7293 $table = new html_table(); 7294 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall); 7295 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 7296 $table->id = 'editormanagement'; 7297 $table->attributes['class'] = 'admintable generaltable'; 7298 $table->data = array(); 7299 7300 // iterate through auth plugins and add to the display table 7301 $updowncount = 1; 7302 $editorcount = count($active_editors); 7303 $url = "editors.php?sesskey=" . sesskey(); 7304 foreach ($editors_available as $editor => $name) { 7305 // hide/show link 7306 $class = ''; 7307 if (in_array($editor, $active_editors)) { 7308 $hideshow = "<a href=\"$url&action=disable&editor=$editor\">"; 7309 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>'; 7310 $enabled = true; 7311 $displayname = $name; 7312 } 7313 else { 7314 $hideshow = "<a href=\"$url&action=enable&editor=$editor\">"; 7315 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>'; 7316 $enabled = false; 7317 $displayname = $name; 7318 $class = 'dimmed_text'; 7319 } 7320 7321 // up/down link (only if auth is enabled) 7322 $updown = ''; 7323 if ($enabled) { 7324 if ($updowncount > 1) { 7325 $updown .= "<a href=\"$url&action=up&editor=$editor\">"; 7326 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a> '; 7327 } 7328 else { 7329 $updown .= $OUTPUT->spacer() . ' '; 7330 } 7331 if ($updowncount < $editorcount) { 7332 $updown .= "<a href=\"$url&action=down&editor=$editor\">"; 7333 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a> '; 7334 } 7335 else { 7336 $updown .= $OUTPUT->spacer() . ' '; 7337 } 7338 ++ $updowncount; 7339 } 7340 7341 // settings link 7342 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) { 7343 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor)); 7344 $settings = "<a href='$eurl'>{$txt->settings}</a>"; 7345 } else { 7346 $settings = ''; 7347 } 7348 7349 $uninstall = ''; 7350 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('editor_'.$editor, 'manage')) { 7351 $uninstall = html_writer::link($uninstallurl, $struninstall); 7352 } 7353 7354 // Add a row to the table. 7355 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall)); 7356 if ($class) { 7357 $row->attributes['class'] = $class; 7358 } 7359 $table->data[] = $row; 7360 } 7361 $return .= html_writer::table($table); 7362 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin'); 7363 $return .= $OUTPUT->box_end(); 7364 return highlight($query, $return); 7365 } 7366 } 7367 7368 /** 7369 * Special class for antiviruses administration. 7370 * 7371 * @copyright 2015 Ruslan Kabalin, Lancaster University. 7372 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7373 */ 7374 class admin_setting_manageantiviruses extends admin_setting { 7375 /** 7376 * Calls parent::__construct with specific arguments 7377 */ 7378 public function __construct() { 7379 $this->nosave = true; 7380 parent::__construct('antivirusesui', get_string('antivirussettings', 'antivirus'), '', ''); 7381 } 7382 7383 /** 7384 * Always returns true, does nothing 7385 * 7386 * @return true 7387 */ 7388 public function get_setting() { 7389 return true; 7390 } 7391 7392 /** 7393 * Always returns true, does nothing 7394 * 7395 * @return true 7396 */ 7397 public function get_defaultsetting() { 7398 return true; 7399 } 7400 7401 /** 7402 * Always returns '', does not write anything 7403 * 7404 * @param string $data Unused 7405 * @return string Always returns '' 7406 */ 7407 public function write_setting($data) { 7408 // Do not write any setting. 7409 return ''; 7410 } 7411 7412 /** 7413 * Checks if $query is one of the available editors 7414 * 7415 * @param string $query The string to search for 7416 * @return bool Returns true if found, false if not 7417 */ 7418 public function is_related($query) { 7419 if (parent::is_related($query)) { 7420 return true; 7421 } 7422 7423 $antivirusesavailable = \core\antivirus\manager::get_available(); 7424 foreach ($antivirusesavailable as $antivirus => $antivirusstr) { 7425 if (strpos($antivirus, $query) !== false) { 7426 return true; 7427 } 7428 if (strpos(core_text::strtolower($antivirusstr), $query) !== false) { 7429 return true; 7430 } 7431 } 7432 return false; 7433 } 7434 7435 /** 7436 * Builds the XHTML to display the control 7437 * 7438 * @param string $data Unused 7439 * @param string $query 7440 * @return string 7441 */ 7442 public function output_html($data, $query='') { 7443 global $CFG, $OUTPUT; 7444 7445 // Display strings. 7446 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable', 7447 'up', 'down', 'none')); 7448 $struninstall = get_string('uninstallplugin', 'core_admin'); 7449 7450 $txt->updown = "$txt->up/$txt->down"; 7451 7452 $antivirusesavailable = \core\antivirus\manager::get_available(); 7453 $activeantiviruses = explode(',', $CFG->antiviruses); 7454 7455 $activeantiviruses = array_reverse($activeantiviruses); 7456 foreach ($activeantiviruses as $key => $antivirus) { 7457 if (empty($antivirusesavailable[$antivirus])) { 7458 unset($activeantiviruses[$key]); 7459 } else { 7460 $name = $antivirusesavailable[$antivirus]; 7461 unset($antivirusesavailable[$antivirus]); 7462 $antivirusesavailable[$antivirus] = $name; 7463 } 7464 } 7465 $antivirusesavailable = array_reverse($antivirusesavailable, true); 7466 $return = $OUTPUT->heading(get_string('actantivirushdr', 'antivirus'), 3, 'main', true); 7467 $return .= $OUTPUT->box_start('generalbox antivirusesui'); 7468 7469 $table = new html_table(); 7470 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall); 7471 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 7472 $table->id = 'antivirusmanagement'; 7473 $table->attributes['class'] = 'admintable generaltable'; 7474 $table->data = array(); 7475 7476 // Iterate through auth plugins and add to the display table. 7477 $updowncount = 1; 7478 $antiviruscount = count($activeantiviruses); 7479 $baseurl = new moodle_url('/admin/antiviruses.php', array('sesskey' => sesskey())); 7480 foreach ($antivirusesavailable as $antivirus => $name) { 7481 // Hide/show link. 7482 $class = ''; 7483 if (in_array($antivirus, $activeantiviruses)) { 7484 $hideshowurl = $baseurl; 7485 $hideshowurl->params(array('action' => 'disable', 'antivirus' => $antivirus)); 7486 $hideshowimg = $OUTPUT->pix_icon('t/hide', get_string('disable')); 7487 $hideshow = html_writer::link($hideshowurl, $hideshowimg); 7488 $enabled = true; 7489 $displayname = $name; 7490 } else { 7491 $hideshowurl = $baseurl; 7492 $hideshowurl->params(array('action' => 'enable', 'antivirus' => $antivirus)); 7493 $hideshowimg = $OUTPUT->pix_icon('t/show', get_string('enable')); 7494 $hideshow = html_writer::link($hideshowurl, $hideshowimg); 7495 $enabled = false; 7496 $displayname = $name; 7497 $class = 'dimmed_text'; 7498 } 7499 7500 // Up/down link. 7501 $updown = ''; 7502 if ($enabled) { 7503 if ($updowncount > 1) { 7504 $updownurl = $baseurl; 7505 $updownurl->params(array('action' => 'up', 'antivirus' => $antivirus)); 7506 $updownimg = $OUTPUT->pix_icon('t/up', get_string('moveup')); 7507 $updown = html_writer::link($updownurl, $updownimg); 7508 } else { 7509 $updownimg = $OUTPUT->spacer(); 7510 } 7511 if ($updowncount < $antiviruscount) { 7512 $updownurl = $baseurl; 7513 $updownurl->params(array('action' => 'down', 'antivirus' => $antivirus)); 7514 $updownimg = $OUTPUT->pix_icon('t/down', get_string('movedown')); 7515 $updown = html_writer::link($updownurl, $updownimg); 7516 } else { 7517 $updownimg = $OUTPUT->spacer(); 7518 } 7519 ++ $updowncount; 7520 } 7521 7522 // Settings link. 7523 if (file_exists($CFG->dirroot.'/lib/antivirus/'.$antivirus.'/settings.php')) { 7524 $eurl = new moodle_url('/admin/settings.php', array('section' => 'antivirussettings'.$antivirus)); 7525 $settings = html_writer::link($eurl, $txt->settings); 7526 } else { 7527 $settings = ''; 7528 } 7529 7530 $uninstall = ''; 7531 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('antivirus_'.$antivirus, 'manage')) { 7532 $uninstall = html_writer::link($uninstallurl, $struninstall); 7533 } 7534 7535 // Add a row to the table. 7536 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall)); 7537 if ($class) { 7538 $row->attributes['class'] = $class; 7539 } 7540 $table->data[] = $row; 7541 } 7542 $return .= html_writer::table($table); 7543 $return .= get_string('configantivirusplugins', 'antivirus') . html_writer::empty_tag('br') . get_string('tablenosave', 'admin'); 7544 $return .= $OUTPUT->box_end(); 7545 return highlight($query, $return); 7546 } 7547 } 7548 7549 /** 7550 * Special class for license administration. 7551 * 7552 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7553 * @deprecated since Moodle 3.9 MDL-45184. Please use \tool_licensemanager\manager instead. 7554 * @todo MDL-45184 This class will be deleted in Moodle 4.1. 7555 */ 7556 class admin_setting_managelicenses extends admin_setting { 7557 /** 7558 * @deprecated since Moodle 3.9 MDL-45184. Please use \tool_licensemanager\manager instead. 7559 * @todo MDL-45184 This class will be deleted in Moodle 4.1 7560 */ 7561 public function __construct() { 7562 global $ADMIN; 7563 7564 debugging('admin_setting_managelicenses class is deprecated. Please use \tool_licensemanager\manager instead.', 7565 DEBUG_DEVELOPER); 7566 7567 // Replace admin setting load with new external page load for tool_licensemanager, if not loaded already. 7568 if (!is_null($ADMIN->locate('licensemanager'))) { 7569 $temp = new admin_externalpage('licensemanager', 7570 get_string('licensemanager', 'tool_licensemanager'), 7571 \tool_licensemanager\helper::get_licensemanager_url()); 7572 7573 $ADMIN->add('license', $temp); 7574 } 7575 } 7576 7577 /** 7578 * Always returns true, does nothing 7579 * 7580 * @deprecated since Moodle 3.9 MDL-45184. 7581 * @todo MDL-45184 This method will be deleted in Moodle 4.1 7582 * 7583 * @return true 7584 */ 7585 public function get_setting() { 7586 debugging('admin_setting_managelicenses class is deprecated. Please use \tool_licensemanager\manager instead.', 7587 DEBUG_DEVELOPER); 7588 7589 return true; 7590 } 7591 7592 /** 7593 * Always returns true, does nothing 7594 * 7595 * @deprecated since Moodle 3.9 MDL-45184. 7596 * @todo MDL-45184 This method will be deleted in Moodle 4.1 7597 * 7598 * @return true 7599 */ 7600 public function get_defaultsetting() { 7601 debugging('admin_setting_managelicenses class is deprecated. Please use \tool_licensemanager\manager instead.', 7602 DEBUG_DEVELOPER); 7603 7604 return true; 7605 } 7606 7607 /** 7608 * Always returns '', does not write anything 7609 * 7610 * @deprecated since Moodle 3.9 MDL-45184. 7611 * @todo MDL-45184 This method will be deleted in Moodle 4.1 7612 * 7613 * @return string Always returns '' 7614 */ 7615 public function write_setting($data) { 7616 debugging('admin_setting_managelicenses class is deprecated. Please use \tool_licensemanager\manager instead.', 7617 DEBUG_DEVELOPER); 7618 7619 // do not write any setting 7620 return ''; 7621 } 7622 7623 /** 7624 * Builds the XHTML to display the control 7625 * 7626 * @deprecated since Moodle 3.9 MDL-45184. Please use \tool_licensemanager\manager instead. 7627 * @todo MDL-45184 This method will be deleted in Moodle 4.1 7628 * 7629 * @param string $data Unused 7630 * @param string $query 7631 * @return string 7632 */ 7633 public function output_html($data, $query='') { 7634 debugging('admin_setting_managelicenses class is deprecated. Please use \tool_licensemanager\manager instead.', 7635 DEBUG_DEVELOPER); 7636 7637 redirect(\tool_licensemanager\helper::get_licensemanager_url()); 7638 } 7639 } 7640 7641 /** 7642 * Course formats manager. Allows to enable/disable formats and jump to settings 7643 */ 7644 class admin_setting_manageformats extends admin_setting { 7645 7646 /** 7647 * Calls parent::__construct with specific arguments 7648 */ 7649 public function __construct() { 7650 $this->nosave = true; 7651 parent::__construct('formatsui', new lang_string('manageformats', 'core_admin'), '', ''); 7652 } 7653 7654 /** 7655 * Always returns true 7656 * 7657 * @return true 7658 */ 7659 public function get_setting() { 7660 return true; 7661 } 7662 7663 /** 7664 * Always returns true 7665 * 7666 * @return true 7667 */ 7668 public function get_defaultsetting() { 7669 return true; 7670 } 7671 7672 /** 7673 * Always returns '' and doesn't write anything 7674 * 7675 * @param mixed $data string or array, must not be NULL 7676 * @return string Always returns '' 7677 */ 7678 public function write_setting($data) { 7679 // do not write any setting 7680 return ''; 7681 } 7682 7683 /** 7684 * Search to find if Query is related to format plugin 7685 * 7686 * @param string $query The string to search for 7687 * @return bool true for related false for not 7688 */ 7689 public function is_related($query) { 7690 if (parent::is_related($query)) { 7691 return true; 7692 } 7693 $formats = core_plugin_manager::instance()->get_plugins_of_type('format'); 7694 foreach ($formats as $format) { 7695 if (strpos($format->component, $query) !== false || 7696 strpos(core_text::strtolower($format->displayname), $query) !== false) { 7697 return true; 7698 } 7699 } 7700 return false; 7701 } 7702 7703 /** 7704 * Return XHTML to display control 7705 * 7706 * @param mixed $data Unused 7707 * @param string $query 7708 * @return string highlight 7709 */ 7710 public function output_html($data, $query='') { 7711 global $CFG, $OUTPUT; 7712 $return = ''; 7713 $return = $OUTPUT->heading(new lang_string('courseformats'), 3, 'main'); 7714 $return .= $OUTPUT->box_start('generalbox formatsui'); 7715 7716 $formats = core_plugin_manager::instance()->get_plugins_of_type('format'); 7717 7718 // display strings 7719 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default')); 7720 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 7721 $txt->updown = "$txt->up/$txt->down"; 7722 7723 $table = new html_table(); 7724 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings); 7725 $table->align = array('left', 'center', 'center', 'center', 'center'); 7726 $table->attributes['class'] = 'manageformattable generaltable admintable'; 7727 $table->data = array(); 7728 7729 $cnt = 0; 7730 $defaultformat = get_config('moodlecourse', 'format'); 7731 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 7732 foreach ($formats as $format) { 7733 $url = new moodle_url('/admin/courseformats.php', 7734 array('sesskey' => sesskey(), 'format' => $format->name)); 7735 $isdefault = ''; 7736 $class = ''; 7737 if ($format->is_enabled()) { 7738 $strformatname = $format->displayname; 7739 if ($defaultformat === $format->name) { 7740 $hideshow = $txt->default; 7741 } else { 7742 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')), 7743 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall'))); 7744 } 7745 } else { 7746 $strformatname = $format->displayname; 7747 $class = 'dimmed_text'; 7748 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')), 7749 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall'))); 7750 } 7751 $updown = ''; 7752 if ($cnt) { 7753 $updown .= html_writer::link($url->out(false, array('action' => 'up')), 7754 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). ''; 7755 } else { 7756 $updown .= $spacer; 7757 } 7758 if ($cnt < count($formats) - 1) { 7759 $updown .= ' '.html_writer::link($url->out(false, array('action' => 'down')), 7760 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall'))); 7761 } else { 7762 $updown .= $spacer; 7763 } 7764 $cnt++; 7765 $settings = ''; 7766 if ($format->get_settings_url()) { 7767 $settings = html_writer::link($format->get_settings_url(), $txt->settings); 7768 } 7769 $uninstall = ''; 7770 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('format_'.$format->name, 'manage')) { 7771 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 7772 } 7773 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings)); 7774 if ($class) { 7775 $row->attributes['class'] = $class; 7776 } 7777 $table->data[] = $row; 7778 } 7779 $return .= html_writer::table($table); 7780 $link = html_writer::link(new moodle_url('/admin/settings.php', array('section' => 'coursesettings')), new lang_string('coursesettings')); 7781 $return .= html_writer::tag('p', get_string('manageformatsgotosettings', 'admin', $link)); 7782 $return .= $OUTPUT->box_end(); 7783 return highlight($query, $return); 7784 } 7785 } 7786 7787 /** 7788 * Custom fields manager. Allows to enable/disable custom fields and jump to settings. 7789 * 7790 * @package core 7791 * @copyright 2018 Toni Barbera 7792 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7793 */ 7794 class admin_setting_managecustomfields extends admin_setting { 7795 7796 /** 7797 * Calls parent::__construct with specific arguments 7798 */ 7799 public function __construct() { 7800 $this->nosave = true; 7801 parent::__construct('customfieldsui', new lang_string('managecustomfields', 'core_admin'), '', ''); 7802 } 7803 7804 /** 7805 * Always returns true 7806 * 7807 * @return true 7808 */ 7809 public function get_setting() { 7810 return true; 7811 } 7812 7813 /** 7814 * Always returns true 7815 * 7816 * @return true 7817 */ 7818 public function get_defaultsetting() { 7819 return true; 7820 } 7821 7822 /** 7823 * Always returns '' and doesn't write anything 7824 * 7825 * @param mixed $data string or array, must not be NULL 7826 * @return string Always returns '' 7827 */ 7828 public function write_setting($data) { 7829 // Do not write any setting. 7830 return ''; 7831 } 7832 7833 /** 7834 * Search to find if Query is related to format plugin 7835 * 7836 * @param string $query The string to search for 7837 * @return bool true for related false for not 7838 */ 7839 public function is_related($query) { 7840 if (parent::is_related($query)) { 7841 return true; 7842 } 7843 $formats = core_plugin_manager::instance()->get_plugins_of_type('customfield'); 7844 foreach ($formats as $format) { 7845 if (strpos($format->component, $query) !== false || 7846 strpos(core_text::strtolower($format->displayname), $query) !== false) { 7847 return true; 7848 } 7849 } 7850 return false; 7851 } 7852 7853 /** 7854 * Return XHTML to display control 7855 * 7856 * @param mixed $data Unused 7857 * @param string $query 7858 * @return string highlight 7859 */ 7860 public function output_html($data, $query='') { 7861 global $CFG, $OUTPUT; 7862 $return = ''; 7863 $return = $OUTPUT->heading(new lang_string('customfields', 'core_customfield'), 3, 'main'); 7864 $return .= $OUTPUT->box_start('generalbox customfieldsui'); 7865 7866 $fields = core_plugin_manager::instance()->get_plugins_of_type('customfield'); 7867 7868 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down')); 7869 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 7870 $txt->updown = "$txt->up/$txt->down"; 7871 7872 $table = new html_table(); 7873 $table->head = array($txt->name, $txt->enable, $txt->uninstall, $txt->settings); 7874 $table->align = array('left', 'center', 'center', 'center'); 7875 $table->attributes['class'] = 'managecustomfieldtable generaltable admintable'; 7876 $table->data = array(); 7877 7878 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 7879 foreach ($fields as $field) { 7880 $url = new moodle_url('/admin/customfields.php', 7881 array('sesskey' => sesskey(), 'field' => $field->name)); 7882 7883 if ($field->is_enabled()) { 7884 $strfieldname = $field->displayname; 7885 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')), 7886 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall'))); 7887 } else { 7888 $strfieldname = $field->displayname; 7889 $class = 'dimmed_text'; 7890 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')), 7891 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall'))); 7892 } 7893 $settings = ''; 7894 if ($field->get_settings_url()) { 7895 $settings = html_writer::link($field->get_settings_url(), $txt->settings); 7896 } 7897 $uninstall = ''; 7898 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('customfield_'.$field->name, 'manage')) { 7899 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 7900 } 7901 $row = new html_table_row(array($strfieldname, $hideshow, $uninstall, $settings)); 7902 $table->data[] = $row; 7903 } 7904 $return .= html_writer::table($table); 7905 $return .= $OUTPUT->box_end(); 7906 return highlight($query, $return); 7907 } 7908 } 7909 7910 /** 7911 * Data formats manager. Allow reorder and to enable/disable data formats and jump to settings 7912 * 7913 * @copyright 2016 Brendan Heywood (brendan@catalyst-au.net) 7914 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7915 */ 7916 class admin_setting_managedataformats extends admin_setting { 7917 7918 /** 7919 * Calls parent::__construct with specific arguments 7920 */ 7921 public function __construct() { 7922 $this->nosave = true; 7923 parent::__construct('managedataformats', new lang_string('managedataformats'), '', ''); 7924 } 7925 7926 /** 7927 * Always returns true 7928 * 7929 * @return true 7930 */ 7931 public function get_setting() { 7932 return true; 7933 } 7934 7935 /** 7936 * Always returns true 7937 * 7938 * @return true 7939 */ 7940 public function get_defaultsetting() { 7941 return true; 7942 } 7943 7944 /** 7945 * Always returns '' and doesn't write anything 7946 * 7947 * @param mixed $data string or array, must not be NULL 7948 * @return string Always returns '' 7949 */ 7950 public function write_setting($data) { 7951 // Do not write any setting. 7952 return ''; 7953 } 7954 7955 /** 7956 * Search to find if Query is related to format plugin 7957 * 7958 * @param string $query The string to search for 7959 * @return bool true for related false for not 7960 */ 7961 public function is_related($query) { 7962 if (parent::is_related($query)) { 7963 return true; 7964 } 7965 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat'); 7966 foreach ($formats as $format) { 7967 if (strpos($format->component, $query) !== false || 7968 strpos(core_text::strtolower($format->displayname), $query) !== false) { 7969 return true; 7970 } 7971 } 7972 return false; 7973 } 7974 7975 /** 7976 * Return XHTML to display control 7977 * 7978 * @param mixed $data Unused 7979 * @param string $query 7980 * @return string highlight 7981 */ 7982 public function output_html($data, $query='') { 7983 global $CFG, $OUTPUT; 7984 $return = ''; 7985 7986 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat'); 7987 7988 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default')); 7989 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 7990 $txt->updown = "$txt->up/$txt->down"; 7991 7992 $table = new html_table(); 7993 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings); 7994 $table->align = array('left', 'center', 'center', 'center', 'center'); 7995 $table->attributes['class'] = 'manageformattable generaltable admintable'; 7996 $table->data = array(); 7997 7998 $cnt = 0; 7999 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 8000 $totalenabled = 0; 8001 foreach ($formats as $format) { 8002 if ($format->is_enabled() && $format->is_installed_and_upgraded()) { 8003 $totalenabled++; 8004 } 8005 } 8006 foreach ($formats as $format) { 8007 $status = $format->get_status(); 8008 $url = new moodle_url('/admin/dataformats.php', 8009 array('sesskey' => sesskey(), 'name' => $format->name)); 8010 8011 $class = ''; 8012 if ($format->is_enabled()) { 8013 $strformatname = $format->displayname; 8014 if ($totalenabled == 1&& $format->is_enabled()) { 8015 $hideshow = ''; 8016 } else { 8017 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')), 8018 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall'))); 8019 } 8020 } else { 8021 $class = 'dimmed_text'; 8022 $strformatname = $format->displayname; 8023 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')), 8024 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall'))); 8025 } 8026 8027 $updown = ''; 8028 if ($cnt) { 8029 $updown .= html_writer::link($url->out(false, array('action' => 'up')), 8030 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). ''; 8031 } else { 8032 $updown .= $spacer; 8033 } 8034 if ($cnt < count($formats) - 1) { 8035 $updown .= ' '.html_writer::link($url->out(false, array('action' => 'down')), 8036 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall'))); 8037 } else { 8038 $updown .= $spacer; 8039 } 8040 8041 $uninstall = ''; 8042 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) { 8043 $uninstall = get_string('status_missing', 'core_plugin'); 8044 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) { 8045 $uninstall = get_string('status_new', 'core_plugin'); 8046 } else if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('dataformat_'.$format->name, 'manage')) { 8047 if ($totalenabled != 1 || !$format->is_enabled()) { 8048 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 8049 } 8050 } 8051 8052 $settings = ''; 8053 if ($format->get_settings_url()) { 8054 $settings = html_writer::link($format->get_settings_url(), $txt->settings); 8055 } 8056 8057 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings)); 8058 if ($class) { 8059 $row->attributes['class'] = $class; 8060 } 8061 $table->data[] = $row; 8062 $cnt++; 8063 } 8064 $return .= html_writer::table($table); 8065 return highlight($query, $return); 8066 } 8067 } 8068 8069 /** 8070 * Special class for filter administration. 8071 * 8072 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8073 */ 8074 class admin_page_managefilters extends admin_externalpage { 8075 /** 8076 * Calls parent::__construct with specific arguments 8077 */ 8078 public function __construct() { 8079 global $CFG; 8080 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php"); 8081 } 8082 8083 /** 8084 * Searches all installed filters for specified filter 8085 * 8086 * @param string $query The filter(string) to search for 8087 * @param string $query 8088 */ 8089 public function search($query) { 8090 global $CFG; 8091 if ($result = parent::search($query)) { 8092 return $result; 8093 } 8094 8095 $found = false; 8096 $filternames = filter_get_all_installed(); 8097 foreach ($filternames as $path => $strfiltername) { 8098 if (strpos(core_text::strtolower($strfiltername), $query) !== false) { 8099 $found = true; 8100 break; 8101 } 8102 if (strpos($path, $query) !== false) { 8103 $found = true; 8104 break; 8105 } 8106 } 8107 8108 if ($found) { 8109 $result = new stdClass; 8110 $result->page = $this; 8111 $result->settings = array(); 8112 return array($this->name => $result); 8113 } else { 8114 return array(); 8115 } 8116 } 8117 } 8118 8119 /** 8120 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin. 8121 * Requires a get_rank method on the plugininfo class for sorting. 8122 * 8123 * @copyright 2017 Damyon Wiese 8124 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8125 */ 8126 abstract class admin_setting_manage_plugins extends admin_setting { 8127 8128 /** 8129 * Get the admin settings section name (just a unique string) 8130 * 8131 * @return string 8132 */ 8133 public function get_section_name() { 8134 return 'manage' . $this->get_plugin_type() . 'plugins'; 8135 } 8136 8137 /** 8138 * Get the admin settings section title (use get_string). 8139 * 8140 * @return string 8141 */ 8142 abstract public function get_section_title(); 8143 8144 /** 8145 * Get the type of plugin to manage. 8146 * 8147 * @return string 8148 */ 8149 abstract public function get_plugin_type(); 8150 8151 /** 8152 * Get the name of the second column. 8153 * 8154 * @return string 8155 */ 8156 public function get_info_column_name() { 8157 return ''; 8158 } 8159 8160 /** 8161 * Get the type of plugin to manage. 8162 * 8163 * @param plugininfo The plugin info class. 8164 * @return string 8165 */ 8166 abstract public function get_info_column($plugininfo); 8167 8168 /** 8169 * Calls parent::__construct with specific arguments 8170 */ 8171 public function __construct() { 8172 $this->nosave = true; 8173 parent::__construct($this->get_section_name(), $this->get_section_title(), '', ''); 8174 } 8175 8176 /** 8177 * Always returns true, does nothing 8178 * 8179 * @return true 8180 */ 8181 public function get_setting() { 8182 return true; 8183 } 8184 8185 /** 8186 * Always returns true, does nothing 8187 * 8188 * @return true 8189 */ 8190 public function get_defaultsetting() { 8191 return true; 8192 } 8193 8194 /** 8195 * Always returns '', does not write anything 8196 * 8197 * @param mixed $data 8198 * @return string Always returns '' 8199 */ 8200 public function write_setting($data) { 8201 // Do not write any setting. 8202 return ''; 8203 } 8204 8205 /** 8206 * Checks if $query is one of the available plugins of this type 8207 * 8208 * @param string $query The string to search for 8209 * @return bool Returns true if found, false if not 8210 */ 8211 public function is_related($query) { 8212 if (parent::is_related($query)) { 8213 return true; 8214 } 8215 8216 $query = core_text::strtolower($query); 8217 $plugins = core_plugin_manager::instance()->get_plugins_of_type($this->get_plugin_type()); 8218 foreach ($plugins as $name => $plugin) { 8219 $localised = $plugin->displayname; 8220 if (strpos(core_text::strtolower($name), $query) !== false) { 8221 return true; 8222 } 8223 if (strpos(core_text::strtolower($localised), $query) !== false) { 8224 return true; 8225 } 8226 } 8227 return false; 8228 } 8229 8230 /** 8231 * The URL for the management page for this plugintype. 8232 * 8233 * @return moodle_url 8234 */ 8235 protected function get_manage_url() { 8236 return new moodle_url('/admin/updatesetting.php'); 8237 } 8238 8239 /** 8240 * Builds the HTML to display the control. 8241 * 8242 * @param string $data Unused 8243 * @param string $query 8244 * @return string 8245 */ 8246 public function output_html($data, $query = '') { 8247 global $CFG, $OUTPUT, $DB, $PAGE; 8248 8249 $context = (object) [ 8250 'manageurl' => new moodle_url($this->get_manage_url(), [ 8251 'type' => $this->get_plugin_type(), 8252 'sesskey' => sesskey(), 8253 ]), 8254 'infocolumnname' => $this->get_info_column_name(), 8255 'plugins' => [], 8256 ]; 8257 8258 $pluginmanager = core_plugin_manager::instance(); 8259 $allplugins = $pluginmanager->get_plugins_of_type($this->get_plugin_type()); 8260 $enabled = $pluginmanager->get_enabled_plugins($this->get_plugin_type()); 8261 $plugins = array_merge($enabled, $allplugins); 8262 foreach ($plugins as $key => $plugin) { 8263 $pluginlink = new moodle_url($context->manageurl, ['plugin' => $key]); 8264 8265 $pluginkey = (object) [ 8266 'plugin' => $plugin->displayname, 8267 'enabled' => $plugin->is_enabled(), 8268 'togglelink' => '', 8269 'moveuplink' => '', 8270 'movedownlink' => '', 8271 'settingslink' => $plugin->get_settings_url(), 8272 'uninstalllink' => '', 8273 'info' => '', 8274 ]; 8275 8276 // Enable/Disable link. 8277 $togglelink = new moodle_url($pluginlink); 8278 if ($plugin->is_enabled()) { 8279 $toggletarget = false; 8280 $togglelink->param('action', 'disable'); 8281 8282 if (count($context->plugins)) { 8283 // This is not the first plugin. 8284 $pluginkey->moveuplink = new moodle_url($pluginlink, ['action' => 'up']); 8285 } 8286 8287 if (count($enabled) > count($context->plugins) + 1) { 8288 // This is not the last plugin. 8289 $pluginkey->movedownlink = new moodle_url($pluginlink, ['action' => 'down']); 8290 } 8291 8292 $pluginkey->info = $this->get_info_column($plugin); 8293 } else { 8294 $toggletarget = true; 8295 $togglelink->param('action', 'enable'); 8296 } 8297 8298 $pluginkey->toggletarget = $toggletarget; 8299 $pluginkey->togglelink = $togglelink; 8300 8301 $frankenstyle = $plugin->type . '_' . $plugin->name; 8302 if ($uninstalllink = core_plugin_manager::instance()->get_uninstall_url($frankenstyle, 'manage')) { 8303 // This plugin supports uninstallation. 8304 $pluginkey->uninstalllink = $uninstalllink; 8305 } 8306 8307 if (!empty($this->get_info_column_name())) { 8308 // This plugintype has an info column. 8309 $pluginkey->info = $this->get_info_column($plugin); 8310 } 8311 8312 $context->plugins[] = $pluginkey; 8313 } 8314 8315 $str = $OUTPUT->render_from_template('core_admin/setting_manage_plugins', $context); 8316 return highlight($query, $str); 8317 } 8318 } 8319 8320 /** 8321 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin. 8322 * Requires a get_rank method on the plugininfo class for sorting. 8323 * 8324 * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk> 8325 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8326 */ 8327 class admin_setting_manage_fileconverter_plugins extends admin_setting_manage_plugins { 8328 public function get_section_title() { 8329 return get_string('type_fileconverter_plural', 'plugin'); 8330 } 8331 8332 public function get_plugin_type() { 8333 return 'fileconverter'; 8334 } 8335 8336 public function get_info_column_name() { 8337 return get_string('supportedconversions', 'plugin'); 8338 } 8339 8340 public function get_info_column($plugininfo) { 8341 return $plugininfo->get_supported_conversions(); 8342 } 8343 } 8344 8345 /** 8346 * Special class for media player plugins management. 8347 * 8348 * @copyright 2016 Marina Glancy 8349 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8350 */ 8351 class admin_setting_managemediaplayers extends admin_setting { 8352 /** 8353 * Calls parent::__construct with specific arguments 8354 */ 8355 public function __construct() { 8356 $this->nosave = true; 8357 parent::__construct('managemediaplayers', get_string('managemediaplayers', 'media'), '', ''); 8358 } 8359 8360 /** 8361 * Always returns true, does nothing 8362 * 8363 * @return true 8364 */ 8365 public function get_setting() { 8366 return true; 8367 } 8368 8369 /** 8370 * Always returns true, does nothing 8371 * 8372 * @return true 8373 */ 8374 public function get_defaultsetting() { 8375 return true; 8376 } 8377 8378 /** 8379 * Always returns '', does not write anything 8380 * 8381 * @param mixed $data 8382 * @return string Always returns '' 8383 */ 8384 public function write_setting($data) { 8385 // Do not write any setting. 8386 return ''; 8387 } 8388 8389 /** 8390 * Checks if $query is one of the available enrol plugins 8391 * 8392 * @param string $query The string to search for 8393 * @return bool Returns true if found, false if not 8394 */ 8395 public function is_related($query) { 8396 if (parent::is_related($query)) { 8397 return true; 8398 } 8399 8400 $query = core_text::strtolower($query); 8401 $plugins = core_plugin_manager::instance()->get_plugins_of_type('media'); 8402 foreach ($plugins as $name => $plugin) { 8403 $localised = $plugin->displayname; 8404 if (strpos(core_text::strtolower($name), $query) !== false) { 8405 return true; 8406 } 8407 if (strpos(core_text::strtolower($localised), $query) !== false) { 8408 return true; 8409 } 8410 } 8411 return false; 8412 } 8413 8414 /** 8415 * Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank. 8416 * @return \core\plugininfo\media[] 8417 */ 8418 protected function get_sorted_plugins() { 8419 $pluginmanager = core_plugin_manager::instance(); 8420 8421 $plugins = $pluginmanager->get_plugins_of_type('media'); 8422 $enabledplugins = $pluginmanager->get_enabled_plugins('media'); 8423 8424 // Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank. 8425 \core_collator::asort_objects_by_method($plugins, 'get_rank', \core_collator::SORT_NUMERIC); 8426 8427 $order = array_values($enabledplugins); 8428 $order = array_merge($order, array_diff(array_reverse(array_keys($plugins)), $order)); 8429 8430 $sortedplugins = array(); 8431 foreach ($order as $name) { 8432 $sortedplugins[$name] = $plugins[$name]; 8433 } 8434 8435 return $sortedplugins; 8436 } 8437 8438 /** 8439 * Builds the XHTML to display the control 8440 * 8441 * @param string $data Unused 8442 * @param string $query 8443 * @return string 8444 */ 8445 public function output_html($data, $query='') { 8446 global $CFG, $OUTPUT, $DB, $PAGE; 8447 8448 // Display strings. 8449 $strup = get_string('up'); 8450 $strdown = get_string('down'); 8451 $strsettings = get_string('settings'); 8452 $strenable = get_string('enable'); 8453 $strdisable = get_string('disable'); 8454 $struninstall = get_string('uninstallplugin', 'core_admin'); 8455 $strversion = get_string('version'); 8456 $strname = get_string('name'); 8457 $strsupports = get_string('supports', 'core_media'); 8458 8459 $pluginmanager = core_plugin_manager::instance(); 8460 8461 $plugins = $this->get_sorted_plugins(); 8462 $enabledplugins = $pluginmanager->get_enabled_plugins('media'); 8463 8464 $return = $OUTPUT->box_start('generalbox mediaplayersui'); 8465 8466 $table = new html_table(); 8467 $table->head = array($strname, $strsupports, $strversion, 8468 $strenable, $strup.'/'.$strdown, $strsettings, $struninstall); 8469 $table->colclasses = array('leftalign', 'leftalign', 'centeralign', 8470 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 8471 $table->id = 'mediaplayerplugins'; 8472 $table->attributes['class'] = 'admintable generaltable'; 8473 $table->data = array(); 8474 8475 // Iterate through media plugins and add to the display table. 8476 $updowncount = 1; 8477 $url = new moodle_url('/admin/media.php', array('sesskey' => sesskey())); 8478 $printed = array(); 8479 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 8480 8481 $usedextensions = []; 8482 foreach ($plugins as $name => $plugin) { 8483 $url->param('media', $name); 8484 $plugininfo = $pluginmanager->get_plugin_info('media_'.$name); 8485 $version = $plugininfo->versiondb; 8486 $supports = $plugininfo->supports($usedextensions); 8487 8488 // Hide/show links. 8489 $class = ''; 8490 if (!$plugininfo->is_installed_and_upgraded()) { 8491 $hideshow = ''; 8492 $enabled = false; 8493 $displayname = '<span class="notifyproblem">'.$name.'</span>'; 8494 } else { 8495 $enabled = $plugininfo->is_enabled(); 8496 if ($enabled) { 8497 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'disable')), 8498 $OUTPUT->pix_icon('t/hide', $strdisable, 'moodle', array('class' => 'iconsmall'))); 8499 } else { 8500 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'enable')), 8501 $OUTPUT->pix_icon('t/show', $strenable, 'moodle', array('class' => 'iconsmall'))); 8502 $class = 'dimmed_text'; 8503 } 8504 $displayname = $plugin->displayname; 8505 if (get_string_manager()->string_exists('pluginname_help', 'media_' . $name)) { 8506 $displayname .= ' ' . $OUTPUT->help_icon('pluginname', 'media_' . $name); 8507 } 8508 } 8509 if ($PAGE->theme->resolve_image_location('icon', 'media_' . $name, false)) { 8510 $icon = $OUTPUT->pix_icon('icon', '', 'media_' . $name, array('class' => 'icon pluginicon')); 8511 } else { 8512 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon')); 8513 } 8514 8515 // Up/down link (only if enrol is enabled). 8516 $updown = ''; 8517 if ($enabled) { 8518 if ($updowncount > 1) { 8519 $updown = html_writer::link(new moodle_url($url, array('action' => 'up')), 8520 $OUTPUT->pix_icon('t/up', $strup, 'moodle', array('class' => 'iconsmall'))); 8521 } else { 8522 $updown = $spacer; 8523 } 8524 if ($updowncount < count($enabledplugins)) { 8525 $updown .= html_writer::link(new moodle_url($url, array('action' => 'down')), 8526 $OUTPUT->pix_icon('t/down', $strdown, 'moodle', array('class' => 'iconsmall'))); 8527 } else { 8528 $updown .= $spacer; 8529 } 8530 ++$updowncount; 8531 } 8532 8533 $uninstall = ''; 8534 $status = $plugininfo->get_status(); 8535 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) { 8536 $uninstall = get_string('status_missing', 'core_plugin') . '<br/>'; 8537 } 8538 if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) { 8539 $uninstall = get_string('status_new', 'core_plugin'); 8540 } else if ($uninstallurl = $pluginmanager->get_uninstall_url('media_'.$name, 'manage')) { 8541 $uninstall .= html_writer::link($uninstallurl, $struninstall); 8542 } 8543 8544 $settings = ''; 8545 if ($plugininfo->get_settings_url()) { 8546 $settings = html_writer::link($plugininfo->get_settings_url(), $strsettings); 8547 } 8548 8549 // Add a row to the table. 8550 $row = new html_table_row(array($icon.$displayname, $supports, $version, $hideshow, $updown, $settings, $uninstall)); 8551 if ($class) { 8552 $row->attributes['class'] = $class; 8553 } 8554 $table->data[] = $row; 8555 8556 $printed[$name] = true; 8557 } 8558 8559 $return .= html_writer::table($table); 8560 $return .= $OUTPUT->box_end(); 8561 return highlight($query, $return); 8562 } 8563 } 8564 8565 8566 /** 8567 * Content bank content types manager. Allow reorder and to enable/disable content bank content types and jump to settings 8568 * 8569 * @copyright 2020 Amaia Anabitarte <amaia@moodle.com> 8570 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8571 */ 8572 class admin_setting_managecontentbankcontenttypes extends admin_setting { 8573 8574 /** 8575 * Calls parent::__construct with specific arguments 8576 */ 8577 public function __construct() { 8578 $this->nosave = true; 8579 parent::__construct('contentbank', new lang_string('managecontentbanktypes'), '', ''); 8580 } 8581 8582 /** 8583 * Always returns true 8584 * 8585 * @return true 8586 */ 8587 public function get_setting() { 8588 return true; 8589 } 8590 8591 /** 8592 * Always returns true 8593 * 8594 * @return true 8595 */ 8596 public function get_defaultsetting() { 8597 return true; 8598 } 8599 8600 /** 8601 * Always returns '' and doesn't write anything 8602 * 8603 * @param mixed $data string or array, must not be NULL 8604 * @return string Always returns '' 8605 */ 8606 public function write_setting($data) { 8607 // Do not write any setting. 8608 return ''; 8609 } 8610 8611 /** 8612 * Search to find if Query is related to content bank plugin 8613 * 8614 * @param string $query The string to search for 8615 * @return bool true for related false for not 8616 */ 8617 public function is_related($query) { 8618 if (parent::is_related($query)) { 8619 return true; 8620 } 8621 $types = core_plugin_manager::instance()->get_plugins_of_type('contenttype'); 8622 foreach ($types as $type) { 8623 if (strpos($type->component, $query) !== false || 8624 strpos(core_text::strtolower($type->displayname), $query) !== false) { 8625 return true; 8626 } 8627 } 8628 return false; 8629 } 8630 8631 /** 8632 * Return XHTML to display control 8633 * 8634 * @param mixed $data Unused 8635 * @param string $query 8636 * @return string highlight 8637 */ 8638 public function output_html($data, $query='') { 8639 global $CFG, $OUTPUT; 8640 $return = ''; 8641 8642 $types = core_plugin_manager::instance()->get_plugins_of_type('contenttype'); 8643 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'order', 'up', 'down', 'default')); 8644 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 8645 8646 $table = new html_table(); 8647 $table->head = array($txt->name, $txt->enable, $txt->order, $txt->settings, $txt->uninstall); 8648 $table->align = array('left', 'center', 'center', 'center', 'center'); 8649 $table->attributes['class'] = 'managecontentbanktable generaltable admintable'; 8650 $table->data = array(); 8651 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 8652 8653 $totalenabled = 0; 8654 $count = 0; 8655 foreach ($types as $type) { 8656 if ($type->is_enabled() && $type->is_installed_and_upgraded()) { 8657 $totalenabled++; 8658 } 8659 } 8660 8661 foreach ($types as $type) { 8662 $url = new moodle_url('/admin/contentbank.php', 8663 array('sesskey' => sesskey(), 'name' => $type->name)); 8664 8665 $class = ''; 8666 $strtypename = $type->displayname; 8667 if ($type->is_enabled()) { 8668 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')), 8669 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall'))); 8670 } else { 8671 $class = 'dimmed_text'; 8672 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')), 8673 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall'))); 8674 } 8675 8676 $updown = ''; 8677 if ($count) { 8678 $updown .= html_writer::link($url->out(false, array('action' => 'up')), 8679 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). ''; 8680 } else { 8681 $updown .= $spacer; 8682 } 8683 if ($count < count($types) - 1) { 8684 $updown .= ' '.html_writer::link($url->out(false, array('action' => 'down')), 8685 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall'))); 8686 } else { 8687 $updown .= $spacer; 8688 } 8689 8690 $settings = ''; 8691 if ($type->get_settings_url()) { 8692 $settings = html_writer::link($type->get_settings_url(), $txt->settings); 8693 } 8694 8695 $uninstall = ''; 8696 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('contenttype_'.$type->name, 'manage')) { 8697 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 8698 } 8699 8700 $row = new html_table_row(array($strtypename, $hideshow, $updown, $settings, $uninstall)); 8701 if ($class) { 8702 $row->attributes['class'] = $class; 8703 } 8704 $table->data[] = $row; 8705 $count++; 8706 } 8707 $return .= html_writer::table($table); 8708 return highlight($query, $return); 8709 } 8710 } 8711 8712 /** 8713 * Initialise admin page - this function does require login and permission 8714 * checks specified in page definition. 8715 * 8716 * This function must be called on each admin page before other code. 8717 * 8718 * @global moodle_page $PAGE 8719 * 8720 * @param string $section name of page 8721 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button. 8722 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be 8723 * added to the turn blocks editing on/off form, so this page reloads correctly. 8724 * @param string $actualurl if the actual page being viewed is not the normal one for this 8725 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here. 8726 * @param array $options Additional options that can be specified for page setup. 8727 * pagelayout - This option can be used to set a specific pagelyaout, admin is default. 8728 */ 8729 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) { 8730 global $CFG, $PAGE, $USER, $SITE, $OUTPUT; 8731 8732 $PAGE->set_context(null); // hack - set context to something, by default to system context 8733 8734 $site = get_site(); 8735 require_login(null, false); 8736 8737 if (!empty($options['pagelayout'])) { 8738 // A specific page layout has been requested. 8739 $PAGE->set_pagelayout($options['pagelayout']); 8740 } else if ($section === 'upgradesettings') { 8741 $PAGE->set_pagelayout('maintenance'); 8742 } else { 8743 $PAGE->set_pagelayout('admin'); 8744 } 8745 8746 $adminroot = admin_get_root(false, false); // settings not required for external pages 8747 $extpage = $adminroot->locate($section, true); 8748 8749 if (empty($extpage) or !($extpage instanceof admin_externalpage)) { 8750 // The requested section isn't in the admin tree 8751 // It could be because the user has inadequate capapbilities or because the section doesn't exist 8752 if (!has_capability('moodle/site:config', context_system::instance())) { 8753 // The requested section could depend on a different capability 8754 // but most likely the user has inadequate capabilities 8755 print_error('accessdenied', 'admin'); 8756 } else { 8757 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/"); 8758 } 8759 } 8760 8761 // this eliminates our need to authenticate on the actual pages 8762 if (!$extpage->check_access()) { 8763 print_error('accessdenied', 'admin'); 8764 die; 8765 } 8766 8767 navigation_node::require_admin_tree(); 8768 8769 // $PAGE->set_extra_button($extrabutton); TODO 8770 8771 if (!$actualurl) { 8772 $actualurl = $extpage->url; 8773 } 8774 8775 $PAGE->set_url($actualurl, $extraurlparams); 8776 if (strpos($PAGE->pagetype, 'admin-') !== 0) { 8777 $PAGE->set_pagetype('admin-' . $PAGE->pagetype); 8778 } 8779 8780 if (empty($SITE->fullname) || empty($SITE->shortname)) { 8781 // During initial install. 8782 $strinstallation = get_string('installation', 'install'); 8783 $strsettings = get_string('settings'); 8784 $PAGE->navbar->add($strsettings); 8785 $PAGE->set_title($strinstallation); 8786 $PAGE->set_heading($strinstallation); 8787 $PAGE->set_cacheable(false); 8788 return; 8789 } 8790 8791 // Locate the current item on the navigation and make it active when found. 8792 $path = $extpage->path; 8793 $node = $PAGE->settingsnav; 8794 while ($node && count($path) > 0) { 8795 $node = $node->get(array_pop($path)); 8796 } 8797 if ($node) { 8798 $node->make_active(); 8799 } 8800 8801 // Normal case. 8802 $adminediting = optional_param('adminedit', -1, PARAM_BOOL); 8803 if ($PAGE->user_allowed_editing() && $adminediting != -1) { 8804 $USER->editing = $adminediting; 8805 } 8806 8807 $visiblepathtosection = array_reverse($extpage->visiblepath); 8808 8809 if ($PAGE->user_allowed_editing()) { 8810 if ($PAGE->user_is_editing()) { 8811 $caption = get_string('blockseditoff'); 8812 $url = new moodle_url($PAGE->url, array('adminedit'=>'0', 'sesskey'=>sesskey())); 8813 } else { 8814 $caption = get_string('blocksediton'); 8815 $url = new moodle_url($PAGE->url, array('adminedit'=>'1', 'sesskey'=>sesskey())); 8816 } 8817 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get')); 8818 } 8819 8820 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection)); 8821 $PAGE->set_heading($SITE->fullname); 8822 8823 // prevent caching in nav block 8824 $PAGE->navigation->clear_cache(); 8825 } 8826 8827 /** 8828 * Returns the reference to admin tree root 8829 * 8830 * @return object admin_root object 8831 */ 8832 function admin_get_root($reload=false, $requirefulltree=true) { 8833 global $CFG, $DB, $OUTPUT, $ADMIN; 8834 8835 if (is_null($ADMIN)) { 8836 // create the admin tree! 8837 $ADMIN = new admin_root($requirefulltree); 8838 } 8839 8840 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) { 8841 $ADMIN->purge_children($requirefulltree); 8842 } 8843 8844 if (!$ADMIN->loaded) { 8845 // we process this file first to create categories first and in correct order 8846 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php'); 8847 8848 // now we process all other files in admin/settings to build the admin tree 8849 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) { 8850 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') { 8851 continue; 8852 } 8853 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') { 8854 // plugins are loaded last - they may insert pages anywhere 8855 continue; 8856 } 8857 require($file); 8858 } 8859 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php'); 8860 8861 $ADMIN->loaded = true; 8862 } 8863 8864 return $ADMIN; 8865 } 8866 8867 /// settings utility functions 8868 8869 /** 8870 * This function applies default settings. 8871 * Because setting the defaults of some settings can enable other settings, 8872 * this function is called recursively until no more new settings are found. 8873 * 8874 * @param object $node, NULL means complete tree, null by default 8875 * @param bool $unconditional if true overrides all values with defaults, true by default 8876 * @param array $admindefaultsettings default admin settings to apply. Used recursively 8877 * @param array $settingsoutput The names and values of the changed settings. Used recursively 8878 * @return array $settingsoutput The names and values of the changed settings 8879 */ 8880 function admin_apply_default_settings($node=null, $unconditional=true, $admindefaultsettings=array(), $settingsoutput=array()) { 8881 $counter = 0; 8882 8883 if (is_null($node)) { 8884 core_plugin_manager::reset_caches(); 8885 $node = admin_get_root(true, true); 8886 $counter = count($settingsoutput); 8887 } 8888 8889 if ($node instanceof admin_category) { 8890 $entries = array_keys($node->children); 8891 foreach ($entries as $entry) { 8892 $settingsoutput = admin_apply_default_settings( 8893 $node->children[$entry], $unconditional, $admindefaultsettings, $settingsoutput 8894 ); 8895 } 8896 8897 } else if ($node instanceof admin_settingpage) { 8898 foreach ($node->settings as $setting) { 8899 if (!$unconditional && !is_null($setting->get_setting())) { 8900 // Do not override existing defaults. 8901 continue; 8902 } 8903 $defaultsetting = $setting->get_defaultsetting(); 8904 if (is_null($defaultsetting)) { 8905 // No value yet - default maybe applied after admin user creation or in upgradesettings. 8906 continue; 8907 } 8908 8909 $settingname = $node->name . '_' . $setting->name; // Get a unique name for the setting. 8910 8911 if (!array_key_exists($settingname, $admindefaultsettings)) { // Only update a setting if not already processed. 8912 $admindefaultsettings[$settingname] = $settingname; 8913 $settingsoutput[$settingname] = $defaultsetting; 8914 8915 // Set the default for this setting. 8916 $setting->write_setting($defaultsetting); 8917 $setting->write_setting_flags(null); 8918 } else { 8919 unset($admindefaultsettings[$settingname]); // Remove processed settings. 8920 } 8921 } 8922 } 8923 8924 // Call this function recursively until all settings are processed. 8925 if (($node instanceof admin_root) && ($counter != count($settingsoutput))) { 8926 $settingsoutput = admin_apply_default_settings(null, $unconditional, $admindefaultsettings, $settingsoutput); 8927 } 8928 // Just in case somebody modifies the list of active plugins directly. 8929 core_plugin_manager::reset_caches(); 8930 8931 return $settingsoutput; 8932 } 8933 8934 /** 8935 * Store changed settings, this function updates the errors variable in $ADMIN 8936 * 8937 * @param object $formdata from form 8938 * @return int number of changed settings 8939 */ 8940 function admin_write_settings($formdata) { 8941 global $CFG, $SITE, $DB; 8942 8943 $olddbsessions = !empty($CFG->dbsessions); 8944 $formdata = (array)$formdata; 8945 8946 $data = array(); 8947 foreach ($formdata as $fullname=>$value) { 8948 if (strpos($fullname, 's_') !== 0) { 8949 continue; // not a config value 8950 } 8951 $data[$fullname] = $value; 8952 } 8953 8954 $adminroot = admin_get_root(); 8955 $settings = admin_find_write_settings($adminroot, $data); 8956 8957 $count = 0; 8958 foreach ($settings as $fullname=>$setting) { 8959 /** @var $setting admin_setting */ 8960 $original = $setting->get_setting(); 8961 $error = $setting->write_setting($data[$fullname]); 8962 if ($error !== '') { 8963 $adminroot->errors[$fullname] = new stdClass(); 8964 $adminroot->errors[$fullname]->data = $data[$fullname]; 8965 $adminroot->errors[$fullname]->id = $setting->get_id(); 8966 $adminroot->errors[$fullname]->error = $error; 8967 } else { 8968 $setting->write_setting_flags($data); 8969 } 8970 if ($setting->post_write_settings($original)) { 8971 $count++; 8972 } 8973 } 8974 8975 if ($olddbsessions != !empty($CFG->dbsessions)) { 8976 require_logout(); 8977 } 8978 8979 // Now update $SITE - just update the fields, in case other people have a 8980 // a reference to it (e.g. $PAGE, $COURSE). 8981 $newsite = $DB->get_record('course', array('id'=>$SITE->id)); 8982 foreach (get_object_vars($newsite) as $field => $value) { 8983 $SITE->$field = $value; 8984 } 8985 8986 // now reload all settings - some of them might depend on the changed 8987 admin_get_root(true); 8988 return $count; 8989 } 8990 8991 /** 8992 * Internal recursive function - finds all settings from submitted form 8993 * 8994 * @param object $node Instance of admin_category, or admin_settingpage 8995 * @param array $data 8996 * @return array 8997 */ 8998 function admin_find_write_settings($node, $data) { 8999 $return = array(); 9000 9001 if (empty($data)) { 9002 return $return; 9003 } 9004 9005 if ($node instanceof admin_category) { 9006 if ($node->check_access()) { 9007 $entries = array_keys($node->children); 9008 foreach ($entries as $entry) { 9009 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data)); 9010 } 9011 } 9012 9013 } else if ($node instanceof admin_settingpage) { 9014 if ($node->check_access()) { 9015 foreach ($node->settings as $setting) { 9016 $fullname = $setting->get_full_name(); 9017 if (array_key_exists($fullname, $data)) { 9018 $return[$fullname] = $setting; 9019 } 9020 } 9021 } 9022 9023 } 9024 9025 return $return; 9026 } 9027 9028 /** 9029 * Internal function - prints the search results 9030 * 9031 * @param string $query String to search for 9032 * @return string empty or XHTML 9033 */ 9034 function admin_search_settings_html($query) { 9035 global $CFG, $OUTPUT, $PAGE; 9036 9037 if (core_text::strlen($query) < 2) { 9038 return ''; 9039 } 9040 $query = core_text::strtolower($query); 9041 9042 $adminroot = admin_get_root(); 9043 $findings = $adminroot->search($query); 9044 $savebutton = false; 9045 9046 $tpldata = (object) [ 9047 'actionurl' => $PAGE->url->out(false), 9048 'results' => [], 9049 'sesskey' => sesskey(), 9050 ]; 9051 9052 foreach ($findings as $found) { 9053 $page = $found->page; 9054 $settings = $found->settings; 9055 if ($page->is_hidden()) { 9056 // hidden pages are not displayed in search results 9057 continue; 9058 } 9059 9060 $heading = highlight($query, $page->visiblename); 9061 $headingurl = null; 9062 if ($page instanceof admin_externalpage) { 9063 $headingurl = new moodle_url($page->url); 9064 } else if ($page instanceof admin_settingpage) { 9065 $headingurl = new moodle_url('/admin/settings.php', ['section' => $page->name]); 9066 } else { 9067 continue; 9068 } 9069 9070 // Locate the page in the admin root and populate its visiblepath attribute. 9071 $path = array(); 9072 $located = $adminroot->locate($page->name, true); 9073 if ($located) { 9074 foreach ($located->visiblepath as $pathitem) { 9075 array_unshift($path, (string) $pathitem); 9076 } 9077 } 9078 9079 $sectionsettings = []; 9080 if (!empty($settings)) { 9081 foreach ($settings as $setting) { 9082 if (empty($setting->nosave)) { 9083 $savebutton = true; 9084 } 9085 $fullname = $setting->get_full_name(); 9086 if (array_key_exists($fullname, $adminroot->errors)) { 9087 $data = $adminroot->errors[$fullname]->data; 9088 } else { 9089 $data = $setting->get_setting(); 9090 // do not use defaults if settings not available - upgradesettings handles the defaults! 9091 } 9092 $sectionsettings[] = $setting->output_html($data, $query); 9093 } 9094 } 9095 9096 $tpldata->results[] = (object) [ 9097 'title' => $heading, 9098 'path' => $path, 9099 'url' => $headingurl->out(false), 9100 'settings' => $sectionsettings 9101 ]; 9102 } 9103 9104 $tpldata->showsave = $savebutton; 9105 $tpldata->hasresults = !empty($tpldata->results); 9106 9107 return $OUTPUT->render_from_template('core_admin/settings_search_results', $tpldata); 9108 } 9109 9110 /** 9111 * Internal function - returns arrays of html pages with uninitialised settings 9112 * 9113 * @param object $node Instance of admin_category or admin_settingpage 9114 * @return array 9115 */ 9116 function admin_output_new_settings_by_page($node) { 9117 global $OUTPUT; 9118 $return = array(); 9119 9120 if ($node instanceof admin_category) { 9121 $entries = array_keys($node->children); 9122 foreach ($entries as $entry) { 9123 $return += admin_output_new_settings_by_page($node->children[$entry]); 9124 } 9125 9126 } else if ($node instanceof admin_settingpage) { 9127 $newsettings = array(); 9128 foreach ($node->settings as $setting) { 9129 if (is_null($setting->get_setting())) { 9130 $newsettings[] = $setting; 9131 } 9132 } 9133 if (count($newsettings) > 0) { 9134 $adminroot = admin_get_root(); 9135 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main'); 9136 $page .= '<fieldset class="adminsettings">'."\n"; 9137 foreach ($newsettings as $setting) { 9138 $fullname = $setting->get_full_name(); 9139 if (array_key_exists($fullname, $adminroot->errors)) { 9140 $data = $adminroot->errors[$fullname]->data; 9141 } else { 9142 $data = $setting->get_setting(); 9143 if (is_null($data)) { 9144 $data = $setting->get_defaultsetting(); 9145 } 9146 } 9147 $page .= '<div class="clearer"><!-- --></div>'."\n"; 9148 $page .= $setting->output_html($data); 9149 } 9150 $page .= '</fieldset>'; 9151 $return[$node->name] = $page; 9152 } 9153 } 9154 9155 return $return; 9156 } 9157 9158 /** 9159 * Format admin settings 9160 * 9161 * @param object $setting 9162 * @param string $title label element 9163 * @param string $form form fragment, html code - not highlighted automatically 9164 * @param string $description 9165 * @param mixed $label link label to id, true by default or string being the label to connect it to 9166 * @param string $warning warning text 9167 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null 9168 * @param string $query search query to be highlighted 9169 * @return string XHTML 9170 */ 9171 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') { 9172 global $CFG, $OUTPUT; 9173 9174 $context = (object) [ 9175 'name' => empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name", 9176 'fullname' => $setting->get_full_name(), 9177 ]; 9178 9179 // Sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate. 9180 if ($label === true) { 9181 $context->labelfor = $setting->get_id(); 9182 } else if ($label === false) { 9183 $context->labelfor = ''; 9184 } else { 9185 $context->labelfor = $label; 9186 } 9187 9188 $form .= $setting->output_setting_flags(); 9189 9190 $context->warning = $warning; 9191 $context->override = ''; 9192 if (empty($setting->plugin)) { 9193 if (array_key_exists($setting->name, $CFG->config_php_settings)) { 9194 $context->override = get_string('configoverride', 'admin'); 9195 } 9196 } else { 9197 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) { 9198 $context->override = get_string('configoverride', 'admin'); 9199 } 9200 } 9201 9202 $defaults = array(); 9203 if (!is_null($defaultinfo)) { 9204 if ($defaultinfo === '') { 9205 $defaultinfo = get_string('emptysettingvalue', 'admin'); 9206 } 9207 $defaults[] = $defaultinfo; 9208 } 9209 9210 $context->default = null; 9211 $setting->get_setting_flag_defaults($defaults); 9212 if (!empty($defaults)) { 9213 $defaultinfo = implode(', ', $defaults); 9214 $defaultinfo = highlight($query, nl2br(s($defaultinfo))); 9215 $context->default = get_string('defaultsettinginfo', 'admin', $defaultinfo); 9216 } 9217 9218 9219 $context->error = ''; 9220 $adminroot = admin_get_root(); 9221 if (array_key_exists($context->fullname, $adminroot->errors)) { 9222 $context->error = $adminroot->errors[$context->fullname]->error; 9223 } 9224 9225 if ($dependenton = $setting->get_dependent_on()) { 9226 $context->dependenton = get_string('settingdependenton', 'admin', implode(', ', $dependenton)); 9227 } 9228 9229 $context->id = 'admin-' . $setting->name; 9230 $context->title = highlightfast($query, $title); 9231 $context->name = highlightfast($query, $context->name); 9232 $context->description = highlight($query, markdown_to_html($description)); 9233 $context->element = $form; 9234 $context->forceltr = $setting->get_force_ltr(); 9235 $context->customcontrol = $setting->has_custom_form_control(); 9236 9237 return $OUTPUT->render_from_template('core_admin/setting', $context); 9238 } 9239 9240 /** 9241 * Based on find_new_settings{@link ()} in upgradesettings.php 9242 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any. 9243 * 9244 * @param object $node Instance of admin_category, or admin_settingpage 9245 * @return boolean true if any settings haven't been initialised, false if they all have 9246 */ 9247 function any_new_admin_settings($node) { 9248 9249 if ($node instanceof admin_category) { 9250 $entries = array_keys($node->children); 9251 foreach ($entries as $entry) { 9252 if (any_new_admin_settings($node->children[$entry])) { 9253 return true; 9254 } 9255 } 9256 9257 } else if ($node instanceof admin_settingpage) { 9258 foreach ($node->settings as $setting) { 9259 if ($setting->get_setting() === NULL) { 9260 return true; 9261 } 9262 } 9263 } 9264 9265 return false; 9266 } 9267 9268 /** 9269 * Given a table and optionally a column name should replaces be done? 9270 * 9271 * @param string $table name 9272 * @param string $column name 9273 * @return bool success or fail 9274 */ 9275 function db_should_replace($table, $column = '', $additionalskiptables = ''): bool { 9276 9277 // TODO: this is horrible hack, we should have a hook and each plugin should be responsible for proper replacing... 9278 $skiptables = ['config', 'config_plugins', 'filter_config', 'sessions', 9279 'events_queue', 'repository_instance_config', 'block_instances', 'files']; 9280 9281 // Additional skip tables. 9282 if (!empty($additionalskiptables)) { 9283 $skiptables = array_merge($skiptables, explode(',', str_replace(' ', '', $additionalskiptables))); 9284 } 9285 9286 // Don't process these. 9287 if (in_array($table, $skiptables)) { 9288 return false; 9289 } 9290 9291 // To be safe never replace inside a table that looks related to logging. 9292 if (preg_match('/(^|_)logs?($|_)/', $table)) { 9293 return false; 9294 } 9295 9296 // Do column based exclusions. 9297 if (!empty($column)) { 9298 // Don't touch anything that looks like a hash. 9299 if (preg_match('/hash$/', $column)) { 9300 return false; 9301 } 9302 } 9303 9304 return true; 9305 } 9306 9307 /** 9308 * Moved from admin/replace.php so that we can use this in cron 9309 * 9310 * @param string $search string to look for 9311 * @param string $replace string to replace 9312 * @return bool success or fail 9313 */ 9314 function db_replace($search, $replace, $additionalskiptables = '') { 9315 global $DB, $CFG, $OUTPUT; 9316 9317 // Turn off time limits, sometimes upgrades can be slow. 9318 core_php_time_limit::raise(); 9319 9320 if (!$tables = $DB->get_tables() ) { // No tables yet at all. 9321 return false; 9322 } 9323 foreach ($tables as $table) { 9324 9325 if (!db_should_replace($table, '', $additionalskiptables)) { 9326 continue; 9327 } 9328 9329 if ($columns = $DB->get_columns($table)) { 9330 $DB->set_debug(true); 9331 foreach ($columns as $column) { 9332 if (!db_should_replace($table, $column->name)) { 9333 continue; 9334 } 9335 $DB->replace_all_text($table, $column, $search, $replace); 9336 } 9337 $DB->set_debug(false); 9338 } 9339 } 9340 9341 // delete modinfo caches 9342 rebuild_course_cache(0, true); 9343 9344 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks... 9345 $blocks = core_component::get_plugin_list('block'); 9346 foreach ($blocks as $blockname=>$fullblock) { 9347 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it 9348 continue; 9349 } 9350 9351 if (!is_readable($fullblock.'/lib.php')) { 9352 continue; 9353 } 9354 9355 $function = 'block_'.$blockname.'_global_db_replace'; 9356 include_once($fullblock.'/lib.php'); 9357 if (!function_exists($function)) { 9358 continue; 9359 } 9360 9361 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess'); 9362 $function($search, $replace); 9363 echo $OUTPUT->notification("...finished", 'notifysuccess'); 9364 } 9365 9366 // Trigger an event. 9367 $eventargs = [ 9368 'context' => context_system::instance(), 9369 'other' => [ 9370 'search' => $search, 9371 'replace' => $replace 9372 ] 9373 ]; 9374 $event = \core\event\database_text_field_content_replaced::create($eventargs); 9375 $event->trigger(); 9376 9377 purge_all_caches(); 9378 9379 return true; 9380 } 9381 9382 /** 9383 * Manage repository settings 9384 * 9385 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9386 */ 9387 class admin_setting_managerepository extends admin_setting { 9388 /** @var string */ 9389 private $baseurl; 9390 9391 /** 9392 * calls parent::__construct with specific arguments 9393 */ 9394 public function __construct() { 9395 global $CFG; 9396 parent::__construct('managerepository', get_string('manage', 'repository'), '', ''); 9397 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey(); 9398 } 9399 9400 /** 9401 * Always returns true, does nothing 9402 * 9403 * @return true 9404 */ 9405 public function get_setting() { 9406 return true; 9407 } 9408 9409 /** 9410 * Always returns true does nothing 9411 * 9412 * @return true 9413 */ 9414 public function get_defaultsetting() { 9415 return true; 9416 } 9417 9418 /** 9419 * Always returns s_managerepository 9420 * 9421 * @return string Always return 's_managerepository' 9422 */ 9423 public function get_full_name() { 9424 return 's_managerepository'; 9425 } 9426 9427 /** 9428 * Always returns '' doesn't do anything 9429 */ 9430 public function write_setting($data) { 9431 $url = $this->baseurl . '&new=' . $data; 9432 return ''; 9433 // TODO 9434 // Should not use redirect and exit here 9435 // Find a better way to do this. 9436 // redirect($url); 9437 // exit; 9438 } 9439 9440 /** 9441 * Searches repository plugins for one that matches $query 9442 * 9443 * @param string $query The string to search for 9444 * @return bool true if found, false if not 9445 */ 9446 public function is_related($query) { 9447 if (parent::is_related($query)) { 9448 return true; 9449 } 9450 9451 $repositories= core_component::get_plugin_list('repository'); 9452 foreach ($repositories as $p => $dir) { 9453 if (strpos($p, $query) !== false) { 9454 return true; 9455 } 9456 } 9457 foreach (repository::get_types() as $instance) { 9458 $title = $instance->get_typename(); 9459 if (strpos(core_text::strtolower($title), $query) !== false) { 9460 return true; 9461 } 9462 } 9463 return false; 9464 } 9465 9466 /** 9467 * Helper function that generates a moodle_url object 9468 * relevant to the repository 9469 */ 9470 9471 function repository_action_url($repository) { 9472 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository)); 9473 } 9474 9475 /** 9476 * Builds XHTML to display the control 9477 * 9478 * @param string $data Unused 9479 * @param string $query 9480 * @return string XHTML 9481 */ 9482 public function output_html($data, $query='') { 9483 global $CFG, $USER, $OUTPUT; 9484 9485 // Get strings that are used 9486 $strshow = get_string('on', 'repository'); 9487 $strhide = get_string('off', 'repository'); 9488 $strdelete = get_string('disabled', 'repository'); 9489 9490 $actionchoicesforexisting = array( 9491 'show' => $strshow, 9492 'hide' => $strhide, 9493 'delete' => $strdelete 9494 ); 9495 9496 $actionchoicesfornew = array( 9497 'newon' => $strshow, 9498 'newoff' => $strhide, 9499 'delete' => $strdelete 9500 ); 9501 9502 $return = ''; 9503 $return .= $OUTPUT->box_start('generalbox'); 9504 9505 // Set strings that are used multiple times 9506 $settingsstr = get_string('settings'); 9507 $disablestr = get_string('disable'); 9508 9509 // Table to list plug-ins 9510 $table = new html_table(); 9511 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr); 9512 $table->align = array('left', 'center', 'center', 'center', 'center'); 9513 $table->data = array(); 9514 9515 // Get list of used plug-ins 9516 $repositorytypes = repository::get_types(); 9517 if (!empty($repositorytypes)) { 9518 // Array to store plugins being used 9519 $alreadyplugins = array(); 9520 $totalrepositorytypes = count($repositorytypes); 9521 $updowncount = 1; 9522 foreach ($repositorytypes as $i) { 9523 $settings = ''; 9524 $typename = $i->get_typename(); 9525 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config) 9526 $typeoptionnames = repository::static_function($typename, 'get_type_option_names'); 9527 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names'); 9528 9529 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) { 9530 // Calculate number of instances in order to display them for the Moodle administrator 9531 if (!empty($instanceoptionnames)) { 9532 $params = array(); 9533 $params['context'] = array(context_system::instance()); 9534 $params['onlyvisible'] = false; 9535 $params['type'] = $typename; 9536 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params)); 9537 // site instances 9538 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber); 9539 $params['context'] = array(); 9540 $instances = repository::static_function($typename, 'get_instances', $params); 9541 $courseinstances = array(); 9542 $userinstances = array(); 9543 9544 foreach ($instances as $instance) { 9545 $repocontext = context::instance_by_id($instance->instance->contextid); 9546 if ($repocontext->contextlevel == CONTEXT_COURSE) { 9547 $courseinstances[] = $instance; 9548 } else if ($repocontext->contextlevel == CONTEXT_USER) { 9549 $userinstances[] = $instance; 9550 } 9551 } 9552 // course instances 9553 $instancenumber = count($courseinstances); 9554 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber); 9555 9556 // user private instances 9557 $instancenumber = count($userinstances); 9558 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber); 9559 } else { 9560 $admininstancenumbertext = ""; 9561 $courseinstancenumbertext = ""; 9562 $userinstancenumbertext = ""; 9563 } 9564 9565 $settings .= '<a href="' . $this->baseurl . '&action=edit&repos=' . $typename . '">' . $settingsstr .'</a>'; 9566 9567 $settings .= $OUTPUT->container_start('mdl-left'); 9568 $settings .= '<br/>'; 9569 $settings .= $admininstancenumbertext; 9570 $settings .= '<br/>'; 9571 $settings .= $courseinstancenumbertext; 9572 $settings .= '<br/>'; 9573 $settings .= $userinstancenumbertext; 9574 $settings .= $OUTPUT->container_end(); 9575 } 9576 // Get the current visibility 9577 if ($i->get_visible()) { 9578 $currentaction = 'show'; 9579 } else { 9580 $currentaction = 'hide'; 9581 } 9582 9583 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename)); 9584 9585 // Display up/down link 9586 $updown = ''; 9587 // Should be done with CSS instead. 9588 $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon')); 9589 9590 if ($updowncount > 1) { 9591 $updown .= "<a href=\"$this->baseurl&action=moveup&repos=".$typename."\">"; 9592 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a> '; 9593 } 9594 else { 9595 $updown .= $spacer; 9596 } 9597 if ($updowncount < $totalrepositorytypes) { 9598 $updown .= "<a href=\"$this->baseurl&action=movedown&repos=".$typename."\">"; 9599 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a> '; 9600 } 9601 else { 9602 $updown .= $spacer; 9603 } 9604 9605 $updowncount++; 9606 9607 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings); 9608 9609 if (!in_array($typename, $alreadyplugins)) { 9610 $alreadyplugins[] = $typename; 9611 } 9612 } 9613 } 9614 9615 // Get all the plugins that exist on disk 9616 $plugins = core_component::get_plugin_list('repository'); 9617 if (!empty($plugins)) { 9618 foreach ($plugins as $plugin => $dir) { 9619 // Check that it has not already been listed 9620 if (!in_array($plugin, $alreadyplugins)) { 9621 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin)); 9622 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', ''); 9623 } 9624 } 9625 } 9626 9627 $return .= html_writer::table($table); 9628 $return .= $OUTPUT->box_end(); 9629 return highlight($query, $return); 9630 } 9631 } 9632 9633 /** 9634 * Special checkbox for enable mobile web service 9635 * If enable then we store the service id of the mobile service into config table 9636 * If disable then we unstore the service id from the config table 9637 */ 9638 class admin_setting_enablemobileservice extends admin_setting_configcheckbox { 9639 9640 /** @var boolean True means that the capability 'webservice/rest:use' is set for authenticated user role */ 9641 private $restuse; 9642 9643 /** 9644 * Return true if Authenticated user role has the capability 'webservice/rest:use', otherwise false. 9645 * 9646 * @return boolean 9647 */ 9648 private function is_protocol_cap_allowed() { 9649 global $DB, $CFG; 9650 9651 // If the $this->restuse variable is not set, it needs to be set. 9652 if (empty($this->restuse) and $this->restuse!==false) { 9653 $params = array(); 9654 $params['permission'] = CAP_ALLOW; 9655 $params['roleid'] = $CFG->defaultuserroleid; 9656 $params['capability'] = 'webservice/rest:use'; 9657 $this->restuse = $DB->record_exists('role_capabilities', $params); 9658 } 9659 9660 return $this->restuse; 9661 } 9662 9663 /** 9664 * Set the 'webservice/rest:use' to the Authenticated user role (allow or not) 9665 * @param type $status true to allow, false to not set 9666 */ 9667 private function set_protocol_cap($status) { 9668 global $CFG; 9669 if ($status and !$this->is_protocol_cap_allowed()) { 9670 //need to allow the cap 9671 $permission = CAP_ALLOW; 9672 $assign = true; 9673 } else if (!$status and $this->is_protocol_cap_allowed()){ 9674 //need to disallow the cap 9675 $permission = CAP_INHERIT; 9676 $assign = true; 9677 } 9678 if (!empty($assign)) { 9679 $systemcontext = context_system::instance(); 9680 assign_capability('webservice/rest:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true); 9681 } 9682 } 9683 9684 /** 9685 * Builds XHTML to display the control. 9686 * The main purpose of this overloading is to display a warning when https 9687 * is not supported by the server 9688 * @param string $data Unused 9689 * @param string $query 9690 * @return string XHTML 9691 */ 9692 public function output_html($data, $query='') { 9693 global $OUTPUT; 9694 $html = parent::output_html($data, $query); 9695 9696 if ((string)$data === $this->yes) { 9697 $notifications = tool_mobile\api::get_potential_config_issues(); // Safe to call, plugin available if we reach here. 9698 foreach ($notifications as $notification) { 9699 $message = get_string($notification[0], $notification[1]); 9700 $html .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING); 9701 } 9702 } 9703 9704 return $html; 9705 } 9706 9707 /** 9708 * Retrieves the current setting using the objects name 9709 * 9710 * @return string 9711 */ 9712 public function get_setting() { 9713 global $CFG; 9714 9715 // First check if is not set. 9716 $result = $this->config_read($this->name); 9717 if (is_null($result)) { 9718 return null; 9719 } 9720 9721 // For install cli script, $CFG->defaultuserroleid is not set so return 0 9722 // Or if web services aren't enabled this can't be, 9723 if (empty($CFG->defaultuserroleid) || empty($CFG->enablewebservices)) { 9724 return 0; 9725 } 9726 9727 require_once($CFG->dirroot . '/webservice/lib.php'); 9728 $webservicemanager = new webservice(); 9729 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 9730 if ($mobileservice->enabled and $this->is_protocol_cap_allowed()) { 9731 return $result; 9732 } else { 9733 return 0; 9734 } 9735 } 9736 9737 /** 9738 * Save the selected setting 9739 * 9740 * @param string $data The selected site 9741 * @return string empty string or error message 9742 */ 9743 public function write_setting($data) { 9744 global $DB, $CFG; 9745 9746 //for install cli script, $CFG->defaultuserroleid is not set so do nothing 9747 if (empty($CFG->defaultuserroleid)) { 9748 return ''; 9749 } 9750 9751 $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE; 9752 9753 require_once($CFG->dirroot . '/webservice/lib.php'); 9754 $webservicemanager = new webservice(); 9755 9756 $updateprotocol = false; 9757 if ((string)$data === $this->yes) { 9758 //code run when enable mobile web service 9759 //enable web service systeme if necessary 9760 set_config('enablewebservices', true); 9761 9762 //enable mobile service 9763 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 9764 $mobileservice->enabled = 1; 9765 $webservicemanager->update_external_service($mobileservice); 9766 9767 // Enable REST server. 9768 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); 9769 9770 if (!in_array('rest', $activeprotocols)) { 9771 $activeprotocols[] = 'rest'; 9772 $updateprotocol = true; 9773 } 9774 9775 if ($updateprotocol) { 9776 set_config('webserviceprotocols', implode(',', $activeprotocols)); 9777 } 9778 9779 // Allow rest:use capability for authenticated user. 9780 $this->set_protocol_cap(true); 9781 } else { 9782 // Disable the mobile service. 9783 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 9784 $mobileservice->enabled = 0; 9785 $webservicemanager->update_external_service($mobileservice); 9786 } 9787 9788 return (parent::write_setting($data)); 9789 } 9790 } 9791 9792 /** 9793 * Special class for management of external services 9794 * 9795 * @author Petr Skoda (skodak) 9796 */ 9797 class admin_setting_manageexternalservices extends admin_setting { 9798 /** 9799 * Calls parent::__construct with specific arguments 9800 */ 9801 public function __construct() { 9802 $this->nosave = true; 9803 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', ''); 9804 } 9805 9806 /** 9807 * Always returns true, does nothing 9808 * 9809 * @return true 9810 */ 9811 public function get_setting() { 9812 return true; 9813 } 9814 9815 /** 9816 * Always returns true, does nothing 9817 * 9818 * @return true 9819 */ 9820 public function get_defaultsetting() { 9821 return true; 9822 } 9823 9824 /** 9825 * Always returns '', does not write anything 9826 * 9827 * @return string Always returns '' 9828 */ 9829 public function write_setting($data) { 9830 // do not write any setting 9831 return ''; 9832 } 9833 9834 /** 9835 * Checks if $query is one of the available external services 9836 * 9837 * @param string $query The string to search for 9838 * @return bool Returns true if found, false if not 9839 */ 9840 public function is_related($query) { 9841 global $DB; 9842 9843 if (parent::is_related($query)) { 9844 return true; 9845 } 9846 9847 $services = $DB->get_records('external_services', array(), 'id, name'); 9848 foreach ($services as $service) { 9849 if (strpos(core_text::strtolower($service->name), $query) !== false) { 9850 return true; 9851 } 9852 } 9853 return false; 9854 } 9855 9856 /** 9857 * Builds the XHTML to display the control 9858 * 9859 * @param string $data Unused 9860 * @param string $query 9861 * @return string 9862 */ 9863 public function output_html($data, $query='') { 9864 global $CFG, $OUTPUT, $DB; 9865 9866 // display strings 9867 $stradministration = get_string('administration'); 9868 $stredit = get_string('edit'); 9869 $strservice = get_string('externalservice', 'webservice'); 9870 $strdelete = get_string('delete'); 9871 $strplugin = get_string('plugin', 'admin'); 9872 $stradd = get_string('add'); 9873 $strfunctions = get_string('functions', 'webservice'); 9874 $strusers = get_string('users'); 9875 $strserviceusers = get_string('serviceusers', 'webservice'); 9876 9877 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php"; 9878 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php"; 9879 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php"; 9880 9881 // built in services 9882 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name'); 9883 $return = ""; 9884 if (!empty($services)) { 9885 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main'); 9886 9887 9888 9889 $table = new html_table(); 9890 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit); 9891 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign '); 9892 $table->id = 'builtinservices'; 9893 $table->attributes['class'] = 'admintable externalservices generaltable'; 9894 $table->data = array(); 9895 9896 // iterate through auth plugins and add to the display table 9897 foreach ($services as $service) { 9898 $name = $service->name; 9899 9900 // hide/show link 9901 if ($service->enabled) { 9902 $displayname = "<span>$name</span>"; 9903 } else { 9904 $displayname = "<span class=\"dimmed_text\">$name</span>"; 9905 } 9906 9907 $plugin = $service->component; 9908 9909 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>"; 9910 9911 if ($service->restrictedusers) { 9912 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>"; 9913 } else { 9914 $users = get_string('allusers', 'webservice'); 9915 } 9916 9917 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>"; 9918 9919 // add a row to the table 9920 $table->data[] = array($displayname, $plugin, $functions, $users, $edit); 9921 } 9922 $return .= html_writer::table($table); 9923 } 9924 9925 // Custom services 9926 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main'); 9927 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name'); 9928 9929 $table = new html_table(); 9930 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit); 9931 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign '); 9932 $table->id = 'customservices'; 9933 $table->attributes['class'] = 'admintable externalservices generaltable'; 9934 $table->data = array(); 9935 9936 // iterate through auth plugins and add to the display table 9937 foreach ($services as $service) { 9938 $name = $service->name; 9939 9940 // hide/show link 9941 if ($service->enabled) { 9942 $displayname = "<span>$name</span>"; 9943 } else { 9944 $displayname = "<span class=\"dimmed_text\">$name</span>"; 9945 } 9946 9947 // delete link 9948 $delete = "<a href=\"$esurl?action=delete&sesskey=".sesskey()."&id=$service->id\">$strdelete</a>"; 9949 9950 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>"; 9951 9952 if ($service->restrictedusers) { 9953 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>"; 9954 } else { 9955 $users = get_string('allusers', 'webservice'); 9956 } 9957 9958 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>"; 9959 9960 // add a row to the table 9961 $table->data[] = array($displayname, $delete, $functions, $users, $edit); 9962 } 9963 // add new custom service option 9964 $return .= html_writer::table($table); 9965 9966 $return .= '<br />'; 9967 // add a token to the table 9968 $return .= "<a href=\"$esurl?id=0\">$stradd</a>"; 9969 9970 return highlight($query, $return); 9971 } 9972 } 9973 9974 /** 9975 * Special class for overview of external services 9976 * 9977 * @author Jerome Mouneyrac 9978 */ 9979 class admin_setting_webservicesoverview extends admin_setting { 9980 9981 /** 9982 * Calls parent::__construct with specific arguments 9983 */ 9984 public function __construct() { 9985 $this->nosave = true; 9986 parent::__construct('webservicesoverviewui', 9987 get_string('webservicesoverview', 'webservice'), '', ''); 9988 } 9989 9990 /** 9991 * Always returns true, does nothing 9992 * 9993 * @return true 9994 */ 9995 public function get_setting() { 9996 return true; 9997 } 9998 9999 /** 10000 * Always returns true, does nothing 10001 * 10002 * @return true 10003 */ 10004 public function get_defaultsetting() { 10005 return true; 10006 } 10007 10008 /** 10009 * Always returns '', does not write anything 10010 * 10011 * @return string Always returns '' 10012 */ 10013 public function write_setting($data) { 10014 // do not write any setting 10015 return ''; 10016 } 10017 10018 /** 10019 * Builds the XHTML to display the control 10020 * 10021 * @param string $data Unused 10022 * @param string $query 10023 * @return string 10024 */ 10025 public function output_html($data, $query='') { 10026 global $CFG, $OUTPUT; 10027 10028 $return = ""; 10029 $brtag = html_writer::empty_tag('br'); 10030 10031 /// One system controlling Moodle with Token 10032 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main'); 10033 $table = new html_table(); 10034 $table->head = array(get_string('step', 'webservice'), get_string('status'), 10035 get_string('description')); 10036 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description'); 10037 $table->id = 'onesystemcontrol'; 10038 $table->attributes['class'] = 'admintable wsoverview generaltable'; 10039 $table->data = array(); 10040 10041 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice') 10042 . $brtag . $brtag; 10043 10044 /// 1. Enable Web Services 10045 $row = array(); 10046 $url = new moodle_url("/admin/search.php?query=enablewebservices"); 10047 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'), 10048 array('href' => $url)); 10049 $status = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 10050 if ($CFG->enablewebservices) { 10051 $status = get_string('yes'); 10052 } 10053 $row[1] = $status; 10054 $row[2] = get_string('enablewsdescription', 'webservice'); 10055 $table->data[] = $row; 10056 10057 /// 2. Enable protocols 10058 $row = array(); 10059 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols"); 10060 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'), 10061 array('href' => $url)); 10062 $status = html_writer::tag('span', get_string('none'), array('class' => 'badge badge-danger')); 10063 //retrieve activated protocol 10064 $active_protocols = empty($CFG->webserviceprotocols) ? 10065 array() : explode(',', $CFG->webserviceprotocols); 10066 if (!empty($active_protocols)) { 10067 $status = ""; 10068 foreach ($active_protocols as $protocol) { 10069 $status .= $protocol . $brtag; 10070 } 10071 } 10072 $row[1] = $status; 10073 $row[2] = get_string('enableprotocolsdescription', 'webservice'); 10074 $table->data[] = $row; 10075 10076 /// 3. Create user account 10077 $row = array(); 10078 $url = new moodle_url("/user/editadvanced.php?id=-1"); 10079 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'), 10080 array('href' => $url)); 10081 $row[1] = ""; 10082 $row[2] = get_string('createuserdescription', 'webservice'); 10083 $table->data[] = $row; 10084 10085 /// 4. Add capability to users 10086 $row = array(); 10087 $url = new moodle_url("/admin/roles/check.php?contextid=1"); 10088 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'), 10089 array('href' => $url)); 10090 $row[1] = ""; 10091 $row[2] = get_string('checkusercapabilitydescription', 'webservice'); 10092 $table->data[] = $row; 10093 10094 /// 5. Select a web service 10095 $row = array(); 10096 $url = new moodle_url("/admin/settings.php?section=externalservices"); 10097 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'), 10098 array('href' => $url)); 10099 $row[1] = ""; 10100 $row[2] = get_string('createservicedescription', 'webservice'); 10101 $table->data[] = $row; 10102 10103 /// 6. Add functions 10104 $row = array(); 10105 $url = new moodle_url("/admin/settings.php?section=externalservices"); 10106 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'), 10107 array('href' => $url)); 10108 $row[1] = ""; 10109 $row[2] = get_string('addfunctionsdescription', 'webservice'); 10110 $table->data[] = $row; 10111 10112 /// 7. Add the specific user 10113 $row = array(); 10114 $url = new moodle_url("/admin/settings.php?section=externalservices"); 10115 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'), 10116 array('href' => $url)); 10117 $row[1] = ""; 10118 $row[2] = get_string('selectspecificuserdescription', 'webservice'); 10119 $table->data[] = $row; 10120 10121 /// 8. Create token for the specific user 10122 $row = array(); 10123 $url = new moodle_url('/admin/webservice/tokens.php', ['action' => 'create']); 10124 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'), 10125 array('href' => $url)); 10126 $row[1] = ""; 10127 $row[2] = get_string('createtokenforuserdescription', 'webservice'); 10128 $table->data[] = $row; 10129 10130 /// 9. Enable the documentation 10131 $row = array(); 10132 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation"); 10133 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'), 10134 array('href' => $url)); 10135 $status = '<span class="warning">' . get_string('no') . '</span>'; 10136 if ($CFG->enablewsdocumentation) { 10137 $status = get_string('yes'); 10138 } 10139 $row[1] = $status; 10140 $row[2] = get_string('enabledocumentationdescription', 'webservice'); 10141 $table->data[] = $row; 10142 10143 /// 10. Test the service 10144 $row = array(); 10145 $url = new moodle_url("/admin/webservice/testclient.php"); 10146 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'), 10147 array('href' => $url)); 10148 $row[1] = ""; 10149 $row[2] = get_string('testwithtestclientdescription', 'webservice'); 10150 $table->data[] = $row; 10151 10152 $return .= html_writer::table($table); 10153 10154 /// Users as clients with token 10155 $return .= $brtag . $brtag . $brtag; 10156 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main'); 10157 $table = new html_table(); 10158 $table->head = array(get_string('step', 'webservice'), get_string('status'), 10159 get_string('description')); 10160 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description'); 10161 $table->id = 'userasclients'; 10162 $table->attributes['class'] = 'admintable wsoverview generaltable'; 10163 $table->data = array(); 10164 10165 $return .= $brtag . get_string('userasclientsdescription', 'webservice') . 10166 $brtag . $brtag; 10167 10168 /// 1. Enable Web Services 10169 $row = array(); 10170 $url = new moodle_url("/admin/search.php?query=enablewebservices"); 10171 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'), 10172 array('href' => $url)); 10173 $status = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 10174 if ($CFG->enablewebservices) { 10175 $status = get_string('yes'); 10176 } 10177 $row[1] = $status; 10178 $row[2] = get_string('enablewsdescription', 'webservice'); 10179 $table->data[] = $row; 10180 10181 /// 2. Enable protocols 10182 $row = array(); 10183 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols"); 10184 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'), 10185 array('href' => $url)); 10186 $status = html_writer::tag('span', get_string('none'), array('class' => 'badge badge-danger')); 10187 //retrieve activated protocol 10188 $active_protocols = empty($CFG->webserviceprotocols) ? 10189 array() : explode(',', $CFG->webserviceprotocols); 10190 if (!empty($active_protocols)) { 10191 $status = ""; 10192 foreach ($active_protocols as $protocol) { 10193 $status .= $protocol . $brtag; 10194 } 10195 } 10196 $row[1] = $status; 10197 $row[2] = get_string('enableprotocolsdescription', 'webservice'); 10198 $table->data[] = $row; 10199 10200 10201 /// 3. Select a web service 10202 $row = array(); 10203 $url = new moodle_url("/admin/settings.php?section=externalservices"); 10204 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'), 10205 array('href' => $url)); 10206 $row[1] = ""; 10207 $row[2] = get_string('createserviceforusersdescription', 'webservice'); 10208 $table->data[] = $row; 10209 10210 /// 4. Add functions 10211 $row = array(); 10212 $url = new moodle_url("/admin/settings.php?section=externalservices"); 10213 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'), 10214 array('href' => $url)); 10215 $row[1] = ""; 10216 $row[2] = get_string('addfunctionsdescription', 'webservice'); 10217 $table->data[] = $row; 10218 10219 /// 5. Add capability to users 10220 $row = array(); 10221 $url = new moodle_url("/admin/roles/check.php?contextid=1"); 10222 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'), 10223 array('href' => $url)); 10224 $row[1] = ""; 10225 $row[2] = get_string('addcapabilitytousersdescription', 'webservice'); 10226 $table->data[] = $row; 10227 10228 /// 6. Test the service 10229 $row = array(); 10230 $url = new moodle_url("/admin/webservice/testclient.php"); 10231 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'), 10232 array('href' => $url)); 10233 $row[1] = ""; 10234 $row[2] = get_string('testauserwithtestclientdescription', 'webservice'); 10235 $table->data[] = $row; 10236 10237 $return .= html_writer::table($table); 10238 10239 return highlight($query, $return); 10240 } 10241 10242 } 10243 10244 10245 /** 10246 * Special class for web service protocol administration. 10247 * 10248 * @author Petr Skoda (skodak) 10249 */ 10250 class admin_setting_managewebserviceprotocols extends admin_setting { 10251 10252 /** 10253 * Calls parent::__construct with specific arguments 10254 */ 10255 public function __construct() { 10256 $this->nosave = true; 10257 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', ''); 10258 } 10259 10260 /** 10261 * Always returns true, does nothing 10262 * 10263 * @return true 10264 */ 10265 public function get_setting() { 10266 return true; 10267 } 10268 10269 /** 10270 * Always returns true, does nothing 10271 * 10272 * @return true 10273 */ 10274 public function get_defaultsetting() { 10275 return true; 10276 } 10277 10278 /** 10279 * Always returns '', does not write anything 10280 * 10281 * @return string Always returns '' 10282 */ 10283 public function write_setting($data) { 10284 // do not write any setting 10285 return ''; 10286 } 10287 10288 /** 10289 * Checks if $query is one of the available webservices 10290 * 10291 * @param string $query The string to search for 10292 * @return bool Returns true if found, false if not 10293 */ 10294 public function is_related($query) { 10295 if (parent::is_related($query)) { 10296 return true; 10297 } 10298 10299 $protocols = core_component::get_plugin_list('webservice'); 10300 foreach ($protocols as $protocol=>$location) { 10301 if (strpos($protocol, $query) !== false) { 10302 return true; 10303 } 10304 $protocolstr = get_string('pluginname', 'webservice_'.$protocol); 10305 if (strpos(core_text::strtolower($protocolstr), $query) !== false) { 10306 return true; 10307 } 10308 } 10309 return false; 10310 } 10311 10312 /** 10313 * Builds the XHTML to display the control 10314 * 10315 * @param string $data Unused 10316 * @param string $query 10317 * @return string 10318 */ 10319 public function output_html($data, $query='') { 10320 global $CFG, $OUTPUT; 10321 10322 // display strings 10323 $stradministration = get_string('administration'); 10324 $strsettings = get_string('settings'); 10325 $stredit = get_string('edit'); 10326 $strprotocol = get_string('protocol', 'webservice'); 10327 $strenable = get_string('enable'); 10328 $strdisable = get_string('disable'); 10329 $strversion = get_string('version'); 10330 10331 $protocols_available = core_component::get_plugin_list('webservice'); 10332 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); 10333 ksort($protocols_available); 10334 10335 foreach ($active_protocols as $key=>$protocol) { 10336 if (empty($protocols_available[$protocol])) { 10337 unset($active_protocols[$key]); 10338 } 10339 } 10340 10341 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main'); 10342 $return .= $OUTPUT->box_start('generalbox webservicesui'); 10343 10344 $table = new html_table(); 10345 $table->head = array($strprotocol, $strversion, $strenable, $strsettings); 10346 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 10347 $table->id = 'webserviceprotocols'; 10348 $table->attributes['class'] = 'admintable generaltable'; 10349 $table->data = array(); 10350 10351 // iterate through auth plugins and add to the display table 10352 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey(); 10353 foreach ($protocols_available as $protocol => $location) { 10354 $name = get_string('pluginname', 'webservice_'.$protocol); 10355 10356 $plugin = new stdClass(); 10357 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) { 10358 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php'); 10359 } 10360 $version = isset($plugin->version) ? $plugin->version : ''; 10361 10362 // hide/show link 10363 if (in_array($protocol, $active_protocols)) { 10364 $hideshow = "<a href=\"$url&action=disable&webservice=$protocol\">"; 10365 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>'; 10366 $displayname = "<span>$name</span>"; 10367 } else { 10368 $hideshow = "<a href=\"$url&action=enable&webservice=$protocol\">"; 10369 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>'; 10370 $displayname = "<span class=\"dimmed_text\">$name</span>"; 10371 } 10372 10373 // settings link 10374 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) { 10375 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>"; 10376 } else { 10377 $settings = ''; 10378 } 10379 10380 // add a row to the table 10381 $table->data[] = array($displayname, $version, $hideshow, $settings); 10382 } 10383 $return .= html_writer::table($table); 10384 $return .= get_string('configwebserviceplugins', 'webservice'); 10385 $return .= $OUTPUT->box_end(); 10386 10387 return highlight($query, $return); 10388 } 10389 } 10390 10391 /** 10392 * Colour picker 10393 * 10394 * @copyright 2010 Sam Hemelryk 10395 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 10396 */ 10397 class admin_setting_configcolourpicker extends admin_setting { 10398 10399 /** 10400 * Information for previewing the colour 10401 * 10402 * @var array|null 10403 */ 10404 protected $previewconfig = null; 10405 10406 /** 10407 * Use default when empty. 10408 */ 10409 protected $usedefaultwhenempty = true; 10410 10411 /** 10412 * 10413 * @param string $name 10414 * @param string $visiblename 10415 * @param string $description 10416 * @param string $defaultsetting 10417 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor'); 10418 */ 10419 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig = null, 10420 $usedefaultwhenempty = true) { 10421 $this->previewconfig = $previewconfig; 10422 $this->usedefaultwhenempty = $usedefaultwhenempty; 10423 parent::__construct($name, $visiblename, $description, $defaultsetting); 10424 $this->set_force_ltr(true); 10425 } 10426 10427 /** 10428 * Return the setting 10429 * 10430 * @return mixed returns config if successful else null 10431 */ 10432 public function get_setting() { 10433 return $this->config_read($this->name); 10434 } 10435 10436 /** 10437 * Saves the setting 10438 * 10439 * @param string $data 10440 * @return bool 10441 */ 10442 public function write_setting($data) { 10443 $data = $this->validate($data); 10444 if ($data === false) { 10445 return get_string('validateerror', 'admin'); 10446 } 10447 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 10448 } 10449 10450 /** 10451 * Validates the colour that was entered by the user 10452 * 10453 * @param string $data 10454 * @return string|false 10455 */ 10456 protected function validate($data) { 10457 /** 10458 * List of valid HTML colour names 10459 * 10460 * @var array 10461 */ 10462 $colornames = array( 10463 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 10464 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 10465 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 10466 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 10467 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 10468 'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta', 10469 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 10470 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 10471 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 10472 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 10473 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 10474 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green', 10475 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 10476 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 10477 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 10478 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen', 10479 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 10480 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 10481 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 10482 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 10483 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 10484 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 10485 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 10486 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 10487 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 10488 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red', 10489 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 10490 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 10491 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 10492 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 10493 'whitesmoke', 'yellow', 'yellowgreen' 10494 ); 10495 10496 if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $data)) { 10497 if (strpos($data, '#')!==0) { 10498 $data = '#'.$data; 10499 } 10500 return $data; 10501 } else if (in_array(strtolower($data), $colornames)) { 10502 return $data; 10503 } else if (preg_match('/rgb\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\)/i', $data)) { 10504 return $data; 10505 } else if (preg_match('/rgba\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\, ?\d(\.\d)?\)/i', $data)) { 10506 return $data; 10507 } else if (preg_match('/hsl\(\d{0,3}\, ?\d{0,3}%, ?\d{0,3}%\)/i', $data)) { 10508 return $data; 10509 } else if (preg_match('/hsla\(\d{0,3}\, ?\d{0,3}%,\d{0,3}%\, ?\d(\.\d)?\)/i', $data)) { 10510 return $data; 10511 } else if (($data == 'transparent') || ($data == 'currentColor') || ($data == 'inherit')) { 10512 return $data; 10513 } else if (empty($data)) { 10514 if ($this->usedefaultwhenempty){ 10515 return $this->defaultsetting; 10516 } else { 10517 return ''; 10518 } 10519 } else { 10520 return false; 10521 } 10522 } 10523 10524 /** 10525 * Generates the HTML for the setting 10526 * 10527 * @global moodle_page $PAGE 10528 * @global core_renderer $OUTPUT 10529 * @param string $data 10530 * @param string $query 10531 */ 10532 public function output_html($data, $query = '') { 10533 global $PAGE, $OUTPUT; 10534 10535 $icon = new pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', ['class' => 'loadingicon']); 10536 $context = (object) [ 10537 'id' => $this->get_id(), 10538 'name' => $this->get_full_name(), 10539 'value' => $data, 10540 'icon' => $icon->export_for_template($OUTPUT), 10541 'haspreviewconfig' => !empty($this->previewconfig), 10542 'forceltr' => $this->get_force_ltr(), 10543 'readonly' => $this->is_readonly(), 10544 ]; 10545 10546 $element = $OUTPUT->render_from_template('core_admin/setting_configcolourpicker', $context); 10547 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig)); 10548 10549 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', 10550 $this->get_defaultsetting(), $query); 10551 } 10552 10553 } 10554 10555 10556 /** 10557 * Class used for uploading of one file into file storage, 10558 * the file name is stored in config table. 10559 * 10560 * Please note you need to implement your own '_pluginfile' callback function, 10561 * this setting only stores the file, it does not deal with file serving. 10562 * 10563 * @copyright 2013 Petr Skoda {@link http://skodak.org} 10564 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 10565 */ 10566 class admin_setting_configstoredfile extends admin_setting { 10567 /** @var array file area options - should be one file only */ 10568 protected $options; 10569 /** @var string name of the file area */ 10570 protected $filearea; 10571 /** @var int intemid */ 10572 protected $itemid; 10573 /** @var string used for detection of changes */ 10574 protected $oldhashes; 10575 10576 /** 10577 * Create new stored file setting. 10578 * 10579 * @param string $name low level setting name 10580 * @param string $visiblename human readable setting name 10581 * @param string $description description of setting 10582 * @param mixed $filearea file area for file storage 10583 * @param int $itemid itemid for file storage 10584 * @param array $options file area options 10585 */ 10586 public function __construct($name, $visiblename, $description, $filearea, $itemid = 0, array $options = null) { 10587 parent::__construct($name, $visiblename, $description, ''); 10588 $this->filearea = $filearea; 10589 $this->itemid = $itemid; 10590 $this->options = (array)$options; 10591 $this->customcontrol = true; 10592 } 10593 10594 /** 10595 * Applies defaults and returns all options. 10596 * @return array 10597 */ 10598 protected function get_options() { 10599 global $CFG; 10600 10601 require_once("$CFG->libdir/filelib.php"); 10602 require_once("$CFG->dirroot/repository/lib.php"); 10603 $defaults = array( 10604 'mainfile' => '', 'subdirs' => 0, 'maxbytes' => -1, 'maxfiles' => 1, 10605 'accepted_types' => '*', 'return_types' => FILE_INTERNAL, 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 10606 'context' => context_system::instance()); 10607 foreach($this->options as $k => $v) { 10608 $defaults[$k] = $v; 10609 } 10610 10611 return $defaults; 10612 } 10613 10614 public function get_setting() { 10615 return $this->config_read($this->name); 10616 } 10617 10618 public function write_setting($data) { 10619 global $USER; 10620 10621 // Let's not deal with validation here, this is for admins only. 10622 $current = $this->get_setting(); 10623 if (empty($data) && $current === null) { 10624 // This will be the case when applying default settings (installation). 10625 return ($this->config_write($this->name, '') ? '' : get_string('errorsetting', 'admin')); 10626 } else if (!is_number($data)) { 10627 // Draft item id is expected here! 10628 return get_string('errorsetting', 'admin'); 10629 } 10630 10631 $options = $this->get_options(); 10632 $fs = get_file_storage(); 10633 $component = is_null($this->plugin) ? 'core' : $this->plugin; 10634 10635 $this->oldhashes = null; 10636 if ($current) { 10637 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current); 10638 if ($file = $fs->get_file_by_hash($hash)) { 10639 $this->oldhashes = $file->get_contenthash().$file->get_pathnamehash(); 10640 } 10641 unset($file); 10642 } 10643 10644 if ($fs->file_exists($options['context']->id, $component, $this->filearea, $this->itemid, '/', '.')) { 10645 // Make sure the settings form was not open for more than 4 days and draft areas deleted in the meantime. 10646 // But we can safely ignore that if the destination area is empty, so that the user is not prompt 10647 // with an error because the draft area does not exist, as he did not use it. 10648 $usercontext = context_user::instance($USER->id); 10649 if (!$fs->file_exists($usercontext->id, 'user', 'draft', $data, '/', '.') && $current !== '') { 10650 return get_string('errorsetting', 'admin'); 10651 } 10652 } 10653 10654 file_save_draft_area_files($data, $options['context']->id, $component, $this->filearea, $this->itemid, $options); 10655 $files = $fs->get_area_files($options['context']->id, $component, $this->filearea, $this->itemid, 'sortorder,filepath,filename', false); 10656 10657 $filepath = ''; 10658 if ($files) { 10659 /** @var stored_file $file */ 10660 $file = reset($files); 10661 $filepath = $file->get_filepath().$file->get_filename(); 10662 } 10663 10664 return ($this->config_write($this->name, $filepath) ? '' : get_string('errorsetting', 'admin')); 10665 } 10666 10667 public function post_write_settings($original) { 10668 $options = $this->get_options(); 10669 $fs = get_file_storage(); 10670 $component = is_null($this->plugin) ? 'core' : $this->plugin; 10671 10672 $current = $this->get_setting(); 10673 $newhashes = null; 10674 if ($current) { 10675 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current); 10676 if ($file = $fs->get_file_by_hash($hash)) { 10677 $newhashes = $file->get_contenthash().$file->get_pathnamehash(); 10678 } 10679 unset($file); 10680 } 10681 10682 if ($this->oldhashes === $newhashes) { 10683 $this->oldhashes = null; 10684 return false; 10685 } 10686 $this->oldhashes = null; 10687 10688 $callbackfunction = $this->updatedcallback; 10689 if (!empty($callbackfunction) and function_exists($callbackfunction)) { 10690 $callbackfunction($this->get_full_name()); 10691 } 10692 return true; 10693 } 10694 10695 public function output_html($data, $query = '') { 10696 global $PAGE, $CFG; 10697 10698 $options = $this->get_options(); 10699 $id = $this->get_id(); 10700 $elname = $this->get_full_name(); 10701 $draftitemid = file_get_submitted_draft_itemid($elname); 10702 $component = is_null($this->plugin) ? 'core' : $this->plugin; 10703 file_prepare_draft_area($draftitemid, $options['context']->id, $component, $this->filearea, $this->itemid, $options); 10704 10705 // Filemanager form element implementation is far from optimal, we need to rework this if we ever fix it... 10706 require_once("$CFG->dirroot/lib/form/filemanager.php"); 10707 10708 $fmoptions = new stdClass(); 10709 $fmoptions->mainfile = $options['mainfile']; 10710 $fmoptions->maxbytes = $options['maxbytes']; 10711 $fmoptions->maxfiles = $options['maxfiles']; 10712 $fmoptions->client_id = uniqid(); 10713 $fmoptions->itemid = $draftitemid; 10714 $fmoptions->subdirs = $options['subdirs']; 10715 $fmoptions->target = $id; 10716 $fmoptions->accepted_types = $options['accepted_types']; 10717 $fmoptions->return_types = $options['return_types']; 10718 $fmoptions->context = $options['context']; 10719 $fmoptions->areamaxbytes = $options['areamaxbytes']; 10720 10721 $fm = new form_filemanager($fmoptions); 10722 $output = $PAGE->get_renderer('core', 'files'); 10723 $html = $output->render($fm); 10724 10725 $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />'; 10726 $html .= '<input value="" id="'.$id.'" type="hidden" />'; 10727 10728 return format_admin_setting($this, $this->visiblename, 10729 '<div class="form-filemanager" data-fieldtype="filemanager">'.$html.'</div>', 10730 $this->description, true, '', '', $query); 10731 } 10732 } 10733 10734 10735 /** 10736 * Administration interface for user specified regular expressions for device detection. 10737 * 10738 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 10739 */ 10740 class admin_setting_devicedetectregex extends admin_setting { 10741 10742 /** 10743 * Calls parent::__construct with specific args 10744 * 10745 * @param string $name 10746 * @param string $visiblename 10747 * @param string $description 10748 * @param mixed $defaultsetting 10749 */ 10750 public function __construct($name, $visiblename, $description, $defaultsetting = '') { 10751 global $CFG; 10752 parent::__construct($name, $visiblename, $description, $defaultsetting); 10753 } 10754 10755 /** 10756 * Return the current setting(s) 10757 * 10758 * @return array Current settings array 10759 */ 10760 public function get_setting() { 10761 global $CFG; 10762 10763 $config = $this->config_read($this->name); 10764 if (is_null($config)) { 10765 return null; 10766 } 10767 10768 return $this->prepare_form_data($config); 10769 } 10770 10771 /** 10772 * Save selected settings 10773 * 10774 * @param array $data Array of settings to save 10775 * @return bool 10776 */ 10777 public function write_setting($data) { 10778 if (empty($data)) { 10779 $data = array(); 10780 } 10781 10782 if ($this->config_write($this->name, $this->process_form_data($data))) { 10783 return ''; // success 10784 } else { 10785 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br'); 10786 } 10787 } 10788 10789 /** 10790 * Return XHTML field(s) for regexes 10791 * 10792 * @param array $data Array of options to set in HTML 10793 * @return string XHTML string for the fields and wrapping div(s) 10794 */ 10795 public function output_html($data, $query='') { 10796 global $OUTPUT; 10797 10798 $context = (object) [ 10799 'expressions' => [], 10800 'name' => $this->get_full_name() 10801 ]; 10802 10803 if (empty($data)) { 10804 $looplimit = 1; 10805 } else { 10806 $looplimit = (count($data)/2)+1; 10807 } 10808 10809 for ($i=0; $i<$looplimit; $i++) { 10810 10811 $expressionname = 'expression'.$i; 10812 10813 if (!empty($data[$expressionname])){ 10814 $expression = $data[$expressionname]; 10815 } else { 10816 $expression = ''; 10817 } 10818 10819 $valuename = 'value'.$i; 10820 10821 if (!empty($data[$valuename])){ 10822 $value = $data[$valuename]; 10823 } else { 10824 $value= ''; 10825 } 10826 10827 $context->expressions[] = [ 10828 'index' => $i, 10829 'expression' => $expression, 10830 'value' => $value 10831 ]; 10832 } 10833 10834 $element = $OUTPUT->render_from_template('core_admin/setting_devicedetectregex', $context); 10835 10836 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query); 10837 } 10838 10839 /** 10840 * Converts the string of regexes 10841 * 10842 * @see self::process_form_data() 10843 * @param $regexes string of regexes 10844 * @return array of form fields and their values 10845 */ 10846 protected function prepare_form_data($regexes) { 10847 10848 $regexes = json_decode($regexes); 10849 10850 $form = array(); 10851 10852 $i = 0; 10853 10854 foreach ($regexes as $value => $regex) { 10855 $expressionname = 'expression'.$i; 10856 $valuename = 'value'.$i; 10857 10858 $form[$expressionname] = $regex; 10859 $form[$valuename] = $value; 10860 $i++; 10861 } 10862 10863 return $form; 10864 } 10865 10866 /** 10867 * Converts the data from admin settings form into a string of regexes 10868 * 10869 * @see self::prepare_form_data() 10870 * @param array $data array of admin form fields and values 10871 * @return false|string of regexes 10872 */ 10873 protected function process_form_data(array $form) { 10874 10875 $count = count($form); // number of form field values 10876 10877 if ($count % 2) { 10878 // we must get five fields per expression 10879 return false; 10880 } 10881 10882 $regexes = array(); 10883 for ($i = 0; $i < $count / 2; $i++) { 10884 $expressionname = "expression".$i; 10885 $valuename = "value".$i; 10886 10887 $expression = trim($form['expression'.$i]); 10888 $value = trim($form['value'.$i]); 10889 10890 if (empty($expression)){ 10891 continue; 10892 } 10893 10894 $regexes[$value] = $expression; 10895 } 10896 10897 $regexes = json_encode($regexes); 10898 10899 return $regexes; 10900 } 10901 10902 } 10903 10904 /** 10905 * Multiselect for current modules 10906 * 10907 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 10908 */ 10909 class admin_setting_configmultiselect_modules extends admin_setting_configmultiselect { 10910 private $excludesystem; 10911 10912 /** 10913 * Calls parent::__construct - note array $choices is not required 10914 * 10915 * @param string $name setting name 10916 * @param string $visiblename localised setting name 10917 * @param string $description setting description 10918 * @param array $defaultsetting a plain array of default module ids 10919 * @param bool $excludesystem If true, excludes modules with 'system' archetype 10920 */ 10921 public function __construct($name, $visiblename, $description, $defaultsetting = array(), 10922 $excludesystem = true) { 10923 parent::__construct($name, $visiblename, $description, $defaultsetting, null); 10924 $this->excludesystem = $excludesystem; 10925 } 10926 10927 /** 10928 * Loads an array of current module choices 10929 * 10930 * @return bool always return true 10931 */ 10932 public function load_choices() { 10933 if (is_array($this->choices)) { 10934 return true; 10935 } 10936 $this->choices = array(); 10937 10938 global $CFG, $DB; 10939 $records = $DB->get_records('modules', array('visible'=>1), 'name'); 10940 foreach ($records as $record) { 10941 // Exclude modules if the code doesn't exist 10942 if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) { 10943 // Also exclude system modules (if specified) 10944 if (!($this->excludesystem && 10945 plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) === 10946 MOD_ARCHETYPE_SYSTEM)) { 10947 $this->choices[$record->id] = $record->name; 10948 } 10949 } 10950 } 10951 return true; 10952 } 10953 } 10954 10955 /** 10956 * Admin setting to show if a php extension is enabled or not. 10957 * 10958 * @copyright 2013 Damyon Wiese 10959 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 10960 */ 10961 class admin_setting_php_extension_enabled extends admin_setting { 10962 10963 /** @var string The name of the extension to check for */ 10964 private $extension; 10965 10966 /** 10967 * Calls parent::__construct with specific arguments 10968 */ 10969 public function __construct($name, $visiblename, $description, $extension) { 10970 $this->extension = $extension; 10971 $this->nosave = true; 10972 parent::__construct($name, $visiblename, $description, ''); 10973 } 10974 10975 /** 10976 * Always returns true, does nothing 10977 * 10978 * @return true 10979 */ 10980 public function get_setting() { 10981 return true; 10982 } 10983 10984 /** 10985 * Always returns true, does nothing 10986 * 10987 * @return true 10988 */ 10989 public function get_defaultsetting() { 10990 return true; 10991 } 10992 10993 /** 10994 * Always returns '', does not write anything 10995 * 10996 * @return string Always returns '' 10997 */ 10998 public function write_setting($data) { 10999 // Do not write any setting. 11000 return ''; 11001 } 11002 11003 /** 11004 * Outputs the html for this setting. 11005 * @return string Returns an XHTML string 11006 */ 11007 public function output_html($data, $query='') { 11008 global $OUTPUT; 11009 11010 $o = ''; 11011 if (!extension_loaded($this->extension)) { 11012 $warning = $OUTPUT->pix_icon('i/warning', '', '', array('role' => 'presentation')) . ' ' . $this->description; 11013 11014 $o .= format_admin_setting($this, $this->visiblename, $warning); 11015 } 11016 return $o; 11017 } 11018 } 11019 11020 /** 11021 * Server timezone setting. 11022 * 11023 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 11024 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11025 * @author Petr Skoda <petr.skoda@totaralms.com> 11026 */ 11027 class admin_setting_servertimezone extends admin_setting_configselect { 11028 /** 11029 * Constructor. 11030 */ 11031 public function __construct() { 11032 $default = core_date::get_default_php_timezone(); 11033 if ($default === 'UTC') { 11034 // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most. 11035 $default = 'Europe/London'; 11036 } 11037 11038 parent::__construct('timezone', 11039 new lang_string('timezone', 'core_admin'), 11040 new lang_string('configtimezone', 'core_admin'), $default, null); 11041 } 11042 11043 /** 11044 * Lazy load timezone options. 11045 * @return bool true if loaded, false if error 11046 */ 11047 public function load_choices() { 11048 global $CFG; 11049 if (is_array($this->choices)) { 11050 return true; 11051 } 11052 11053 $current = isset($CFG->timezone) ? $CFG->timezone : null; 11054 $this->choices = core_date::get_list_of_timezones($current, false); 11055 if ($current == 99) { 11056 // Do not show 99 unless it is current value, we want to get rid of it over time. 11057 $this->choices['99'] = new lang_string('timezonephpdefault', 'core_admin', 11058 core_date::get_default_php_timezone()); 11059 } 11060 11061 return true; 11062 } 11063 } 11064 11065 /** 11066 * Forced user timezone setting. 11067 * 11068 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 11069 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11070 * @author Petr Skoda <petr.skoda@totaralms.com> 11071 */ 11072 class admin_setting_forcetimezone extends admin_setting_configselect { 11073 /** 11074 * Constructor. 11075 */ 11076 public function __construct() { 11077 parent::__construct('forcetimezone', 11078 new lang_string('forcetimezone', 'core_admin'), 11079 new lang_string('helpforcetimezone', 'core_admin'), '99', null); 11080 } 11081 11082 /** 11083 * Lazy load timezone options. 11084 * @return bool true if loaded, false if error 11085 */ 11086 public function load_choices() { 11087 global $CFG; 11088 if (is_array($this->choices)) { 11089 return true; 11090 } 11091 11092 $current = isset($CFG->forcetimezone) ? $CFG->forcetimezone : null; 11093 $this->choices = core_date::get_list_of_timezones($current, true); 11094 $this->choices['99'] = new lang_string('timezonenotforced', 'core_admin'); 11095 11096 return true; 11097 } 11098 } 11099 11100 11101 /** 11102 * Search setup steps info. 11103 * 11104 * @package core 11105 * @copyright 2016 David Monllao {@link http://www.davidmonllao.com} 11106 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11107 */ 11108 class admin_setting_searchsetupinfo extends admin_setting { 11109 11110 /** 11111 * Calls parent::__construct with specific arguments 11112 */ 11113 public function __construct() { 11114 $this->nosave = true; 11115 parent::__construct('searchsetupinfo', '', '', ''); 11116 } 11117 11118 /** 11119 * Always returns true, does nothing 11120 * 11121 * @return true 11122 */ 11123 public function get_setting() { 11124 return true; 11125 } 11126 11127 /** 11128 * Always returns true, does nothing 11129 * 11130 * @return true 11131 */ 11132 public function get_defaultsetting() { 11133 return true; 11134 } 11135 11136 /** 11137 * Always returns '', does not write anything 11138 * 11139 * @param array $data 11140 * @return string Always returns '' 11141 */ 11142 public function write_setting($data) { 11143 // Do not write any setting. 11144 return ''; 11145 } 11146 11147 /** 11148 * Builds the HTML to display the control 11149 * 11150 * @param string $data Unused 11151 * @param string $query 11152 * @return string 11153 */ 11154 public function output_html($data, $query='') { 11155 global $CFG, $OUTPUT, $ADMIN; 11156 11157 $return = ''; 11158 $brtag = html_writer::empty_tag('br'); 11159 11160 $searchareas = \core_search\manager::get_search_areas_list(); 11161 $anyenabled = !empty(\core_search\manager::get_search_areas_list(true)); 11162 $anyindexed = false; 11163 foreach ($searchareas as $areaid => $searcharea) { 11164 list($componentname, $varname) = $searcharea->get_config_var_name(); 11165 if (get_config($componentname, $varname . '_indexingstart')) { 11166 $anyindexed = true; 11167 break; 11168 } 11169 } 11170 11171 $return .= $OUTPUT->heading(get_string('searchsetupinfo', 'admin'), 3, 'main'); 11172 11173 $table = new html_table(); 11174 $table->head = array(get_string('step', 'search'), get_string('status')); 11175 $table->colclasses = array('leftalign step', 'leftalign status'); 11176 $table->id = 'searchsetup'; 11177 $table->attributes['class'] = 'admintable generaltable'; 11178 $table->data = array(); 11179 11180 $return .= $brtag . get_string('searchsetupdescription', 'search') . $brtag . $brtag; 11181 11182 // Select a search engine. 11183 $row = array(); 11184 $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#admin-searchengine'); 11185 $row[0] = '1. ' . html_writer::tag('a', get_string('selectsearchengine', 'admin'), 11186 array('href' => $url)); 11187 11188 $status = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 11189 if (!empty($CFG->searchengine)) { 11190 $status = html_writer::tag('span', get_string('pluginname', 'search_' . $CFG->searchengine), 11191 array('class' => 'badge badge-success')); 11192 11193 } 11194 $row[1] = $status; 11195 $table->data[] = $row; 11196 11197 // Available areas. 11198 $row = array(); 11199 $url = new moodle_url('/admin/searchareas.php'); 11200 $row[0] = '2. ' . html_writer::tag('a', get_string('enablesearchareas', 'admin'), 11201 array('href' => $url)); 11202 11203 $status = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 11204 if ($anyenabled) { 11205 $status = html_writer::tag('span', get_string('yes'), array('class' => 'badge badge-success')); 11206 11207 } 11208 $row[1] = $status; 11209 $table->data[] = $row; 11210 11211 // Setup search engine. 11212 $row = array(); 11213 if (empty($CFG->searchengine)) { 11214 $row[0] = '3. ' . get_string('setupsearchengine', 'admin'); 11215 $row[1] = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 11216 } else { 11217 if ($ADMIN->locate('search' . $CFG->searchengine)) { 11218 $url = new moodle_url('/admin/settings.php?section=search' . $CFG->searchengine); 11219 $row[0] = '3. ' . html_writer::link($url, get_string('setupsearchengine', 'core_admin')); 11220 } else { 11221 $row[0] = '3. ' . get_string('setupsearchengine', 'core_admin'); 11222 } 11223 11224 // Check the engine status. 11225 $searchengine = \core_search\manager::search_engine_instance(); 11226 try { 11227 $serverstatus = $searchengine->is_server_ready(); 11228 } catch (\moodle_exception $e) { 11229 $serverstatus = $e->getMessage(); 11230 } 11231 if ($serverstatus === true) { 11232 $status = html_writer::tag('span', get_string('yes'), array('class' => 'badge badge-success')); 11233 } else { 11234 $status = html_writer::tag('span', $serverstatus, array('class' => 'badge badge-danger')); 11235 } 11236 $row[1] = $status; 11237 } 11238 $table->data[] = $row; 11239 11240 // Indexed data. 11241 $row = array(); 11242 $url = new moodle_url('/admin/searchareas.php'); 11243 $row[0] = '4. ' . html_writer::tag('a', get_string('indexdata', 'admin'), array('href' => $url)); 11244 if ($anyindexed) { 11245 $status = html_writer::tag('span', get_string('yes'), array('class' => 'badge badge-success')); 11246 } else { 11247 $status = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 11248 } 11249 $row[1] = $status; 11250 $table->data[] = $row; 11251 11252 // Enable global search. 11253 $row = array(); 11254 $url = new moodle_url("/admin/search.php?query=enableglobalsearch"); 11255 $row[0] = '5. ' . html_writer::tag('a', get_string('enableglobalsearch', 'admin'), 11256 array('href' => $url)); 11257 $status = html_writer::tag('span', get_string('no'), array('class' => 'badge badge-danger')); 11258 if (\core_search\manager::is_global_search_enabled()) { 11259 $status = html_writer::tag('span', get_string('yes'), array('class' => 'badge badge-success')); 11260 } 11261 $row[1] = $status; 11262 $table->data[] = $row; 11263 11264 $return .= html_writer::table($table); 11265 11266 return highlight($query, $return); 11267 } 11268 11269 } 11270 11271 /** 11272 * Used to validate the contents of SCSS code and ensuring they are parsable. 11273 * 11274 * It does not attempt to detect undefined SCSS variables because it is designed 11275 * to be used without knowledge of other config/scss included. 11276 * 11277 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11278 * @copyright 2016 Dan Poltawski <dan@moodle.com> 11279 */ 11280 class admin_setting_scsscode extends admin_setting_configtextarea { 11281 11282 /** 11283 * Validate the contents of the SCSS to ensure its parsable. Does not 11284 * attempt to detect undefined scss variables. 11285 * 11286 * @param string $data The scss code from text field. 11287 * @return mixed bool true for success or string:error on failure. 11288 */ 11289 public function validate($data) { 11290 if (empty($data)) { 11291 return true; 11292 } 11293 11294 $scss = new core_scss(); 11295 try { 11296 $scss->compile($data); 11297 } catch (ScssPhp\ScssPhp\Exception\ParserException $e) { 11298 return get_string('scssinvalid', 'admin', $e->getMessage()); 11299 } catch (ScssPhp\ScssPhp\Exception\CompilerException $e) { 11300 // Silently ignore this - it could be a scss variable defined from somewhere 11301 // else which we are not examining here. 11302 return true; 11303 } 11304 11305 return true; 11306 } 11307 } 11308 11309 11310 /** 11311 * Administration setting to define a list of file types. 11312 * 11313 * @copyright 2016 Jonathon Fowler <fowlerj@usq.edu.au> 11314 * @copyright 2017 David Mudrák <david@moodle.com> 11315 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11316 */ 11317 class admin_setting_filetypes extends admin_setting_configtext { 11318 11319 /** @var array Allow selection from these file types only. */ 11320 protected $onlytypes = []; 11321 11322 /** @var bool Allow selection of 'All file types' (will be stored as '*'). */ 11323 protected $allowall = true; 11324 11325 /** @var core_form\filetypes_util instance to use as a helper. */ 11326 protected $util = null; 11327 11328 /** 11329 * Constructor. 11330 * 11331 * @param string $name Unique ascii name like 'mycoresetting' or 'myplugin/mysetting' 11332 * @param string $visiblename Localised label of the setting 11333 * @param string $description Localised description of the setting 11334 * @param string $defaultsetting Default setting value. 11335 * @param array $options Setting widget options, an array with optional keys: 11336 * 'onlytypes' => array Allow selection from these file types only; for example ['onlytypes' => ['web_image']]. 11337 * 'allowall' => bool Allow to select 'All file types', defaults to true. Does not apply if onlytypes are set. 11338 */ 11339 public function __construct($name, $visiblename, $description, $defaultsetting = '', array $options = []) { 11340 11341 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW); 11342 11343 if (array_key_exists('onlytypes', $options) && is_array($options['onlytypes'])) { 11344 $this->onlytypes = $options['onlytypes']; 11345 } 11346 11347 if (!$this->onlytypes && array_key_exists('allowall', $options)) { 11348 $this->allowall = (bool)$options['allowall']; 11349 } 11350 11351 $this->util = new \core_form\filetypes_util(); 11352 } 11353 11354 /** 11355 * Normalize the user's input and write it to the database as comma separated list. 11356 * 11357 * Comma separated list as a text representation of the array was chosen to 11358 * make this compatible with how the $CFG->courseoverviewfilesext values are stored. 11359 * 11360 * @param string $data Value submitted by the admin. 11361 * @return string Epty string if all good, error message otherwise. 11362 */ 11363 public function write_setting($data) { 11364 return parent::write_setting(implode(',', $this->util->normalize_file_types($data))); 11365 } 11366 11367 /** 11368 * Validate data before storage 11369 * 11370 * @param string $data The setting values provided by the admin 11371 * @return bool|string True if ok, the string if error found 11372 */ 11373 public function validate($data) { 11374 11375 // No need to call parent's validation here as we are PARAM_RAW. 11376 11377 if ($this->util->is_listed($data, $this->onlytypes)) { 11378 return true; 11379 11380 } else { 11381 $troublemakers = $this->util->get_not_listed($data, $this->onlytypes); 11382 return get_string('filetypesnotallowed', 'core_form', implode(' ', $troublemakers)); 11383 } 11384 } 11385 11386 /** 11387 * Return an HTML string for the setting element. 11388 * 11389 * @param string $data The current setting value 11390 * @param string $query Admin search query to be highlighted 11391 * @return string HTML to be displayed 11392 */ 11393 public function output_html($data, $query='') { 11394 global $OUTPUT, $PAGE; 11395 11396 $default = $this->get_defaultsetting(); 11397 $context = (object) [ 11398 'id' => $this->get_id(), 11399 'name' => $this->get_full_name(), 11400 'value' => $data, 11401 'descriptions' => $this->util->describe_file_types($data), 11402 ]; 11403 $element = $OUTPUT->render_from_template('core_admin/setting_filetypes', $context); 11404 11405 $PAGE->requires->js_call_amd('core_form/filetypes', 'init', [ 11406 $this->get_id(), 11407 $this->visiblename->out(), 11408 $this->onlytypes, 11409 $this->allowall, 11410 ]); 11411 11412 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); 11413 } 11414 11415 /** 11416 * Should the values be always displayed in LTR mode? 11417 * 11418 * We always return true here because these values are not RTL compatible. 11419 * 11420 * @return bool True because these values are not RTL compatible. 11421 */ 11422 public function get_force_ltr() { 11423 return true; 11424 } 11425 } 11426 11427 /** 11428 * Used to validate the content and format of the age of digital consent map and ensuring it is parsable. 11429 * 11430 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11431 * @copyright 2018 Mihail Geshoski <mihail@moodle.com> 11432 */ 11433 class admin_setting_agedigitalconsentmap extends admin_setting_configtextarea { 11434 11435 /** 11436 * Constructor. 11437 * 11438 * @param string $name 11439 * @param string $visiblename 11440 * @param string $description 11441 * @param mixed $defaultsetting string or array 11442 * @param mixed $paramtype 11443 * @param string $cols 11444 * @param string $rows 11445 */ 11446 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype = PARAM_RAW, 11447 $cols = '60', $rows = '8') { 11448 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows); 11449 // Pre-set force LTR to false. 11450 $this->set_force_ltr(false); 11451 } 11452 11453 /** 11454 * Validate the content and format of the age of digital consent map to ensure it is parsable. 11455 * 11456 * @param string $data The age of digital consent map from text field. 11457 * @return mixed bool true for success or string:error on failure. 11458 */ 11459 public function validate($data) { 11460 if (empty($data)) { 11461 return true; 11462 } 11463 11464 try { 11465 \core_auth\digital_consent::parse_age_digital_consent_map($data); 11466 } catch (\moodle_exception $e) { 11467 return get_string('invalidagedigitalconsent', 'admin', $e->getMessage()); 11468 } 11469 11470 return true; 11471 } 11472 } 11473 11474 /** 11475 * Selection of plugins that can work as site policy handlers 11476 * 11477 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11478 * @copyright 2018 Marina Glancy 11479 */ 11480 class admin_settings_sitepolicy_handler_select extends admin_setting_configselect { 11481 11482 /** 11483 * Constructor 11484 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' 11485 * for ones in config_plugins. 11486 * @param string $visiblename localised 11487 * @param string $description long localised info 11488 * @param string $defaultsetting 11489 */ 11490 public function __construct($name, $visiblename, $description, $defaultsetting = '') { 11491 parent::__construct($name, $visiblename, $description, $defaultsetting, null); 11492 } 11493 11494 /** 11495 * Lazy-load the available choices for the select box 11496 */ 11497 public function load_choices() { 11498 if (during_initial_install()) { 11499 return false; 11500 } 11501 if (is_array($this->choices)) { 11502 return true; 11503 } 11504 11505 $this->choices = ['' => new lang_string('sitepolicyhandlercore', 'core_admin')]; 11506 $manager = new \core_privacy\local\sitepolicy\manager(); 11507 $plugins = $manager->get_all_handlers(); 11508 foreach ($plugins as $pname => $unused) { 11509 $this->choices[$pname] = new lang_string('sitepolicyhandlerplugin', 'core_admin', 11510 ['name' => new lang_string('pluginname', $pname), 'component' => $pname]); 11511 } 11512 11513 return true; 11514 } 11515 } 11516 11517 /** 11518 * Used to validate theme presets code and ensuring they compile well. 11519 * 11520 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11521 * @copyright 2019 Bas Brands <bas@moodle.com> 11522 */ 11523 class admin_setting_configthemepreset extends admin_setting_configselect { 11524 11525 /** @var string The name of the theme to check for */ 11526 private $themename; 11527 11528 /** 11529 * Constructor 11530 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 11531 * or 'myplugin/mysetting' for ones in config_plugins. 11532 * @param string $visiblename localised 11533 * @param string $description long localised info 11534 * @param string|int $defaultsetting 11535 * @param array $choices array of $value=>$label for each selection 11536 * @param string $themename name of theme to check presets for. 11537 */ 11538 public function __construct($name, $visiblename, $description, $defaultsetting, $choices, $themename) { 11539 $this->themename = $themename; 11540 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); 11541 } 11542 11543 /** 11544 * Write settings if validated 11545 * 11546 * @param string $data 11547 * @return string 11548 */ 11549 public function write_setting($data) { 11550 $validated = $this->validate($data); 11551 if ($validated !== true) { 11552 return $validated; 11553 } 11554 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 11555 } 11556 11557 /** 11558 * Validate the preset file to ensure its parsable. 11559 * 11560 * @param string $data The preset file chosen. 11561 * @return mixed bool true for success or string:error on failure. 11562 */ 11563 public function validate($data) { 11564 11565 if (in_array($data, ['default.scss', 'plain.scss'])) { 11566 return true; 11567 } 11568 11569 $fs = get_file_storage(); 11570 $theme = theme_config::load($this->themename); 11571 $context = context_system::instance(); 11572 11573 // If the preset has not changed there is no need to validate it. 11574 if ($theme->settings->preset == $data) { 11575 return true; 11576 } 11577 11578 if ($presetfile = $fs->get_file($context->id, 'theme_' . $this->themename, 'preset', 0, '/', $data)) { 11579 // This operation uses a lot of resources. 11580 raise_memory_limit(MEMORY_EXTRA); 11581 core_php_time_limit::raise(300); 11582 11583 // TODO: MDL-62757 When changing anything in this method please do not forget to check 11584 // if the get_css_content_from_scss() method in class theme_config needs updating too. 11585 11586 $compiler = new core_scss(); 11587 $compiler->prepend_raw_scss($theme->get_pre_scss_code()); 11588 $compiler->append_raw_scss($presetfile->get_content()); 11589 if ($scssproperties = $theme->get_scss_property()) { 11590 $compiler->setImportPaths($scssproperties[0]); 11591 } 11592 $compiler->append_raw_scss($theme->get_extra_scss_code()); 11593 11594 try { 11595 $compiler->to_css(); 11596 } catch (Exception $e) { 11597 return get_string('invalidthemepreset', 'admin', $e->getMessage()); 11598 } 11599 11600 // Try to save memory. 11601 $compiler = null; 11602 unset($compiler); 11603 } 11604 11605 return true; 11606 } 11607 } 11608 11609 /** 11610 * Selection of plugins that can work as H5P libraries handlers 11611 * 11612 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 11613 * @copyright 2020 Sara Arjona <sara@moodle.com> 11614 */ 11615 class admin_settings_h5plib_handler_select extends admin_setting_configselect { 11616 11617 /** 11618 * Constructor 11619 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' 11620 * for ones in config_plugins. 11621 * @param string $visiblename localised 11622 * @param string $description long localised info 11623 * @param string $defaultsetting 11624 */ 11625 public function __construct($name, $visiblename, $description, $defaultsetting = '') { 11626 parent::__construct($name, $visiblename, $description, $defaultsetting, null); 11627 } 11628 11629 /** 11630 * Lazy-load the available choices for the select box 11631 */ 11632 public function load_choices() { 11633 if (during_initial_install()) { 11634 return false; 11635 } 11636 if (is_array($this->choices)) { 11637 return true; 11638 } 11639 11640 $this->choices = \core_h5p\local\library\autoloader::get_all_handlers(); 11641 foreach ($this->choices as $name => $class) { 11642 $this->choices[$name] = new lang_string('sitepolicyhandlerplugin', 'core_admin', 11643 ['name' => new lang_string('pluginname', $name), 'component' => $name]); 11644 } 11645 11646 return true; 11647 } 11648 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body