[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 if (file_exists("$base/db/subplugins.php")) { 136 $subplugins = array(); 137 include("$base/db/subplugins.php"); 138 foreach ($subplugins as $subplugintype=>$dir) { 139 $instances = core_component::get_plugin_list($subplugintype); 140 foreach ($instances as $subpluginname => $notusedpluginpath) { 141 uninstall_plugin($subplugintype, $subpluginname); 142 } 143 } 144 } 145 146 } 147 148 $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum' 149 150 if ($type === 'mod') { 151 $pluginname = $name; // eg. 'forum' 152 if (get_string_manager()->string_exists('modulename', $component)) { 153 $strpluginname = get_string('modulename', $component); 154 } else { 155 $strpluginname = $component; 156 } 157 158 } else { 159 $pluginname = $component; 160 if (get_string_manager()->string_exists('pluginname', $component)) { 161 $strpluginname = get_string('pluginname', $component); 162 } else { 163 $strpluginname = $component; 164 } 165 } 166 167 echo $OUTPUT->heading($pluginname); 168 169 // Delete all tag areas, collections and instances associated with this plugin. 170 core_tag_area::uninstall($component); 171 172 // Custom plugin uninstall. 173 $plugindirectory = core_component::get_plugin_directory($type, $name); 174 $uninstalllib = $plugindirectory . '/db/uninstall.php'; 175 if (file_exists($uninstalllib)) { 176 require_once($uninstalllib); 177 $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()' 178 if (function_exists($uninstallfunction)) { 179 // Do not verify result, let plugin complain if necessary. 180 $uninstallfunction(); 181 } 182 } 183 184 // Specific plugin type cleanup. 185 $plugininfo = core_plugin_manager::instance()->get_plugin_info($component); 186 if ($plugininfo) { 187 $plugininfo->uninstall_cleanup(); 188 core_plugin_manager::reset_caches(); 189 } 190 $plugininfo = null; 191 192 // perform clean-up task common for all the plugin/subplugin types 193 194 //delete the web service functions and pre-built services 195 require_once($CFG->dirroot.'/lib/externallib.php'); 196 external_delete_descriptions($component); 197 198 // delete calendar events 199 $DB->delete_records('event', array('modulename' => $pluginname)); 200 201 // Delete scheduled tasks. 202 $DB->delete_records('task_scheduled', array('component' => $component)); 203 204 // Delete Inbound Message datakeys. 205 $DB->delete_records_select('messageinbound_datakeys', 206 'handler IN (SELECT id FROM {messageinbound_handlers} WHERE component = ?)', array($component)); 207 208 // Delete Inbound Message handlers. 209 $DB->delete_records('messageinbound_handlers', array('component' => $component)); 210 211 // delete all the logs 212 $DB->delete_records('log', array('module' => $pluginname)); 213 214 // delete log_display information 215 $DB->delete_records('log_display', array('component' => $component)); 216 217 // delete the module configuration records 218 unset_all_config_for_plugin($component); 219 if ($type === 'mod') { 220 unset_all_config_for_plugin($pluginname); 221 } 222 223 // delete message provider 224 message_provider_uninstall($component); 225 226 // delete the plugin tables 227 $xmldbfilepath = $plugindirectory . '/db/install.xml'; 228 drop_plugin_tables($component, $xmldbfilepath, false); 229 if ($type === 'mod' or $type === 'block') { 230 // non-frankenstyle table prefixes 231 drop_plugin_tables($name, $xmldbfilepath, false); 232 } 233 234 // delete the capabilities that were defined by this module 235 capabilities_cleanup($component); 236 237 // remove event handlers and dequeue pending events 238 events_uninstall($component); 239 240 // Delete all remaining files in the filepool owned by the component. 241 $fs = get_file_storage(); 242 $fs->delete_component_files($component); 243 244 // Finally purge all caches. 245 purge_all_caches(); 246 247 // Invalidate the hash used for upgrade detections. 248 set_config('allversionshash', ''); 249 250 echo $OUTPUT->notification(get_string('success'), 'notifysuccess'); 251 } 252 253 /** 254 * Returns the version of installed component 255 * 256 * @param string $component component name 257 * @param string $source either 'disk' or 'installed' - where to get the version information from 258 * @return string|bool version number or false if the component is not found 259 */ 260 function get_component_version($component, $source='installed') { 261 global $CFG, $DB; 262 263 list($type, $name) = core_component::normalize_component($component); 264 265 // moodle core or a core subsystem 266 if ($type === 'core') { 267 if ($source === 'installed') { 268 if (empty($CFG->version)) { 269 return false; 270 } else { 271 return $CFG->version; 272 } 273 } else { 274 if (!is_readable($CFG->dirroot.'/version.php')) { 275 return false; 276 } else { 277 $version = null; //initialize variable for IDEs 278 include($CFG->dirroot.'/version.php'); 279 return $version; 280 } 281 } 282 } 283 284 // activity module 285 if ($type === 'mod') { 286 if ($source === 'installed') { 287 if ($CFG->version < 2013092001.02) { 288 return $DB->get_field('modules', 'version', array('name'=>$name)); 289 } else { 290 return get_config('mod_'.$name, 'version'); 291 } 292 293 } else { 294 $mods = core_component::get_plugin_list('mod'); 295 if (empty($mods[$name]) or !is_readable($mods[$name].'/version.php')) { 296 return false; 297 } else { 298 $plugin = new stdClass(); 299 $plugin->version = null; 300 $module = $plugin; 301 include($mods[$name].'/version.php'); 302 return $plugin->version; 303 } 304 } 305 } 306 307 // block 308 if ($type === 'block') { 309 if ($source === 'installed') { 310 if ($CFG->version < 2013092001.02) { 311 return $DB->get_field('block', 'version', array('name'=>$name)); 312 } else { 313 return get_config('block_'.$name, 'version'); 314 } 315 } else { 316 $blocks = core_component::get_plugin_list('block'); 317 if (empty($blocks[$name]) or !is_readable($blocks[$name].'/version.php')) { 318 return false; 319 } else { 320 $plugin = new stdclass(); 321 include($blocks[$name].'/version.php'); 322 return $plugin->version; 323 } 324 } 325 } 326 327 // all other plugin types 328 if ($source === 'installed') { 329 return get_config($type.'_'.$name, 'version'); 330 } else { 331 $plugins = core_component::get_plugin_list($type); 332 if (empty($plugins[$name])) { 333 return false; 334 } else { 335 $plugin = new stdclass(); 336 include($plugins[$name].'/version.php'); 337 return $plugin->version; 338 } 339 } 340 } 341 342 /** 343 * Delete all plugin tables 344 * 345 * @param string $name Name of plugin, used as table prefix 346 * @param string $file Path to install.xml file 347 * @param bool $feedback defaults to true 348 * @return bool Always returns true 349 */ 350 function drop_plugin_tables($name, $file, $feedback=true) { 351 global $CFG, $DB; 352 353 // first try normal delete 354 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) { 355 return true; 356 } 357 358 // then try to find all tables that start with name and are not in any xml file 359 $used_tables = get_used_table_names(); 360 361 $tables = $DB->get_tables(); 362 363 /// Iterate over, fixing id fields as necessary 364 foreach ($tables as $table) { 365 if (in_array($table, $used_tables)) { 366 continue; 367 } 368 369 if (strpos($table, $name) !== 0) { 370 continue; 371 } 372 373 // found orphan table --> delete it 374 if ($DB->get_manager()->table_exists($table)) { 375 $xmldb_table = new xmldb_table($table); 376 $DB->get_manager()->drop_table($xmldb_table); 377 } 378 } 379 380 return true; 381 } 382 383 /** 384 * Returns names of all known tables == tables that moodle knows about. 385 * 386 * @return array Array of lowercase table names 387 */ 388 function get_used_table_names() { 389 $table_names = array(); 390 $dbdirs = get_db_directories(); 391 392 foreach ($dbdirs as $dbdir) { 393 $file = $dbdir.'/install.xml'; 394 395 $xmldb_file = new xmldb_file($file); 396 397 if (!$xmldb_file->fileExists()) { 398 continue; 399 } 400 401 $loaded = $xmldb_file->loadXMLStructure(); 402 $structure = $xmldb_file->getStructure(); 403 404 if ($loaded and $tables = $structure->getTables()) { 405 foreach($tables as $table) { 406 $table_names[] = strtolower($table->getName()); 407 } 408 } 409 } 410 411 return $table_names; 412 } 413 414 /** 415 * Returns list of all directories where we expect install.xml files 416 * @return array Array of paths 417 */ 418 function get_db_directories() { 419 global $CFG; 420 421 $dbdirs = array(); 422 423 /// First, the main one (lib/db) 424 $dbdirs[] = $CFG->libdir.'/db'; 425 426 /// Then, all the ones defined by core_component::get_plugin_types() 427 $plugintypes = core_component::get_plugin_types(); 428 foreach ($plugintypes as $plugintype => $pluginbasedir) { 429 if ($plugins = core_component::get_plugin_list($plugintype)) { 430 foreach ($plugins as $plugin => $plugindir) { 431 $dbdirs[] = $plugindir.'/db'; 432 } 433 } 434 } 435 436 return $dbdirs; 437 } 438 439 /** 440 * Try to obtain or release the cron lock. 441 * @param string $name name of lock 442 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionally 443 * @param bool $ignorecurrent ignore current lock state, usually extend previous lock, defaults to false 444 * @return bool true if lock obtained 445 */ 446 function set_cron_lock($name, $until, $ignorecurrent=false) { 447 global $DB; 448 if (empty($name)) { 449 debugging("Tried to get a cron lock for a null fieldname"); 450 return false; 451 } 452 453 // remove lock by force == remove from config table 454 if (is_null($until)) { 455 set_config($name, null); 456 return true; 457 } 458 459 if (!$ignorecurrent) { 460 // read value from db - other processes might have changed it 461 $value = $DB->get_field('config', 'value', array('name'=>$name)); 462 463 if ($value and $value > time()) { 464 //lock active 465 return false; 466 } 467 } 468 469 set_config($name, $until); 470 return true; 471 } 472 473 /** 474 * Test if and critical warnings are present 475 * @return bool 476 */ 477 function admin_critical_warnings_present() { 478 global $SESSION; 479 480 if (!has_capability('moodle/site:config', context_system::instance())) { 481 return 0; 482 } 483 484 if (!isset($SESSION->admin_critical_warning)) { 485 $SESSION->admin_critical_warning = 0; 486 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) { 487 $SESSION->admin_critical_warning = 1; 488 } 489 } 490 491 return $SESSION->admin_critical_warning; 492 } 493 494 /** 495 * Detects if float supports at least 10 decimal digits 496 * 497 * Detects if float supports at least 10 decimal digits 498 * and also if float-->string conversion works as expected. 499 * 500 * @return bool true if problem found 501 */ 502 function is_float_problem() { 503 $num1 = 2009010200.01; 504 $num2 = 2009010200.02; 505 506 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1); 507 } 508 509 /** 510 * Try to verify that dataroot is not accessible from web. 511 * 512 * Try to verify that dataroot is not accessible from web. 513 * It is not 100% correct but might help to reduce number of vulnerable sites. 514 * Protection from httpd.conf and .htaccess is not detected properly. 515 * 516 * @uses INSECURE_DATAROOT_WARNING 517 * @uses INSECURE_DATAROOT_ERROR 518 * @param bool $fetchtest try to test public access by fetching file, default false 519 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING might be problematic 520 */ 521 function is_dataroot_insecure($fetchtest=false) { 522 global $CFG; 523 524 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround 525 526 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1); 527 $rp = strrev(trim($rp, '/')); 528 $rp = explode('/', $rp); 529 foreach($rp as $r) { 530 if (strpos($siteroot, '/'.$r.'/') === 0) { 531 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory 532 } else { 533 break; // probably alias root 534 } 535 } 536 537 $siteroot = strrev($siteroot); 538 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/'); 539 540 if (strpos($dataroot, $siteroot) !== 0) { 541 return false; 542 } 543 544 if (!$fetchtest) { 545 return INSECURE_DATAROOT_WARNING; 546 } 547 548 // now try all methods to fetch a test file using http protocol 549 550 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); 551 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches); 552 $httpdocroot = $matches[1]; 553 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot)); 554 make_upload_directory('diag'); 555 $testfile = $CFG->dataroot.'/diag/public.txt'; 556 if (!file_exists($testfile)) { 557 file_put_contents($testfile, 'test file, do not delete'); 558 @chmod($testfile, $CFG->filepermissions); 559 } 560 $teststr = trim(file_get_contents($testfile)); 561 if (empty($teststr)) { 562 // hmm, strange 563 return INSECURE_DATAROOT_WARNING; 564 } 565 566 $testurl = $datarooturl.'/diag/public.txt'; 567 if (extension_loaded('curl') and 568 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and 569 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and 570 ($ch = @curl_init($testurl)) !== false) { 571 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 572 curl_setopt($ch, CURLOPT_HEADER, false); 573 $data = curl_exec($ch); 574 if (!curl_errno($ch)) { 575 $data = trim($data); 576 if ($data === $teststr) { 577 curl_close($ch); 578 return INSECURE_DATAROOT_ERROR; 579 } 580 } 581 curl_close($ch); 582 } 583 584 if ($data = @file_get_contents($testurl)) { 585 $data = trim($data); 586 if ($data === $teststr) { 587 return INSECURE_DATAROOT_ERROR; 588 } 589 } 590 591 preg_match('|https?://([^/]+)|i', $testurl, $matches); 592 $sitename = $matches[1]; 593 $error = 0; 594 if ($fp = @fsockopen($sitename, 80, $error)) { 595 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches); 596 $localurl = $matches[1]; 597 $out = "GET $localurl HTTP/1.1\r\n"; 598 $out .= "Host: $sitename\r\n"; 599 $out .= "Connection: Close\r\n\r\n"; 600 fwrite($fp, $out); 601 $data = ''; 602 $incoming = false; 603 while (!feof($fp)) { 604 if ($incoming) { 605 $data .= fgets($fp, 1024); 606 } else if (@fgets($fp, 1024) === "\r\n") { 607 $incoming = true; 608 } 609 } 610 fclose($fp); 611 $data = trim($data); 612 if ($data === $teststr) { 613 return INSECURE_DATAROOT_ERROR; 614 } 615 } 616 617 return INSECURE_DATAROOT_WARNING; 618 } 619 620 /** 621 * Enables CLI maintenance mode by creating new dataroot/climaintenance.html file. 622 */ 623 function enable_cli_maintenance_mode() { 624 global $CFG; 625 626 if (file_exists("$CFG->dataroot/climaintenance.html")) { 627 unlink("$CFG->dataroot/climaintenance.html"); 628 } 629 630 if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) { 631 $data = $CFG->maintenance_message; 632 $data = bootstrap_renderer::early_error_content($data, null, null, null); 633 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data); 634 635 } else if (file_exists("$CFG->dataroot/climaintenance.template.html")) { 636 $data = file_get_contents("$CFG->dataroot/climaintenance.template.html"); 637 638 } else { 639 $data = get_string('sitemaintenance', 'admin'); 640 $data = bootstrap_renderer::early_error_content($data, null, null, null); 641 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data); 642 } 643 644 file_put_contents("$CFG->dataroot/climaintenance.html", $data); 645 chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions); 646 } 647 648 /// CLASS DEFINITIONS ///////////////////////////////////////////////////////// 649 650 651 /** 652 * Interface for anything appearing in the admin tree 653 * 654 * The interface that is implemented by anything that appears in the admin tree 655 * block. It forces inheriting classes to define a method for checking user permissions 656 * and methods for finding something in the admin tree. 657 * 658 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 659 */ 660 interface part_of_admin_tree { 661 662 /** 663 * Finds a named part_of_admin_tree. 664 * 665 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree 666 * and not parentable_part_of_admin_tree, then this function should only check if 667 * $this->name matches $name. If it does, it should return a reference to $this, 668 * otherwise, it should return a reference to NULL. 669 * 670 * If a class inherits parentable_part_of_admin_tree, this method should be called 671 * recursively on all child objects (assuming, of course, the parent object's name 672 * doesn't match the search criterion). 673 * 674 * @param string $name The internal name of the part_of_admin_tree we're searching for. 675 * @return mixed An object reference or a NULL reference. 676 */ 677 public function locate($name); 678 679 /** 680 * Removes named part_of_admin_tree. 681 * 682 * @param string $name The internal name of the part_of_admin_tree we want to remove. 683 * @return bool success. 684 */ 685 public function prune($name); 686 687 /** 688 * Search using query 689 * @param string $query 690 * @return mixed array-object structure of found settings and pages 691 */ 692 public function search($query); 693 694 /** 695 * Verifies current user's access to this part_of_admin_tree. 696 * 697 * Used to check if the current user has access to this part of the admin tree or 698 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree, 699 * then this method is usually just a call to has_capability() in the site context. 700 * 701 * If a class inherits parentable_part_of_admin_tree, this method should return the 702 * logical OR of the return of check_access() on all child objects. 703 * 704 * @return bool True if the user has access, false if she doesn't. 705 */ 706 public function check_access(); 707 708 /** 709 * Mostly useful for removing of some parts of the tree in admin tree block. 710 * 711 * @return True is hidden from normal list view 712 */ 713 public function is_hidden(); 714 715 /** 716 * Show we display Save button at the page bottom? 717 * @return bool 718 */ 719 public function show_save(); 720 } 721 722 723 /** 724 * Interface implemented by any part_of_admin_tree that has children. 725 * 726 * The interface implemented by any part_of_admin_tree that can be a parent 727 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart 728 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods 729 * include an add method for adding other part_of_admin_tree objects as children. 730 * 731 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 732 */ 733 interface parentable_part_of_admin_tree extends part_of_admin_tree { 734 735 /** 736 * Adds a part_of_admin_tree object to the admin tree. 737 * 738 * Used to add a part_of_admin_tree object to this object or a child of this 739 * object. $something should only be added if $destinationname matches 740 * $this->name. If it doesn't, add should be called on child objects that are 741 * also parentable_part_of_admin_tree's. 742 * 743 * $something should be appended as the last child in the $destinationname. If the 744 * $beforesibling is specified, $something should be prepended to it. If the given 745 * sibling is not found, $something should be appended to the end of $destinationname 746 * and a developer debugging message should be displayed. 747 * 748 * @param string $destinationname The internal name of the new parent for $something. 749 * @param part_of_admin_tree $something The object to be added. 750 * @return bool True on success, false on failure. 751 */ 752 public function add($destinationname, $something, $beforesibling = null); 753 754 } 755 756 757 /** 758 * The object used to represent folders (a.k.a. categories) in the admin tree block. 759 * 760 * Each admin_category object contains a number of part_of_admin_tree objects. 761 * 762 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 763 */ 764 class admin_category implements parentable_part_of_admin_tree { 765 766 /** @var part_of_admin_tree[] An array of part_of_admin_tree objects that are this object's children */ 767 protected $children; 768 /** @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */ 769 public $name; 770 /** @var string The displayed name for this category. Usually obtained through get_string() */ 771 public $visiblename; 772 /** @var bool Should this category be hidden in admin tree block? */ 773 public $hidden; 774 /** @var mixed Either a string or an array or strings */ 775 public $path; 776 /** @var mixed Either a string or an array or strings */ 777 public $visiblepath; 778 779 /** @var array fast lookup category cache, all categories of one tree point to one cache */ 780 protected $category_cache; 781 782 /** @var bool If set to true children will be sorted when calling {@link admin_category::get_children()} */ 783 protected $sort = false; 784 /** @var bool If set to true children will be sorted in ascending order. */ 785 protected $sortasc = true; 786 /** @var bool If set to true sub categories and pages will be split and then sorted.. */ 787 protected $sortsplit = true; 788 /** @var bool $sorted True if the children have been sorted and don't need resorting */ 789 protected $sorted = false; 790 791 /** 792 * Constructor for an empty admin category 793 * 794 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects 795 * @param string $visiblename The displayed named for this category. Usually obtained through get_string() 796 * @param bool $hidden hide category in admin tree block, defaults to false 797 */ 798 public function __construct($name, $visiblename, $hidden=false) { 799 $this->children = array(); 800 $this->name = $name; 801 $this->visiblename = $visiblename; 802 $this->hidden = $hidden; 803 } 804 805 /** 806 * Returns a reference to the part_of_admin_tree object with internal name $name. 807 * 808 * @param string $name The internal name of the object we want. 809 * @param bool $findpath initialize path and visiblepath arrays 810 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL. 811 * defaults to false 812 */ 813 public function locate($name, $findpath=false) { 814 if (!isset($this->category_cache[$this->name])) { 815 // somebody much have purged the cache 816 $this->category_cache[$this->name] = $this; 817 } 818 819 if ($this->name == $name) { 820 if ($findpath) { 821 $this->visiblepath[] = $this->visiblename; 822 $this->path[] = $this->name; 823 } 824 return $this; 825 } 826 827 // quick category lookup 828 if (!$findpath and isset($this->category_cache[$name])) { 829 return $this->category_cache[$name]; 830 } 831 832 $return = NULL; 833 foreach($this->children as $childid=>$unused) { 834 if ($return = $this->children[$childid]->locate($name, $findpath)) { 835 break; 836 } 837 } 838 839 if (!is_null($return) and $findpath) { 840 $return->visiblepath[] = $this->visiblename; 841 $return->path[] = $this->name; 842 } 843 844 return $return; 845 } 846 847 /** 848 * Search using query 849 * 850 * @param string query 851 * @return mixed array-object structure of found settings and pages 852 */ 853 public function search($query) { 854 $result = array(); 855 foreach ($this->get_children() as $child) { 856 $subsearch = $child->search($query); 857 if (!is_array($subsearch)) { 858 debugging('Incorrect search result from '.$child->name); 859 continue; 860 } 861 $result = array_merge($result, $subsearch); 862 } 863 return $result; 864 } 865 866 /** 867 * Removes part_of_admin_tree object with internal name $name. 868 * 869 * @param string $name The internal name of the object we want to remove. 870 * @return bool success 871 */ 872 public function prune($name) { 873 874 if ($this->name == $name) { 875 return false; //can not remove itself 876 } 877 878 foreach($this->children as $precedence => $child) { 879 if ($child->name == $name) { 880 // clear cache and delete self 881 while($this->category_cache) { 882 // delete the cache, but keep the original array address 883 array_pop($this->category_cache); 884 } 885 unset($this->children[$precedence]); 886 return true; 887 } else if ($this->children[$precedence]->prune($name)) { 888 return true; 889 } 890 } 891 return false; 892 } 893 894 /** 895 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object. 896 * 897 * By default the new part of the tree is appended as the last child of the parent. You 898 * can specify a sibling node that the new part should be prepended to. If the given 899 * sibling is not found, the part is appended to the end (as it would be by default) and 900 * a developer debugging message is displayed. 901 * 902 * @throws coding_exception if the $beforesibling is empty string or is not string at all. 903 * @param string $destinationame The internal name of the immediate parent that we want for $something. 904 * @param mixed $something A part_of_admin_tree or setting instance to be added. 905 * @param string $beforesibling The name of the parent's child the $something should be prepended to. 906 * @return bool True if successfully added, false if $something can not be added. 907 */ 908 public function add($parentname, $something, $beforesibling = null) { 909 global $CFG; 910 911 $parent = $this->locate($parentname); 912 if (is_null($parent)) { 913 debugging('parent does not exist!'); 914 return false; 915 } 916 917 if ($something instanceof part_of_admin_tree) { 918 if (!($parent instanceof parentable_part_of_admin_tree)) { 919 debugging('error - parts of tree can be inserted only into parentable parts'); 920 return false; 921 } 922 if ($CFG->debugdeveloper && !is_null($this->locate($something->name))) { 923 // The name of the node is already used, simply warn the developer that this should not happen. 924 // It is intentional to check for the debug level before performing the check. 925 debugging('Duplicate admin page name: ' . $something->name, DEBUG_DEVELOPER); 926 } 927 if (is_null($beforesibling)) { 928 // Append $something as the parent's last child. 929 $parent->children[] = $something; 930 } else { 931 if (!is_string($beforesibling) or trim($beforesibling) === '') { 932 throw new coding_exception('Unexpected value of the beforesibling parameter'); 933 } 934 // Try to find the position of the sibling. 935 $siblingposition = null; 936 foreach ($parent->children as $childposition => $child) { 937 if ($child->name === $beforesibling) { 938 $siblingposition = $childposition; 939 break; 940 } 941 } 942 if (is_null($siblingposition)) { 943 debugging('Sibling '.$beforesibling.' not found', DEBUG_DEVELOPER); 944 $parent->children[] = $something; 945 } else { 946 $parent->children = array_merge( 947 array_slice($parent->children, 0, $siblingposition), 948 array($something), 949 array_slice($parent->children, $siblingposition) 950 ); 951 } 952 } 953 if ($something instanceof admin_category) { 954 if (isset($this->category_cache[$something->name])) { 955 debugging('Duplicate admin category name: '.$something->name); 956 } else { 957 $this->category_cache[$something->name] = $something; 958 $something->category_cache =& $this->category_cache; 959 foreach ($something->children as $child) { 960 // just in case somebody already added subcategories 961 if ($child instanceof admin_category) { 962 if (isset($this->category_cache[$child->name])) { 963 debugging('Duplicate admin category name: '.$child->name); 964 } else { 965 $this->category_cache[$child->name] = $child; 966 $child->category_cache =& $this->category_cache; 967 } 968 } 969 } 970 } 971 } 972 return true; 973 974 } else { 975 debugging('error - can not add this element'); 976 return false; 977 } 978 979 } 980 981 /** 982 * Checks if the user has access to anything in this category. 983 * 984 * @return bool True if the user has access to at least one child in this category, false otherwise. 985 */ 986 public function check_access() { 987 foreach ($this->children as $child) { 988 if ($child->check_access()) { 989 return true; 990 } 991 } 992 return false; 993 } 994 995 /** 996 * Is this category hidden in admin tree block? 997 * 998 * @return bool True if hidden 999 */ 1000 public function is_hidden() { 1001 return $this->hidden; 1002 } 1003 1004 /** 1005 * Show we display Save button at the page bottom? 1006 * @return bool 1007 */ 1008 public function show_save() { 1009 foreach ($this->children as $child) { 1010 if ($child->show_save()) { 1011 return true; 1012 } 1013 } 1014 return false; 1015 } 1016 1017 /** 1018 * Sets sorting on this category. 1019 * 1020 * Please note this function doesn't actually do the sorting. 1021 * It can be called anytime. 1022 * Sorting occurs when the user calls get_children. 1023 * Code using the children array directly won't see the sorted results. 1024 * 1025 * @param bool $sort If set to true children will be sorted, if false they won't be. 1026 * @param bool $asc If true sorting will be ascending, otherwise descending. 1027 * @param bool $split If true we sort pages and sub categories separately. 1028 */ 1029 public function set_sorting($sort, $asc = true, $split = true) { 1030 $this->sort = (bool)$sort; 1031 $this->sortasc = (bool)$asc; 1032 $this->sortsplit = (bool)$split; 1033 } 1034 1035 /** 1036 * Returns the children associated with this category. 1037 * 1038 * @return part_of_admin_tree[] 1039 */ 1040 public function get_children() { 1041 // If we should sort and it hasn't already been sorted. 1042 if ($this->sort && !$this->sorted) { 1043 if ($this->sortsplit) { 1044 $categories = array(); 1045 $pages = array(); 1046 foreach ($this->children as $child) { 1047 if ($child instanceof admin_category) { 1048 $categories[] = $child; 1049 } else { 1050 $pages[] = $child; 1051 } 1052 } 1053 core_collator::asort_objects_by_property($categories, 'visiblename'); 1054 core_collator::asort_objects_by_property($pages, 'visiblename'); 1055 if (!$this->sortasc) { 1056 $categories = array_reverse($categories); 1057 $pages = array_reverse($pages); 1058 } 1059 $this->children = array_merge($pages, $categories); 1060 } else { 1061 core_collator::asort_objects_by_property($this->children, 'visiblename'); 1062 if (!$this->sortasc) { 1063 $this->children = array_reverse($this->children); 1064 } 1065 } 1066 $this->sorted = true; 1067 } 1068 return $this->children; 1069 } 1070 1071 /** 1072 * Magically gets a property from this object. 1073 * 1074 * @param $property 1075 * @return part_of_admin_tree[] 1076 * @throws coding_exception 1077 */ 1078 public function __get($property) { 1079 if ($property === 'children') { 1080 return $this->get_children(); 1081 } 1082 throw new coding_exception('Invalid property requested.'); 1083 } 1084 1085 /** 1086 * Magically sets a property against this object. 1087 * 1088 * @param string $property 1089 * @param mixed $value 1090 * @throws coding_exception 1091 */ 1092 public function __set($property, $value) { 1093 if ($property === 'children') { 1094 $this->sorted = false; 1095 $this->children = $value; 1096 } else { 1097 throw new coding_exception('Invalid property requested.'); 1098 } 1099 } 1100 1101 /** 1102 * Checks if an inaccessible property is set. 1103 * 1104 * @param string $property 1105 * @return bool 1106 * @throws coding_exception 1107 */ 1108 public function __isset($property) { 1109 if ($property === 'children') { 1110 return isset($this->children); 1111 } 1112 throw new coding_exception('Invalid property requested.'); 1113 } 1114 } 1115 1116 1117 /** 1118 * Root of admin settings tree, does not have any parent. 1119 * 1120 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1121 */ 1122 class admin_root extends admin_category { 1123 /** @var array List of errors */ 1124 public $errors; 1125 /** @var string search query */ 1126 public $search; 1127 /** @var bool full tree flag - true means all settings required, false only pages required */ 1128 public $fulltree; 1129 /** @var bool flag indicating loaded tree */ 1130 public $loaded; 1131 /** @var mixed site custom defaults overriding defaults in settings files*/ 1132 public $custom_defaults; 1133 1134 /** 1135 * @param bool $fulltree true means all settings required, 1136 * false only pages required 1137 */ 1138 public function __construct($fulltree) { 1139 global $CFG; 1140 1141 parent::__construct('root', get_string('administration'), false); 1142 $this->errors = array(); 1143 $this->search = ''; 1144 $this->fulltree = $fulltree; 1145 $this->loaded = false; 1146 1147 $this->category_cache = array(); 1148 1149 // load custom defaults if found 1150 $this->custom_defaults = null; 1151 $defaultsfile = "$CFG->dirroot/local/defaults.php"; 1152 if (is_readable($defaultsfile)) { 1153 $defaults = array(); 1154 include($defaultsfile); 1155 if (is_array($defaults) and count($defaults)) { 1156 $this->custom_defaults = $defaults; 1157 } 1158 } 1159 } 1160 1161 /** 1162 * Empties children array, and sets loaded to false 1163 * 1164 * @param bool $requirefulltree 1165 */ 1166 public function purge_children($requirefulltree) { 1167 $this->children = array(); 1168 $this->fulltree = ($requirefulltree || $this->fulltree); 1169 $this->loaded = false; 1170 //break circular dependencies - this helps PHP 5.2 1171 while($this->category_cache) { 1172 array_pop($this->category_cache); 1173 } 1174 $this->category_cache = array(); 1175 } 1176 } 1177 1178 1179 /** 1180 * Links external PHP pages into the admin tree. 1181 * 1182 * See detailed usage example at the top of this document (adminlib.php) 1183 * 1184 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1185 */ 1186 class admin_externalpage implements part_of_admin_tree { 1187 1188 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */ 1189 public $name; 1190 1191 /** @var string The displayed name for this external page. Usually obtained through get_string(). */ 1192 public $visiblename; 1193 1194 /** @var string The external URL that we should link to when someone requests this external page. */ 1195 public $url; 1196 1197 /** @var string The role capability/permission a user must have to access this external page. */ 1198 public $req_capability; 1199 1200 /** @var object The context in which capability/permission should be checked, default is site context. */ 1201 public $context; 1202 1203 /** @var bool hidden in admin tree block. */ 1204 public $hidden; 1205 1206 /** @var mixed either string or array of string */ 1207 public $path; 1208 1209 /** @var array list of visible names of page parents */ 1210 public $visiblepath; 1211 1212 /** 1213 * Constructor for adding an external page into the admin tree. 1214 * 1215 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects. 1216 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string(). 1217 * @param string $url The external URL that we should link to when someone requests this external page. 1218 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'. 1219 * @param boolean $hidden Is this external page hidden in admin tree block? Default false. 1220 * @param stdClass $context The context the page relates to. Not sure what happens 1221 * if you specify something other than system or front page. Defaults to system. 1222 */ 1223 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) { 1224 $this->name = $name; 1225 $this->visiblename = $visiblename; 1226 $this->url = $url; 1227 if (is_array($req_capability)) { 1228 $this->req_capability = $req_capability; 1229 } else { 1230 $this->req_capability = array($req_capability); 1231 } 1232 $this->hidden = $hidden; 1233 $this->context = $context; 1234 } 1235 1236 /** 1237 * Returns a reference to the part_of_admin_tree object with internal name $name. 1238 * 1239 * @param string $name The internal name of the object we want. 1240 * @param bool $findpath defaults to false 1241 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL. 1242 */ 1243 public function locate($name, $findpath=false) { 1244 if ($this->name == $name) { 1245 if ($findpath) { 1246 $this->visiblepath = array($this->visiblename); 1247 $this->path = array($this->name); 1248 } 1249 return $this; 1250 } else { 1251 $return = NULL; 1252 return $return; 1253 } 1254 } 1255 1256 /** 1257 * This function always returns false, required function by interface 1258 * 1259 * @param string $name 1260 * @return false 1261 */ 1262 public function prune($name) { 1263 return false; 1264 } 1265 1266 /** 1267 * Search using query 1268 * 1269 * @param string $query 1270 * @return mixed array-object structure of found settings and pages 1271 */ 1272 public function search($query) { 1273 $found = false; 1274 if (strpos(strtolower($this->name), $query) !== false) { 1275 $found = true; 1276 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) { 1277 $found = true; 1278 } 1279 if ($found) { 1280 $result = new stdClass(); 1281 $result->page = $this; 1282 $result->settings = array(); 1283 return array($this->name => $result); 1284 } else { 1285 return array(); 1286 } 1287 } 1288 1289 /** 1290 * Determines if the current user has access to this external page based on $this->req_capability. 1291 * 1292 * @return bool True if user has access, false otherwise. 1293 */ 1294 public function check_access() { 1295 global $CFG; 1296 $context = empty($this->context) ? context_system::instance() : $this->context; 1297 foreach($this->req_capability as $cap) { 1298 if (has_capability($cap, $context)) { 1299 return true; 1300 } 1301 } 1302 return false; 1303 } 1304 1305 /** 1306 * Is this external page hidden in admin tree block? 1307 * 1308 * @return bool True if hidden 1309 */ 1310 public function is_hidden() { 1311 return $this->hidden; 1312 } 1313 1314 /** 1315 * Show we display Save button at the page bottom? 1316 * @return bool 1317 */ 1318 public function show_save() { 1319 return false; 1320 } 1321 } 1322 1323 1324 /** 1325 * Used to group a number of admin_setting objects into a page and add them to the admin tree. 1326 * 1327 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1328 */ 1329 class admin_settingpage implements part_of_admin_tree { 1330 1331 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */ 1332 public $name; 1333 1334 /** @var string The displayed name for this external page. Usually obtained through get_string(). */ 1335 public $visiblename; 1336 1337 /** @var mixed An array of admin_setting objects that are part of this setting page. */ 1338 public $settings; 1339 1340 /** @var string The role capability/permission a user must have to access this external page. */ 1341 public $req_capability; 1342 1343 /** @var object The context in which capability/permission should be checked, default is site context. */ 1344 public $context; 1345 1346 /** @var bool hidden in admin tree block. */ 1347 public $hidden; 1348 1349 /** @var mixed string of paths or array of strings of paths */ 1350 public $path; 1351 1352 /** @var array list of visible names of page parents */ 1353 public $visiblepath; 1354 1355 /** 1356 * see admin_settingpage for details of this function 1357 * 1358 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects. 1359 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string(). 1360 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'. 1361 * @param boolean $hidden Is this external page hidden in admin tree block? Default false. 1362 * @param stdClass $context The context the page relates to. Not sure what happens 1363 * if you specify something other than system or front page. Defaults to system. 1364 */ 1365 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) { 1366 $this->settings = new stdClass(); 1367 $this->name = $name; 1368 $this->visiblename = $visiblename; 1369 if (is_array($req_capability)) { 1370 $this->req_capability = $req_capability; 1371 } else { 1372 $this->req_capability = array($req_capability); 1373 } 1374 $this->hidden = $hidden; 1375 $this->context = $context; 1376 } 1377 1378 /** 1379 * see admin_category 1380 * 1381 * @param string $name 1382 * @param bool $findpath 1383 * @return mixed Object (this) if name == this->name, else returns null 1384 */ 1385 public function locate($name, $findpath=false) { 1386 if ($this->name == $name) { 1387 if ($findpath) { 1388 $this->visiblepath = array($this->visiblename); 1389 $this->path = array($this->name); 1390 } 1391 return $this; 1392 } else { 1393 $return = NULL; 1394 return $return; 1395 } 1396 } 1397 1398 /** 1399 * Search string in settings page. 1400 * 1401 * @param string $query 1402 * @return array 1403 */ 1404 public function search($query) { 1405 $found = array(); 1406 1407 foreach ($this->settings as $setting) { 1408 if ($setting->is_related($query)) { 1409 $found[] = $setting; 1410 } 1411 } 1412 1413 if ($found) { 1414 $result = new stdClass(); 1415 $result->page = $this; 1416 $result->settings = $found; 1417 return array($this->name => $result); 1418 } 1419 1420 $found = false; 1421 if (strpos(strtolower($this->name), $query) !== false) { 1422 $found = true; 1423 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) { 1424 $found = true; 1425 } 1426 if ($found) { 1427 $result = new stdClass(); 1428 $result->page = $this; 1429 $result->settings = array(); 1430 return array($this->name => $result); 1431 } else { 1432 return array(); 1433 } 1434 } 1435 1436 /** 1437 * This function always returns false, required by interface 1438 * 1439 * @param string $name 1440 * @return bool Always false 1441 */ 1442 public function prune($name) { 1443 return false; 1444 } 1445 1446 /** 1447 * adds an admin_setting to this admin_settingpage 1448 * 1449 * 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 1450 * n.b. each admin_setting in an admin_settingpage must have a unique internal name 1451 * 1452 * @param object $setting is the admin_setting object you want to add 1453 * @return bool true if successful, false if not 1454 */ 1455 public function add($setting) { 1456 if (!($setting instanceof admin_setting)) { 1457 debugging('error - not a setting instance'); 1458 return false; 1459 } 1460 1461 $name = $setting->name; 1462 if ($setting->plugin) { 1463 $name = $setting->plugin . $name; 1464 } 1465 $this->settings->{$name} = $setting; 1466 return true; 1467 } 1468 1469 /** 1470 * see admin_externalpage 1471 * 1472 * @return bool Returns true for yes false for no 1473 */ 1474 public function check_access() { 1475 global $CFG; 1476 $context = empty($this->context) ? context_system::instance() : $this->context; 1477 foreach($this->req_capability as $cap) { 1478 if (has_capability($cap, $context)) { 1479 return true; 1480 } 1481 } 1482 return false; 1483 } 1484 1485 /** 1486 * outputs this page as html in a table (suitable for inclusion in an admin pagetype) 1487 * @return string Returns an XHTML string 1488 */ 1489 public function output_html() { 1490 $adminroot = admin_get_root(); 1491 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n"; 1492 foreach($this->settings as $setting) { 1493 $fullname = $setting->get_full_name(); 1494 if (array_key_exists($fullname, $adminroot->errors)) { 1495 $data = $adminroot->errors[$fullname]->data; 1496 } else { 1497 $data = $setting->get_setting(); 1498 // do not use defaults if settings not available - upgrade settings handles the defaults! 1499 } 1500 $return .= $setting->output_html($data); 1501 } 1502 $return .= '</fieldset>'; 1503 return $return; 1504 } 1505 1506 /** 1507 * Is this settings page hidden in admin tree block? 1508 * 1509 * @return bool True if hidden 1510 */ 1511 public function is_hidden() { 1512 return $this->hidden; 1513 } 1514 1515 /** 1516 * Show we display Save button at the page bottom? 1517 * @return bool 1518 */ 1519 public function show_save() { 1520 foreach($this->settings as $setting) { 1521 if (empty($setting->nosave)) { 1522 return true; 1523 } 1524 } 1525 return false; 1526 } 1527 } 1528 1529 1530 /** 1531 * Admin settings class. Only exists on setting pages. 1532 * Read & write happens at this level; no authentication. 1533 * 1534 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1535 */ 1536 abstract class admin_setting { 1537 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */ 1538 public $name; 1539 /** @var string localised name */ 1540 public $visiblename; 1541 /** @var string localised long description in Markdown format */ 1542 public $description; 1543 /** @var mixed Can be string or array of string */ 1544 public $defaultsetting; 1545 /** @var string */ 1546 public $updatedcallback; 1547 /** @var mixed can be String or Null. Null means main config table */ 1548 public $plugin; // null means main config table 1549 /** @var bool true indicates this setting does not actually save anything, just information */ 1550 public $nosave = false; 1551 /** @var bool if set, indicates that a change to this setting requires rebuild course cache */ 1552 public $affectsmodinfo = false; 1553 /** @var array of admin_setting_flag - These are extra checkboxes attached to a setting. */ 1554 private $flags = array(); 1555 1556 /** 1557 * Constructor 1558 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 1559 * or 'myplugin/mysetting' for ones in config_plugins. 1560 * @param string $visiblename localised name 1561 * @param string $description localised long description 1562 * @param mixed $defaultsetting string or array depending on implementation 1563 */ 1564 public function __construct($name, $visiblename, $description, $defaultsetting) { 1565 $this->parse_setting_name($name); 1566 $this->visiblename = $visiblename; 1567 $this->description = $description; 1568 $this->defaultsetting = $defaultsetting; 1569 } 1570 1571 /** 1572 * Generic function to add a flag to this admin setting. 1573 * 1574 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1575 * @param bool $default - The default for the flag 1576 * @param string $shortname - The shortname for this flag. Used as a suffix for the setting name. 1577 * @param string $displayname - The display name for this flag. Used as a label next to the checkbox. 1578 */ 1579 protected function set_flag_options($enabled, $default, $shortname, $displayname) { 1580 if (empty($this->flags[$shortname])) { 1581 $this->flags[$shortname] = new admin_setting_flag($enabled, $default, $shortname, $displayname); 1582 } else { 1583 $this->flags[$shortname]->set_options($enabled, $default); 1584 } 1585 } 1586 1587 /** 1588 * Set the enabled options flag on this admin setting. 1589 * 1590 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1591 * @param bool $default - The default for the flag 1592 */ 1593 public function set_enabled_flag_options($enabled, $default) { 1594 $this->set_flag_options($enabled, $default, 'enabled', new lang_string('enabled', 'core_admin')); 1595 } 1596 1597 /** 1598 * Set the advanced options flag on this admin setting. 1599 * 1600 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1601 * @param bool $default - The default for the flag 1602 */ 1603 public function set_advanced_flag_options($enabled, $default) { 1604 $this->set_flag_options($enabled, $default, 'adv', new lang_string('advanced')); 1605 } 1606 1607 1608 /** 1609 * Set the locked options flag on this admin setting. 1610 * 1611 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED 1612 * @param bool $default - The default for the flag 1613 */ 1614 public function set_locked_flag_options($enabled, $default) { 1615 $this->set_flag_options($enabled, $default, 'locked', new lang_string('locked', 'core_admin')); 1616 } 1617 1618 /** 1619 * Get the currently saved value for a setting flag 1620 * 1621 * @param admin_setting_flag $flag - One of the admin_setting_flag for this admin_setting. 1622 * @return bool 1623 */ 1624 public function get_setting_flag_value(admin_setting_flag $flag) { 1625 $value = $this->config_read($this->name . '_' . $flag->get_shortname()); 1626 if (!isset($value)) { 1627 $value = $flag->get_default(); 1628 } 1629 1630 return !empty($value); 1631 } 1632 1633 /** 1634 * Get the list of defaults for the flags on this setting. 1635 * 1636 * @param array of strings describing the defaults for this setting. This is appended to by this function. 1637 */ 1638 public function get_setting_flag_defaults(& $defaults) { 1639 foreach ($this->flags as $flag) { 1640 if ($flag->is_enabled() && $flag->get_default()) { 1641 $defaults[] = $flag->get_displayname(); 1642 } 1643 } 1644 } 1645 1646 /** 1647 * Output the input fields for the advanced and locked flags on this setting. 1648 * 1649 * @param bool $adv - The current value of the advanced flag. 1650 * @param bool $locked - The current value of the locked flag. 1651 * @return string $output - The html for the flags. 1652 */ 1653 public function output_setting_flags() { 1654 $output = ''; 1655 1656 foreach ($this->flags as $flag) { 1657 if ($flag->is_enabled()) { 1658 $output .= $flag->output_setting_flag($this); 1659 } 1660 } 1661 1662 if (!empty($output)) { 1663 return html_writer::tag('span', $output, array('class' => 'adminsettingsflags')); 1664 } 1665 return $output; 1666 } 1667 1668 /** 1669 * Write the values of the flags for this admin setting. 1670 * 1671 * @param array $data - The data submitted from the form or null to set the default value for new installs. 1672 * @return bool - true if successful. 1673 */ 1674 public function write_setting_flags($data) { 1675 $result = true; 1676 foreach ($this->flags as $flag) { 1677 $result = $result && $flag->write_setting_flag($this, $data); 1678 } 1679 return $result; 1680 } 1681 1682 /** 1683 * Set up $this->name and potentially $this->plugin 1684 * 1685 * Set up $this->name and possibly $this->plugin based on whether $name looks 1686 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking 1687 * on the names, that is, output a developer debug warning if the name 1688 * contains anything other than [a-zA-Z0-9_]+. 1689 * 1690 * @param string $name the setting name passed in to the constructor. 1691 */ 1692 private function parse_setting_name($name) { 1693 $bits = explode('/', $name); 1694 if (count($bits) > 2) { 1695 throw new moodle_exception('invalidadminsettingname', '', '', $name); 1696 } 1697 $this->name = array_pop($bits); 1698 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) { 1699 throw new moodle_exception('invalidadminsettingname', '', '', $name); 1700 } 1701 if (!empty($bits)) { 1702 $this->plugin = array_pop($bits); 1703 if ($this->plugin === 'moodle') { 1704 $this->plugin = null; 1705 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) { 1706 throw new moodle_exception('invalidadminsettingname', '', '', $name); 1707 } 1708 } 1709 } 1710 1711 /** 1712 * Returns the fullname prefixed by the plugin 1713 * @return string 1714 */ 1715 public function get_full_name() { 1716 return 's_'.$this->plugin.'_'.$this->name; 1717 } 1718 1719 /** 1720 * Returns the ID string based on plugin and name 1721 * @return string 1722 */ 1723 public function get_id() { 1724 return 'id_s_'.$this->plugin.'_'.$this->name; 1725 } 1726 1727 /** 1728 * @param bool $affectsmodinfo If true, changes to this setting will 1729 * cause the course cache to be rebuilt 1730 */ 1731 public function set_affects_modinfo($affectsmodinfo) { 1732 $this->affectsmodinfo = $affectsmodinfo; 1733 } 1734 1735 /** 1736 * Returns the config if possible 1737 * 1738 * @return mixed returns config if successful else null 1739 */ 1740 public function config_read($name) { 1741 global $CFG; 1742 if (!empty($this->plugin)) { 1743 $value = get_config($this->plugin, $name); 1744 return $value === false ? NULL : $value; 1745 1746 } else { 1747 if (isset($CFG->$name)) { 1748 return $CFG->$name; 1749 } else { 1750 return NULL; 1751 } 1752 } 1753 } 1754 1755 /** 1756 * Used to set a config pair and log change 1757 * 1758 * @param string $name 1759 * @param mixed $value Gets converted to string if not null 1760 * @return bool Write setting to config table 1761 */ 1762 public function config_write($name, $value) { 1763 global $DB, $USER, $CFG; 1764 1765 if ($this->nosave) { 1766 return true; 1767 } 1768 1769 // make sure it is a real change 1770 $oldvalue = get_config($this->plugin, $name); 1771 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise 1772 $value = is_null($value) ? null : (string)$value; 1773 1774 if ($oldvalue === $value) { 1775 return true; 1776 } 1777 1778 // store change 1779 set_config($name, $value, $this->plugin); 1780 1781 // Some admin settings affect course modinfo 1782 if ($this->affectsmodinfo) { 1783 // Clear course cache for all courses 1784 rebuild_course_cache(0, true); 1785 } 1786 1787 $this->add_to_config_log($name, $oldvalue, $value); 1788 1789 return true; // BC only 1790 } 1791 1792 /** 1793 * Log config changes if necessary. 1794 * @param string $name 1795 * @param string $oldvalue 1796 * @param string $value 1797 */ 1798 protected function add_to_config_log($name, $oldvalue, $value) { 1799 add_to_config_log($name, $oldvalue, $value, $this->plugin); 1800 } 1801 1802 /** 1803 * Returns current value of this setting 1804 * @return mixed array or string depending on instance, NULL means not set yet 1805 */ 1806 public abstract function get_setting(); 1807 1808 /** 1809 * Returns default setting if exists 1810 * @return mixed array or string depending on instance; NULL means no default, user must supply 1811 */ 1812 public function get_defaultsetting() { 1813 $adminroot = admin_get_root(false, false); 1814 if (!empty($adminroot->custom_defaults)) { 1815 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin; 1816 if (isset($adminroot->custom_defaults[$plugin])) { 1817 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-) 1818 return $adminroot->custom_defaults[$plugin][$this->name]; 1819 } 1820 } 1821 } 1822 return $this->defaultsetting; 1823 } 1824 1825 /** 1826 * Store new setting 1827 * 1828 * @param mixed $data string or array, must not be NULL 1829 * @return string empty string if ok, string error message otherwise 1830 */ 1831 public abstract function write_setting($data); 1832 1833 /** 1834 * Return part of form with setting 1835 * This function should always be overwritten 1836 * 1837 * @param mixed $data array or string depending on setting 1838 * @param string $query 1839 * @return string 1840 */ 1841 public function output_html($data, $query='') { 1842 // should be overridden 1843 return; 1844 } 1845 1846 /** 1847 * Function called if setting updated - cleanup, cache reset, etc. 1848 * @param string $functionname Sets the function name 1849 * @return void 1850 */ 1851 public function set_updatedcallback($functionname) { 1852 $this->updatedcallback = $functionname; 1853 } 1854 1855 /** 1856 * Execute postupdatecallback if necessary. 1857 * @param mixed $original original value before write_setting() 1858 * @return bool true if changed, false if not. 1859 */ 1860 public function post_write_settings($original) { 1861 // Comparison must work for arrays too. 1862 if (serialize($original) === serialize($this->get_setting())) { 1863 return false; 1864 } 1865 1866 $callbackfunction = $this->updatedcallback; 1867 if (!empty($callbackfunction) and function_exists($callbackfunction)) { 1868 $callbackfunction($this->get_full_name()); 1869 } 1870 return true; 1871 } 1872 1873 /** 1874 * Is setting related to query text - used when searching 1875 * @param string $query 1876 * @return bool 1877 */ 1878 public function is_related($query) { 1879 if (strpos(strtolower($this->name), $query) !== false) { 1880 return true; 1881 } 1882 if (strpos(core_text::strtolower($this->visiblename), $query) !== false) { 1883 return true; 1884 } 1885 if (strpos(core_text::strtolower($this->description), $query) !== false) { 1886 return true; 1887 } 1888 $current = $this->get_setting(); 1889 if (!is_null($current)) { 1890 if (is_string($current)) { 1891 if (strpos(core_text::strtolower($current), $query) !== false) { 1892 return true; 1893 } 1894 } 1895 } 1896 $default = $this->get_defaultsetting(); 1897 if (!is_null($default)) { 1898 if (is_string($default)) { 1899 if (strpos(core_text::strtolower($default), $query) !== false) { 1900 return true; 1901 } 1902 } 1903 } 1904 return false; 1905 } 1906 } 1907 1908 /** 1909 * An additional option that can be applied to an admin setting. 1910 * The currently supported options are 'ADVANCED' and 'LOCKED'. 1911 * 1912 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1913 */ 1914 class admin_setting_flag { 1915 /** @var bool Flag to indicate if this option can be toggled for this setting */ 1916 private $enabled = false; 1917 /** @var bool Flag to indicate if this option defaults to true or false */ 1918 private $default = false; 1919 /** @var string Short string used to create setting name - e.g. 'adv' */ 1920 private $shortname = ''; 1921 /** @var string String used as the label for this flag */ 1922 private $displayname = ''; 1923 /** @const Checkbox for this flag is displayed in admin page */ 1924 const ENABLED = true; 1925 /** @const Checkbox for this flag is not displayed in admin page */ 1926 const DISABLED = false; 1927 1928 /** 1929 * Constructor 1930 * 1931 * @param bool $enabled Can this option can be toggled. 1932 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED. 1933 * @param bool $default The default checked state for this setting option. 1934 * @param string $shortname The shortname of this flag. Currently supported flags are 'locked' and 'adv' 1935 * @param string $displayname The displayname of this flag. Used as a label for the flag. 1936 */ 1937 public function __construct($enabled, $default, $shortname, $displayname) { 1938 $this->shortname = $shortname; 1939 $this->displayname = $displayname; 1940 $this->set_options($enabled, $default); 1941 } 1942 1943 /** 1944 * Update the values of this setting options class 1945 * 1946 * @param bool $enabled Can this option can be toggled. 1947 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED. 1948 * @param bool $default The default checked state for this setting option. 1949 */ 1950 public function set_options($enabled, $default) { 1951 $this->enabled = $enabled; 1952 $this->default = $default; 1953 } 1954 1955 /** 1956 * Should this option appear in the interface and be toggleable? 1957 * 1958 * @return bool Is it enabled? 1959 */ 1960 public function is_enabled() { 1961 return $this->enabled; 1962 } 1963 1964 /** 1965 * Should this option be checked by default? 1966 * 1967 * @return bool Is it on by default? 1968 */ 1969 public function get_default() { 1970 return $this->default; 1971 } 1972 1973 /** 1974 * Return the short name for this flag. e.g. 'adv' or 'locked' 1975 * 1976 * @return string 1977 */ 1978 public function get_shortname() { 1979 return $this->shortname; 1980 } 1981 1982 /** 1983 * Return the display name for this flag. e.g. 'Advanced' or 'Locked' 1984 * 1985 * @return string 1986 */ 1987 public function get_displayname() { 1988 return $this->displayname; 1989 } 1990 1991 /** 1992 * Save the submitted data for this flag - or set it to the default if $data is null. 1993 * 1994 * @param admin_setting $setting - The admin setting for this flag 1995 * @param array $data - The data submitted from the form or null to set the default value for new installs. 1996 * @return bool 1997 */ 1998 public function write_setting_flag(admin_setting $setting, $data) { 1999 $result = true; 2000 if ($this->is_enabled()) { 2001 if (!isset($data)) { 2002 $value = $this->get_default(); 2003 } else { 2004 $value = !empty($data[$setting->get_full_name() . '_' . $this->get_shortname()]); 2005 } 2006 $result = $setting->config_write($setting->name . '_' . $this->get_shortname(), $value); 2007 } 2008 2009 return $result; 2010 2011 } 2012 2013 /** 2014 * Output the checkbox for this setting flag. Should only be called if the flag is enabled. 2015 * 2016 * @param admin_setting $setting - The admin setting for this flag 2017 * @return string - The html for the checkbox. 2018 */ 2019 public function output_setting_flag(admin_setting $setting) { 2020 $value = $setting->get_setting_flag_value($this); 2021 $output = ' <input type="checkbox" class="form-checkbox" ' . 2022 ' id="' . $setting->get_id() . '_' . $this->get_shortname() . '" ' . 2023 ' name="' . $setting->get_full_name() . '_' . $this->get_shortname() . '" ' . 2024 ' value="1" ' . ($value ? 'checked="checked"' : '') . ' />' . 2025 ' <label for="' . $setting->get_id() . '_' . $this->get_shortname() . '">' . 2026 $this->get_displayname() . 2027 ' </label> '; 2028 return $output; 2029 } 2030 } 2031 2032 2033 /** 2034 * No setting - just heading and text. 2035 * 2036 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2037 */ 2038 class admin_setting_heading extends admin_setting { 2039 2040 /** 2041 * not a setting, just text 2042 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2043 * @param string $heading heading 2044 * @param string $information text in box 2045 */ 2046 public function __construct($name, $heading, $information) { 2047 $this->nosave = true; 2048 parent::__construct($name, $heading, $information, ''); 2049 } 2050 2051 /** 2052 * Always returns true 2053 * @return bool Always returns true 2054 */ 2055 public function get_setting() { 2056 return true; 2057 } 2058 2059 /** 2060 * Always returns true 2061 * @return bool Always returns true 2062 */ 2063 public function get_defaultsetting() { 2064 return true; 2065 } 2066 2067 /** 2068 * Never write settings 2069 * @return string Always returns an empty string 2070 */ 2071 public function write_setting($data) { 2072 // do not write any setting 2073 return ''; 2074 } 2075 2076 /** 2077 * Returns an HTML string 2078 * @return string Returns an HTML string 2079 */ 2080 public function output_html($data, $query='') { 2081 global $OUTPUT; 2082 $return = ''; 2083 if ($this->visiblename != '') { 2084 $return .= $OUTPUT->heading($this->visiblename, 3, 'main'); 2085 } 2086 if ($this->description != '') { 2087 $return .= $OUTPUT->box(highlight($query, markdown_to_html($this->description)), 'generalbox formsettingheading'); 2088 } 2089 return $return; 2090 } 2091 } 2092 2093 2094 /** 2095 * The most flexibly setting, user is typing text 2096 * 2097 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2098 */ 2099 class admin_setting_configtext extends admin_setting { 2100 2101 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */ 2102 public $paramtype; 2103 /** @var int default field size */ 2104 public $size; 2105 2106 /** 2107 * Config text constructor 2108 * 2109 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2110 * @param string $visiblename localised 2111 * @param string $description long localised info 2112 * @param string $defaultsetting 2113 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex 2114 * @param int $size default field size 2115 */ 2116 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) { 2117 $this->paramtype = $paramtype; 2118 if (!is_null($size)) { 2119 $this->size = $size; 2120 } else { 2121 $this->size = ($paramtype === PARAM_INT) ? 5 : 30; 2122 } 2123 parent::__construct($name, $visiblename, $description, $defaultsetting); 2124 } 2125 2126 /** 2127 * Return the setting 2128 * 2129 * @return mixed returns config if successful else null 2130 */ 2131 public function get_setting() { 2132 return $this->config_read($this->name); 2133 } 2134 2135 public function write_setting($data) { 2136 if ($this->paramtype === PARAM_INT and $data === '') { 2137 // do not complain if '' used instead of 0 2138 $data = 0; 2139 } 2140 // $data is a string 2141 $validated = $this->validate($data); 2142 if ($validated !== true) { 2143 return $validated; 2144 } 2145 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 2146 } 2147 2148 /** 2149 * Validate data before storage 2150 * @param string data 2151 * @return mixed true if ok string if error found 2152 */ 2153 public function validate($data) { 2154 // allow paramtype to be a custom regex if it is the form of /pattern/ 2155 if (preg_match('#^/.*/$#', $this->paramtype)) { 2156 if (preg_match($this->paramtype, $data)) { 2157 return true; 2158 } else { 2159 return get_string('validateerror', 'admin'); 2160 } 2161 2162 } else if ($this->paramtype === PARAM_RAW) { 2163 return true; 2164 2165 } else { 2166 $cleaned = clean_param($data, $this->paramtype); 2167 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison 2168 return true; 2169 } else { 2170 return get_string('validateerror', 'admin'); 2171 } 2172 } 2173 } 2174 2175 /** 2176 * Return an XHTML string for the setting 2177 * @return string Returns an XHTML string 2178 */ 2179 public function output_html($data, $query='') { 2180 $default = $this->get_defaultsetting(); 2181 2182 return format_admin_setting($this, $this->visiblename, 2183 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>', 2184 $this->description, true, '', $default, $query); 2185 } 2186 } 2187 2188 /** 2189 * Text input with a maximum length constraint. 2190 * 2191 * @copyright 2015 onwards Ankit Agarwal 2192 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2193 */ 2194 class admin_setting_configtext_with_maxlength extends admin_setting_configtext { 2195 2196 /** @var int maximum number of chars allowed. */ 2197 protected $maxlength; 2198 2199 /** 2200 * Config text constructor 2201 * 2202 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 2203 * or 'myplugin/mysetting' for ones in config_plugins. 2204 * @param string $visiblename localised 2205 * @param string $description long localised info 2206 * @param string $defaultsetting 2207 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex 2208 * @param int $size default field size 2209 * @param mixed $maxlength int maxlength allowed, 0 for infinite. 2210 */ 2211 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, 2212 $size=null, $maxlength = 0) { 2213 $this->maxlength = $maxlength; 2214 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size); 2215 } 2216 2217 /** 2218 * Validate data before storage 2219 * 2220 * @param string $data data 2221 * @return mixed true if ok string if error found 2222 */ 2223 public function validate($data) { 2224 $parentvalidation = parent::validate($data); 2225 if ($parentvalidation === true) { 2226 if ($this->maxlength > 0) { 2227 // Max length check. 2228 $length = core_text::strlen($data); 2229 if ($length > $this->maxlength) { 2230 return get_string('maximumchars', 'moodle', $this->maxlength); 2231 } 2232 return true; 2233 } else { 2234 return true; // No max length check needed. 2235 } 2236 } else { 2237 return $parentvalidation; 2238 } 2239 } 2240 } 2241 2242 /** 2243 * General text area without html editor. 2244 * 2245 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2246 */ 2247 class admin_setting_configtextarea extends admin_setting_configtext { 2248 private $rows; 2249 private $cols; 2250 2251 /** 2252 * @param string $name 2253 * @param string $visiblename 2254 * @param string $description 2255 * @param mixed $defaultsetting string or array 2256 * @param mixed $paramtype 2257 * @param string $cols The number of columns to make the editor 2258 * @param string $rows The number of rows to make the editor 2259 */ 2260 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') { 2261 $this->rows = $rows; 2262 $this->cols = $cols; 2263 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype); 2264 } 2265 2266 /** 2267 * Returns an XHTML string for the editor 2268 * 2269 * @param string $data 2270 * @param string $query 2271 * @return string XHTML string for the editor 2272 */ 2273 public function output_html($data, $query='') { 2274 $default = $this->get_defaultsetting(); 2275 2276 $defaultinfo = $default; 2277 if (!is_null($default) and $default !== '') { 2278 $defaultinfo = "\n".$default; 2279 } 2280 2281 return format_admin_setting($this, $this->visiblename, 2282 '<div class="form-textarea" ><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'" spellcheck="true">'. s($data) .'</textarea></div>', 2283 $this->description, true, '', $defaultinfo, $query); 2284 } 2285 } 2286 2287 2288 /** 2289 * General text area with html editor. 2290 */ 2291 class admin_setting_confightmleditor extends admin_setting_configtext { 2292 private $rows; 2293 private $cols; 2294 2295 /** 2296 * @param string $name 2297 * @param string $visiblename 2298 * @param string $description 2299 * @param mixed $defaultsetting string or array 2300 * @param mixed $paramtype 2301 */ 2302 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') { 2303 $this->rows = $rows; 2304 $this->cols = $cols; 2305 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype); 2306 editors_head_setup(); 2307 } 2308 2309 /** 2310 * Returns an XHTML string for the editor 2311 * 2312 * @param string $data 2313 * @param string $query 2314 * @return string XHTML string for the editor 2315 */ 2316 public function output_html($data, $query='') { 2317 $default = $this->get_defaultsetting(); 2318 2319 $defaultinfo = $default; 2320 if (!is_null($default) and $default !== '') { 2321 $defaultinfo = "\n".$default; 2322 } 2323 2324 $editor = editors_get_preferred_editor(FORMAT_HTML); 2325 $editor->set_text($data); 2326 $editor->use_editor($this->get_id(), array('noclean'=>true)); 2327 2328 return format_admin_setting($this, $this->visiblename, 2329 '<div class="form-textarea"><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'" spellcheck="true">'. s($data) .'</textarea></div>', 2330 $this->description, true, '', $defaultinfo, $query); 2331 } 2332 } 2333 2334 2335 /** 2336 * Password field, allows unmasking of password 2337 * 2338 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2339 */ 2340 class admin_setting_configpasswordunmask extends admin_setting_configtext { 2341 /** 2342 * Constructor 2343 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2344 * @param string $visiblename localised 2345 * @param string $description long localised info 2346 * @param string $defaultsetting default password 2347 */ 2348 public function __construct($name, $visiblename, $description, $defaultsetting) { 2349 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30); 2350 } 2351 2352 /** 2353 * Log config changes if necessary. 2354 * @param string $name 2355 * @param string $oldvalue 2356 * @param string $value 2357 */ 2358 protected function add_to_config_log($name, $oldvalue, $value) { 2359 if ($value !== '') { 2360 $value = '********'; 2361 } 2362 if ($oldvalue !== '' and $oldvalue !== null) { 2363 $oldvalue = '********'; 2364 } 2365 parent::add_to_config_log($name, $oldvalue, $value); 2366 } 2367 2368 /** 2369 * Returns XHTML for the field 2370 * Writes Javascript into the HTML below right before the last div 2371 * 2372 * @todo Make javascript available through newer methods if possible 2373 * @param string $data Value for the field 2374 * @param string $query Passed as final argument for format_admin_setting 2375 * @return string XHTML field 2376 */ 2377 public function output_html($data, $query='') { 2378 $id = $this->get_id(); 2379 $unmask = get_string('unmaskpassword', 'form'); 2380 $unmaskjs = '<script type="text/javascript"> 2381 //<![CDATA[ 2382 var is_ie = (navigator.userAgent.toLowerCase().indexOf("msie") != -1); 2383 2384 document.getElementById("'.$id.'").setAttribute("autocomplete", "off"); 2385 2386 var unmaskdiv = document.getElementById("'.$id.'unmaskdiv"); 2387 2388 var unmaskchb = document.createElement("input"); 2389 unmaskchb.setAttribute("type", "checkbox"); 2390 unmaskchb.setAttribute("id", "'.$id.'unmask"); 2391 unmaskchb.onchange = function() {unmaskPassword("'.$id.'");}; 2392 unmaskdiv.appendChild(unmaskchb); 2393 2394 var unmasklbl = document.createElement("label"); 2395 unmasklbl.innerHTML = "'.addslashes_js($unmask).'"; 2396 if (is_ie) { 2397 unmasklbl.setAttribute("htmlFor", "'.$id.'unmask"); 2398 } else { 2399 unmasklbl.setAttribute("for", "'.$id.'unmask"); 2400 } 2401 unmaskdiv.appendChild(unmasklbl); 2402 2403 if (is_ie) { 2404 // ugly hack to work around the famous onchange IE bug 2405 unmaskchb.onclick = function() {this.blur();}; 2406 unmaskdiv.onclick = function() {this.blur();}; 2407 } 2408 //]]> 2409 </script>'; 2410 return format_admin_setting($this, $this->visiblename, 2411 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$id.'" name="'.$this->get_full_name().'" value="'.s($data).'" /><div class="unmask" id="'.$id.'unmaskdiv"></div>'.$unmaskjs.'</div>', 2412 $this->description, true, '', NULL, $query); 2413 } 2414 } 2415 2416 /** 2417 * Empty setting used to allow flags (advanced) on settings that can have no sensible default. 2418 * Note: Only advanced makes sense right now - locked does not. 2419 * 2420 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2421 */ 2422 class admin_setting_configempty extends admin_setting_configtext { 2423 2424 /** 2425 * @param string $name 2426 * @param string $visiblename 2427 * @param string $description 2428 */ 2429 public function __construct($name, $visiblename, $description) { 2430 parent::__construct($name, $visiblename, $description, '', PARAM_RAW); 2431 } 2432 2433 /** 2434 * Returns an XHTML string for the hidden field 2435 * 2436 * @param string $data 2437 * @param string $query 2438 * @return string XHTML string for the editor 2439 */ 2440 public function output_html($data, $query='') { 2441 return format_admin_setting($this, 2442 $this->visiblename, 2443 '<div class="form-empty" >' . 2444 '<input type="hidden"' . 2445 ' id="'. $this->get_id() .'"' . 2446 ' name="'. $this->get_full_name() .'"' . 2447 ' value=""/></div>', 2448 $this->description, 2449 true, 2450 '', 2451 get_string('none'), 2452 $query); 2453 } 2454 } 2455 2456 2457 /** 2458 * Path to directory 2459 * 2460 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2461 */ 2462 class admin_setting_configfile extends admin_setting_configtext { 2463 /** 2464 * Constructor 2465 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2466 * @param string $visiblename localised 2467 * @param string $description long localised info 2468 * @param string $defaultdirectory default directory location 2469 */ 2470 public function __construct($name, $visiblename, $description, $defaultdirectory) { 2471 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50); 2472 } 2473 2474 /** 2475 * Returns XHTML for the field 2476 * 2477 * Returns XHTML for the field and also checks whether the file 2478 * specified in $data exists using file_exists() 2479 * 2480 * @param string $data File name and path to use in value attr 2481 * @param string $query 2482 * @return string XHTML field 2483 */ 2484 public function output_html($data, $query='') { 2485 global $CFG; 2486 $default = $this->get_defaultsetting(); 2487 2488 if ($data) { 2489 if (file_exists($data)) { 2490 $executable = '<span class="pathok">✔</span>'; 2491 } else { 2492 $executable = '<span class="patherror">✘</span>'; 2493 } 2494 } else { 2495 $executable = ''; 2496 } 2497 $readonly = ''; 2498 if (!empty($CFG->preventexecpath)) { 2499 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>'; 2500 $readonly = 'readonly="readonly"'; 2501 } 2502 2503 return format_admin_setting($this, $this->visiblename, 2504 '<div class="form-file defaultsnext"><input '.$readonly.' type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>', 2505 $this->description, true, '', $default, $query); 2506 } 2507 2508 /** 2509 * Checks if execpatch has been disabled in config.php 2510 */ 2511 public function write_setting($data) { 2512 global $CFG; 2513 if (!empty($CFG->preventexecpath)) { 2514 if ($this->get_setting() === null) { 2515 // Use default during installation. 2516 $data = $this->get_defaultsetting(); 2517 if ($data === null) { 2518 $data = ''; 2519 } 2520 } else { 2521 return ''; 2522 } 2523 } 2524 return parent::write_setting($data); 2525 } 2526 } 2527 2528 2529 /** 2530 * Path to executable file 2531 * 2532 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2533 */ 2534 class admin_setting_configexecutable extends admin_setting_configfile { 2535 2536 /** 2537 * Returns an XHTML field 2538 * 2539 * @param string $data This is the value for the field 2540 * @param string $query 2541 * @return string XHTML field 2542 */ 2543 public function output_html($data, $query='') { 2544 global $CFG; 2545 $default = $this->get_defaultsetting(); 2546 require_once("$CFG->libdir/filelib.php"); 2547 2548 if ($data) { 2549 if (file_exists($data) and !is_dir($data) and file_is_executable($data)) { 2550 $executable = '<span class="pathok">✔</span>'; 2551 } else { 2552 $executable = '<span class="patherror">✘</span>'; 2553 } 2554 } else { 2555 $executable = ''; 2556 } 2557 $readonly = ''; 2558 if (!empty($CFG->preventexecpath)) { 2559 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>'; 2560 $readonly = 'readonly="readonly"'; 2561 } 2562 2563 return format_admin_setting($this, $this->visiblename, 2564 '<div class="form-file defaultsnext"><input '.$readonly.' type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>', 2565 $this->description, true, '', $default, $query); 2566 } 2567 } 2568 2569 2570 /** 2571 * Path to directory 2572 * 2573 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2574 */ 2575 class admin_setting_configdirectory extends admin_setting_configfile { 2576 2577 /** 2578 * Returns an XHTML field 2579 * 2580 * @param string $data This is the value for the field 2581 * @param string $query 2582 * @return string XHTML 2583 */ 2584 public function output_html($data, $query='') { 2585 global $CFG; 2586 $default = $this->get_defaultsetting(); 2587 2588 if ($data) { 2589 if (file_exists($data) and is_dir($data)) { 2590 $executable = '<span class="pathok">✔</span>'; 2591 } else { 2592 $executable = '<span class="patherror">✘</span>'; 2593 } 2594 } else { 2595 $executable = ''; 2596 } 2597 $readonly = ''; 2598 if (!empty($CFG->preventexecpath)) { 2599 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>'; 2600 $readonly = 'readonly="readonly"'; 2601 } 2602 2603 return format_admin_setting($this, $this->visiblename, 2604 '<div class="form-file defaultsnext"><input '.$readonly.' type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>', 2605 $this->description, true, '', $default, $query); 2606 } 2607 } 2608 2609 2610 /** 2611 * Checkbox 2612 * 2613 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2614 */ 2615 class admin_setting_configcheckbox extends admin_setting { 2616 /** @var string Value used when checked */ 2617 public $yes; 2618 /** @var string Value used when not checked */ 2619 public $no; 2620 2621 /** 2622 * Constructor 2623 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2624 * @param string $visiblename localised 2625 * @param string $description long localised info 2626 * @param string $defaultsetting 2627 * @param string $yes value used when checked 2628 * @param string $no value used when not checked 2629 */ 2630 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { 2631 parent::__construct($name, $visiblename, $description, $defaultsetting); 2632 $this->yes = (string)$yes; 2633 $this->no = (string)$no; 2634 } 2635 2636 /** 2637 * Retrieves the current setting using the objects name 2638 * 2639 * @return string 2640 */ 2641 public function get_setting() { 2642 return $this->config_read($this->name); 2643 } 2644 2645 /** 2646 * Sets the value for the setting 2647 * 2648 * Sets the value for the setting to either the yes or no values 2649 * of the object by comparing $data to yes 2650 * 2651 * @param mixed $data Gets converted to str for comparison against yes value 2652 * @return string empty string or error 2653 */ 2654 public function write_setting($data) { 2655 if ((string)$data === $this->yes) { // convert to strings before comparison 2656 $data = $this->yes; 2657 } else { 2658 $data = $this->no; 2659 } 2660 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 2661 } 2662 2663 /** 2664 * Returns an XHTML checkbox field 2665 * 2666 * @param string $data If $data matches yes then checkbox is checked 2667 * @param string $query 2668 * @return string XHTML field 2669 */ 2670 public function output_html($data, $query='') { 2671 $default = $this->get_defaultsetting(); 2672 2673 if (!is_null($default)) { 2674 if ((string)$default === $this->yes) { 2675 $defaultinfo = get_string('checkboxyes', 'admin'); 2676 } else { 2677 $defaultinfo = get_string('checkboxno', 'admin'); 2678 } 2679 } else { 2680 $defaultinfo = NULL; 2681 } 2682 2683 if ((string)$data === $this->yes) { // convert to strings before comparison 2684 $checked = 'checked="checked"'; 2685 } else { 2686 $checked = ''; 2687 } 2688 2689 return format_admin_setting($this, $this->visiblename, 2690 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> ' 2691 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>', 2692 $this->description, true, '', $defaultinfo, $query); 2693 } 2694 } 2695 2696 2697 /** 2698 * Multiple checkboxes, each represents different value, stored in csv format 2699 * 2700 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2701 */ 2702 class admin_setting_configmulticheckbox extends admin_setting { 2703 /** @var array Array of choices value=>label */ 2704 public $choices; 2705 2706 /** 2707 * Constructor: uses parent::__construct 2708 * 2709 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2710 * @param string $visiblename localised 2711 * @param string $description long localised info 2712 * @param array $defaultsetting array of selected 2713 * @param array $choices array of $value=>$label for each checkbox 2714 */ 2715 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 2716 $this->choices = $choices; 2717 parent::__construct($name, $visiblename, $description, $defaultsetting); 2718 } 2719 2720 /** 2721 * This public function may be used in ancestors for lazy loading of choices 2722 * 2723 * @todo Check if this function is still required content commented out only returns true 2724 * @return bool true if loaded, false if error 2725 */ 2726 public function load_choices() { 2727 /* 2728 if (is_array($this->choices)) { 2729 return true; 2730 } 2731 .... load choices here 2732 */ 2733 return true; 2734 } 2735 2736 /** 2737 * Is setting related to query text - used when searching 2738 * 2739 * @param string $query 2740 * @return bool true on related, false on not or failure 2741 */ 2742 public function is_related($query) { 2743 if (!$this->load_choices() or empty($this->choices)) { 2744 return false; 2745 } 2746 if (parent::is_related($query)) { 2747 return true; 2748 } 2749 2750 foreach ($this->choices as $desc) { 2751 if (strpos(core_text::strtolower($desc), $query) !== false) { 2752 return true; 2753 } 2754 } 2755 return false; 2756 } 2757 2758 /** 2759 * Returns the current setting if it is set 2760 * 2761 * @return mixed null if null, else an array 2762 */ 2763 public function get_setting() { 2764 $result = $this->config_read($this->name); 2765 2766 if (is_null($result)) { 2767 return NULL; 2768 } 2769 if ($result === '') { 2770 return array(); 2771 } 2772 $enabled = explode(',', $result); 2773 $setting = array(); 2774 foreach ($enabled as $option) { 2775 $setting[$option] = 1; 2776 } 2777 return $setting; 2778 } 2779 2780 /** 2781 * Saves the setting(s) provided in $data 2782 * 2783 * @param array $data An array of data, if not array returns empty str 2784 * @return mixed empty string on useless data or bool true=success, false=failed 2785 */ 2786 public function write_setting($data) { 2787 if (!is_array($data)) { 2788 return ''; // ignore it 2789 } 2790 if (!$this->load_choices() or empty($this->choices)) { 2791 return ''; 2792 } 2793 unset($data['xxxxx']); 2794 $result = array(); 2795 foreach ($data as $key => $value) { 2796 if ($value and array_key_exists($key, $this->choices)) { 2797 $result[] = $key; 2798 } 2799 } 2800 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin'); 2801 } 2802 2803 /** 2804 * Returns XHTML field(s) as required by choices 2805 * 2806 * Relies on data being an array should data ever be another valid vartype with 2807 * acceptable value this may cause a warning/error 2808 * if (!is_array($data)) would fix the problem 2809 * 2810 * @todo Add vartype handling to ensure $data is an array 2811 * 2812 * @param array $data An array of checked values 2813 * @param string $query 2814 * @return string XHTML field 2815 */ 2816 public function output_html($data, $query='') { 2817 if (!$this->load_choices() or empty($this->choices)) { 2818 return ''; 2819 } 2820 $default = $this->get_defaultsetting(); 2821 if (is_null($default)) { 2822 $default = array(); 2823 } 2824 if (is_null($data)) { 2825 $data = array(); 2826 } 2827 $options = array(); 2828 $defaults = array(); 2829 foreach ($this->choices as $key=>$description) { 2830 if (!empty($data[$key])) { 2831 $checked = 'checked="checked"'; 2832 } else { 2833 $checked = ''; 2834 } 2835 if (!empty($default[$key])) { 2836 $defaults[] = $description; 2837 } 2838 2839 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />' 2840 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>'; 2841 } 2842 2843 if (is_null($default)) { 2844 $defaultinfo = NULL; 2845 } else if (!empty($defaults)) { 2846 $defaultinfo = implode(', ', $defaults); 2847 } else { 2848 $defaultinfo = get_string('none'); 2849 } 2850 2851 $return = '<div class="form-multicheckbox">'; 2852 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected 2853 if ($options) { 2854 $return .= '<ul>'; 2855 foreach ($options as $option) { 2856 $return .= '<li>'.$option.'</li>'; 2857 } 2858 $return .= '</ul>'; 2859 } 2860 $return .= '</div>'; 2861 2862 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query); 2863 2864 } 2865 } 2866 2867 2868 /** 2869 * Multiple checkboxes 2, value stored as string 00101011 2870 * 2871 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2872 */ 2873 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox { 2874 2875 /** 2876 * Returns the setting if set 2877 * 2878 * @return mixed null if not set, else an array of set settings 2879 */ 2880 public function get_setting() { 2881 $result = $this->config_read($this->name); 2882 if (is_null($result)) { 2883 return NULL; 2884 } 2885 if (!$this->load_choices()) { 2886 return NULL; 2887 } 2888 $result = str_pad($result, count($this->choices), '0'); 2889 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY); 2890 $setting = array(); 2891 foreach ($this->choices as $key=>$unused) { 2892 $value = array_shift($result); 2893 if ($value) { 2894 $setting[$key] = 1; 2895 } 2896 } 2897 return $setting; 2898 } 2899 2900 /** 2901 * Save setting(s) provided in $data param 2902 * 2903 * @param array $data An array of settings to save 2904 * @return mixed empty string for bad data or bool true=>success, false=>error 2905 */ 2906 public function write_setting($data) { 2907 if (!is_array($data)) { 2908 return ''; // ignore it 2909 } 2910 if (!$this->load_choices() or empty($this->choices)) { 2911 return ''; 2912 } 2913 $result = ''; 2914 foreach ($this->choices as $key=>$unused) { 2915 if (!empty($data[$key])) { 2916 $result .= '1'; 2917 } else { 2918 $result .= '0'; 2919 } 2920 } 2921 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'); 2922 } 2923 } 2924 2925 2926 /** 2927 * Select one value from list 2928 * 2929 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2930 */ 2931 class admin_setting_configselect extends admin_setting { 2932 /** @var array Array of choices value=>label */ 2933 public $choices; 2934 2935 /** 2936 * Constructor 2937 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 2938 * @param string $visiblename localised 2939 * @param string $description long localised info 2940 * @param string|int $defaultsetting 2941 * @param array $choices array of $value=>$label for each selection 2942 */ 2943 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 2944 $this->choices = $choices; 2945 parent::__construct($name, $visiblename, $description, $defaultsetting); 2946 } 2947 2948 /** 2949 * This function may be used in ancestors for lazy loading of choices 2950 * 2951 * Override this method if loading of choices is expensive, such 2952 * as when it requires multiple db requests. 2953 * 2954 * @return bool true if loaded, false if error 2955 */ 2956 public function load_choices() { 2957 /* 2958 if (is_array($this->choices)) { 2959 return true; 2960 } 2961 .... load choices here 2962 */ 2963 return true; 2964 } 2965 2966 /** 2967 * Check if this is $query is related to a choice 2968 * 2969 * @param string $query 2970 * @return bool true if related, false if not 2971 */ 2972 public function is_related($query) { 2973 if (parent::is_related($query)) { 2974 return true; 2975 } 2976 if (!$this->load_choices()) { 2977 return false; 2978 } 2979 foreach ($this->choices as $key=>$value) { 2980 if (strpos(core_text::strtolower($key), $query) !== false) { 2981 return true; 2982 } 2983 if (strpos(core_text::strtolower($value), $query) !== false) { 2984 return true; 2985 } 2986 } 2987 return false; 2988 } 2989 2990 /** 2991 * Return the setting 2992 * 2993 * @return mixed returns config if successful else null 2994 */ 2995 public function get_setting() { 2996 return $this->config_read($this->name); 2997 } 2998 2999 /** 3000 * Save a setting 3001 * 3002 * @param string $data 3003 * @return string empty of error string 3004 */ 3005 public function write_setting($data) { 3006 if (!$this->load_choices() or empty($this->choices)) { 3007 return ''; 3008 } 3009 if (!array_key_exists($data, $this->choices)) { 3010 return ''; // ignore it 3011 } 3012 3013 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 3014 } 3015 3016 /** 3017 * Returns XHTML select field 3018 * 3019 * Ensure the options are loaded, and generate the XHTML for the select 3020 * element and any warning message. Separating this out from output_html 3021 * makes it easier to subclass this class. 3022 * 3023 * @param string $data the option to show as selected. 3024 * @param string $current the currently selected option in the database, null if none. 3025 * @param string $default the default selected option. 3026 * @return array the HTML for the select element, and a warning message. 3027 */ 3028 public function output_select_html($data, $current, $default, $extraname = '') { 3029 if (!$this->load_choices() or empty($this->choices)) { 3030 return array('', ''); 3031 } 3032 3033 $warning = ''; 3034 if (is_null($current)) { 3035 // first run 3036 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) { 3037 // no warning 3038 } else if (!array_key_exists($current, $this->choices)) { 3039 $warning = get_string('warningcurrentsetting', 'admin', s($current)); 3040 if (!is_null($default) and $data == $current) { 3041 $data = $default; // use default instead of first value when showing the form 3042 } 3043 } 3044 3045 $selecthtml = '<select id="'.$this->get_id().'" name="'.$this->get_full_name().$extraname.'">'; 3046 foreach ($this->choices as $key => $value) { 3047 // the string cast is needed because key may be integer - 0 is equal to most strings! 3048 $selecthtml .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>'; 3049 } 3050 $selecthtml .= '</select>'; 3051 return array($selecthtml, $warning); 3052 } 3053 3054 /** 3055 * Returns XHTML select field and wrapping div(s) 3056 * 3057 * @see output_select_html() 3058 * 3059 * @param string $data the option to show as selected 3060 * @param string $query 3061 * @return string XHTML field and wrapping div 3062 */ 3063 public function output_html($data, $query='') { 3064 $default = $this->get_defaultsetting(); 3065 $current = $this->get_setting(); 3066 3067 list($selecthtml, $warning) = $this->output_select_html($data, $current, $default); 3068 if (!$selecthtml) { 3069 return ''; 3070 } 3071 3072 if (!is_null($default) and array_key_exists($default, $this->choices)) { 3073 $defaultinfo = $this->choices[$default]; 3074 } else { 3075 $defaultinfo = NULL; 3076 } 3077 3078 $return = '<div class="form-select defaultsnext">' . $selecthtml . '</div>'; 3079 3080 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query); 3081 } 3082 } 3083 3084 3085 /** 3086 * Select multiple items from list 3087 * 3088 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3089 */ 3090 class admin_setting_configmultiselect extends admin_setting_configselect { 3091 /** 3092 * Constructor 3093 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 3094 * @param string $visiblename localised 3095 * @param string $description long localised info 3096 * @param array $defaultsetting array of selected items 3097 * @param array $choices array of $value=>$label for each list item 3098 */ 3099 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 3100 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); 3101 } 3102 3103 /** 3104 * Returns the select setting(s) 3105 * 3106 * @return mixed null or array. Null if no settings else array of setting(s) 3107 */ 3108 public function get_setting() { 3109 $result = $this->config_read($this->name); 3110 if (is_null($result)) { 3111 return NULL; 3112 } 3113 if ($result === '') { 3114 return array(); 3115 } 3116 return explode(',', $result); 3117 } 3118 3119 /** 3120 * Saves setting(s) provided through $data 3121 * 3122 * Potential bug in the works should anyone call with this function 3123 * using a vartype that is not an array 3124 * 3125 * @param array $data 3126 */ 3127 public function write_setting($data) { 3128 if (!is_array($data)) { 3129 return ''; //ignore it 3130 } 3131 if (!$this->load_choices() or empty($this->choices)) { 3132 return ''; 3133 } 3134 3135 unset($data['xxxxx']); 3136 3137 $save = array(); 3138 foreach ($data as $value) { 3139 if (!array_key_exists($value, $this->choices)) { 3140 continue; // ignore it 3141 } 3142 $save[] = $value; 3143 } 3144 3145 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin')); 3146 } 3147 3148 /** 3149 * Is setting related to query text - used when searching 3150 * 3151 * @param string $query 3152 * @return bool true if related, false if not 3153 */ 3154 public function is_related($query) { 3155 if (!$this->load_choices() or empty($this->choices)) { 3156 return false; 3157 } 3158 if (parent::is_related($query)) { 3159 return true; 3160 } 3161 3162 foreach ($this->choices as $desc) { 3163 if (strpos(core_text::strtolower($desc), $query) !== false) { 3164 return true; 3165 } 3166 } 3167 return false; 3168 } 3169 3170 /** 3171 * Returns XHTML multi-select field 3172 * 3173 * @todo Add vartype handling to ensure $data is an array 3174 * @param array $data Array of values to select by default 3175 * @param string $query 3176 * @return string XHTML multi-select field 3177 */ 3178 public function output_html($data, $query='') { 3179 if (!$this->load_choices() or empty($this->choices)) { 3180 return ''; 3181 } 3182 $choices = $this->choices; 3183 $default = $this->get_defaultsetting(); 3184 if (is_null($default)) { 3185 $default = array(); 3186 } 3187 if (is_null($data)) { 3188 $data = array(); 3189 } 3190 3191 $defaults = array(); 3192 $size = min(10, count($this->choices)); 3193 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected 3194 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">'; 3195 foreach ($this->choices as $key => $description) { 3196 if (in_array($key, $data)) { 3197 $selected = 'selected="selected"'; 3198 } else { 3199 $selected = ''; 3200 } 3201 if (in_array($key, $default)) { 3202 $defaults[] = $description; 3203 } 3204 3205 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>'; 3206 } 3207 3208 if (is_null($default)) { 3209 $defaultinfo = NULL; 3210 } if (!empty($defaults)) { 3211 $defaultinfo = implode(', ', $defaults); 3212 } else { 3213 $defaultinfo = get_string('none'); 3214 } 3215 3216 $return .= '</select></div>'; 3217 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query); 3218 } 3219 } 3220 3221 /** 3222 * Time selector 3223 * 3224 * This is a liiitle bit messy. we're using two selects, but we're returning 3225 * them as an array named after $name (so we only use $name2 internally for the setting) 3226 * 3227 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3228 */ 3229 class admin_setting_configtime extends admin_setting { 3230 /** @var string Used for setting second select (minutes) */ 3231 public $name2; 3232 3233 /** 3234 * Constructor 3235 * @param string $hoursname setting for hours 3236 * @param string $minutesname setting for hours 3237 * @param string $visiblename localised 3238 * @param string $description long localised info 3239 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes 3240 */ 3241 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) { 3242 $this->name2 = $minutesname; 3243 parent::__construct($hoursname, $visiblename, $description, $defaultsetting); 3244 } 3245 3246 /** 3247 * Get the selected time 3248 * 3249 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set 3250 */ 3251 public function get_setting() { 3252 $result1 = $this->config_read($this->name); 3253 $result2 = $this->config_read($this->name2); 3254 if (is_null($result1) or is_null($result2)) { 3255 return NULL; 3256 } 3257 3258 return array('h' => $result1, 'm' => $result2); 3259 } 3260 3261 /** 3262 * Store the time (hours and minutes) 3263 * 3264 * @param array $data Must be form 'h'=>xx, 'm'=>xx 3265 * @return bool true if success, false if not 3266 */ 3267 public function write_setting($data) { 3268 if (!is_array($data)) { 3269 return ''; 3270 } 3271 3272 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']); 3273 return ($result ? '' : get_string('errorsetting', 'admin')); 3274 } 3275 3276 /** 3277 * Returns XHTML time select fields 3278 * 3279 * @param array $data Must be form 'h'=>xx, 'm'=>xx 3280 * @param string $query 3281 * @return string XHTML time select fields and wrapping div(s) 3282 */ 3283 public function output_html($data, $query='') { 3284 $default = $this->get_defaultsetting(); 3285 3286 if (is_array($default)) { 3287 $defaultinfo = $default['h'].':'.$default['m']; 3288 } else { 3289 $defaultinfo = NULL; 3290 } 3291 3292 $return = '<div class="form-time defaultsnext">'; 3293 $return .= '<label class="accesshide" for="' . $this->get_id() . 'h">' . get_string('hours') . '</label>'; 3294 $return .= '<select id="' . $this->get_id() . 'h" name="' . $this->get_full_name() . '[h]">'; 3295 for ($i = 0; $i < 24; $i++) { 3296 $return .= '<option value="' . $i . '"' . ($i == $data['h'] ? ' selected="selected"' : '') . '>' . $i . '</option>'; 3297 } 3298 $return .= '</select>:'; 3299 $return .= '<label class="accesshide" for="' . $this->get_id() . 'm">' . get_string('minutes') . '</label>'; 3300 $return .= '<select id="' . $this->get_id() . 'm" name="' . $this->get_full_name() . '[m]">'; 3301 for ($i = 0; $i < 60; $i += 5) { 3302 $return .= '<option value="' . $i . '"' . ($i == $data['m'] ? ' selected="selected"' : '') . '>' . $i . '</option>'; 3303 } 3304 $return .= '</select>'; 3305 $return .= '</div>'; 3306 return format_admin_setting($this, $this->visiblename, $return, $this->description, 3307 $this->get_id() . 'h', '', $defaultinfo, $query); 3308 } 3309 3310 } 3311 3312 3313 /** 3314 * Seconds duration setting. 3315 * 3316 * @copyright 2012 Petr Skoda (http://skodak.org) 3317 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3318 */ 3319 class admin_setting_configduration extends admin_setting { 3320 3321 /** @var int default duration unit */ 3322 protected $defaultunit; 3323 3324 /** 3325 * Constructor 3326 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 3327 * or 'myplugin/mysetting' for ones in config_plugins. 3328 * @param string $visiblename localised name 3329 * @param string $description localised long description 3330 * @param mixed $defaultsetting string or array depending on implementation 3331 * @param int $defaultunit - day, week, etc. (in seconds) 3332 */ 3333 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) { 3334 if (is_number($defaultsetting)) { 3335 $defaultsetting = self::parse_seconds($defaultsetting); 3336 } 3337 $units = self::get_units(); 3338 if (isset($units[$defaultunit])) { 3339 $this->defaultunit = $defaultunit; 3340 } else { 3341 $this->defaultunit = 86400; 3342 } 3343 parent::__construct($name, $visiblename, $description, $defaultsetting); 3344 } 3345 3346 /** 3347 * Returns selectable units. 3348 * @static 3349 * @return array 3350 */ 3351 protected static function get_units() { 3352 return array( 3353 604800 => get_string('weeks'), 3354 86400 => get_string('days'), 3355 3600 => get_string('hours'), 3356 60 => get_string('minutes'), 3357 1 => get_string('seconds'), 3358 ); 3359 } 3360 3361 /** 3362 * Converts seconds to some more user friendly string. 3363 * @static 3364 * @param int $seconds 3365 * @return string 3366 */ 3367 protected static function get_duration_text($seconds) { 3368 if (empty($seconds)) { 3369 return get_string('none'); 3370 } 3371 $data = self::parse_seconds($seconds); 3372 switch ($data['u']) { 3373 case (60*60*24*7): 3374 return get_string('numweeks', '', $data['v']); 3375 case (60*60*24): 3376 return get_string('numdays', '', $data['v']); 3377 case (60*60): 3378 return get_string('numhours', '', $data['v']); 3379 case (60): 3380 return get_string('numminutes', '', $data['v']); 3381 default: 3382 return get_string('numseconds', '', $data['v']*$data['u']); 3383 } 3384 } 3385 3386 /** 3387 * Finds suitable units for given duration. 3388 * @static 3389 * @param int $seconds 3390 * @return array 3391 */ 3392 protected static function parse_seconds($seconds) { 3393 foreach (self::get_units() as $unit => $unused) { 3394 if ($seconds % $unit === 0) { 3395 return array('v'=>(int)($seconds/$unit), 'u'=>$unit); 3396 } 3397 } 3398 return array('v'=>(int)$seconds, 'u'=>1); 3399 } 3400 3401 /** 3402 * Get the selected duration as array. 3403 * 3404 * @return mixed An array containing 'v'=>xx, 'u'=>xx, or null if not set 3405 */ 3406 public function get_setting() { 3407 $seconds = $this->config_read($this->name); 3408 if (is_null($seconds)) { 3409 return null; 3410 } 3411 3412 return self::parse_seconds($seconds); 3413 } 3414 3415 /** 3416 * Store the duration as seconds. 3417 * 3418 * @param array $data Must be form 'h'=>xx, 'm'=>xx 3419 * @return bool true if success, false if not 3420 */ 3421 public function write_setting($data) { 3422 if (!is_array($data)) { 3423 return ''; 3424 } 3425 3426 $seconds = (int)($data['v']*$data['u']); 3427 if ($seconds < 0) { 3428 return get_string('errorsetting', 'admin'); 3429 } 3430 3431 $result = $this->config_write($this->name, $seconds); 3432 return ($result ? '' : get_string('errorsetting', 'admin')); 3433 } 3434 3435 /** 3436 * Returns duration text+select fields. 3437 * 3438 * @param array $data Must be form 'v'=>xx, 'u'=>xx 3439 * @param string $query 3440 * @return string duration text+select fields and wrapping div(s) 3441 */ 3442 public function output_html($data, $query='') { 3443 $default = $this->get_defaultsetting(); 3444 3445 if (is_number($default)) { 3446 $defaultinfo = self::get_duration_text($default); 3447 } else if (is_array($default)) { 3448 $defaultinfo = self::get_duration_text($default['v']*$default['u']); 3449 } else { 3450 $defaultinfo = null; 3451 } 3452 3453 $units = self::get_units(); 3454 3455 $inputid = $this->get_id() . 'v'; 3456 3457 $return = '<div class="form-duration defaultsnext">'; 3458 $return .= '<input type="text" size="5" id="' . $inputid . '" name="' . $this->get_full_name() . 3459 '[v]" value="' . s($data['v']) . '" />'; 3460 $return .= '<label for="' . $this->get_id() . 'u" class="accesshide">' . 3461 get_string('durationunits', 'admin') . '</label>'; 3462 $return .= '<select id="'.$this->get_id().'u" name="'.$this->get_full_name().'[u]">'; 3463 foreach ($units as $val => $text) { 3464 $selected = ''; 3465 if ($data['v'] == 0) { 3466 if ($val == $this->defaultunit) { 3467 $selected = ' selected="selected"'; 3468 } 3469 } else if ($val == $data['u']) { 3470 $selected = ' selected="selected"'; 3471 } 3472 $return .= '<option value="'.$val.'"'.$selected.'>'.$text.'</option>'; 3473 } 3474 $return .= '</select></div>'; 3475 return format_admin_setting($this, $this->visiblename, $return, $this->description, $inputid, '', $defaultinfo, $query); 3476 } 3477 } 3478 3479 3480 /** 3481 * Seconds duration setting with an advanced checkbox, that controls a additional 3482 * $name.'_adv' setting. 3483 * 3484 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3485 * @copyright 2014 The Open University 3486 */ 3487 class admin_setting_configduration_with_advanced extends admin_setting_configduration { 3488 /** 3489 * Constructor 3490 * @param string $name unique ascii name, either 'mysetting' for settings that in config, 3491 * or 'myplugin/mysetting' for ones in config_plugins. 3492 * @param string $visiblename localised name 3493 * @param string $description localised long description 3494 * @param array $defaultsetting array of int value, and bool whether it is 3495 * is advanced by default. 3496 * @param int $defaultunit - day, week, etc. (in seconds) 3497 */ 3498 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) { 3499 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $defaultunit); 3500 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 3501 } 3502 } 3503 3504 3505 /** 3506 * Used to validate a textarea used for ip addresses 3507 * 3508 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3509 * @copyright 2011 Petr Skoda (http://skodak.org) 3510 */ 3511 class admin_setting_configiplist extends admin_setting_configtextarea { 3512 3513 /** 3514 * Validate the contents of the textarea as IP addresses 3515 * 3516 * Used to validate a new line separated list of IP addresses collected from 3517 * a textarea control 3518 * 3519 * @param string $data A list of IP Addresses separated by new lines 3520 * @return mixed bool true for success or string:error on failure 3521 */ 3522 public function validate($data) { 3523 if(!empty($data)) { 3524 $ips = explode("\n", $data); 3525 } else { 3526 return true; 3527 } 3528 $result = true; 3529 $badips = array(); 3530 foreach($ips as $ip) { 3531 $ip = trim($ip); 3532 if (empty($ip)) { 3533 continue; 3534 } 3535 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) || 3536 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) || 3537 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) { 3538 } else { 3539 $result = false; 3540 $badips[] = $ip; 3541 } 3542 } 3543 if($result) { 3544 return true; 3545 } else { 3546 return get_string('validateiperror', 'admin', join(', ', $badips)); 3547 } 3548 } 3549 } 3550 3551 3552 /** 3553 * An admin setting for selecting one or more users who have a capability 3554 * in the system context 3555 * 3556 * An admin setting for selecting one or more users, who have a particular capability 3557 * in the system context. Warning, make sure the list will never be too long. There is 3558 * no paging or searching of this list. 3559 * 3560 * To correctly get a list of users from this config setting, you need to call the 3561 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php. 3562 * 3563 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3564 */ 3565 class admin_setting_users_with_capability extends admin_setting_configmultiselect { 3566 /** @var string The capabilities name */ 3567 protected $capability; 3568 /** @var int include admin users too */ 3569 protected $includeadmins; 3570 3571 /** 3572 * Constructor. 3573 * 3574 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 3575 * @param string $visiblename localised name 3576 * @param string $description localised long description 3577 * @param array $defaultsetting array of usernames 3578 * @param string $capability string capability name. 3579 * @param bool $includeadmins include administrators 3580 */ 3581 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) { 3582 $this->capability = $capability; 3583 $this->includeadmins = $includeadmins; 3584 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL); 3585 } 3586 3587 /** 3588 * Load all of the uses who have the capability into choice array 3589 * 3590 * @return bool Always returns true 3591 */ 3592 function load_choices() { 3593 if (is_array($this->choices)) { 3594 return true; 3595 } 3596 list($sort, $sortparams) = users_order_by_sql('u'); 3597 if (!empty($sortparams)) { 3598 throw new coding_exception('users_order_by_sql returned some query parameters. ' . 3599 'This is unexpected, and a problem because there is no way to pass these ' . 3600 'parameters to get_users_by_capability. See MDL-34657.'); 3601 } 3602 $userfields = 'u.id, u.username, ' . get_all_user_name_fields(true, 'u'); 3603 $users = get_users_by_capability(context_system::instance(), $this->capability, $userfields, $sort); 3604 $this->choices = array( 3605 '$@NONE@$' => get_string('nobody'), 3606 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)), 3607 ); 3608 if ($this->includeadmins) { 3609 $admins = get_admins(); 3610 foreach ($admins as $user) { 3611 $this->choices[$user->id] = fullname($user); 3612 } 3613 } 3614 if (is_array($users)) { 3615 foreach ($users as $user) { 3616 $this->choices[$user->id] = fullname($user); 3617 } 3618 } 3619 return true; 3620 } 3621 3622 /** 3623 * Returns the default setting for class 3624 * 3625 * @return mixed Array, or string. Empty string if no default 3626 */ 3627 public function get_defaultsetting() { 3628 $this->load_choices(); 3629 $defaultsetting = parent::get_defaultsetting(); 3630 if (empty($defaultsetting)) { 3631 return array('$@NONE@$'); 3632 } else if (array_key_exists($defaultsetting, $this->choices)) { 3633 return $defaultsetting; 3634 } else { 3635 return ''; 3636 } 3637 } 3638 3639 /** 3640 * Returns the current setting 3641 * 3642 * @return mixed array or string 3643 */ 3644 public function get_setting() { 3645 $result = parent::get_setting(); 3646 if ($result === null) { 3647 // this is necessary for settings upgrade 3648 return null; 3649 } 3650 if (empty($result)) { 3651 $result = array('$@NONE@$'); 3652 } 3653 return $result; 3654 } 3655 3656 /** 3657 * Save the chosen setting provided as $data 3658 * 3659 * @param array $data 3660 * @return mixed string or array 3661 */ 3662 public function write_setting($data) { 3663 // If all is selected, remove any explicit options. 3664 if (in_array('$@ALL@$', $data)) { 3665 $data = array('$@ALL@$'); 3666 } 3667 // None never needs to be written to the DB. 3668 if (in_array('$@NONE@$', $data)) { 3669 unset($data[array_search('$@NONE@$', $data)]); 3670 } 3671 return parent::write_setting($data); 3672 } 3673 } 3674 3675 3676 /** 3677 * Special checkbox for calendar - resets SESSION vars. 3678 * 3679 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3680 */ 3681 class admin_setting_special_adminseesall extends admin_setting_configcheckbox { 3682 /** 3683 * Calls the parent::__construct with default values 3684 * 3685 * name => calendar_adminseesall 3686 * visiblename => get_string('adminseesall', 'admin') 3687 * description => get_string('helpadminseesall', 'admin') 3688 * defaultsetting => 0 3689 */ 3690 public function __construct() { 3691 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'), 3692 get_string('helpadminseesall', 'admin'), '0'); 3693 } 3694 3695 /** 3696 * Stores the setting passed in $data 3697 * 3698 * @param mixed gets converted to string for comparison 3699 * @return string empty string or error message 3700 */ 3701 public function write_setting($data) { 3702 global $SESSION; 3703 return parent::write_setting($data); 3704 } 3705 } 3706 3707 /** 3708 * Special select for settings that are altered in setup.php and can not be altered on the fly 3709 * 3710 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3711 */ 3712 class admin_setting_special_selectsetup extends admin_setting_configselect { 3713 /** 3714 * Reads the setting directly from the database 3715 * 3716 * @return mixed 3717 */ 3718 public function get_setting() { 3719 // read directly from db! 3720 return get_config(NULL, $this->name); 3721 } 3722 3723 /** 3724 * Save the setting passed in $data 3725 * 3726 * @param string $data The setting to save 3727 * @return string empty or error message 3728 */ 3729 public function write_setting($data) { 3730 global $CFG; 3731 // do not change active CFG setting! 3732 $current = $CFG->{$this->name}; 3733 $result = parent::write_setting($data); 3734 $CFG->{$this->name} = $current; 3735 return $result; 3736 } 3737 } 3738 3739 3740 /** 3741 * Special select for frontpage - stores data in course table 3742 * 3743 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3744 */ 3745 class admin_setting_sitesetselect extends admin_setting_configselect { 3746 /** 3747 * Returns the site name for the selected site 3748 * 3749 * @see get_site() 3750 * @return string The site name of the selected site 3751 */ 3752 public function get_setting() { 3753 $site = course_get_format(get_site())->get_course(); 3754 return $site->{$this->name}; 3755 } 3756 3757 /** 3758 * Updates the database and save the setting 3759 * 3760 * @param string data 3761 * @return string empty or error message 3762 */ 3763 public function write_setting($data) { 3764 global $DB, $SITE, $COURSE; 3765 if (!in_array($data, array_keys($this->choices))) { 3766 return get_string('errorsetting', 'admin'); 3767 } 3768 $record = new stdClass(); 3769 $record->id = SITEID; 3770 $temp = $this->name; 3771 $record->$temp = $data; 3772 $record->timemodified = time(); 3773 3774 course_get_format($SITE)->update_course_format_options($record); 3775 $DB->update_record('course', $record); 3776 3777 // Reset caches. 3778 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 3779 if ($SITE->id == $COURSE->id) { 3780 $COURSE = $SITE; 3781 } 3782 format_base::reset_course_cache($SITE->id); 3783 3784 return ''; 3785 3786 } 3787 } 3788 3789 3790 /** 3791 * Select for blog's bloglevel setting: if set to 0, will set blog_menu 3792 * block to hidden. 3793 * 3794 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3795 */ 3796 class admin_setting_bloglevel extends admin_setting_configselect { 3797 /** 3798 * Updates the database and save the setting 3799 * 3800 * @param string data 3801 * @return string empty or error message 3802 */ 3803 public function write_setting($data) { 3804 global $DB, $CFG; 3805 if ($data == 0) { 3806 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1"); 3807 foreach ($blogblocks as $block) { 3808 $DB->set_field('block', 'visible', 0, array('id' => $block->id)); 3809 } 3810 } else { 3811 // reenable all blocks only when switching from disabled blogs 3812 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) { 3813 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0"); 3814 foreach ($blogblocks as $block) { 3815 $DB->set_field('block', 'visible', 1, array('id' => $block->id)); 3816 } 3817 } 3818 } 3819 return parent::write_setting($data); 3820 } 3821 } 3822 3823 3824 /** 3825 * Special select - lists on the frontpage - hacky 3826 * 3827 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3828 */ 3829 class admin_setting_courselist_frontpage extends admin_setting { 3830 /** @var array Array of choices value=>label */ 3831 public $choices; 3832 3833 /** 3834 * Construct override, requires one param 3835 * 3836 * @param bool $loggedin Is the user logged in 3837 */ 3838 public function __construct($loggedin) { 3839 global $CFG; 3840 require_once($CFG->dirroot.'/course/lib.php'); 3841 $name = 'frontpage'.($loggedin ? 'loggedin' : ''); 3842 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin'); 3843 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin'); 3844 $defaults = array(FRONTPAGEALLCOURSELIST); 3845 parent::__construct($name, $visiblename, $description, $defaults); 3846 } 3847 3848 /** 3849 * Loads the choices available 3850 * 3851 * @return bool always returns true 3852 */ 3853 public function load_choices() { 3854 if (is_array($this->choices)) { 3855 return true; 3856 } 3857 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'), 3858 FRONTPAGEALLCOURSELIST => get_string('frontpagecourselist'), 3859 FRONTPAGEENROLLEDCOURSELIST => get_string('frontpageenrolledcourselist'), 3860 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'), 3861 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'), 3862 FRONTPAGECOURSESEARCH => get_string('frontpagecoursesearch'), 3863 'none' => get_string('none')); 3864 if ($this->name === 'frontpage') { 3865 unset($this->choices[FRONTPAGEENROLLEDCOURSELIST]); 3866 } 3867 return true; 3868 } 3869 3870 /** 3871 * Returns the selected settings 3872 * 3873 * @param mixed array or setting or null 3874 */ 3875 public function get_setting() { 3876 $result = $this->config_read($this->name); 3877 if (is_null($result)) { 3878 return NULL; 3879 } 3880 if ($result === '') { 3881 return array(); 3882 } 3883 return explode(',', $result); 3884 } 3885 3886 /** 3887 * Save the selected options 3888 * 3889 * @param array $data 3890 * @return mixed empty string (data is not an array) or bool true=success false=failure 3891 */ 3892 public function write_setting($data) { 3893 if (!is_array($data)) { 3894 return ''; 3895 } 3896 $this->load_choices(); 3897 $save = array(); 3898 foreach($data as $datum) { 3899 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) { 3900 continue; 3901 } 3902 $save[$datum] = $datum; // no duplicates 3903 } 3904 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin')); 3905 } 3906 3907 /** 3908 * Return XHTML select field and wrapping div 3909 * 3910 * @todo Add vartype handling to make sure $data is an array 3911 * @param array $data Array of elements to select by default 3912 * @return string XHTML select field and wrapping div 3913 */ 3914 public function output_html($data, $query='') { 3915 $this->load_choices(); 3916 $currentsetting = array(); 3917 foreach ($data as $key) { 3918 if ($key != 'none' and array_key_exists($key, $this->choices)) { 3919 $currentsetting[] = $key; // already selected first 3920 } 3921 } 3922 3923 $return = '<div class="form-group">'; 3924 for ($i = 0; $i < count($this->choices) - 1; $i++) { 3925 if (!array_key_exists($i, $currentsetting)) { 3926 $currentsetting[$i] = 'none'; //none 3927 } 3928 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">'; 3929 foreach ($this->choices as $key => $value) { 3930 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>'; 3931 } 3932 $return .= '</select>'; 3933 if ($i !== count($this->choices) - 2) { 3934 $return .= '<br />'; 3935 } 3936 } 3937 $return .= '</div>'; 3938 3939 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); 3940 } 3941 } 3942 3943 3944 /** 3945 * Special checkbox for frontpage - stores data in course table 3946 * 3947 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3948 */ 3949 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox { 3950 /** 3951 * Returns the current sites name 3952 * 3953 * @return string 3954 */ 3955 public function get_setting() { 3956 $site = course_get_format(get_site())->get_course(); 3957 return $site->{$this->name}; 3958 } 3959 3960 /** 3961 * Save the selected setting 3962 * 3963 * @param string $data The selected site 3964 * @return string empty string or error message 3965 */ 3966 public function write_setting($data) { 3967 global $DB, $SITE, $COURSE; 3968 $record = new stdClass(); 3969 $record->id = $SITE->id; 3970 $record->{$this->name} = ($data == '1' ? 1 : 0); 3971 $record->timemodified = time(); 3972 3973 course_get_format($SITE)->update_course_format_options($record); 3974 $DB->update_record('course', $record); 3975 3976 // Reset caches. 3977 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 3978 if ($SITE->id == $COURSE->id) { 3979 $COURSE = $SITE; 3980 } 3981 format_base::reset_course_cache($SITE->id); 3982 3983 return ''; 3984 } 3985 } 3986 3987 /** 3988 * Special text for frontpage - stores data in course table. 3989 * Empty string means not set here. Manual setting is required. 3990 * 3991 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3992 */ 3993 class admin_setting_sitesettext extends admin_setting_configtext { 3994 /** 3995 * Return the current setting 3996 * 3997 * @return mixed string or null 3998 */ 3999 public function get_setting() { 4000 $site = course_get_format(get_site())->get_course(); 4001 return $site->{$this->name} != '' ? $site->{$this->name} : NULL; 4002 } 4003 4004 /** 4005 * Validate the selected data 4006 * 4007 * @param string $data The selected value to validate 4008 * @return mixed true or message string 4009 */ 4010 public function validate($data) { 4011 global $DB, $SITE; 4012 $cleaned = clean_param($data, PARAM_TEXT); 4013 if ($cleaned === '') { 4014 return get_string('required'); 4015 } 4016 if ($this->name ==='shortname' && 4017 $DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data, $SITE->id))) { 4018 return get_string('shortnametaken', 'error', $data); 4019 } 4020 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison 4021 return true; 4022 } else { 4023 return get_string('validateerror', 'admin'); 4024 } 4025 } 4026 4027 /** 4028 * Save the selected setting 4029 * 4030 * @param string $data The selected value 4031 * @return string empty or error message 4032 */ 4033 public function write_setting($data) { 4034 global $DB, $SITE, $COURSE; 4035 $data = trim($data); 4036 $validated = $this->validate($data); 4037 if ($validated !== true) { 4038 return $validated; 4039 } 4040 4041 $record = new stdClass(); 4042 $record->id = $SITE->id; 4043 $record->{$this->name} = $data; 4044 $record->timemodified = time(); 4045 4046 course_get_format($SITE)->update_course_format_options($record); 4047 $DB->update_record('course', $record); 4048 4049 // Reset caches. 4050 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 4051 if ($SITE->id == $COURSE->id) { 4052 $COURSE = $SITE; 4053 } 4054 format_base::reset_course_cache($SITE->id); 4055 4056 return ''; 4057 } 4058 } 4059 4060 4061 /** 4062 * Special text editor for site description. 4063 * 4064 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4065 */ 4066 class admin_setting_special_frontpagedesc extends admin_setting { 4067 /** 4068 * Calls parent::__construct with specific arguments 4069 */ 4070 public function __construct() { 4071 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL); 4072 editors_head_setup(); 4073 } 4074 4075 /** 4076 * Return the current setting 4077 * @return string The current setting 4078 */ 4079 public function get_setting() { 4080 $site = course_get_format(get_site())->get_course(); 4081 return $site->{$this->name}; 4082 } 4083 4084 /** 4085 * Save the new setting 4086 * 4087 * @param string $data The new value to save 4088 * @return string empty or error message 4089 */ 4090 public function write_setting($data) { 4091 global $DB, $SITE, $COURSE; 4092 $record = new stdClass(); 4093 $record->id = $SITE->id; 4094 $record->{$this->name} = $data; 4095 $record->timemodified = time(); 4096 4097 course_get_format($SITE)->update_course_format_options($record); 4098 $DB->update_record('course', $record); 4099 4100 // Reset caches. 4101 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST); 4102 if ($SITE->id == $COURSE->id) { 4103 $COURSE = $SITE; 4104 } 4105 format_base::reset_course_cache($SITE->id); 4106 4107 return ''; 4108 } 4109 4110 /** 4111 * Returns XHTML for the field plus wrapping div 4112 * 4113 * @param string $data The current value 4114 * @param string $query 4115 * @return string The XHTML output 4116 */ 4117 public function output_html($data, $query='') { 4118 global $CFG; 4119 4120 $return = '<div class="form-htmlarea">'.print_textarea(true, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'</div>'; 4121 4122 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); 4123 } 4124 } 4125 4126 4127 /** 4128 * Administration interface for emoticon_manager settings. 4129 * 4130 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4131 */ 4132 class admin_setting_emoticons extends admin_setting { 4133 4134 /** 4135 * Calls parent::__construct with specific args 4136 */ 4137 public function __construct() { 4138 global $CFG; 4139 4140 $manager = get_emoticon_manager(); 4141 $defaults = $this->prepare_form_data($manager->default_emoticons()); 4142 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults); 4143 } 4144 4145 /** 4146 * Return the current setting(s) 4147 * 4148 * @return array Current settings array 4149 */ 4150 public function get_setting() { 4151 global $CFG; 4152 4153 $manager = get_emoticon_manager(); 4154 4155 $config = $this->config_read($this->name); 4156 if (is_null($config)) { 4157 return null; 4158 } 4159 4160 $config = $manager->decode_stored_config($config); 4161 if (is_null($config)) { 4162 return null; 4163 } 4164 4165 return $this->prepare_form_data($config); 4166 } 4167 4168 /** 4169 * Save selected settings 4170 * 4171 * @param array $data Array of settings to save 4172 * @return bool 4173 */ 4174 public function write_setting($data) { 4175 4176 $manager = get_emoticon_manager(); 4177 $emoticons = $this->process_form_data($data); 4178 4179 if ($emoticons === false) { 4180 return false; 4181 } 4182 4183 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) { 4184 return ''; // success 4185 } else { 4186 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br'); 4187 } 4188 } 4189 4190 /** 4191 * Return XHTML field(s) for options 4192 * 4193 * @param array $data Array of options to set in HTML 4194 * @return string XHTML string for the fields and wrapping div(s) 4195 */ 4196 public function output_html($data, $query='') { 4197 global $OUTPUT; 4198 4199 $out = html_writer::start_tag('table', array('id' => 'emoticonsetting', 'class' => 'admintable generaltable')); 4200 $out .= html_writer::start_tag('thead'); 4201 $out .= html_writer::start_tag('tr'); 4202 $out .= html_writer::tag('th', get_string('emoticontext', 'admin')); 4203 $out .= html_writer::tag('th', get_string('emoticonimagename', 'admin')); 4204 $out .= html_writer::tag('th', get_string('emoticoncomponent', 'admin')); 4205 $out .= html_writer::tag('th', get_string('emoticonalt', 'admin'), array('colspan' => 2)); 4206 $out .= html_writer::tag('th', ''); 4207 $out .= html_writer::end_tag('tr'); 4208 $out .= html_writer::end_tag('thead'); 4209 $out .= html_writer::start_tag('tbody'); 4210 $i = 0; 4211 foreach($data as $field => $value) { 4212 switch ($i) { 4213 case 0: 4214 $out .= html_writer::start_tag('tr'); 4215 $current_text = $value; 4216 $current_filename = ''; 4217 $current_imagecomponent = ''; 4218 $current_altidentifier = ''; 4219 $current_altcomponent = ''; 4220 case 1: 4221 $current_filename = $value; 4222 case 2: 4223 $current_imagecomponent = $value; 4224 case 3: 4225 $current_altidentifier = $value; 4226 case 4: 4227 $current_altcomponent = $value; 4228 } 4229 4230 $out .= html_writer::tag('td', 4231 html_writer::empty_tag('input', 4232 array( 4233 'type' => 'text', 4234 'class' => 'form-text', 4235 'name' => $this->get_full_name().'['.$field.']', 4236 'value' => $value, 4237 ) 4238 ), array('class' => 'c'.$i) 4239 ); 4240 4241 if ($i == 4) { 4242 if (get_string_manager()->string_exists($current_altidentifier, $current_altcomponent)) { 4243 $alt = get_string($current_altidentifier, $current_altcomponent); 4244 } else { 4245 $alt = $current_text; 4246 } 4247 if ($current_filename) { 4248 $out .= html_writer::tag('td', $OUTPUT->render(new pix_emoticon($current_filename, $alt, $current_imagecomponent))); 4249 } else { 4250 $out .= html_writer::tag('td', ''); 4251 } 4252 $out .= html_writer::end_tag('tr'); 4253 $i = 0; 4254 } else { 4255 $i++; 4256 } 4257 4258 } 4259 $out .= html_writer::end_tag('tbody'); 4260 $out .= html_writer::end_tag('table'); 4261 $out = html_writer::tag('div', $out, array('class' => 'form-group')); 4262 $out .= html_writer::tag('div', html_writer::link(new moodle_url('/admin/resetemoticons.php'), get_string('emoticonsreset', 'admin'))); 4263 4264 return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', NULL, $query); 4265 } 4266 4267 /** 4268 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data 4269 * 4270 * @see self::process_form_data() 4271 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager} 4272 * @return array of form fields and their values 4273 */ 4274 protected function prepare_form_data(array $emoticons) { 4275 4276 $form = array(); 4277 $i = 0; 4278 foreach ($emoticons as $emoticon) { 4279 $form['text'.$i] = $emoticon->text; 4280 $form['imagename'.$i] = $emoticon->imagename; 4281 $form['imagecomponent'.$i] = $emoticon->imagecomponent; 4282 $form['altidentifier'.$i] = $emoticon->altidentifier; 4283 $form['altcomponent'.$i] = $emoticon->altcomponent; 4284 $i++; 4285 } 4286 // add one more blank field set for new object 4287 $form['text'.$i] = ''; 4288 $form['imagename'.$i] = ''; 4289 $form['imagecomponent'.$i] = ''; 4290 $form['altidentifier'.$i] = ''; 4291 $form['altcomponent'.$i] = ''; 4292 4293 return $form; 4294 } 4295 4296 /** 4297 * Converts the data from admin settings form into an array of emoticon objects 4298 * 4299 * @see self::prepare_form_data() 4300 * @param array $data array of admin form fields and values 4301 * @return false|array of emoticon objects 4302 */ 4303 protected function process_form_data(array $form) { 4304 4305 $count = count($form); // number of form field values 4306 4307 if ($count % 5) { 4308 // we must get five fields per emoticon object 4309 return false; 4310 } 4311 4312 $emoticons = array(); 4313 for ($i = 0; $i < $count / 5; $i++) { 4314 $emoticon = new stdClass(); 4315 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS); 4316 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH); 4317 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_COMPONENT); 4318 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID); 4319 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_COMPONENT); 4320 4321 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) { 4322 // prevent from breaking http://url.addresses by accident 4323 $emoticon->text = ''; 4324 } 4325 4326 if (strlen($emoticon->text) < 2) { 4327 // do not allow single character emoticons 4328 $emoticon->text = ''; 4329 } 4330 4331 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) { 4332 // emoticon text must contain some non-alphanumeric character to prevent 4333 // breaking HTML tags 4334 $emoticon->text = ''; 4335 } 4336 4337 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') { 4338 $emoticons[] = $emoticon; 4339 } 4340 } 4341 return $emoticons; 4342 } 4343 } 4344 4345 4346 /** 4347 * Special setting for limiting of the list of available languages. 4348 * 4349 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4350 */ 4351 class admin_setting_langlist extends admin_setting_configtext { 4352 /** 4353 * Calls parent::__construct with specific arguments 4354 */ 4355 public function __construct() { 4356 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS); 4357 } 4358 4359 /** 4360 * Save the new setting 4361 * 4362 * @param string $data The new setting 4363 * @return bool 4364 */ 4365 public function write_setting($data) { 4366 $return = parent::write_setting($data); 4367 get_string_manager()->reset_caches(); 4368 return $return; 4369 } 4370 } 4371 4372 4373 /** 4374 * Selection of one of the recognised countries using the list 4375 * returned by {@link get_list_of_countries()}. 4376 * 4377 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4378 */ 4379 class admin_settings_country_select extends admin_setting_configselect { 4380 protected $includeall; 4381 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) { 4382 $this->includeall = $includeall; 4383 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL); 4384 } 4385 4386 /** 4387 * Lazy-load the available choices for the select box 4388 */ 4389 public function load_choices() { 4390 global $CFG; 4391 if (is_array($this->choices)) { 4392 return true; 4393 } 4394 $this->choices = array_merge( 4395 array('0' => get_string('choosedots')), 4396 get_string_manager()->get_list_of_countries($this->includeall)); 4397 return true; 4398 } 4399 } 4400 4401 4402 /** 4403 * admin_setting_configselect for the default number of sections in a course, 4404 * simply so we can lazy-load the choices. 4405 * 4406 * @copyright 2011 The Open University 4407 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4408 */ 4409 class admin_settings_num_course_sections extends admin_setting_configselect { 4410 public function __construct($name, $visiblename, $description, $defaultsetting) { 4411 parent::__construct($name, $visiblename, $description, $defaultsetting, array()); 4412 } 4413 4414 /** Lazy-load the available choices for the select box */ 4415 public function load_choices() { 4416 $max = get_config('moodlecourse', 'maxsections'); 4417 if (!isset($max) || !is_numeric($max)) { 4418 $max = 52; 4419 } 4420 for ($i = 0; $i <= $max; $i++) { 4421 $this->choices[$i] = "$i"; 4422 } 4423 return true; 4424 } 4425 } 4426 4427 4428 /** 4429 * Course category selection 4430 * 4431 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4432 */ 4433 class admin_settings_coursecat_select extends admin_setting_configselect { 4434 /** 4435 * Calls parent::__construct with specific arguments 4436 */ 4437 public function __construct($name, $visiblename, $description, $defaultsetting) { 4438 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL); 4439 } 4440 4441 /** 4442 * Load the available choices for the select box 4443 * 4444 * @return bool 4445 */ 4446 public function load_choices() { 4447 global $CFG; 4448 require_once($CFG->dirroot.'/course/lib.php'); 4449 if (is_array($this->choices)) { 4450 return true; 4451 } 4452 $this->choices = make_categories_options(); 4453 return true; 4454 } 4455 } 4456 4457 4458 /** 4459 * Special control for selecting days to backup 4460 * 4461 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4462 */ 4463 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 { 4464 /** 4465 * Calls parent::__construct with specific arguments 4466 */ 4467 public function __construct() { 4468 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL); 4469 $this->plugin = 'backup'; 4470 } 4471 4472 /** 4473 * Load the available choices for the select box 4474 * 4475 * @return bool Always returns true 4476 */ 4477 public function load_choices() { 4478 if (is_array($this->choices)) { 4479 return true; 4480 } 4481 $this->choices = array(); 4482 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); 4483 foreach ($days as $day) { 4484 $this->choices[$day] = get_string($day, 'calendar'); 4485 } 4486 return true; 4487 } 4488 } 4489 4490 /** 4491 * Special setting for backup auto destination. 4492 * 4493 * @package core 4494 * @subpackage admin 4495 * @copyright 2014 Frédéric Massart - FMCorz.net 4496 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4497 */ 4498 class admin_setting_special_backup_auto_destination extends admin_setting_configdirectory { 4499 4500 /** 4501 * Calls parent::__construct with specific arguments. 4502 */ 4503 public function __construct() { 4504 parent::__construct('backup/backup_auto_destination', new lang_string('saveto'), new lang_string('backupsavetohelp'), ''); 4505 } 4506 4507 /** 4508 * Check if the directory must be set, depending on backup/backup_auto_storage. 4509 * 4510 * Note: backup/backup_auto_storage must be specified BEFORE this setting otherwise 4511 * there will be conflicts if this validation happens before the other one. 4512 * 4513 * @param string $data Form data. 4514 * @return string Empty when no errors. 4515 */ 4516 public function write_setting($data) { 4517 $storage = (int) get_config('backup', 'backup_auto_storage'); 4518 if ($storage !== 0) { 4519 if (empty($data) || !file_exists($data) || !is_dir($data) || !is_writable($data) ) { 4520 // The directory must exist and be writable. 4521 return get_string('backuperrorinvaliddestination'); 4522 } 4523 } 4524 return parent::write_setting($data); 4525 } 4526 } 4527 4528 4529 /** 4530 * Special debug setting 4531 * 4532 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4533 */ 4534 class admin_setting_special_debug extends admin_setting_configselect { 4535 /** 4536 * Calls parent::__construct with specific arguments 4537 */ 4538 public function __construct() { 4539 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL); 4540 } 4541 4542 /** 4543 * Load the available choices for the select box 4544 * 4545 * @return bool 4546 */ 4547 public function load_choices() { 4548 if (is_array($this->choices)) { 4549 return true; 4550 } 4551 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'), 4552 DEBUG_MINIMAL => get_string('debugminimal', 'admin'), 4553 DEBUG_NORMAL => get_string('debugnormal', 'admin'), 4554 DEBUG_ALL => get_string('debugall', 'admin'), 4555 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')); 4556 return true; 4557 } 4558 } 4559 4560 4561 /** 4562 * Special admin control 4563 * 4564 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4565 */ 4566 class admin_setting_special_calendar_weekend extends admin_setting { 4567 /** 4568 * Calls parent::__construct with specific arguments 4569 */ 4570 public function __construct() { 4571 $name = 'calendar_weekend'; 4572 $visiblename = get_string('calendar_weekend', 'admin'); 4573 $description = get_string('helpweekenddays', 'admin'); 4574 $default = array ('0', '6'); // Saturdays and Sundays 4575 parent::__construct($name, $visiblename, $description, $default); 4576 } 4577 4578 /** 4579 * Gets the current settings as an array 4580 * 4581 * @return mixed Null if none, else array of settings 4582 */ 4583 public function get_setting() { 4584 $result = $this->config_read($this->name); 4585 if (is_null($result)) { 4586 return NULL; 4587 } 4588 if ($result === '') { 4589 return array(); 4590 } 4591 $settings = array(); 4592 for ($i=0; $i<7; $i++) { 4593 if ($result & (1 << $i)) { 4594 $settings[] = $i; 4595 } 4596 } 4597 return $settings; 4598 } 4599 4600 /** 4601 * Save the new settings 4602 * 4603 * @param array $data Array of new settings 4604 * @return bool 4605 */ 4606 public function write_setting($data) { 4607 if (!is_array($data)) { 4608 return ''; 4609 } 4610 unset($data['xxxxx']); 4611 $result = 0; 4612 foreach($data as $index) { 4613 $result |= 1 << $index; 4614 } 4615 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin')); 4616 } 4617 4618 /** 4619 * Return XHTML to display the control 4620 * 4621 * @param array $data array of selected days 4622 * @param string $query 4623 * @return string XHTML for display (field + wrapping div(s) 4624 */ 4625 public function output_html($data, $query='') { 4626 // The order matters very much because of the implied numeric keys 4627 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); 4628 $return = '<table><thead><tr>'; 4629 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected 4630 foreach($days as $index => $day) { 4631 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>'; 4632 } 4633 $return .= '</tr></thead><tbody><tr>'; 4634 foreach($days as $index => $day) { 4635 $return .= '<td><input type="checkbox" class="form-checkbox" id="'.$this->get_id().$index.'" name="'.$this->get_full_name().'[]" value="'.$index.'" '.(in_array("$index", $data) ? 'checked="checked"' : '').' /></td>'; 4636 } 4637 $return .= '</tr></tbody></table>'; 4638 4639 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); 4640 4641 } 4642 } 4643 4644 4645 /** 4646 * Admin setting that allows a user to pick a behaviour. 4647 * 4648 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4649 */ 4650 class admin_setting_question_behaviour extends admin_setting_configselect { 4651 /** 4652 * @param string $name name of config variable 4653 * @param string $visiblename display name 4654 * @param string $description description 4655 * @param string $default default. 4656 */ 4657 public function __construct($name, $visiblename, $description, $default) { 4658 parent::__construct($name, $visiblename, $description, $default, NULL); 4659 } 4660 4661 /** 4662 * Load list of behaviours as choices 4663 * @return bool true => success, false => error. 4664 */ 4665 public function load_choices() { 4666 global $CFG; 4667 require_once($CFG->dirroot . '/question/engine/lib.php'); 4668 $this->choices = question_engine::get_behaviour_options(''); 4669 return true; 4670 } 4671 } 4672 4673 4674 /** 4675 * Admin setting that allows a user to pick appropriate roles for something. 4676 * 4677 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4678 */ 4679 class admin_setting_pickroles extends admin_setting_configmulticheckbox { 4680 /** @var array Array of capabilities which identify roles */ 4681 private $types; 4682 4683 /** 4684 * @param string $name Name of config variable 4685 * @param string $visiblename Display name 4686 * @param string $description Description 4687 * @param array $types Array of archetypes which identify 4688 * roles that will be enabled by default. 4689 */ 4690 public function __construct($name, $visiblename, $description, $types) { 4691 parent::__construct($name, $visiblename, $description, NULL, NULL); 4692 $this->types = $types; 4693 } 4694 4695 /** 4696 * Load roles as choices 4697 * 4698 * @return bool true=>success, false=>error 4699 */ 4700 public function load_choices() { 4701 global $CFG, $DB; 4702 if (during_initial_install()) { 4703 return false; 4704 } 4705 if (is_array($this->choices)) { 4706 return true; 4707 } 4708 if ($roles = get_all_roles()) { 4709 $this->choices = role_fix_names($roles, null, ROLENAME_ORIGINAL, true); 4710 return true; 4711 } else { 4712 return false; 4713 } 4714 } 4715 4716 /** 4717 * Return the default setting for this control 4718 * 4719 * @return array Array of default settings 4720 */ 4721 public function get_defaultsetting() { 4722 global $CFG; 4723 4724 if (during_initial_install()) { 4725 return null; 4726 } 4727 $result = array(); 4728 foreach($this->types as $archetype) { 4729 if ($caproles = get_archetype_roles($archetype)) { 4730 foreach ($caproles as $caprole) { 4731 $result[$caprole->id] = 1; 4732 } 4733 } 4734 } 4735 return $result; 4736 } 4737 } 4738 4739 4740 /** 4741 * Admin setting that is a list of installed filter plugins. 4742 * 4743 * @copyright 2015 The Open University 4744 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4745 */ 4746 class admin_setting_pickfilters extends admin_setting_configmulticheckbox { 4747 4748 /** 4749 * Constructor 4750 * 4751 * @param string $name unique ascii name, either 'mysetting' for settings 4752 * that in config, or 'myplugin/mysetting' for ones in config_plugins. 4753 * @param string $visiblename localised name 4754 * @param string $description localised long description 4755 * @param array $default the default. E.g. array('urltolink' => 1, 'emoticons' => 1) 4756 */ 4757 public function __construct($name, $visiblename, $description, $default) { 4758 if (empty($default)) { 4759 $default = array(); 4760 } 4761 $this->load_choices(); 4762 foreach ($default as $plugin) { 4763 if (!isset($this->choices[$plugin])) { 4764 unset($default[$plugin]); 4765 } 4766 } 4767 parent::__construct($name, $visiblename, $description, $default, null); 4768 } 4769 4770 public function load_choices() { 4771 if (is_array($this->choices)) { 4772 return true; 4773 } 4774 $this->choices = array(); 4775 4776 foreach (core_component::get_plugin_list('filter') as $plugin => $unused) { 4777 $this->choices[$plugin] = filter_get_name($plugin); 4778 } 4779 return true; 4780 } 4781 } 4782 4783 4784 /** 4785 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting. 4786 * 4787 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4788 */ 4789 class admin_setting_configtext_with_advanced extends admin_setting_configtext { 4790 /** 4791 * Constructor 4792 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 4793 * @param string $visiblename localised 4794 * @param string $description long localised info 4795 * @param array $defaultsetting ('value'=>string, '__construct'=>bool) 4796 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex 4797 * @param int $size default field size 4798 */ 4799 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) { 4800 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $paramtype, $size); 4801 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 4802 } 4803 } 4804 4805 4806 /** 4807 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting. 4808 * 4809 * @copyright 2009 Petr Skoda (http://skodak.org) 4810 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4811 */ 4812 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox { 4813 4814 /** 4815 * Constructor 4816 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 4817 * @param string $visiblename localised 4818 * @param string $description long localised info 4819 * @param array $defaultsetting ('value'=>string, 'adv'=>bool) 4820 * @param string $yes value used when checked 4821 * @param string $no value used when not checked 4822 */ 4823 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { 4824 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no); 4825 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 4826 } 4827 4828 } 4829 4830 4831 /** 4832 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting. 4833 * 4834 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv 4835 * 4836 * @copyright 2010 Sam Hemelryk 4837 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4838 */ 4839 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox { 4840 /** 4841 * Constructor 4842 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. 4843 * @param string $visiblename localised 4844 * @param string $description long localised info 4845 * @param array $defaultsetting ('value'=>string, 'locked'=>bool) 4846 * @param string $yes value used when checked 4847 * @param string $no value used when not checked 4848 */ 4849 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { 4850 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no); 4851 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked'])); 4852 } 4853 4854 } 4855 4856 4857 /** 4858 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting. 4859 * 4860 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4861 */ 4862 class admin_setting_configselect_with_advanced extends admin_setting_configselect { 4863 /** 4864 * Calls parent::__construct with specific arguments 4865 */ 4866 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 4867 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices); 4868 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv'])); 4869 } 4870 4871 } 4872 4873 4874 /** 4875 * Graded roles in gradebook 4876 * 4877 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4878 */ 4879 class admin_setting_special_gradebookroles extends admin_setting_pickroles { 4880 /** 4881 * Calls parent::__construct with specific arguments 4882 */ 4883 public function __construct() { 4884 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'), 4885 get_string('configgradebookroles', 'admin'), 4886 array('student')); 4887 } 4888 } 4889 4890 4891 /** 4892 * 4893 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4894 */ 4895 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox { 4896 /** 4897 * Saves the new settings passed in $data 4898 * 4899 * @param string $data 4900 * @return mixed string or Array 4901 */ 4902 public function write_setting($data) { 4903 global $CFG, $DB; 4904 4905 $oldvalue = $this->config_read($this->name); 4906 $return = parent::write_setting($data); 4907 $newvalue = $this->config_read($this->name); 4908 4909 if ($oldvalue !== $newvalue) { 4910 // force full regrading 4911 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0)); 4912 } 4913 4914 return $return; 4915 } 4916 } 4917 4918 4919 /** 4920 * Which roles to show on course description page 4921 * 4922 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4923 */ 4924 class admin_setting_special_coursecontact extends admin_setting_pickroles { 4925 /** 4926 * Calls parent::__construct with specific arguments 4927 */ 4928 public function __construct() { 4929 parent::__construct('coursecontact', get_string('coursecontact', 'admin'), 4930 get_string('coursecontact_desc', 'admin'), 4931 array('editingteacher')); 4932 $this->set_updatedcallback(create_function('', 4933 "cache::make('core', 'coursecontacts')->purge();")); 4934 } 4935 } 4936 4937 4938 /** 4939 * 4940 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4941 */ 4942 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox { 4943 /** 4944 * Calls parent::__construct with specific arguments 4945 */ 4946 public function __construct() { 4947 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'), 4948 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0'); 4949 } 4950 4951 /** 4952 * Old syntax of class constructor. Deprecated in PHP7. 4953 * 4954 * @deprecated since Moodle 3.1 4955 */ 4956 public function admin_setting_special_gradelimiting() { 4957 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER); 4958 self::__construct(); 4959 } 4960 4961 /** 4962 * Force site regrading 4963 */ 4964 function regrade_all() { 4965 global $CFG; 4966 require_once("$CFG->libdir/gradelib.php"); 4967 grade_force_site_regrading(); 4968 } 4969 4970 /** 4971 * Saves the new settings 4972 * 4973 * @param mixed $data 4974 * @return string empty string or error message 4975 */ 4976 function write_setting($data) { 4977 $previous = $this->get_setting(); 4978 4979 if ($previous === null) { 4980 if ($data) { 4981 $this->regrade_all(); 4982 } 4983 } else { 4984 if ($data != $previous) { 4985 $this->regrade_all(); 4986 } 4987 } 4988 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 4989 } 4990 4991 } 4992 4993 /** 4994 * Special setting for $CFG->grade_minmaxtouse. 4995 * 4996 * @package core 4997 * @copyright 2015 Frédéric Massart - FMCorz.net 4998 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 4999 */ 5000 class admin_setting_special_grademinmaxtouse extends admin_setting_configselect { 5001 5002 /** 5003 * Constructor. 5004 */ 5005 public function __construct() { 5006 parent::__construct('grade_minmaxtouse', new lang_string('minmaxtouse', 'grades'), 5007 new lang_string('minmaxtouse_desc', 'grades'), GRADE_MIN_MAX_FROM_GRADE_ITEM, 5008 array( 5009 GRADE_MIN_MAX_FROM_GRADE_ITEM => get_string('gradeitemminmax', 'grades'), 5010 GRADE_MIN_MAX_FROM_GRADE_GRADE => get_string('gradegrademinmax', 'grades') 5011 ) 5012 ); 5013 } 5014 5015 /** 5016 * Saves the new setting. 5017 * 5018 * @param mixed $data 5019 * @return string empty string or error message 5020 */ 5021 function write_setting($data) { 5022 global $CFG; 5023 5024 $previous = $this->get_setting(); 5025 $result = parent::write_setting($data); 5026 5027 // If saved and the value has changed. 5028 if (empty($result) && $previous != $data) { 5029 require_once($CFG->libdir . '/gradelib.php'); 5030 grade_force_site_regrading(); 5031 } 5032 5033 return $result; 5034 } 5035 5036 } 5037 5038 5039 /** 5040 * Primary grade export plugin - has state tracking. 5041 * 5042 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5043 */ 5044 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox { 5045 /** 5046 * Calls parent::__construct with specific arguments 5047 */ 5048 public function __construct() { 5049 parent::__construct('gradeexport', get_string('gradeexport', 'admin'), 5050 get_string('configgradeexport', 'admin'), array(), NULL); 5051 } 5052 5053 /** 5054 * Load the available choices for the multicheckbox 5055 * 5056 * @return bool always returns true 5057 */ 5058 public function load_choices() { 5059 if (is_array($this->choices)) { 5060 return true; 5061 } 5062 $this->choices = array(); 5063 5064 if ($plugins = core_component::get_plugin_list('gradeexport')) { 5065 foreach($plugins as $plugin => $unused) { 5066 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin); 5067 } 5068 } 5069 return true; 5070 } 5071 } 5072 5073 5074 /** 5075 * A setting for setting the default grade point value. Must be an integer between 1 and $CFG->gradepointmax. 5076 * 5077 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5078 */ 5079 class admin_setting_special_gradepointdefault extends admin_setting_configtext { 5080 /** 5081 * Config gradepointmax constructor 5082 * 5083 * @param string $name Overidden by "gradepointmax" 5084 * @param string $visiblename Overridden by "gradepointmax" language string. 5085 * @param string $description Overridden by "gradepointmax_help" language string. 5086 * @param string $defaultsetting Not used, overridden by 100. 5087 * @param mixed $paramtype Overridden by PARAM_INT. 5088 * @param int $size Overridden by 5. 5089 */ 5090 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) { 5091 $name = 'gradepointdefault'; 5092 $visiblename = get_string('gradepointdefault', 'grades'); 5093 $description = get_string('gradepointdefault_help', 'grades'); 5094 $defaultsetting = 100; 5095 $paramtype = PARAM_INT; 5096 $size = 5; 5097 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size); 5098 } 5099 5100 /** 5101 * Validate data before storage 5102 * @param string $data The submitted data 5103 * @return bool|string true if ok, string if error found 5104 */ 5105 public function validate($data) { 5106 global $CFG; 5107 if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) { 5108 return true; 5109 } else { 5110 return get_string('gradepointdefault_validateerror', 'grades'); 5111 } 5112 } 5113 } 5114 5115 5116 /** 5117 * A setting for setting the maximum grade value. Must be an integer between 1 and 10000. 5118 * 5119 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5120 */ 5121 class admin_setting_special_gradepointmax extends admin_setting_configtext { 5122 5123 /** 5124 * Config gradepointmax constructor 5125 * 5126 * @param string $name Overidden by "gradepointmax" 5127 * @param string $visiblename Overridden by "gradepointmax" language string. 5128 * @param string $description Overridden by "gradepointmax_help" language string. 5129 * @param string $defaultsetting Not used, overridden by 100. 5130 * @param mixed $paramtype Overridden by PARAM_INT. 5131 * @param int $size Overridden by 5. 5132 */ 5133 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) { 5134 $name = 'gradepointmax'; 5135 $visiblename = get_string('gradepointmax', 'grades'); 5136 $description = get_string('gradepointmax_help', 'grades'); 5137 $defaultsetting = 100; 5138 $paramtype = PARAM_INT; 5139 $size = 5; 5140 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size); 5141 } 5142 5143 /** 5144 * Save the selected setting 5145 * 5146 * @param string $data The selected site 5147 * @return string empty string or error message 5148 */ 5149 public function write_setting($data) { 5150 if ($data === '') { 5151 $data = (int)$this->defaultsetting; 5152 } else { 5153 $data = $data; 5154 } 5155 return parent::write_setting($data); 5156 } 5157 5158 /** 5159 * Validate data before storage 5160 * @param string $data The submitted data 5161 * @return bool|string true if ok, string if error found 5162 */ 5163 public function validate($data) { 5164 if (((string)(int)$data === (string)$data && $data > 0 && $data <= 10000)) { 5165 return true; 5166 } else { 5167 return get_string('gradepointmax_validateerror', 'grades'); 5168 } 5169 } 5170 5171 /** 5172 * Return an XHTML string for the setting 5173 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx 5174 * @param string $query search query to be highlighted 5175 * @return string XHTML to display control 5176 */ 5177 public function output_html($data, $query = '') { 5178 $default = $this->get_defaultsetting(); 5179 5180 $attr = array( 5181 'type' => 'text', 5182 'size' => $this->size, 5183 'id' => $this->get_id(), 5184 'name' => $this->get_full_name(), 5185 'value' => s($data), 5186 'maxlength' => '5' 5187 ); 5188 $input = html_writer::empty_tag('input', $attr); 5189 5190 $attr = array('class' => 'form-text defaultsnext'); 5191 $div = html_writer::tag('div', $input, $attr); 5192 return format_admin_setting($this, $this->visiblename, $div, $this->description, true, '', $default, $query); 5193 } 5194 } 5195 5196 5197 /** 5198 * Grade category settings 5199 * 5200 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5201 */ 5202 class admin_setting_gradecat_combo extends admin_setting { 5203 /** @var array Array of choices */ 5204 public $choices; 5205 5206 /** 5207 * Sets choices and calls parent::__construct with passed arguments 5208 * @param string $name 5209 * @param string $visiblename 5210 * @param string $description 5211 * @param mixed $defaultsetting string or array depending on implementation 5212 * @param array $choices An array of choices for the control 5213 */ 5214 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 5215 $this->choices = $choices; 5216 parent::__construct($name, $visiblename, $description, $defaultsetting); 5217 } 5218 5219 /** 5220 * Return the current setting(s) array 5221 * 5222 * @return array Array of value=>xx, forced=>xx, adv=>xx 5223 */ 5224 public function get_setting() { 5225 global $CFG; 5226 5227 $value = $this->config_read($this->name); 5228 $flag = $this->config_read($this->name.'_flag'); 5229 5230 if (is_null($value) or is_null($flag)) { 5231 return NULL; 5232 } 5233 5234 $flag = (int)$flag; 5235 $forced = (boolean)(1 & $flag); // first bit 5236 $adv = (boolean)(2 & $flag); // second bit 5237 5238 return array('value' => $value, 'forced' => $forced, 'adv' => $adv); 5239 } 5240 5241 /** 5242 * Save the new settings passed in $data 5243 * 5244 * @todo Add vartype handling to ensure $data is array 5245 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx 5246 * @return string empty or error message 5247 */ 5248 public function write_setting($data) { 5249 global $CFG; 5250 5251 $value = $data['value']; 5252 $forced = empty($data['forced']) ? 0 : 1; 5253 $adv = empty($data['adv']) ? 0 : 2; 5254 $flag = ($forced | $adv); //bitwise or 5255 5256 if (!in_array($value, array_keys($this->choices))) { 5257 return 'Error setting '; 5258 } 5259 5260 $oldvalue = $this->config_read($this->name); 5261 $oldflag = (int)$this->config_read($this->name.'_flag'); 5262 $oldforced = (1 & $oldflag); // first bit 5263 5264 $result1 = $this->config_write($this->name, $value); 5265 $result2 = $this->config_write($this->name.'_flag', $flag); 5266 5267 // force regrade if needed 5268 if ($oldforced != $forced or ($forced and $value != $oldvalue)) { 5269 require_once($CFG->libdir.'/gradelib.php'); 5270 grade_category::updated_forced_settings(); 5271 } 5272 5273 if ($result1 and $result2) { 5274 return ''; 5275 } else { 5276 return get_string('errorsetting', 'admin'); 5277 } 5278 } 5279 5280 /** 5281 * Return XHTML to display the field and wrapping div 5282 * 5283 * @todo Add vartype handling to ensure $data is array 5284 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx 5285 * @param string $query 5286 * @return string XHTML to display control 5287 */ 5288 public function output_html($data, $query='') { 5289 $value = $data['value']; 5290 $forced = !empty($data['forced']); 5291 $adv = !empty($data['adv']); 5292 5293 $default = $this->get_defaultsetting(); 5294 if (!is_null($default)) { 5295 $defaultinfo = array(); 5296 if (isset($this->choices[$default['value']])) { 5297 $defaultinfo[] = $this->choices[$default['value']]; 5298 } 5299 if (!empty($default['forced'])) { 5300 $defaultinfo[] = get_string('force'); 5301 } 5302 if (!empty($default['adv'])) { 5303 $defaultinfo[] = get_string('advanced'); 5304 } 5305 $defaultinfo = implode(', ', $defaultinfo); 5306 5307 } else { 5308 $defaultinfo = NULL; 5309 } 5310 5311 5312 $return = '<div class="form-group">'; 5313 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">'; 5314 foreach ($this->choices as $key => $val) { 5315 // the string cast is needed because key may be integer - 0 is equal to most strings! 5316 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>'; 5317 } 5318 $return .= '</select>'; 5319 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />' 5320 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>'; 5321 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />' 5322 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>'; 5323 $return .= '</div>'; 5324 5325 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query); 5326 } 5327 } 5328 5329 5330 /** 5331 * Selection of grade report in user profiles 5332 * 5333 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5334 */ 5335 class admin_setting_grade_profilereport extends admin_setting_configselect { 5336 /** 5337 * Calls parent::__construct with specific arguments 5338 */ 5339 public function __construct() { 5340 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null); 5341 } 5342 5343 /** 5344 * Loads an array of choices for the configselect control 5345 * 5346 * @return bool always return true 5347 */ 5348 public function load_choices() { 5349 if (is_array($this->choices)) { 5350 return true; 5351 } 5352 $this->choices = array(); 5353 5354 global $CFG; 5355 require_once($CFG->libdir.'/gradelib.php'); 5356 5357 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) { 5358 if (file_exists($plugindir.'/lib.php')) { 5359 require_once ($plugindir.'/lib.php'); 5360 $functionname = 'grade_report_'.$plugin.'_profilereport'; 5361 if (function_exists($functionname)) { 5362 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin); 5363 } 5364 } 5365 } 5366 return true; 5367 } 5368 } 5369 5370 /** 5371 * Provides a selection of grade reports to be used for "grades". 5372 * 5373 * @copyright 2015 Adrian Greeve <adrian@moodle.com> 5374 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5375 */ 5376 class admin_setting_my_grades_report extends admin_setting_configselect { 5377 5378 /** 5379 * Calls parent::__construct with specific arguments. 5380 */ 5381 public function __construct() { 5382 parent::__construct('grade_mygrades_report', new lang_string('mygrades', 'grades'), 5383 new lang_string('mygrades_desc', 'grades'), 'overview', null); 5384 } 5385 5386 /** 5387 * Loads an array of choices for the configselect control. 5388 * 5389 * @return bool always returns true. 5390 */ 5391 public function load_choices() { 5392 global $CFG; // Remove this line and behold the horror of behat test failures! 5393 $this->choices = array(); 5394 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) { 5395 if (file_exists($plugindir . '/lib.php')) { 5396 require_once($plugindir . '/lib.php'); 5397 // Check to see if the class exists. Check the correct plugin convention first. 5398 if (class_exists('gradereport_' . $plugin)) { 5399 $classname = 'gradereport_' . $plugin; 5400 } else if (class_exists('grade_report_' . $plugin)) { 5401 // We are using the old plugin naming convention. 5402 $classname = 'grade_report_' . $plugin; 5403 } else { 5404 continue; 5405 } 5406 if ($classname::supports_mygrades()) { 5407 $this->choices[$plugin] = get_string('pluginname', 'gradereport_' . $plugin); 5408 } 5409 } 5410 } 5411 // Add an option to specify an external url. 5412 $this->choices['external'] = get_string('externalurl', 'grades'); 5413 return true; 5414 } 5415 } 5416 5417 /** 5418 * Special class for register auth selection 5419 * 5420 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5421 */ 5422 class admin_setting_special_registerauth extends admin_setting_configselect { 5423 /** 5424 * Calls parent::__construct with specific arguments 5425 */ 5426 public function __construct() { 5427 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null); 5428 } 5429 5430 /** 5431 * Returns the default option 5432 * 5433 * @return string empty or default option 5434 */ 5435 public function get_defaultsetting() { 5436 $this->load_choices(); 5437 $defaultsetting = parent::get_defaultsetting(); 5438 if (array_key_exists($defaultsetting, $this->choices)) { 5439 return $defaultsetting; 5440 } else { 5441 return ''; 5442 } 5443 } 5444 5445 /** 5446 * Loads the possible choices for the array 5447 * 5448 * @return bool always returns true 5449 */ 5450 public function load_choices() { 5451 global $CFG; 5452 5453 if (is_array($this->choices)) { 5454 return true; 5455 } 5456 $this->choices = array(); 5457 $this->choices[''] = get_string('disable'); 5458 5459 $authsenabled = get_enabled_auth_plugins(true); 5460 5461 foreach ($authsenabled as $auth) { 5462 $authplugin = get_auth_plugin($auth); 5463 if (!$authplugin->can_signup()) { 5464 continue; 5465 } 5466 // Get the auth title (from core or own auth lang files) 5467 $authtitle = $authplugin->get_title(); 5468 $this->choices[$auth] = $authtitle; 5469 } 5470 return true; 5471 } 5472 } 5473 5474 5475 /** 5476 * General plugins manager 5477 */ 5478 class admin_page_pluginsoverview extends admin_externalpage { 5479 5480 /** 5481 * Sets basic information about the external page 5482 */ 5483 public function __construct() { 5484 global $CFG; 5485 parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'), 5486 "$CFG->wwwroot/$CFG->admin/plugins.php"); 5487 } 5488 } 5489 5490 /** 5491 * Module manage page 5492 * 5493 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5494 */ 5495 class admin_page_managemods extends admin_externalpage { 5496 /** 5497 * Calls parent::__construct with specific arguments 5498 */ 5499 public function __construct() { 5500 global $CFG; 5501 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php"); 5502 } 5503 5504 /** 5505 * Try to find the specified module 5506 * 5507 * @param string $query The module to search for 5508 * @return array 5509 */ 5510 public function search($query) { 5511 global $CFG, $DB; 5512 if ($result = parent::search($query)) { 5513 return $result; 5514 } 5515 5516 $found = false; 5517 if ($modules = $DB->get_records('modules')) { 5518 foreach ($modules as $module) { 5519 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) { 5520 continue; 5521 } 5522 if (strpos($module->name, $query) !== false) { 5523 $found = true; 5524 break; 5525 } 5526 $strmodulename = get_string('modulename', $module->name); 5527 if (strpos(core_text::strtolower($strmodulename), $query) !== false) { 5528 $found = true; 5529 break; 5530 } 5531 } 5532 } 5533 if ($found) { 5534 $result = new stdClass(); 5535 $result->page = $this; 5536 $result->settings = array(); 5537 return array($this->name => $result); 5538 } else { 5539 return array(); 5540 } 5541 } 5542 } 5543 5544 5545 /** 5546 * Special class for enrol plugins management. 5547 * 5548 * @copyright 2010 Petr Skoda {@link http://skodak.org} 5549 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5550 */ 5551 class admin_setting_manageenrols extends admin_setting { 5552 /** 5553 * Calls parent::__construct with specific arguments 5554 */ 5555 public function __construct() { 5556 $this->nosave = true; 5557 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', ''); 5558 } 5559 5560 /** 5561 * Always returns true, does nothing 5562 * 5563 * @return true 5564 */ 5565 public function get_setting() { 5566 return true; 5567 } 5568 5569 /** 5570 * Always returns true, does nothing 5571 * 5572 * @return true 5573 */ 5574 public function get_defaultsetting() { 5575 return true; 5576 } 5577 5578 /** 5579 * Always returns '', does not write anything 5580 * 5581 * @return string Always returns '' 5582 */ 5583 public function write_setting($data) { 5584 // do not write any setting 5585 return ''; 5586 } 5587 5588 /** 5589 * Checks if $query is one of the available enrol plugins 5590 * 5591 * @param string $query The string to search for 5592 * @return bool Returns true if found, false if not 5593 */ 5594 public function is_related($query) { 5595 if (parent::is_related($query)) { 5596 return true; 5597 } 5598 5599 $query = core_text::strtolower($query); 5600 $enrols = enrol_get_plugins(false); 5601 foreach ($enrols as $name=>$enrol) { 5602 $localised = get_string('pluginname', 'enrol_'.$name); 5603 if (strpos(core_text::strtolower($name), $query) !== false) { 5604 return true; 5605 } 5606 if (strpos(core_text::strtolower($localised), $query) !== false) { 5607 return true; 5608 } 5609 } 5610 return false; 5611 } 5612 5613 /** 5614 * Builds the XHTML to display the control 5615 * 5616 * @param string $data Unused 5617 * @param string $query 5618 * @return string 5619 */ 5620 public function output_html($data, $query='') { 5621 global $CFG, $OUTPUT, $DB, $PAGE; 5622 5623 // Display strings. 5624 $strup = get_string('up'); 5625 $strdown = get_string('down'); 5626 $strsettings = get_string('settings'); 5627 $strenable = get_string('enable'); 5628 $strdisable = get_string('disable'); 5629 $struninstall = get_string('uninstallplugin', 'core_admin'); 5630 $strusage = get_string('enrolusage', 'enrol'); 5631 $strversion = get_string('version'); 5632 $strtest = get_string('testsettings', 'core_enrol'); 5633 5634 $pluginmanager = core_plugin_manager::instance(); 5635 5636 $enrols_available = enrol_get_plugins(false); 5637 $active_enrols = enrol_get_plugins(true); 5638 5639 $allenrols = array(); 5640 foreach ($active_enrols as $key=>$enrol) { 5641 $allenrols[$key] = true; 5642 } 5643 foreach ($enrols_available as $key=>$enrol) { 5644 $allenrols[$key] = true; 5645 } 5646 // Now find all borked plugins and at least allow then to uninstall. 5647 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}"); 5648 foreach ($condidates as $candidate) { 5649 if (empty($allenrols[$candidate])) { 5650 $allenrols[$candidate] = true; 5651 } 5652 } 5653 5654 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true); 5655 $return .= $OUTPUT->box_start('generalbox enrolsui'); 5656 5657 $table = new html_table(); 5658 $table->head = array(get_string('name'), $strusage, $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $strtest, $struninstall); 5659 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 5660 $table->id = 'courseenrolmentplugins'; 5661 $table->attributes['class'] = 'admintable generaltable'; 5662 $table->data = array(); 5663 5664 // Iterate through enrol plugins and add to the display table. 5665 $updowncount = 1; 5666 $enrolcount = count($active_enrols); 5667 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey())); 5668 $printed = array(); 5669 foreach($allenrols as $enrol => $unused) { 5670 $plugininfo = $pluginmanager->get_plugin_info('enrol_'.$enrol); 5671 $version = get_config('enrol_'.$enrol, 'version'); 5672 if ($version === false) { 5673 $version = ''; 5674 } 5675 5676 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) { 5677 $name = get_string('pluginname', 'enrol_'.$enrol); 5678 } else { 5679 $name = $enrol; 5680 } 5681 // Usage. 5682 $ci = $DB->count_records('enrol', array('enrol'=>$enrol)); 5683 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol)); 5684 $usage = "$ci / $cp"; 5685 5686 // Hide/show links. 5687 $class = ''; 5688 if (isset($active_enrols[$enrol])) { 5689 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol)); 5690 $hideshow = "<a href=\"$aurl\">"; 5691 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"$strdisable\" /></a>"; 5692 $enabled = true; 5693 $displayname = $name; 5694 } else if (isset($enrols_available[$enrol])) { 5695 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol)); 5696 $hideshow = "<a href=\"$aurl\">"; 5697 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"$strenable\" /></a>"; 5698 $enabled = false; 5699 $displayname = $name; 5700 $class = 'dimmed_text'; 5701 } else { 5702 $hideshow = ''; 5703 $enabled = false; 5704 $displayname = '<span class="notifyproblem">'.$name.'</span>'; 5705 } 5706 if ($PAGE->theme->resolve_image_location('icon', 'enrol_' . $name, false)) { 5707 $icon = $OUTPUT->pix_icon('icon', '', 'enrol_' . $name, array('class' => 'icon pluginicon')); 5708 } else { 5709 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon')); 5710 } 5711 5712 // Up/down link (only if enrol is enabled). 5713 $updown = ''; 5714 if ($enabled) { 5715 if ($updowncount > 1) { 5716 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol)); 5717 $updown .= "<a href=\"$aurl\">"; 5718 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /></a> "; 5719 } else { 5720 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> "; 5721 } 5722 if ($updowncount < $enrolcount) { 5723 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol)); 5724 $updown .= "<a href=\"$aurl\">"; 5725 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" /></a>"; 5726 } else { 5727 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />"; 5728 } 5729 ++$updowncount; 5730 } 5731 5732 // Add settings link. 5733 if (!$version) { 5734 $settings = ''; 5735 } else if ($surl = $plugininfo->get_settings_url()) { 5736 $settings = html_writer::link($surl, $strsettings); 5737 } else { 5738 $settings = ''; 5739 } 5740 5741 // Add uninstall info. 5742 $uninstall = ''; 5743 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('enrol_'.$enrol, 'manage')) { 5744 $uninstall = html_writer::link($uninstallurl, $struninstall); 5745 } 5746 5747 $test = ''; 5748 if (!empty($enrols_available[$enrol]) and method_exists($enrols_available[$enrol], 'test_settings')) { 5749 $testsettingsurl = new moodle_url('/enrol/test_settings.php', array('enrol'=>$enrol, 'sesskey'=>sesskey())); 5750 $test = html_writer::link($testsettingsurl, $strtest); 5751 } 5752 5753 // Add a row to the table. 5754 $row = new html_table_row(array($icon.$displayname, $usage, $version, $hideshow, $updown, $settings, $test, $uninstall)); 5755 if ($class) { 5756 $row->attributes['class'] = $class; 5757 } 5758 $table->data[] = $row; 5759 5760 $printed[$enrol] = true; 5761 } 5762 5763 $return .= html_writer::table($table); 5764 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin'); 5765 $return .= $OUTPUT->box_end(); 5766 return highlight($query, $return); 5767 } 5768 } 5769 5770 5771 /** 5772 * Blocks manage page 5773 * 5774 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5775 */ 5776 class admin_page_manageblocks extends admin_externalpage { 5777 /** 5778 * Calls parent::__construct with specific arguments 5779 */ 5780 public function __construct() { 5781 global $CFG; 5782 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php"); 5783 } 5784 5785 /** 5786 * Search for a specific block 5787 * 5788 * @param string $query The string to search for 5789 * @return array 5790 */ 5791 public function search($query) { 5792 global $CFG, $DB; 5793 if ($result = parent::search($query)) { 5794 return $result; 5795 } 5796 5797 $found = false; 5798 if ($blocks = $DB->get_records('block')) { 5799 foreach ($blocks as $block) { 5800 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) { 5801 continue; 5802 } 5803 if (strpos($block->name, $query) !== false) { 5804 $found = true; 5805 break; 5806 } 5807 $strblockname = get_string('pluginname', 'block_'.$block->name); 5808 if (strpos(core_text::strtolower($strblockname), $query) !== false) { 5809 $found = true; 5810 break; 5811 } 5812 } 5813 } 5814 if ($found) { 5815 $result = new stdClass(); 5816 $result->page = $this; 5817 $result->settings = array(); 5818 return array($this->name => $result); 5819 } else { 5820 return array(); 5821 } 5822 } 5823 } 5824 5825 /** 5826 * Message outputs configuration 5827 * 5828 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5829 */ 5830 class admin_page_managemessageoutputs extends admin_externalpage { 5831 /** 5832 * Calls parent::__construct with specific arguments 5833 */ 5834 public function __construct() { 5835 global $CFG; 5836 parent::__construct('managemessageoutputs', get_string('managemessageoutputs', 'message'), new moodle_url('/admin/message.php')); 5837 } 5838 5839 /** 5840 * Search for a specific message processor 5841 * 5842 * @param string $query The string to search for 5843 * @return array 5844 */ 5845 public function search($query) { 5846 global $CFG, $DB; 5847 if ($result = parent::search($query)) { 5848 return $result; 5849 } 5850 5851 $found = false; 5852 if ($processors = get_message_processors()) { 5853 foreach ($processors as $processor) { 5854 if (!$processor->available) { 5855 continue; 5856 } 5857 if (strpos($processor->name, $query) !== false) { 5858 $found = true; 5859 break; 5860 } 5861 $strprocessorname = get_string('pluginname', 'message_'.$processor->name); 5862 if (strpos(core_text::strtolower($strprocessorname), $query) !== false) { 5863 $found = true; 5864 break; 5865 } 5866 } 5867 } 5868 if ($found) { 5869 $result = new stdClass(); 5870 $result->page = $this; 5871 $result->settings = array(); 5872 return array($this->name => $result); 5873 } else { 5874 return array(); 5875 } 5876 } 5877 } 5878 5879 /** 5880 * Default message outputs configuration 5881 * 5882 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5883 */ 5884 class admin_page_defaultmessageoutputs extends admin_page_managemessageoutputs { 5885 /** 5886 * Calls parent::__construct with specific arguments 5887 */ 5888 public function __construct() { 5889 global $CFG; 5890 admin_externalpage::__construct('defaultmessageoutputs', get_string('defaultmessageoutputs', 'message'), new moodle_url('/message/defaultoutputs.php')); 5891 } 5892 } 5893 5894 5895 /** 5896 * Manage question behaviours page 5897 * 5898 * @copyright 2011 The Open University 5899 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5900 */ 5901 class admin_page_manageqbehaviours extends admin_externalpage { 5902 /** 5903 * Constructor 5904 */ 5905 public function __construct() { 5906 global $CFG; 5907 parent::__construct('manageqbehaviours', get_string('manageqbehaviours', 'admin'), 5908 new moodle_url('/admin/qbehaviours.php')); 5909 } 5910 5911 /** 5912 * Search question behaviours for the specified string 5913 * 5914 * @param string $query The string to search for in question behaviours 5915 * @return array 5916 */ 5917 public function search($query) { 5918 global $CFG; 5919 if ($result = parent::search($query)) { 5920 return $result; 5921 } 5922 5923 $found = false; 5924 require_once($CFG->dirroot . '/question/engine/lib.php'); 5925 foreach (core_component::get_plugin_list('qbehaviour') as $behaviour => $notused) { 5926 if (strpos(core_text::strtolower(question_engine::get_behaviour_name($behaviour)), 5927 $query) !== false) { 5928 $found = true; 5929 break; 5930 } 5931 } 5932 if ($found) { 5933 $result = new stdClass(); 5934 $result->page = $this; 5935 $result->settings = array(); 5936 return array($this->name => $result); 5937 } else { 5938 return array(); 5939 } 5940 } 5941 } 5942 5943 5944 /** 5945 * Question type manage page 5946 * 5947 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 5948 */ 5949 class admin_page_manageqtypes extends admin_externalpage { 5950 /** 5951 * Calls parent::__construct with specific arguments 5952 */ 5953 public function __construct() { 5954 global $CFG; 5955 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'), 5956 new moodle_url('/admin/qtypes.php')); 5957 } 5958 5959 /** 5960 * Search question types for the specified string 5961 * 5962 * @param string $query The string to search for in question types 5963 * @return array 5964 */ 5965 public function search($query) { 5966 global $CFG; 5967 if ($result = parent::search($query)) { 5968 return $result; 5969 } 5970 5971 $found = false; 5972 require_once($CFG->dirroot . '/question/engine/bank.php'); 5973 foreach (question_bank::get_all_qtypes() as $qtype) { 5974 if (strpos(core_text::strtolower($qtype->local_name()), $query) !== false) { 5975 $found = true; 5976 break; 5977 } 5978 } 5979 if ($found) { 5980 $result = new stdClass(); 5981 $result->page = $this; 5982 $result->settings = array(); 5983 return array($this->name => $result); 5984 } else { 5985 return array(); 5986 } 5987 } 5988 } 5989 5990 5991 class admin_page_manageportfolios extends admin_externalpage { 5992 /** 5993 * Calls parent::__construct with specific arguments 5994 */ 5995 public function __construct() { 5996 global $CFG; 5997 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'), 5998 "$CFG->wwwroot/$CFG->admin/portfolio.php"); 5999 } 6000 6001 /** 6002 * Searches page for the specified string. 6003 * @param string $query The string to search for 6004 * @return bool True if it is found on this page 6005 */ 6006 public function search($query) { 6007 global $CFG; 6008 if ($result = parent::search($query)) { 6009 return $result; 6010 } 6011 6012 $found = false; 6013 $portfolios = core_component::get_plugin_list('portfolio'); 6014 foreach ($portfolios as $p => $dir) { 6015 if (strpos($p, $query) !== false) { 6016 $found = true; 6017 break; 6018 } 6019 } 6020 if (!$found) { 6021 foreach (portfolio_instances(false, false) as $instance) { 6022 $title = $instance->get('name'); 6023 if (strpos(core_text::strtolower($title), $query) !== false) { 6024 $found = true; 6025 break; 6026 } 6027 } 6028 } 6029 6030 if ($found) { 6031 $result = new stdClass(); 6032 $result->page = $this; 6033 $result->settings = array(); 6034 return array($this->name => $result); 6035 } else { 6036 return array(); 6037 } 6038 } 6039 } 6040 6041 6042 class admin_page_managerepositories extends admin_externalpage { 6043 /** 6044 * Calls parent::__construct with specific arguments 6045 */ 6046 public function __construct() { 6047 global $CFG; 6048 parent::__construct('managerepositories', get_string('manage', 6049 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php"); 6050 } 6051 6052 /** 6053 * Searches page for the specified string. 6054 * @param string $query The string to search for 6055 * @return bool True if it is found on this page 6056 */ 6057 public function search($query) { 6058 global $CFG; 6059 if ($result = parent::search($query)) { 6060 return $result; 6061 } 6062 6063 $found = false; 6064 $repositories= core_component::get_plugin_list('repository'); 6065 foreach ($repositories as $p => $dir) { 6066 if (strpos($p, $query) !== false) { 6067 $found = true; 6068 break; 6069 } 6070 } 6071 if (!$found) { 6072 foreach (repository::get_types() as $instance) { 6073 $title = $instance->get_typename(); 6074 if (strpos(core_text::strtolower($title), $query) !== false) { 6075 $found = true; 6076 break; 6077 } 6078 } 6079 } 6080 6081 if ($found) { 6082 $result = new stdClass(); 6083 $result->page = $this; 6084 $result->settings = array(); 6085 return array($this->name => $result); 6086 } else { 6087 return array(); 6088 } 6089 } 6090 } 6091 6092 6093 /** 6094 * Special class for authentication administration. 6095 * 6096 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6097 */ 6098 class admin_setting_manageauths extends admin_setting { 6099 /** 6100 * Calls parent::__construct with specific arguments 6101 */ 6102 public function __construct() { 6103 $this->nosave = true; 6104 parent::__construct('authsui', get_string('authsettings', 'admin'), '', ''); 6105 } 6106 6107 /** 6108 * Always returns true 6109 * 6110 * @return true 6111 */ 6112 public function get_setting() { 6113 return true; 6114 } 6115 6116 /** 6117 * Always returns true 6118 * 6119 * @return true 6120 */ 6121 public function get_defaultsetting() { 6122 return true; 6123 } 6124 6125 /** 6126 * Always returns '' and doesn't write anything 6127 * 6128 * @return string Always returns '' 6129 */ 6130 public function write_setting($data) { 6131 // do not write any setting 6132 return ''; 6133 } 6134 6135 /** 6136 * Search to find if Query is related to auth plugin 6137 * 6138 * @param string $query The string to search for 6139 * @return bool true for related false for not 6140 */ 6141 public function is_related($query) { 6142 if (parent::is_related($query)) { 6143 return true; 6144 } 6145 6146 $authsavailable = core_component::get_plugin_list('auth'); 6147 foreach ($authsavailable as $auth => $dir) { 6148 if (strpos($auth, $query) !== false) { 6149 return true; 6150 } 6151 $authplugin = get_auth_plugin($auth); 6152 $authtitle = $authplugin->get_title(); 6153 if (strpos(core_text::strtolower($authtitle), $query) !== false) { 6154 return true; 6155 } 6156 } 6157 return false; 6158 } 6159 6160 /** 6161 * Return XHTML to display control 6162 * 6163 * @param mixed $data Unused 6164 * @param string $query 6165 * @return string highlight 6166 */ 6167 public function output_html($data, $query='') { 6168 global $CFG, $OUTPUT, $DB; 6169 6170 // display strings 6171 $txt = get_strings(array('authenticationplugins', 'users', 'administration', 6172 'settings', 'edit', 'name', 'enable', 'disable', 6173 'up', 'down', 'none', 'users')); 6174 $txt->updown = "$txt->up/$txt->down"; 6175 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 6176 $txt->testsettings = get_string('testsettings', 'core_auth'); 6177 6178 $authsavailable = core_component::get_plugin_list('auth'); 6179 get_enabled_auth_plugins(true); // fix the list of enabled auths 6180 if (empty($CFG->auth)) { 6181 $authsenabled = array(); 6182 } else { 6183 $authsenabled = explode(',', $CFG->auth); 6184 } 6185 6186 // construct the display array, with enabled auth plugins at the top, in order 6187 $displayauths = array(); 6188 $registrationauths = array(); 6189 $registrationauths[''] = $txt->disable; 6190 $authplugins = array(); 6191 foreach ($authsenabled as $auth) { 6192 $authplugin = get_auth_plugin($auth); 6193 $authplugins[$auth] = $authplugin; 6194 /// Get the auth title (from core or own auth lang files) 6195 $authtitle = $authplugin->get_title(); 6196 /// Apply titles 6197 $displayauths[$auth] = $authtitle; 6198 if ($authplugin->can_signup()) { 6199 $registrationauths[$auth] = $authtitle; 6200 } 6201 } 6202 6203 foreach ($authsavailable as $auth => $dir) { 6204 if (array_key_exists($auth, $displayauths)) { 6205 continue; //already in the list 6206 } 6207 $authplugin = get_auth_plugin($auth); 6208 $authplugins[$auth] = $authplugin; 6209 /// Get the auth title (from core or own auth lang files) 6210 $authtitle = $authplugin->get_title(); 6211 /// Apply titles 6212 $displayauths[$auth] = $authtitle; 6213 if ($authplugin->can_signup()) { 6214 $registrationauths[$auth] = $authtitle; 6215 } 6216 } 6217 6218 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main'); 6219 $return .= $OUTPUT->box_start('generalbox authsui'); 6220 6221 $table = new html_table(); 6222 $table->head = array($txt->name, $txt->users, $txt->enable, $txt->updown, $txt->settings, $txt->testsettings, $txt->uninstall); 6223 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 6224 $table->data = array(); 6225 $table->attributes['class'] = 'admintable generaltable'; 6226 $table->id = 'manageauthtable'; 6227 6228 //add always enabled plugins first 6229 $displayname = $displayauths['manual']; 6230 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>"; 6231 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>"; 6232 $usercount = $DB->count_records('user', array('auth'=>'manual', 'deleted'=>0)); 6233 $table->data[] = array($displayname, $usercount, '', '', $settings, '', ''); 6234 $displayname = $displayauths['nologin']; 6235 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>"; 6236 $usercount = $DB->count_records('user', array('auth'=>'nologin', 'deleted'=>0)); 6237 $table->data[] = array($displayname, $usercount, '', '', $settings, '', ''); 6238 6239 6240 // iterate through auth plugins and add to the display table 6241 $updowncount = 1; 6242 $authcount = count($authsenabled); 6243 $url = "auth.php?sesskey=" . sesskey(); 6244 foreach ($displayauths as $auth => $name) { 6245 if ($auth == 'manual' or $auth == 'nologin') { 6246 continue; 6247 } 6248 $class = ''; 6249 // hide/show link 6250 if (in_array($auth, $authsenabled)) { 6251 $hideshow = "<a href=\"$url&action=disable&auth=$auth\">"; 6252 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"disable\" /></a>"; 6253 // $hideshow = "<a href=\"$url&action=disable&auth=$auth\"><input type=\"checkbox\" checked /></a>"; 6254 $enabled = true; 6255 $displayname = $name; 6256 } 6257 else { 6258 $hideshow = "<a href=\"$url&action=enable&auth=$auth\">"; 6259 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"enable\" /></a>"; 6260 // $hideshow = "<a href=\"$url&action=enable&auth=$auth\"><input type=\"checkbox\" /></a>"; 6261 $enabled = false; 6262 $displayname = $name; 6263 $class = 'dimmed_text'; 6264 } 6265 6266 $usercount = $DB->count_records('user', array('auth'=>$auth, 'deleted'=>0)); 6267 6268 // up/down link (only if auth is enabled) 6269 $updown = ''; 6270 if ($enabled) { 6271 if ($updowncount > 1) { 6272 $updown .= "<a href=\"$url&action=up&auth=$auth\">"; 6273 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a> "; 6274 } 6275 else { 6276 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> "; 6277 } 6278 if ($updowncount < $authcount) { 6279 $updown .= "<a href=\"$url&action=down&auth=$auth\">"; 6280 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>"; 6281 } 6282 else { 6283 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />"; 6284 } 6285 ++ $updowncount; 6286 } 6287 6288 // settings link 6289 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) { 6290 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>"; 6291 } else { 6292 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>"; 6293 } 6294 6295 // Uninstall link. 6296 $uninstall = ''; 6297 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('auth_'.$auth, 'manage')) { 6298 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 6299 } 6300 6301 $test = ''; 6302 if (!empty($authplugins[$auth]) and method_exists($authplugins[$auth], 'test_settings')) { 6303 $testurl = new moodle_url('/auth/test_settings.php', array('auth'=>$auth, 'sesskey'=>sesskey())); 6304 $test = html_writer::link($testurl, $txt->testsettings); 6305 } 6306 6307 // Add a row to the table. 6308 $row = new html_table_row(array($displayname, $usercount, $hideshow, $updown, $settings, $test, $uninstall)); 6309 if ($class) { 6310 $row->attributes['class'] = $class; 6311 } 6312 $table->data[] = $row; 6313 } 6314 $return .= html_writer::table($table); 6315 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters'); 6316 $return .= $OUTPUT->box_end(); 6317 return highlight($query, $return); 6318 } 6319 } 6320 6321 6322 /** 6323 * Special class for authentication administration. 6324 * 6325 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6326 */ 6327 class admin_setting_manageeditors extends admin_setting { 6328 /** 6329 * Calls parent::__construct with specific arguments 6330 */ 6331 public function __construct() { 6332 $this->nosave = true; 6333 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', ''); 6334 } 6335 6336 /** 6337 * Always returns true, does nothing 6338 * 6339 * @return true 6340 */ 6341 public function get_setting() { 6342 return true; 6343 } 6344 6345 /** 6346 * Always returns true, does nothing 6347 * 6348 * @return true 6349 */ 6350 public function get_defaultsetting() { 6351 return true; 6352 } 6353 6354 /** 6355 * Always returns '', does not write anything 6356 * 6357 * @return string Always returns '' 6358 */ 6359 public function write_setting($data) { 6360 // do not write any setting 6361 return ''; 6362 } 6363 6364 /** 6365 * Checks if $query is one of the available editors 6366 * 6367 * @param string $query The string to search for 6368 * @return bool Returns true if found, false if not 6369 */ 6370 public function is_related($query) { 6371 if (parent::is_related($query)) { 6372 return true; 6373 } 6374 6375 $editors_available = editors_get_available(); 6376 foreach ($editors_available as $editor=>$editorstr) { 6377 if (strpos($editor, $query) !== false) { 6378 return true; 6379 } 6380 if (strpos(core_text::strtolower($editorstr), $query) !== false) { 6381 return true; 6382 } 6383 } 6384 return false; 6385 } 6386 6387 /** 6388 * Builds the XHTML to display the control 6389 * 6390 * @param string $data Unused 6391 * @param string $query 6392 * @return string 6393 */ 6394 public function output_html($data, $query='') { 6395 global $CFG, $OUTPUT; 6396 6397 // display strings 6398 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable', 6399 'up', 'down', 'none')); 6400 $struninstall = get_string('uninstallplugin', 'core_admin'); 6401 6402 $txt->updown = "$txt->up/$txt->down"; 6403 6404 $editors_available = editors_get_available(); 6405 $active_editors = explode(',', $CFG->texteditors); 6406 6407 $active_editors = array_reverse($active_editors); 6408 foreach ($active_editors as $key=>$editor) { 6409 if (empty($editors_available[$editor])) { 6410 unset($active_editors[$key]); 6411 } else { 6412 $name = $editors_available[$editor]; 6413 unset($editors_available[$editor]); 6414 $editors_available[$editor] = $name; 6415 } 6416 } 6417 if (empty($active_editors)) { 6418 //$active_editors = array('textarea'); 6419 } 6420 $editors_available = array_reverse($editors_available, true); 6421 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true); 6422 $return .= $OUTPUT->box_start('generalbox editorsui'); 6423 6424 $table = new html_table(); 6425 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall); 6426 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 6427 $table->id = 'editormanagement'; 6428 $table->attributes['class'] = 'admintable generaltable'; 6429 $table->data = array(); 6430 6431 // iterate through auth plugins and add to the display table 6432 $updowncount = 1; 6433 $editorcount = count($active_editors); 6434 $url = "editors.php?sesskey=" . sesskey(); 6435 foreach ($editors_available as $editor => $name) { 6436 // hide/show link 6437 $class = ''; 6438 if (in_array($editor, $active_editors)) { 6439 $hideshow = "<a href=\"$url&action=disable&editor=$editor\">"; 6440 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"disable\" /></a>"; 6441 // $hideshow = "<a href=\"$url&action=disable&editor=$editor\"><input type=\"checkbox\" checked /></a>"; 6442 $enabled = true; 6443 $displayname = $name; 6444 } 6445 else { 6446 $hideshow = "<a href=\"$url&action=enable&editor=$editor\">"; 6447 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"enable\" /></a>"; 6448 // $hideshow = "<a href=\"$url&action=enable&editor=$editor\"><input type=\"checkbox\" /></a>"; 6449 $enabled = false; 6450 $displayname = $name; 6451 $class = 'dimmed_text'; 6452 } 6453 6454 // up/down link (only if auth is enabled) 6455 $updown = ''; 6456 if ($enabled) { 6457 if ($updowncount > 1) { 6458 $updown .= "<a href=\"$url&action=up&editor=$editor\">"; 6459 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a> "; 6460 } 6461 else { 6462 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> "; 6463 } 6464 if ($updowncount < $editorcount) { 6465 $updown .= "<a href=\"$url&action=down&editor=$editor\">"; 6466 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>"; 6467 } 6468 else { 6469 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />"; 6470 } 6471 ++ $updowncount; 6472 } 6473 6474 // settings link 6475 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) { 6476 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor)); 6477 $settings = "<a href='$eurl'>{$txt->settings}</a>"; 6478 } else { 6479 $settings = ''; 6480 } 6481 6482 $uninstall = ''; 6483 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('editor_'.$editor, 'manage')) { 6484 $uninstall = html_writer::link($uninstallurl, $struninstall); 6485 } 6486 6487 // Add a row to the table. 6488 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall)); 6489 if ($class) { 6490 $row->attributes['class'] = $class; 6491 } 6492 $table->data[] = $row; 6493 } 6494 $return .= html_writer::table($table); 6495 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin'); 6496 $return .= $OUTPUT->box_end(); 6497 return highlight($query, $return); 6498 } 6499 } 6500 6501 /** 6502 * Special class for antiviruses administration. 6503 * 6504 * @copyright 2015 Ruslan Kabalin, Lancaster University. 6505 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6506 */ 6507 class admin_setting_manageantiviruses extends admin_setting { 6508 /** 6509 * Calls parent::__construct with specific arguments 6510 */ 6511 public function __construct() { 6512 $this->nosave = true; 6513 parent::__construct('antivirusesui', get_string('antivirussettings', 'antivirus'), '', ''); 6514 } 6515 6516 /** 6517 * Always returns true, does nothing 6518 * 6519 * @return true 6520 */ 6521 public function get_setting() { 6522 return true; 6523 } 6524 6525 /** 6526 * Always returns true, does nothing 6527 * 6528 * @return true 6529 */ 6530 public function get_defaultsetting() { 6531 return true; 6532 } 6533 6534 /** 6535 * Always returns '', does not write anything 6536 * 6537 * @param string $data Unused 6538 * @return string Always returns '' 6539 */ 6540 public function write_setting($data) { 6541 // Do not write any setting. 6542 return ''; 6543 } 6544 6545 /** 6546 * Checks if $query is one of the available editors 6547 * 6548 * @param string $query The string to search for 6549 * @return bool Returns true if found, false if not 6550 */ 6551 public function is_related($query) { 6552 if (parent::is_related($query)) { 6553 return true; 6554 } 6555 6556 $antivirusesavailable = \core\antivirus\manager::get_available(); 6557 foreach ($antivirusesavailable as $antivirus => $antivirusstr) { 6558 if (strpos($antivirus, $query) !== false) { 6559 return true; 6560 } 6561 if (strpos(core_text::strtolower($antivirusstr), $query) !== false) { 6562 return true; 6563 } 6564 } 6565 return false; 6566 } 6567 6568 /** 6569 * Builds the XHTML to display the control 6570 * 6571 * @param string $data Unused 6572 * @param string $query 6573 * @return string 6574 */ 6575 public function output_html($data, $query='') { 6576 global $CFG, $OUTPUT; 6577 6578 // Display strings. 6579 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable', 6580 'up', 'down', 'none')); 6581 $struninstall = get_string('uninstallplugin', 'core_admin'); 6582 6583 $txt->updown = "$txt->up/$txt->down"; 6584 6585 $antivirusesavailable = \core\antivirus\manager::get_available(); 6586 $activeantiviruses = explode(',', $CFG->antiviruses); 6587 6588 $activeantiviruses = array_reverse($activeantiviruses); 6589 foreach ($activeantiviruses as $key => $antivirus) { 6590 if (empty($antivirusesavailable[$antivirus])) { 6591 unset($activeantiviruses[$key]); 6592 } else { 6593 $name = $antivirusesavailable[$antivirus]; 6594 unset($antivirusesavailable[$antivirus]); 6595 $antivirusesavailable[$antivirus] = $name; 6596 } 6597 } 6598 $antivirusesavailable = array_reverse($antivirusesavailable, true); 6599 $return = $OUTPUT->heading(get_string('actantivirushdr', 'antivirus'), 3, 'main', true); 6600 $return .= $OUTPUT->box_start('generalbox antivirusesui'); 6601 6602 $table = new html_table(); 6603 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall); 6604 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 6605 $table->id = 'antivirusmanagement'; 6606 $table->attributes['class'] = 'admintable generaltable'; 6607 $table->data = array(); 6608 6609 // Iterate through auth plugins and add to the display table. 6610 $updowncount = 1; 6611 $antiviruscount = count($activeantiviruses); 6612 $baseurl = new moodle_url('/admin/antiviruses.php', array('sesskey' => sesskey())); 6613 foreach ($antivirusesavailable as $antivirus => $name) { 6614 // Hide/show link. 6615 $class = ''; 6616 if (in_array($antivirus, $activeantiviruses)) { 6617 $hideshowurl = $baseurl; 6618 $hideshowurl->params(array('action' => 'disable', 'antivirus' => $antivirus)); 6619 $hideshowimg = html_writer::img($OUTPUT->pix_url('t/hide'), 'disable', array('class' => 'iconsmall')); 6620 $hideshow = html_writer::link($hideshowurl, $hideshowimg); 6621 $enabled = true; 6622 $displayname = $name; 6623 } else { 6624 $hideshowurl = $baseurl; 6625 $hideshowurl->params(array('action' => 'enable', 'antivirus' => $antivirus)); 6626 $hideshowimg = html_writer::img($OUTPUT->pix_url('t/show'), 'enable', array('class' => 'iconsmall')); 6627 $hideshow = html_writer::link($hideshowurl, $hideshowimg); 6628 $enabled = false; 6629 $displayname = $name; 6630 $class = 'dimmed_text'; 6631 } 6632 6633 // Up/down link. 6634 $updown = ''; 6635 if ($enabled) { 6636 if ($updowncount > 1) { 6637 $updownurl = $baseurl; 6638 $updownurl->params(array('action' => 'up', 'antivirus' => $antivirus)); 6639 $updownimg = html_writer::img($OUTPUT->pix_url('t/up'), 'up', array('class' => 'iconsmall')); 6640 $updown = html_writer::link($updownurl, $updownimg); 6641 } else { 6642 $updown .= html_writer::img($OUTPUT->pix_url('spacer'), '', array('class' => 'iconsmall')); 6643 } 6644 if ($updowncount < $antiviruscount) { 6645 $updownurl = $baseurl; 6646 $updownurl->params(array('action' => 'down', 'antivirus' => $antivirus)); 6647 $updownimg = html_writer::img($OUTPUT->pix_url('t/down'), 'down', array('class' => 'iconsmall')); 6648 $updown = html_writer::link($updownurl, $updownimg); 6649 } else { 6650 $updown .= html_writer::img($OUTPUT->pix_url('spacer'), '', array('class' => 'iconsmall')); 6651 } 6652 ++ $updowncount; 6653 } 6654 6655 // Settings link. 6656 if (file_exists($CFG->dirroot.'/lib/antivirus/'.$antivirus.'/settings.php')) { 6657 $eurl = new moodle_url('/admin/settings.php', array('section' => 'antivirussettings'.$antivirus)); 6658 $settings = html_writer::link($eurl, $txt->settings); 6659 } else { 6660 $settings = ''; 6661 } 6662 6663 $uninstall = ''; 6664 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('antivirus_'.$antivirus, 'manage')) { 6665 $uninstall = html_writer::link($uninstallurl, $struninstall); 6666 } 6667 6668 // Add a row to the table. 6669 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall)); 6670 if ($class) { 6671 $row->attributes['class'] = $class; 6672 } 6673 $table->data[] = $row; 6674 } 6675 $return .= html_writer::table($table); 6676 $return .= get_string('configantivirusplugins', 'antivirus') . html_writer::empty_tag('br') . get_string('tablenosave', 'admin'); 6677 $return .= $OUTPUT->box_end(); 6678 return highlight($query, $return); 6679 } 6680 } 6681 6682 /** 6683 * Special class for license administration. 6684 * 6685 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6686 */ 6687 class admin_setting_managelicenses extends admin_setting { 6688 /** 6689 * Calls parent::__construct with specific arguments 6690 */ 6691 public function __construct() { 6692 $this->nosave = true; 6693 parent::__construct('licensesui', get_string('licensesettings', 'admin'), '', ''); 6694 } 6695 6696 /** 6697 * Always returns true, does nothing 6698 * 6699 * @return true 6700 */ 6701 public function get_setting() { 6702 return true; 6703 } 6704 6705 /** 6706 * Always returns true, does nothing 6707 * 6708 * @return true 6709 */ 6710 public function get_defaultsetting() { 6711 return true; 6712 } 6713 6714 /** 6715 * Always returns '', does not write anything 6716 * 6717 * @return string Always returns '' 6718 */ 6719 public function write_setting($data) { 6720 // do not write any setting 6721 return ''; 6722 } 6723 6724 /** 6725 * Builds the XHTML to display the control 6726 * 6727 * @param string $data Unused 6728 * @param string $query 6729 * @return string 6730 */ 6731 public function output_html($data, $query='') { 6732 global $CFG, $OUTPUT; 6733 require_once($CFG->libdir . '/licenselib.php'); 6734 $url = "licenses.php?sesskey=" . sesskey(); 6735 6736 // display strings 6737 $txt = get_strings(array('administration', 'settings', 'name', 'enable', 'disable', 'none')); 6738 $licenses = license_manager::get_licenses(); 6739 6740 $return = $OUTPUT->heading(get_string('availablelicenses', 'admin'), 3, 'main', true); 6741 6742 $return .= $OUTPUT->box_start('generalbox editorsui'); 6743 6744 $table = new html_table(); 6745 $table->head = array($txt->name, $txt->enable); 6746 $table->colclasses = array('leftalign', 'centeralign'); 6747 $table->id = 'availablelicenses'; 6748 $table->attributes['class'] = 'admintable generaltable'; 6749 $table->data = array(); 6750 6751 foreach ($licenses as $value) { 6752 $displayname = html_writer::link($value->source, get_string($value->shortname, 'license'), array('target'=>'_blank')); 6753 6754 if ($value->enabled == 1) { 6755 $hideshow = html_writer::link($url.'&action=disable&license='.$value->shortname, 6756 html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('t/hide'), 'class'=>'iconsmall', 'alt'=>'disable'))); 6757 } else { 6758 $hideshow = html_writer::link($url.'&action=enable&license='.$value->shortname, 6759 html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('t/show'), 'class'=>'iconsmall', 'alt'=>'enable'))); 6760 } 6761 6762 if ($value->shortname == $CFG->sitedefaultlicense) { 6763 $displayname .= ' '.html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('t/locked'), 'class'=>'iconsmall', 'alt'=>get_string('default'), 'title'=>get_string('default'))); 6764 $hideshow = ''; 6765 } 6766 6767 $enabled = true; 6768 6769 $table->data[] =array($displayname, $hideshow); 6770 } 6771 $return .= html_writer::table($table); 6772 $return .= $OUTPUT->box_end(); 6773 return highlight($query, $return); 6774 } 6775 } 6776 6777 /** 6778 * Course formats manager. Allows to enable/disable formats and jump to settings 6779 */ 6780 class admin_setting_manageformats extends admin_setting { 6781 6782 /** 6783 * Calls parent::__construct with specific arguments 6784 */ 6785 public function __construct() { 6786 $this->nosave = true; 6787 parent::__construct('formatsui', new lang_string('manageformats', 'core_admin'), '', ''); 6788 } 6789 6790 /** 6791 * Always returns true 6792 * 6793 * @return true 6794 */ 6795 public function get_setting() { 6796 return true; 6797 } 6798 6799 /** 6800 * Always returns true 6801 * 6802 * @return true 6803 */ 6804 public function get_defaultsetting() { 6805 return true; 6806 } 6807 6808 /** 6809 * Always returns '' and doesn't write anything 6810 * 6811 * @param mixed $data string or array, must not be NULL 6812 * @return string Always returns '' 6813 */ 6814 public function write_setting($data) { 6815 // do not write any setting 6816 return ''; 6817 } 6818 6819 /** 6820 * Search to find if Query is related to format plugin 6821 * 6822 * @param string $query The string to search for 6823 * @return bool true for related false for not 6824 */ 6825 public function is_related($query) { 6826 if (parent::is_related($query)) { 6827 return true; 6828 } 6829 $formats = core_plugin_manager::instance()->get_plugins_of_type('format'); 6830 foreach ($formats as $format) { 6831 if (strpos($format->component, $query) !== false || 6832 strpos(core_text::strtolower($format->displayname), $query) !== false) { 6833 return true; 6834 } 6835 } 6836 return false; 6837 } 6838 6839 /** 6840 * Return XHTML to display control 6841 * 6842 * @param mixed $data Unused 6843 * @param string $query 6844 * @return string highlight 6845 */ 6846 public function output_html($data, $query='') { 6847 global $CFG, $OUTPUT; 6848 $return = ''; 6849 $return = $OUTPUT->heading(new lang_string('courseformats'), 3, 'main'); 6850 $return .= $OUTPUT->box_start('generalbox formatsui'); 6851 6852 $formats = core_plugin_manager::instance()->get_plugins_of_type('format'); 6853 6854 // display strings 6855 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default')); 6856 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 6857 $txt->updown = "$txt->up/$txt->down"; 6858 6859 $table = new html_table(); 6860 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings); 6861 $table->align = array('left', 'center', 'center', 'center', 'center'); 6862 $table->attributes['class'] = 'manageformattable generaltable admintable'; 6863 $table->data = array(); 6864 6865 $cnt = 0; 6866 $defaultformat = get_config('moodlecourse', 'format'); 6867 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 6868 foreach ($formats as $format) { 6869 $url = new moodle_url('/admin/courseformats.php', 6870 array('sesskey' => sesskey(), 'format' => $format->name)); 6871 $isdefault = ''; 6872 $class = ''; 6873 if ($format->is_enabled()) { 6874 $strformatname = $format->displayname; 6875 if ($defaultformat === $format->name) { 6876 $hideshow = $txt->default; 6877 } else { 6878 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')), 6879 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall'))); 6880 } 6881 } else { 6882 $strformatname = $format->displayname; 6883 $class = 'dimmed_text'; 6884 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')), 6885 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall'))); 6886 } 6887 $updown = ''; 6888 if ($cnt) { 6889 $updown .= html_writer::link($url->out(false, array('action' => 'up')), 6890 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). ''; 6891 } else { 6892 $updown .= $spacer; 6893 } 6894 if ($cnt < count($formats) - 1) { 6895 $updown .= ' '.html_writer::link($url->out(false, array('action' => 'down')), 6896 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall'))); 6897 } else { 6898 $updown .= $spacer; 6899 } 6900 $cnt++; 6901 $settings = ''; 6902 if ($format->get_settings_url()) { 6903 $settings = html_writer::link($format->get_settings_url(), $txt->settings); 6904 } 6905 $uninstall = ''; 6906 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('format_'.$format->name, 'manage')) { 6907 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 6908 } 6909 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings)); 6910 if ($class) { 6911 $row->attributes['class'] = $class; 6912 } 6913 $table->data[] = $row; 6914 } 6915 $return .= html_writer::table($table); 6916 $link = html_writer::link(new moodle_url('/admin/settings.php', array('section' => 'coursesettings')), new lang_string('coursesettings')); 6917 $return .= html_writer::tag('p', get_string('manageformatsgotosettings', 'admin', $link)); 6918 $return .= $OUTPUT->box_end(); 6919 return highlight($query, $return); 6920 } 6921 } 6922 6923 /** 6924 * Data formats manager. Allow reorder and to enable/disable data formats and jump to settings 6925 * 6926 * @copyright 2016 Brendan Heywood (brendan@catalyst-au.net) 6927 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 6928 */ 6929 class admin_setting_managedataformats extends admin_setting { 6930 6931 /** 6932 * Calls parent::__construct with specific arguments 6933 */ 6934 public function __construct() { 6935 $this->nosave = true; 6936 parent::__construct('managedataformats', new lang_string('managedataformats'), '', ''); 6937 } 6938 6939 /** 6940 * Always returns true 6941 * 6942 * @return true 6943 */ 6944 public function get_setting() { 6945 return true; 6946 } 6947 6948 /** 6949 * Always returns true 6950 * 6951 * @return true 6952 */ 6953 public function get_defaultsetting() { 6954 return true; 6955 } 6956 6957 /** 6958 * Always returns '' and doesn't write anything 6959 * 6960 * @param mixed $data string or array, must not be NULL 6961 * @return string Always returns '' 6962 */ 6963 public function write_setting($data) { 6964 // Do not write any setting. 6965 return ''; 6966 } 6967 6968 /** 6969 * Search to find if Query is related to format plugin 6970 * 6971 * @param string $query The string to search for 6972 * @return bool true for related false for not 6973 */ 6974 public function is_related($query) { 6975 if (parent::is_related($query)) { 6976 return true; 6977 } 6978 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat'); 6979 foreach ($formats as $format) { 6980 if (strpos($format->component, $query) !== false || 6981 strpos(core_text::strtolower($format->displayname), $query) !== false) { 6982 return true; 6983 } 6984 } 6985 return false; 6986 } 6987 6988 /** 6989 * Return XHTML to display control 6990 * 6991 * @param mixed $data Unused 6992 * @param string $query 6993 * @return string highlight 6994 */ 6995 public function output_html($data, $query='') { 6996 global $CFG, $OUTPUT; 6997 $return = ''; 6998 6999 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat'); 7000 7001 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default')); 7002 $txt->uninstall = get_string('uninstallplugin', 'core_admin'); 7003 $txt->updown = "$txt->up/$txt->down"; 7004 7005 $table = new html_table(); 7006 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings); 7007 $table->align = array('left', 'center', 'center', 'center', 'center'); 7008 $table->attributes['class'] = 'manageformattable generaltable admintable'; 7009 $table->data = array(); 7010 7011 $cnt = 0; 7012 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall')); 7013 $totalenabled = 0; 7014 foreach ($formats as $format) { 7015 if ($format->is_enabled() && $format->is_installed_and_upgraded()) { 7016 $totalenabled++; 7017 } 7018 } 7019 foreach ($formats as $format) { 7020 $status = $format->get_status(); 7021 $url = new moodle_url('/admin/dataformats.php', 7022 array('sesskey' => sesskey(), 'name' => $format->name)); 7023 7024 $class = ''; 7025 if ($format->is_enabled()) { 7026 $strformatname = $format->displayname; 7027 if ($totalenabled == 1&& $format->is_enabled()) { 7028 $hideshow = ''; 7029 } else { 7030 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')), 7031 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall'))); 7032 } 7033 } else { 7034 $class = 'dimmed_text'; 7035 $strformatname = $format->displayname; 7036 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')), 7037 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall'))); 7038 } 7039 7040 $updown = ''; 7041 if ($cnt) { 7042 $updown .= html_writer::link($url->out(false, array('action' => 'up')), 7043 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). ''; 7044 } else { 7045 $updown .= $spacer; 7046 } 7047 if ($cnt < count($formats) - 1) { 7048 $updown .= ' '.html_writer::link($url->out(false, array('action' => 'down')), 7049 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall'))); 7050 } else { 7051 $updown .= $spacer; 7052 } 7053 7054 $uninstall = ''; 7055 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) { 7056 $uninstall = get_string('status_missing', 'core_plugin'); 7057 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) { 7058 $uninstall = get_string('status_new', 'core_plugin'); 7059 } else if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('dataformat_'.$format->name, 'manage')) { 7060 if ($totalenabled != 1 || !$format->is_enabled()) { 7061 $uninstall = html_writer::link($uninstallurl, $txt->uninstall); 7062 } 7063 } 7064 7065 $settings = ''; 7066 if ($format->get_settings_url()) { 7067 $settings = html_writer::link($format->get_settings_url(), $txt->settings); 7068 } 7069 7070 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings)); 7071 if ($class) { 7072 $row->attributes['class'] = $class; 7073 } 7074 $table->data[] = $row; 7075 $cnt++; 7076 } 7077 $return .= html_writer::table($table); 7078 return highlight($query, $return); 7079 } 7080 } 7081 7082 /** 7083 * Special class for filter administration. 7084 * 7085 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7086 */ 7087 class admin_page_managefilters extends admin_externalpage { 7088 /** 7089 * Calls parent::__construct with specific arguments 7090 */ 7091 public function __construct() { 7092 global $CFG; 7093 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php"); 7094 } 7095 7096 /** 7097 * Searches all installed filters for specified filter 7098 * 7099 * @param string $query The filter(string) to search for 7100 * @param string $query 7101 */ 7102 public function search($query) { 7103 global $CFG; 7104 if ($result = parent::search($query)) { 7105 return $result; 7106 } 7107 7108 $found = false; 7109 $filternames = filter_get_all_installed(); 7110 foreach ($filternames as $path => $strfiltername) { 7111 if (strpos(core_text::strtolower($strfiltername), $query) !== false) { 7112 $found = true; 7113 break; 7114 } 7115 if (strpos($path, $query) !== false) { 7116 $found = true; 7117 break; 7118 } 7119 } 7120 7121 if ($found) { 7122 $result = new stdClass; 7123 $result->page = $this; 7124 $result->settings = array(); 7125 return array($this->name => $result); 7126 } else { 7127 return array(); 7128 } 7129 } 7130 } 7131 7132 7133 /** 7134 * Initialise admin page - this function does require login and permission 7135 * checks specified in page definition. 7136 * 7137 * This function must be called on each admin page before other code. 7138 * 7139 * @global moodle_page $PAGE 7140 * 7141 * @param string $section name of page 7142 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button. 7143 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be 7144 * added to the turn blocks editing on/off form, so this page reloads correctly. 7145 * @param string $actualurl if the actual page being viewed is not the normal one for this 7146 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here. 7147 * @param array $options Additional options that can be specified for page setup. 7148 * pagelayout - This option can be used to set a specific pagelyaout, admin is default. 7149 */ 7150 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) { 7151 global $CFG, $PAGE, $USER, $SITE, $OUTPUT; 7152 7153 $PAGE->set_context(null); // hack - set context to something, by default to system context 7154 7155 $site = get_site(); 7156 require_login(); 7157 7158 if (!empty($options['pagelayout'])) { 7159 // A specific page layout has been requested. 7160 $PAGE->set_pagelayout($options['pagelayout']); 7161 } else if ($section === 'upgradesettings') { 7162 $PAGE->set_pagelayout('maintenance'); 7163 } else { 7164 $PAGE->set_pagelayout('admin'); 7165 } 7166 7167 $adminroot = admin_get_root(false, false); // settings not required for external pages 7168 $extpage = $adminroot->locate($section, true); 7169 7170 if (empty($extpage) or !($extpage instanceof admin_externalpage)) { 7171 // The requested section isn't in the admin tree 7172 // It could be because the user has inadequate capapbilities or because the section doesn't exist 7173 if (!has_capability('moodle/site:config', context_system::instance())) { 7174 // The requested section could depend on a different capability 7175 // but most likely the user has inadequate capabilities 7176 print_error('accessdenied', 'admin'); 7177 } else { 7178 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/"); 7179 } 7180 } 7181 7182 // this eliminates our need to authenticate on the actual pages 7183 if (!$extpage->check_access()) { 7184 print_error('accessdenied', 'admin'); 7185 die; 7186 } 7187 7188 navigation_node::require_admin_tree(); 7189 7190 // $PAGE->set_extra_button($extrabutton); TODO 7191 7192 if (!$actualurl) { 7193 $actualurl = $extpage->url; 7194 } 7195 7196 $PAGE->set_url($actualurl, $extraurlparams); 7197 if (strpos($PAGE->pagetype, 'admin-') !== 0) { 7198 $PAGE->set_pagetype('admin-' . $PAGE->pagetype); 7199 } 7200 7201 if (empty($SITE->fullname) || empty($SITE->shortname)) { 7202 // During initial install. 7203 $strinstallation = get_string('installation', 'install'); 7204 $strsettings = get_string('settings'); 7205 $PAGE->navbar->add($strsettings); 7206 $PAGE->set_title($strinstallation); 7207 $PAGE->set_heading($strinstallation); 7208 $PAGE->set_cacheable(false); 7209 return; 7210 } 7211 7212 // Locate the current item on the navigation and make it active when found. 7213 $path = $extpage->path; 7214 $node = $PAGE->settingsnav; 7215 while ($node && count($path) > 0) { 7216 $node = $node->get(array_pop($path)); 7217 } 7218 if ($node) { 7219 $node->make_active(); 7220 } 7221 7222 // Normal case. 7223 $adminediting = optional_param('adminedit', -1, PARAM_BOOL); 7224 if ($PAGE->user_allowed_editing() && $adminediting != -1) { 7225 $USER->editing = $adminediting; 7226 } 7227 7228 $visiblepathtosection = array_reverse($extpage->visiblepath); 7229 7230 if ($PAGE->user_allowed_editing()) { 7231 if ($PAGE->user_is_editing()) { 7232 $caption = get_string('blockseditoff'); 7233 $url = new moodle_url($PAGE->url, array('adminedit'=>'0', 'sesskey'=>sesskey())); 7234 } else { 7235 $caption = get_string('blocksediton'); 7236 $url = new moodle_url($PAGE->url, array('adminedit'=>'1', 'sesskey'=>sesskey())); 7237 } 7238 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get')); 7239 } 7240 7241 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection)); 7242 $PAGE->set_heading($SITE->fullname); 7243 7244 // prevent caching in nav block 7245 $PAGE->navigation->clear_cache(); 7246 } 7247 7248 /** 7249 * Returns the reference to admin tree root 7250 * 7251 * @return object admin_root object 7252 */ 7253 function admin_get_root($reload=false, $requirefulltree=true) { 7254 global $CFG, $DB, $OUTPUT; 7255 7256 static $ADMIN = NULL; 7257 7258 if (is_null($ADMIN)) { 7259 // create the admin tree! 7260 $ADMIN = new admin_root($requirefulltree); 7261 } 7262 7263 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) { 7264 $ADMIN->purge_children($requirefulltree); 7265 } 7266 7267 if (!$ADMIN->loaded) { 7268 // we process this file first to create categories first and in correct order 7269 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php'); 7270 7271 // now we process all other files in admin/settings to build the admin tree 7272 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) { 7273 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') { 7274 continue; 7275 } 7276 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') { 7277 // plugins are loaded last - they may insert pages anywhere 7278 continue; 7279 } 7280 require($file); 7281 } 7282 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php'); 7283 7284 $ADMIN->loaded = true; 7285 } 7286 7287 return $ADMIN; 7288 } 7289 7290 /// settings utility functions 7291 7292 /** 7293 * This function applies default settings. 7294 * 7295 * @param object $node, NULL means complete tree, null by default 7296 * @param bool $unconditional if true overrides all values with defaults, null buy default 7297 */ 7298 function admin_apply_default_settings($node=NULL, $unconditional=true) { 7299 global $CFG; 7300 7301 if (is_null($node)) { 7302 core_plugin_manager::reset_caches(); 7303 $node = admin_get_root(true, true); 7304 } 7305 7306 if ($node instanceof admin_category) { 7307 $entries = array_keys($node->children); 7308 foreach ($entries as $entry) { 7309 admin_apply_default_settings($node->children[$entry], $unconditional); 7310 } 7311 7312 } else if ($node instanceof admin_settingpage) { 7313 foreach ($node->settings as $setting) { 7314 if (!$unconditional and !is_null($setting->get_setting())) { 7315 //do not override existing defaults 7316 continue; 7317 } 7318 $defaultsetting = $setting->get_defaultsetting(); 7319 if (is_null($defaultsetting)) { 7320 // no value yet - default maybe applied after admin user creation or in upgradesettings 7321 continue; 7322 } 7323 $setting->write_setting($defaultsetting); 7324 $setting->write_setting_flags(null); 7325 } 7326 } 7327 // Just in case somebody modifies the list of active plugins directly. 7328 core_plugin_manager::reset_caches(); 7329 } 7330 7331 /** 7332 * Store changed settings, this function updates the errors variable in $ADMIN 7333 * 7334 * @param object $formdata from form 7335 * @return int number of changed settings 7336 */ 7337 function admin_write_settings($formdata) { 7338 global $CFG, $SITE, $DB; 7339 7340 $olddbsessions = !empty($CFG->dbsessions); 7341 $formdata = (array)$formdata; 7342 7343 $data = array(); 7344 foreach ($formdata as $fullname=>$value) { 7345 if (strpos($fullname, 's_') !== 0) { 7346 continue; // not a config value 7347 } 7348 $data[$fullname] = $value; 7349 } 7350 7351 $adminroot = admin_get_root(); 7352 $settings = admin_find_write_settings($adminroot, $data); 7353 7354 $count = 0; 7355 foreach ($settings as $fullname=>$setting) { 7356 /** @var $setting admin_setting */ 7357 $original = $setting->get_setting(); 7358 $error = $setting->write_setting($data[$fullname]); 7359 if ($error !== '') { 7360 $adminroot->errors[$fullname] = new stdClass(); 7361 $adminroot->errors[$fullname]->data = $data[$fullname]; 7362 $adminroot->errors[$fullname]->id = $setting->get_id(); 7363 $adminroot->errors[$fullname]->error = $error; 7364 } else { 7365 $setting->write_setting_flags($data); 7366 } 7367 if ($setting->post_write_settings($original)) { 7368 $count++; 7369 } 7370 } 7371 7372 if ($olddbsessions != !empty($CFG->dbsessions)) { 7373 require_logout(); 7374 } 7375 7376 // Now update $SITE - just update the fields, in case other people have a 7377 // a reference to it (e.g. $PAGE, $COURSE). 7378 $newsite = $DB->get_record('course', array('id'=>$SITE->id)); 7379 foreach (get_object_vars($newsite) as $field => $value) { 7380 $SITE->$field = $value; 7381 } 7382 7383 // now reload all settings - some of them might depend on the changed 7384 admin_get_root(true); 7385 return $count; 7386 } 7387 7388 /** 7389 * Internal recursive function - finds all settings from submitted form 7390 * 7391 * @param object $node Instance of admin_category, or admin_settingpage 7392 * @param array $data 7393 * @return array 7394 */ 7395 function admin_find_write_settings($node, $data) { 7396 $return = array(); 7397 7398 if (empty($data)) { 7399 return $return; 7400 } 7401 7402 if ($node instanceof admin_category) { 7403 $entries = array_keys($node->children); 7404 foreach ($entries as $entry) { 7405 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data)); 7406 } 7407 7408 } else if ($node instanceof admin_settingpage) { 7409 foreach ($node->settings as $setting) { 7410 $fullname = $setting->get_full_name(); 7411 if (array_key_exists($fullname, $data)) { 7412 $return[$fullname] = $setting; 7413 } 7414 } 7415 7416 } 7417 7418 return $return; 7419 } 7420 7421 /** 7422 * Internal function - prints the search results 7423 * 7424 * @param string $query String to search for 7425 * @return string empty or XHTML 7426 */ 7427 function admin_search_settings_html($query) { 7428 global $CFG, $OUTPUT; 7429 7430 if (core_text::strlen($query) < 2) { 7431 return ''; 7432 } 7433 $query = core_text::strtolower($query); 7434 7435 $adminroot = admin_get_root(); 7436 $findings = $adminroot->search($query); 7437 $return = ''; 7438 $savebutton = false; 7439 7440 foreach ($findings as $found) { 7441 $page = $found->page; 7442 $settings = $found->settings; 7443 if ($page->is_hidden()) { 7444 // hidden pages are not displayed in search results 7445 continue; 7446 } 7447 if ($page instanceof admin_externalpage) { 7448 $return .= $OUTPUT->heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', 2, 'main'); 7449 } else if ($page instanceof admin_settingpage) { 7450 $return .= $OUTPUT->heading(get_string('searchresults','admin').' - <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section='.$page->name.'">'.highlight($query, $page->visiblename).'</a>', 2, 'main'); 7451 } else { 7452 continue; 7453 } 7454 if (!empty($settings)) { 7455 $return .= '<fieldset class="adminsettings">'."\n"; 7456 foreach ($settings as $setting) { 7457 if (empty($setting->nosave)) { 7458 $savebutton = true; 7459 } 7460 $return .= '<div class="clearer"><!-- --></div>'."\n"; 7461 $fullname = $setting->get_full_name(); 7462 if (array_key_exists($fullname, $adminroot->errors)) { 7463 $data = $adminroot->errors[$fullname]->data; 7464 } else { 7465 $data = $setting->get_setting(); 7466 // do not use defaults if settings not available - upgradesettings handles the defaults! 7467 } 7468 $return .= $setting->output_html($data, $query); 7469 } 7470 $return .= '</fieldset>'; 7471 } 7472 } 7473 7474 if ($savebutton) { 7475 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>'; 7476 } 7477 7478 return $return; 7479 } 7480 7481 /** 7482 * Internal function - returns arrays of html pages with uninitialised settings 7483 * 7484 * @param object $node Instance of admin_category or admin_settingpage 7485 * @return array 7486 */ 7487 function admin_output_new_settings_by_page($node) { 7488 global $OUTPUT; 7489 $return = array(); 7490 7491 if ($node instanceof admin_category) { 7492 $entries = array_keys($node->children); 7493 foreach ($entries as $entry) { 7494 $return += admin_output_new_settings_by_page($node->children[$entry]); 7495 } 7496 7497 } else if ($node instanceof admin_settingpage) { 7498 $newsettings = array(); 7499 foreach ($node->settings as $setting) { 7500 if (is_null($setting->get_setting())) { 7501 $newsettings[] = $setting; 7502 } 7503 } 7504 if (count($newsettings) > 0) { 7505 $adminroot = admin_get_root(); 7506 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main'); 7507 $page .= '<fieldset class="adminsettings">'."\n"; 7508 foreach ($newsettings as $setting) { 7509 $fullname = $setting->get_full_name(); 7510 if (array_key_exists($fullname, $adminroot->errors)) { 7511 $data = $adminroot->errors[$fullname]->data; 7512 } else { 7513 $data = $setting->get_setting(); 7514 if (is_null($data)) { 7515 $data = $setting->get_defaultsetting(); 7516 } 7517 } 7518 $page .= '<div class="clearer"><!-- --></div>'."\n"; 7519 $page .= $setting->output_html($data); 7520 } 7521 $page .= '</fieldset>'; 7522 $return[$node->name] = $page; 7523 } 7524 } 7525 7526 return $return; 7527 } 7528 7529 /** 7530 * Format admin settings 7531 * 7532 * @param object $setting 7533 * @param string $title label element 7534 * @param string $form form fragment, html code - not highlighted automatically 7535 * @param string $description 7536 * @param mixed $label link label to id, true by default or string being the label to connect it to 7537 * @param string $warning warning text 7538 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null 7539 * @param string $query search query to be highlighted 7540 * @return string XHTML 7541 */ 7542 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') { 7543 global $CFG; 7544 7545 $name = empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name"; 7546 $fullname = $setting->get_full_name(); 7547 7548 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate 7549 if ($label === true) { 7550 $labelfor = 'for = "'.$setting->get_id().'"'; 7551 } else if ($label === false) { 7552 $labelfor = ''; 7553 } else { 7554 $labelfor = 'for="' . $label . '"'; 7555 } 7556 $form .= $setting->output_setting_flags(); 7557 7558 $override = ''; 7559 if (empty($setting->plugin)) { 7560 if (array_key_exists($setting->name, $CFG->config_php_settings)) { 7561 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>'; 7562 } 7563 } else { 7564 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) { 7565 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>'; 7566 } 7567 } 7568 7569 if ($warning !== '') { 7570 $warning = '<div class="form-warning">'.$warning.'</div>'; 7571 } 7572 7573 $defaults = array(); 7574 if (!is_null($defaultinfo)) { 7575 if ($defaultinfo === '') { 7576 $defaultinfo = get_string('emptysettingvalue', 'admin'); 7577 } 7578 $defaults[] = $defaultinfo; 7579 } 7580 7581 $setting->get_setting_flag_defaults($defaults); 7582 7583 if (!empty($defaults)) { 7584 $defaultinfo = implode(', ', $defaults); 7585 $defaultinfo = highlight($query, nl2br(s($defaultinfo))); 7586 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>'; 7587 } 7588 7589 7590 $adminroot = admin_get_root(); 7591 $error = ''; 7592 if (array_key_exists($fullname, $adminroot->errors)) { 7593 $error = '<div><span class="error">' . $adminroot->errors[$fullname]->error . '</span></div>'; 7594 } 7595 7596 $str = ' 7597 <div class="form-item clearfix" id="admin-'.$setting->name.'"> 7598 <div class="form-label"> 7599 <label '.$labelfor.'>'.highlightfast($query, $title).$override.$warning.'</label> 7600 <span class="form-shortname">'.highlightfast($query, $name).'</span> 7601 </div> 7602 <div class="form-setting">'.$error.$form.$defaultinfo.'</div> 7603 <div class="form-description">'.highlight($query, markdown_to_html($description)).'</div> 7604 </div>'; 7605 7606 return $str; 7607 } 7608 7609 /** 7610 * Based on find_new_settings{@link ()} in upgradesettings.php 7611 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any. 7612 * 7613 * @param object $node Instance of admin_category, or admin_settingpage 7614 * @return boolean true if any settings haven't been initialised, false if they all have 7615 */ 7616 function any_new_admin_settings($node) { 7617 7618 if ($node instanceof admin_category) { 7619 $entries = array_keys($node->children); 7620 foreach ($entries as $entry) { 7621 if (any_new_admin_settings($node->children[$entry])) { 7622 return true; 7623 } 7624 } 7625 7626 } else if ($node instanceof admin_settingpage) { 7627 foreach ($node->settings as $setting) { 7628 if ($setting->get_setting() === NULL) { 7629 return true; 7630 } 7631 } 7632 } 7633 7634 return false; 7635 } 7636 7637 /** 7638 * Moved from admin/replace.php so that we can use this in cron 7639 * 7640 * @param string $search string to look for 7641 * @param string $replace string to replace 7642 * @return bool success or fail 7643 */ 7644 function db_replace($search, $replace) { 7645 global $DB, $CFG, $OUTPUT; 7646 7647 // TODO: this is horrible hack, we should do whitelisting and each plugin should be responsible for proper replacing... 7648 $skiptables = array('config', 'config_plugins', 'config_log', 'upgrade_log', 'log', 7649 'filter_config', 'sessions', 'events_queue', 'repository_instance_config', 7650 'block_instances', ''); 7651 7652 // Turn off time limits, sometimes upgrades can be slow. 7653 core_php_time_limit::raise(); 7654 7655 if (!$tables = $DB->get_tables() ) { // No tables yet at all. 7656 return false; 7657 } 7658 foreach ($tables as $table) { 7659 7660 if (in_array($table, $skiptables)) { // Don't process these 7661 continue; 7662 } 7663 7664 if ($columns = $DB->get_columns($table)) { 7665 $DB->set_debug(true); 7666 foreach ($columns as $column) { 7667 $DB->replace_all_text($table, $column, $search, $replace); 7668 } 7669 $DB->set_debug(false); 7670 } 7671 } 7672 7673 // delete modinfo caches 7674 rebuild_course_cache(0, true); 7675 7676 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks... 7677 $blocks = core_component::get_plugin_list('block'); 7678 foreach ($blocks as $blockname=>$fullblock) { 7679 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it 7680 continue; 7681 } 7682 7683 if (!is_readable($fullblock.'/lib.php')) { 7684 continue; 7685 } 7686 7687 $function = 'block_'.$blockname.'_global_db_replace'; 7688 include_once($fullblock.'/lib.php'); 7689 if (!function_exists($function)) { 7690 continue; 7691 } 7692 7693 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess'); 7694 $function($search, $replace); 7695 echo $OUTPUT->notification("...finished", 'notifysuccess'); 7696 } 7697 7698 purge_all_caches(); 7699 7700 return true; 7701 } 7702 7703 /** 7704 * Manage repository settings 7705 * 7706 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7707 */ 7708 class admin_setting_managerepository extends admin_setting { 7709 /** @var string */ 7710 private $baseurl; 7711 7712 /** 7713 * calls parent::__construct with specific arguments 7714 */ 7715 public function __construct() { 7716 global $CFG; 7717 parent::__construct('managerepository', get_string('manage', 'repository'), '', ''); 7718 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey(); 7719 } 7720 7721 /** 7722 * Always returns true, does nothing 7723 * 7724 * @return true 7725 */ 7726 public function get_setting() { 7727 return true; 7728 } 7729 7730 /** 7731 * Always returns true does nothing 7732 * 7733 * @return true 7734 */ 7735 public function get_defaultsetting() { 7736 return true; 7737 } 7738 7739 /** 7740 * Always returns s_managerepository 7741 * 7742 * @return string Always return 's_managerepository' 7743 */ 7744 public function get_full_name() { 7745 return 's_managerepository'; 7746 } 7747 7748 /** 7749 * Always returns '' doesn't do anything 7750 */ 7751 public function write_setting($data) { 7752 $url = $this->baseurl . '&new=' . $data; 7753 return ''; 7754 // TODO 7755 // Should not use redirect and exit here 7756 // Find a better way to do this. 7757 // redirect($url); 7758 // exit; 7759 } 7760 7761 /** 7762 * Searches repository plugins for one that matches $query 7763 * 7764 * @param string $query The string to search for 7765 * @return bool true if found, false if not 7766 */ 7767 public function is_related($query) { 7768 if (parent::is_related($query)) { 7769 return true; 7770 } 7771 7772 $repositories= core_component::get_plugin_list('repository'); 7773 foreach ($repositories as $p => $dir) { 7774 if (strpos($p, $query) !== false) { 7775 return true; 7776 } 7777 } 7778 foreach (repository::get_types() as $instance) { 7779 $title = $instance->get_typename(); 7780 if (strpos(core_text::strtolower($title), $query) !== false) { 7781 return true; 7782 } 7783 } 7784 return false; 7785 } 7786 7787 /** 7788 * Helper function that generates a moodle_url object 7789 * relevant to the repository 7790 */ 7791 7792 function repository_action_url($repository) { 7793 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository)); 7794 } 7795 7796 /** 7797 * Builds XHTML to display the control 7798 * 7799 * @param string $data Unused 7800 * @param string $query 7801 * @return string XHTML 7802 */ 7803 public function output_html($data, $query='') { 7804 global $CFG, $USER, $OUTPUT; 7805 7806 // Get strings that are used 7807 $strshow = get_string('on', 'repository'); 7808 $strhide = get_string('off', 'repository'); 7809 $strdelete = get_string('disabled', 'repository'); 7810 7811 $actionchoicesforexisting = array( 7812 'show' => $strshow, 7813 'hide' => $strhide, 7814 'delete' => $strdelete 7815 ); 7816 7817 $actionchoicesfornew = array( 7818 'newon' => $strshow, 7819 'newoff' => $strhide, 7820 'delete' => $strdelete 7821 ); 7822 7823 $return = ''; 7824 $return .= $OUTPUT->box_start('generalbox'); 7825 7826 // Set strings that are used multiple times 7827 $settingsstr = get_string('settings'); 7828 $disablestr = get_string('disable'); 7829 7830 // Table to list plug-ins 7831 $table = new html_table(); 7832 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr); 7833 $table->align = array('left', 'center', 'center', 'center', 'center'); 7834 $table->data = array(); 7835 7836 // Get list of used plug-ins 7837 $repositorytypes = repository::get_types(); 7838 if (!empty($repositorytypes)) { 7839 // Array to store plugins being used 7840 $alreadyplugins = array(); 7841 $totalrepositorytypes = count($repositorytypes); 7842 $updowncount = 1; 7843 foreach ($repositorytypes as $i) { 7844 $settings = ''; 7845 $typename = $i->get_typename(); 7846 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config) 7847 $typeoptionnames = repository::static_function($typename, 'get_type_option_names'); 7848 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names'); 7849 7850 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) { 7851 // Calculate number of instances in order to display them for the Moodle administrator 7852 if (!empty($instanceoptionnames)) { 7853 $params = array(); 7854 $params['context'] = array(context_system::instance()); 7855 $params['onlyvisible'] = false; 7856 $params['type'] = $typename; 7857 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params)); 7858 // site instances 7859 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber); 7860 $params['context'] = array(); 7861 $instances = repository::static_function($typename, 'get_instances', $params); 7862 $courseinstances = array(); 7863 $userinstances = array(); 7864 7865 foreach ($instances as $instance) { 7866 $repocontext = context::instance_by_id($instance->instance->contextid); 7867 if ($repocontext->contextlevel == CONTEXT_COURSE) { 7868 $courseinstances[] = $instance; 7869 } else if ($repocontext->contextlevel == CONTEXT_USER) { 7870 $userinstances[] = $instance; 7871 } 7872 } 7873 // course instances 7874 $instancenumber = count($courseinstances); 7875 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber); 7876 7877 // user private instances 7878 $instancenumber = count($userinstances); 7879 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber); 7880 } else { 7881 $admininstancenumbertext = ""; 7882 $courseinstancenumbertext = ""; 7883 $userinstancenumbertext = ""; 7884 } 7885 7886 $settings .= '<a href="' . $this->baseurl . '&action=edit&repos=' . $typename . '">' . $settingsstr .'</a>'; 7887 7888 $settings .= $OUTPUT->container_start('mdl-left'); 7889 $settings .= '<br/>'; 7890 $settings .= $admininstancenumbertext; 7891 $settings .= '<br/>'; 7892 $settings .= $courseinstancenumbertext; 7893 $settings .= '<br/>'; 7894 $settings .= $userinstancenumbertext; 7895 $settings .= $OUTPUT->container_end(); 7896 } 7897 // Get the current visibility 7898 if ($i->get_visible()) { 7899 $currentaction = 'show'; 7900 } else { 7901 $currentaction = 'hide'; 7902 } 7903 7904 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename)); 7905 7906 // Display up/down link 7907 $updown = ''; 7908 // Should be done with CSS instead. 7909 $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon')); 7910 7911 if ($updowncount > 1) { 7912 $updown .= "<a href=\"$this->baseurl&action=moveup&repos=".$typename."\">"; 7913 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a> "; 7914 } 7915 else { 7916 $updown .= $spacer; 7917 } 7918 if ($updowncount < $totalrepositorytypes) { 7919 $updown .= "<a href=\"$this->baseurl&action=movedown&repos=".$typename."\">"; 7920 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>"; 7921 } 7922 else { 7923 $updown .= $spacer; 7924 } 7925 7926 $updowncount++; 7927 7928 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings); 7929 7930 if (!in_array($typename, $alreadyplugins)) { 7931 $alreadyplugins[] = $typename; 7932 } 7933 } 7934 } 7935 7936 // Get all the plugins that exist on disk 7937 $plugins = core_component::get_plugin_list('repository'); 7938 if (!empty($plugins)) { 7939 foreach ($plugins as $plugin => $dir) { 7940 // Check that it has not already been listed 7941 if (!in_array($plugin, $alreadyplugins)) { 7942 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin)); 7943 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', ''); 7944 } 7945 } 7946 } 7947 7948 $return .= html_writer::table($table); 7949 $return .= $OUTPUT->box_end(); 7950 return highlight($query, $return); 7951 } 7952 } 7953 7954 /** 7955 * Special checkbox for enable mobile web service 7956 * If enable then we store the service id of the mobile service into config table 7957 * If disable then we unstore the service id from the config table 7958 */ 7959 class admin_setting_enablemobileservice extends admin_setting_configcheckbox { 7960 7961 /** @var boolean True means that the capability 'webservice/rest:use' is set for authenticated user role */ 7962 private $restuse; 7963 7964 /** 7965 * Return true if Authenticated user role has the capability 'webservice/rest:use', otherwise false. 7966 * 7967 * @return boolean 7968 */ 7969 private function is_protocol_cap_allowed() { 7970 global $DB, $CFG; 7971 7972 // If the $this->restuse variable is not set, it needs to be set. 7973 if (empty($this->restuse) and $this->restuse!==false) { 7974 $params = array(); 7975 $params['permission'] = CAP_ALLOW; 7976 $params['roleid'] = $CFG->defaultuserroleid; 7977 $params['capability'] = 'webservice/rest:use'; 7978 $this->restuse = $DB->record_exists('role_capabilities', $params); 7979 } 7980 7981 return $this->restuse; 7982 } 7983 7984 /** 7985 * Set the 'webservice/rest:use' to the Authenticated user role (allow or not) 7986 * @param type $status true to allow, false to not set 7987 */ 7988 private function set_protocol_cap($status) { 7989 global $CFG; 7990 if ($status and !$this->is_protocol_cap_allowed()) { 7991 //need to allow the cap 7992 $permission = CAP_ALLOW; 7993 $assign = true; 7994 } else if (!$status and $this->is_protocol_cap_allowed()){ 7995 //need to disallow the cap 7996 $permission = CAP_INHERIT; 7997 $assign = true; 7998 } 7999 if (!empty($assign)) { 8000 $systemcontext = context_system::instance(); 8001 assign_capability('webservice/rest:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true); 8002 } 8003 } 8004 8005 /** 8006 * Builds XHTML to display the control. 8007 * The main purpose of this overloading is to display a warning when https 8008 * is not supported by the server 8009 * @param string $data Unused 8010 * @param string $query 8011 * @return string XHTML 8012 */ 8013 public function output_html($data, $query='') { 8014 global $CFG, $OUTPUT; 8015 $html = parent::output_html($data, $query); 8016 8017 if ((string)$data === $this->yes) { 8018 require_once($CFG->dirroot . "/lib/filelib.php"); 8019 $curl = new curl(); 8020 $httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); //force https url 8021 $curl->head($httpswwwroot . "/login/index.php"); 8022 $info = $curl->get_info(); 8023 if (empty($info['http_code']) or ($info['http_code'] >= 400)) { 8024 $html .= $OUTPUT->notification(get_string('nohttpsformobilewarning', 'admin')); 8025 } 8026 } 8027 8028 return $html; 8029 } 8030 8031 /** 8032 * Retrieves the current setting using the objects name 8033 * 8034 * @return string 8035 */ 8036 public function get_setting() { 8037 global $CFG; 8038 8039 // First check if is not set. 8040 $result = $this->config_read($this->name); 8041 if (is_null($result)) { 8042 return null; 8043 } 8044 8045 // For install cli script, $CFG->defaultuserroleid is not set so return 0 8046 // Or if web services aren't enabled this can't be, 8047 if (empty($CFG->defaultuserroleid) || empty($CFG->enablewebservices)) { 8048 return 0; 8049 } 8050 8051 require_once($CFG->dirroot . '/webservice/lib.php'); 8052 $webservicemanager = new webservice(); 8053 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 8054 if ($mobileservice->enabled and $this->is_protocol_cap_allowed()) { 8055 return $result; 8056 } else { 8057 return 0; 8058 } 8059 } 8060 8061 /** 8062 * Save the selected setting 8063 * 8064 * @param string $data The selected site 8065 * @return string empty string or error message 8066 */ 8067 public function write_setting($data) { 8068 global $DB, $CFG; 8069 8070 //for install cli script, $CFG->defaultuserroleid is not set so do nothing 8071 if (empty($CFG->defaultuserroleid)) { 8072 return ''; 8073 } 8074 8075 $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE; 8076 8077 require_once($CFG->dirroot . '/webservice/lib.php'); 8078 $webservicemanager = new webservice(); 8079 8080 $updateprotocol = false; 8081 if ((string)$data === $this->yes) { 8082 //code run when enable mobile web service 8083 //enable web service systeme if necessary 8084 set_config('enablewebservices', true); 8085 8086 //enable mobile service 8087 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 8088 $mobileservice->enabled = 1; 8089 $webservicemanager->update_external_service($mobileservice); 8090 8091 // Enable REST server. 8092 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); 8093 8094 if (!in_array('rest', $activeprotocols)) { 8095 $activeprotocols[] = 'rest'; 8096 $updateprotocol = true; 8097 } 8098 8099 if ($updateprotocol) { 8100 set_config('webserviceprotocols', implode(',', $activeprotocols)); 8101 } 8102 8103 // Allow rest:use capability for authenticated user. 8104 $this->set_protocol_cap(true); 8105 8106 } else { 8107 //disable web service system if no other services are enabled 8108 $otherenabledservices = $DB->get_records_select('external_services', 8109 'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1, 8110 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 8111 if (empty($otherenabledservices)) { 8112 set_config('enablewebservices', false); 8113 8114 // Also disable REST server. 8115 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); 8116 8117 $protocolkey = array_search('rest', $activeprotocols); 8118 if ($protocolkey !== false) { 8119 unset($activeprotocols[$protocolkey]); 8120 $updateprotocol = true; 8121 } 8122 8123 if ($updateprotocol) { 8124 set_config('webserviceprotocols', implode(',', $activeprotocols)); 8125 } 8126 8127 // Disallow rest:use capability for authenticated user. 8128 $this->set_protocol_cap(false); 8129 } 8130 8131 //disable the mobile service 8132 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 8133 $mobileservice->enabled = 0; 8134 $webservicemanager->update_external_service($mobileservice); 8135 } 8136 8137 return (parent::write_setting($data)); 8138 } 8139 } 8140 8141 /** 8142 * Special class for management of external services 8143 * 8144 * @author Petr Skoda (skodak) 8145 */ 8146 class admin_setting_manageexternalservices extends admin_setting { 8147 /** 8148 * Calls parent::__construct with specific arguments 8149 */ 8150 public function __construct() { 8151 $this->nosave = true; 8152 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', ''); 8153 } 8154 8155 /** 8156 * Always returns true, does nothing 8157 * 8158 * @return true 8159 */ 8160 public function get_setting() { 8161 return true; 8162 } 8163 8164 /** 8165 * Always returns true, does nothing 8166 * 8167 * @return true 8168 */ 8169 public function get_defaultsetting() { 8170 return true; 8171 } 8172 8173 /** 8174 * Always returns '', does not write anything 8175 * 8176 * @return string Always returns '' 8177 */ 8178 public function write_setting($data) { 8179 // do not write any setting 8180 return ''; 8181 } 8182 8183 /** 8184 * Checks if $query is one of the available external services 8185 * 8186 * @param string $query The string to search for 8187 * @return bool Returns true if found, false if not 8188 */ 8189 public function is_related($query) { 8190 global $DB; 8191 8192 if (parent::is_related($query)) { 8193 return true; 8194 } 8195 8196 $services = $DB->get_records('external_services', array(), 'id, name'); 8197 foreach ($services as $service) { 8198 if (strpos(core_text::strtolower($service->name), $query) !== false) { 8199 return true; 8200 } 8201 } 8202 return false; 8203 } 8204 8205 /** 8206 * Builds the XHTML to display the control 8207 * 8208 * @param string $data Unused 8209 * @param string $query 8210 * @return string 8211 */ 8212 public function output_html($data, $query='') { 8213 global $CFG, $OUTPUT, $DB; 8214 8215 // display strings 8216 $stradministration = get_string('administration'); 8217 $stredit = get_string('edit'); 8218 $strservice = get_string('externalservice', 'webservice'); 8219 $strdelete = get_string('delete'); 8220 $strplugin = get_string('plugin', 'admin'); 8221 $stradd = get_string('add'); 8222 $strfunctions = get_string('functions', 'webservice'); 8223 $strusers = get_string('users'); 8224 $strserviceusers = get_string('serviceusers', 'webservice'); 8225 8226 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php"; 8227 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php"; 8228 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php"; 8229 8230 // built in services 8231 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name'); 8232 $return = ""; 8233 if (!empty($services)) { 8234 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main'); 8235 8236 8237 8238 $table = new html_table(); 8239 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit); 8240 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign '); 8241 $table->id = 'builtinservices'; 8242 $table->attributes['class'] = 'admintable externalservices generaltable'; 8243 $table->data = array(); 8244 8245 // iterate through auth plugins and add to the display table 8246 foreach ($services as $service) { 8247 $name = $service->name; 8248 8249 // hide/show link 8250 if ($service->enabled) { 8251 $displayname = "<span>$name</span>"; 8252 } else { 8253 $displayname = "<span class=\"dimmed_text\">$name</span>"; 8254 } 8255 8256 $plugin = $service->component; 8257 8258 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>"; 8259 8260 if ($service->restrictedusers) { 8261 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>"; 8262 } else { 8263 $users = get_string('allusers', 'webservice'); 8264 } 8265 8266 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>"; 8267 8268 // add a row to the table 8269 $table->data[] = array($displayname, $plugin, $functions, $users, $edit); 8270 } 8271 $return .= html_writer::table($table); 8272 } 8273 8274 // Custom services 8275 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main'); 8276 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name'); 8277 8278 $table = new html_table(); 8279 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit); 8280 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign '); 8281 $table->id = 'customservices'; 8282 $table->attributes['class'] = 'admintable externalservices generaltable'; 8283 $table->data = array(); 8284 8285 // iterate through auth plugins and add to the display table 8286 foreach ($services as $service) { 8287 $name = $service->name; 8288 8289 // hide/show link 8290 if ($service->enabled) { 8291 $displayname = "<span>$name</span>"; 8292 } else { 8293 $displayname = "<span class=\"dimmed_text\">$name</span>"; 8294 } 8295 8296 // delete link 8297 $delete = "<a href=\"$esurl?action=delete&sesskey=".sesskey()."&id=$service->id\">$strdelete</a>"; 8298 8299 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>"; 8300 8301 if ($service->restrictedusers) { 8302 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>"; 8303 } else { 8304 $users = get_string('allusers', 'webservice'); 8305 } 8306 8307 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>"; 8308 8309 // add a row to the table 8310 $table->data[] = array($displayname, $delete, $functions, $users, $edit); 8311 } 8312 // add new custom service option 8313 $return .= html_writer::table($table); 8314 8315 $return .= '<br />'; 8316 // add a token to the table 8317 $return .= "<a href=\"$esurl?id=0\">$stradd</a>"; 8318 8319 return highlight($query, $return); 8320 } 8321 } 8322 8323 /** 8324 * Special class for overview of external services 8325 * 8326 * @author Jerome Mouneyrac 8327 */ 8328 class admin_setting_webservicesoverview extends admin_setting { 8329 8330 /** 8331 * Calls parent::__construct with specific arguments 8332 */ 8333 public function __construct() { 8334 $this->nosave = true; 8335 parent::__construct('webservicesoverviewui', 8336 get_string('webservicesoverview', 'webservice'), '', ''); 8337 } 8338 8339 /** 8340 * Always returns true, does nothing 8341 * 8342 * @return true 8343 */ 8344 public function get_setting() { 8345 return true; 8346 } 8347 8348 /** 8349 * Always returns true, does nothing 8350 * 8351 * @return true 8352 */ 8353 public function get_defaultsetting() { 8354 return true; 8355 } 8356 8357 /** 8358 * Always returns '', does not write anything 8359 * 8360 * @return string Always returns '' 8361 */ 8362 public function write_setting($data) { 8363 // do not write any setting 8364 return ''; 8365 } 8366 8367 /** 8368 * Builds the XHTML to display the control 8369 * 8370 * @param string $data Unused 8371 * @param string $query 8372 * @return string 8373 */ 8374 public function output_html($data, $query='') { 8375 global $CFG, $OUTPUT; 8376 8377 $return = ""; 8378 $brtag = html_writer::empty_tag('br'); 8379 8380 // Enable mobile web service 8381 $enablemobile = new admin_setting_enablemobileservice('enablemobilewebservice', 8382 get_string('enablemobilewebservice', 'admin'), 8383 get_string('configenablemobilewebservice', 8384 'admin', ''), 0); //we don't want to display it but to know the ws mobile status 8385 $manageserviceurl = new moodle_url("/admin/settings.php?section=mobile"); 8386 $wsmobileparam = new stdClass(); 8387 $wsmobileparam->enablemobileservice = get_string('enablemobilewebservice', 'admin'); 8388 $wsmobileparam->manageservicelink = html_writer::link($manageserviceurl, 8389 get_string('mobile', 'admin')); 8390 $mobilestatus = $enablemobile->get_setting()?get_string('mobilewsenabled', 'webservice'):get_string('mobilewsdisabled', 'webservice'); 8391 $wsmobileparam->wsmobilestatus = html_writer::tag('strong', $mobilestatus); 8392 $return .= $OUTPUT->heading(get_string('enablemobilewebservice', 'admin'), 3, 'main'); 8393 $return .= $brtag . get_string('enablemobilewsoverview', 'webservice', $wsmobileparam) 8394 . $brtag . $brtag; 8395 8396 /// One system controlling Moodle with Token 8397 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main'); 8398 $table = new html_table(); 8399 $table->head = array(get_string('step', 'webservice'), get_string('status'), 8400 get_string('description')); 8401 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description'); 8402 $table->id = 'onesystemcontrol'; 8403 $table->attributes['class'] = 'admintable wsoverview generaltable'; 8404 $table->data = array(); 8405 8406 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice') 8407 . $brtag . $brtag; 8408 8409 /// 1. Enable Web Services 8410 $row = array(); 8411 $url = new moodle_url("/admin/search.php?query=enablewebservices"); 8412 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'), 8413 array('href' => $url)); 8414 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 8415 if ($CFG->enablewebservices) { 8416 $status = get_string('yes'); 8417 } 8418 $row[1] = $status; 8419 $row[2] = get_string('enablewsdescription', 'webservice'); 8420 $table->data[] = $row; 8421 8422 /// 2. Enable protocols 8423 $row = array(); 8424 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols"); 8425 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'), 8426 array('href' => $url)); 8427 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical')); 8428 //retrieve activated protocol 8429 $active_protocols = empty($CFG->webserviceprotocols) ? 8430 array() : explode(',', $CFG->webserviceprotocols); 8431 if (!empty($active_protocols)) { 8432 $status = ""; 8433 foreach ($active_protocols as $protocol) { 8434 $status .= $protocol . $brtag; 8435 } 8436 } 8437 $row[1] = $status; 8438 $row[2] = get_string('enableprotocolsdescription', 'webservice'); 8439 $table->data[] = $row; 8440 8441 /// 3. Create user account 8442 $row = array(); 8443 $url = new moodle_url("/user/editadvanced.php?id=-1"); 8444 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'), 8445 array('href' => $url)); 8446 $row[1] = ""; 8447 $row[2] = get_string('createuserdescription', 'webservice'); 8448 $table->data[] = $row; 8449 8450 /// 4. Add capability to users 8451 $row = array(); 8452 $url = new moodle_url("/admin/roles/check.php?contextid=1"); 8453 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'), 8454 array('href' => $url)); 8455 $row[1] = ""; 8456 $row[2] = get_string('checkusercapabilitydescription', 'webservice'); 8457 $table->data[] = $row; 8458 8459 /// 5. Select a web service 8460 $row = array(); 8461 $url = new moodle_url("/admin/settings.php?section=externalservices"); 8462 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'), 8463 array('href' => $url)); 8464 $row[1] = ""; 8465 $row[2] = get_string('createservicedescription', 'webservice'); 8466 $table->data[] = $row; 8467 8468 /// 6. Add functions 8469 $row = array(); 8470 $url = new moodle_url("/admin/settings.php?section=externalservices"); 8471 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'), 8472 array('href' => $url)); 8473 $row[1] = ""; 8474 $row[2] = get_string('addfunctionsdescription', 'webservice'); 8475 $table->data[] = $row; 8476 8477 /// 7. Add the specific user 8478 $row = array(); 8479 $url = new moodle_url("/admin/settings.php?section=externalservices"); 8480 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'), 8481 array('href' => $url)); 8482 $row[1] = ""; 8483 $row[2] = get_string('selectspecificuserdescription', 'webservice'); 8484 $table->data[] = $row; 8485 8486 /// 8. Create token for the specific user 8487 $row = array(); 8488 $url = new moodle_url("/admin/webservice/tokens.php?sesskey=" . sesskey() . "&action=create"); 8489 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'), 8490 array('href' => $url)); 8491 $row[1] = ""; 8492 $row[2] = get_string('createtokenforuserdescription', 'webservice'); 8493 $table->data[] = $row; 8494 8495 /// 9. Enable the documentation 8496 $row = array(); 8497 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation"); 8498 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'), 8499 array('href' => $url)); 8500 $status = '<span class="warning">' . get_string('no') . '</span>'; 8501 if ($CFG->enablewsdocumentation) { 8502 $status = get_string('yes'); 8503 } 8504 $row[1] = $status; 8505 $row[2] = get_string('enabledocumentationdescription', 'webservice'); 8506 $table->data[] = $row; 8507 8508 /// 10. Test the service 8509 $row = array(); 8510 $url = new moodle_url("/admin/webservice/testclient.php"); 8511 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'), 8512 array('href' => $url)); 8513 $row[1] = ""; 8514 $row[2] = get_string('testwithtestclientdescription', 'webservice'); 8515 $table->data[] = $row; 8516 8517 $return .= html_writer::table($table); 8518 8519 /// Users as clients with token 8520 $return .= $brtag . $brtag . $brtag; 8521 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main'); 8522 $table = new html_table(); 8523 $table->head = array(get_string('step', 'webservice'), get_string('status'), 8524 get_string('description')); 8525 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description'); 8526 $table->id = 'userasclients'; 8527 $table->attributes['class'] = 'admintable wsoverview generaltable'; 8528 $table->data = array(); 8529 8530 $return .= $brtag . get_string('userasclientsdescription', 'webservice') . 8531 $brtag . $brtag; 8532 8533 /// 1. Enable Web Services 8534 $row = array(); 8535 $url = new moodle_url("/admin/search.php?query=enablewebservices"); 8536 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'), 8537 array('href' => $url)); 8538 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 8539 if ($CFG->enablewebservices) { 8540 $status = get_string('yes'); 8541 } 8542 $row[1] = $status; 8543 $row[2] = get_string('enablewsdescription', 'webservice'); 8544 $table->data[] = $row; 8545 8546 /// 2. Enable protocols 8547 $row = array(); 8548 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols"); 8549 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'), 8550 array('href' => $url)); 8551 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical')); 8552 //retrieve activated protocol 8553 $active_protocols = empty($CFG->webserviceprotocols) ? 8554 array() : explode(',', $CFG->webserviceprotocols); 8555 if (!empty($active_protocols)) { 8556 $status = ""; 8557 foreach ($active_protocols as $protocol) { 8558 $status .= $protocol . $brtag; 8559 } 8560 } 8561 $row[1] = $status; 8562 $row[2] = get_string('enableprotocolsdescription', 'webservice'); 8563 $table->data[] = $row; 8564 8565 8566 /// 3. Select a web service 8567 $row = array(); 8568 $url = new moodle_url("/admin/settings.php?section=externalservices"); 8569 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'), 8570 array('href' => $url)); 8571 $row[1] = ""; 8572 $row[2] = get_string('createserviceforusersdescription', 'webservice'); 8573 $table->data[] = $row; 8574 8575 /// 4. Add functions 8576 $row = array(); 8577 $url = new moodle_url("/admin/settings.php?section=externalservices"); 8578 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'), 8579 array('href' => $url)); 8580 $row[1] = ""; 8581 $row[2] = get_string('addfunctionsdescription', 'webservice'); 8582 $table->data[] = $row; 8583 8584 /// 5. Add capability to users 8585 $row = array(); 8586 $url = new moodle_url("/admin/roles/check.php?contextid=1"); 8587 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'), 8588 array('href' => $url)); 8589 $row[1] = ""; 8590 $row[2] = get_string('addcapabilitytousersdescription', 'webservice'); 8591 $table->data[] = $row; 8592 8593 /// 6. Test the service 8594 $row = array(); 8595 $url = new moodle_url("/admin/webservice/testclient.php"); 8596 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'), 8597 array('href' => $url)); 8598 $row[1] = ""; 8599 $row[2] = get_string('testauserwithtestclientdescription', 'webservice'); 8600 $table->data[] = $row; 8601 8602 $return .= html_writer::table($table); 8603 8604 return highlight($query, $return); 8605 } 8606 8607 } 8608 8609 8610 /** 8611 * Special class for web service protocol administration. 8612 * 8613 * @author Petr Skoda (skodak) 8614 */ 8615 class admin_setting_managewebserviceprotocols extends admin_setting { 8616 8617 /** 8618 * Calls parent::__construct with specific arguments 8619 */ 8620 public function __construct() { 8621 $this->nosave = true; 8622 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', ''); 8623 } 8624 8625 /** 8626 * Always returns true, does nothing 8627 * 8628 * @return true 8629 */ 8630 public function get_setting() { 8631 return true; 8632 } 8633 8634 /** 8635 * Always returns true, does nothing 8636 * 8637 * @return true 8638 */ 8639 public function get_defaultsetting() { 8640 return true; 8641 } 8642 8643 /** 8644 * Always returns '', does not write anything 8645 * 8646 * @return string Always returns '' 8647 */ 8648 public function write_setting($data) { 8649 // do not write any setting 8650 return ''; 8651 } 8652 8653 /** 8654 * Checks if $query is one of the available webservices 8655 * 8656 * @param string $query The string to search for 8657 * @return bool Returns true if found, false if not 8658 */ 8659 public function is_related($query) { 8660 if (parent::is_related($query)) { 8661 return true; 8662 } 8663 8664 $protocols = core_component::get_plugin_list('webservice'); 8665 foreach ($protocols as $protocol=>$location) { 8666 if (strpos($protocol, $query) !== false) { 8667 return true; 8668 } 8669 $protocolstr = get_string('pluginname', 'webservice_'.$protocol); 8670 if (strpos(core_text::strtolower($protocolstr), $query) !== false) { 8671 return true; 8672 } 8673 } 8674 return false; 8675 } 8676 8677 /** 8678 * Builds the XHTML to display the control 8679 * 8680 * @param string $data Unused 8681 * @param string $query 8682 * @return string 8683 */ 8684 public function output_html($data, $query='') { 8685 global $CFG, $OUTPUT; 8686 8687 // display strings 8688 $stradministration = get_string('administration'); 8689 $strsettings = get_string('settings'); 8690 $stredit = get_string('edit'); 8691 $strprotocol = get_string('protocol', 'webservice'); 8692 $strenable = get_string('enable'); 8693 $strdisable = get_string('disable'); 8694 $strversion = get_string('version'); 8695 8696 $protocols_available = core_component::get_plugin_list('webservice'); 8697 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); 8698 ksort($protocols_available); 8699 8700 foreach ($active_protocols as $key=>$protocol) { 8701 if (empty($protocols_available[$protocol])) { 8702 unset($active_protocols[$key]); 8703 } 8704 } 8705 8706 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main'); 8707 $return .= $OUTPUT->box_start('generalbox webservicesui'); 8708 8709 $table = new html_table(); 8710 $table->head = array($strprotocol, $strversion, $strenable, $strsettings); 8711 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); 8712 $table->id = 'webserviceprotocols'; 8713 $table->attributes['class'] = 'admintable generaltable'; 8714 $table->data = array(); 8715 8716 // iterate through auth plugins and add to the display table 8717 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey(); 8718 foreach ($protocols_available as $protocol => $location) { 8719 $name = get_string('pluginname', 'webservice_'.$protocol); 8720 8721 $plugin = new stdClass(); 8722 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) { 8723 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php'); 8724 } 8725 $version = isset($plugin->version) ? $plugin->version : ''; 8726 8727 // hide/show link 8728 if (in_array($protocol, $active_protocols)) { 8729 $hideshow = "<a href=\"$url&action=disable&webservice=$protocol\">"; 8730 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"$strdisable\" /></a>"; 8731 $displayname = "<span>$name</span>"; 8732 } else { 8733 $hideshow = "<a href=\"$url&action=enable&webservice=$protocol\">"; 8734 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"$strenable\" /></a>"; 8735 $displayname = "<span class=\"dimmed_text\">$name</span>"; 8736 } 8737 8738 // settings link 8739 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) { 8740 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>"; 8741 } else { 8742 $settings = ''; 8743 } 8744 8745 // add a row to the table 8746 $table->data[] = array($displayname, $version, $hideshow, $settings); 8747 } 8748 $return .= html_writer::table($table); 8749 $return .= get_string('configwebserviceplugins', 'webservice'); 8750 $return .= $OUTPUT->box_end(); 8751 8752 return highlight($query, $return); 8753 } 8754 } 8755 8756 8757 /** 8758 * Special class for web service token administration. 8759 * 8760 * @author Jerome Mouneyrac 8761 */ 8762 class admin_setting_managewebservicetokens extends admin_setting { 8763 8764 /** 8765 * Calls parent::__construct with specific arguments 8766 */ 8767 public function __construct() { 8768 $this->nosave = true; 8769 parent::__construct('webservicestokenui', get_string('managetokens', 'webservice'), '', ''); 8770 } 8771 8772 /** 8773 * Always returns true, does nothing 8774 * 8775 * @return true 8776 */ 8777 public function get_setting() { 8778 return true; 8779 } 8780 8781 /** 8782 * Always returns true, does nothing 8783 * 8784 * @return true 8785 */ 8786 public function get_defaultsetting() { 8787 return true; 8788 } 8789 8790 /** 8791 * Always returns '', does not write anything 8792 * 8793 * @return string Always returns '' 8794 */ 8795 public function write_setting($data) { 8796 // do not write any setting 8797 return ''; 8798 } 8799 8800 /** 8801 * Builds the XHTML to display the control 8802 * 8803 * @param string $data Unused 8804 * @param string $query 8805 * @return string 8806 */ 8807 public function output_html($data, $query='') { 8808 global $CFG, $OUTPUT, $DB, $USER; 8809 8810 // display strings 8811 $stroperation = get_string('operation', 'webservice'); 8812 $strtoken = get_string('token', 'webservice'); 8813 $strservice = get_string('service', 'webservice'); 8814 $struser = get_string('user'); 8815 $strcontext = get_string('context', 'webservice'); 8816 $strvaliduntil = get_string('validuntil', 'webservice'); 8817 $striprestriction = get_string('iprestriction', 'webservice'); 8818 8819 $return = $OUTPUT->box_start('generalbox webservicestokenui'); 8820 8821 $table = new html_table(); 8822 $table->head = array($strtoken, $struser, $strservice, $striprestriction, $strvaliduntil, $stroperation); 8823 $table->colclasses = array('leftalign', 'leftalign', 'leftalign', 'centeralign', 'centeralign', 'centeralign'); 8824 $table->id = 'webservicetokens'; 8825 $table->attributes['class'] = 'admintable generaltable'; 8826 $table->data = array(); 8827 8828 $tokenpageurl = "$CFG->wwwroot/$CFG->admin/webservice/tokens.php?sesskey=" . sesskey(); 8829 8830 //TODO: in order to let the administrator delete obsolete token, split this request in multiple request or use LEFT JOIN 8831 8832 //here retrieve token list (including linked users firstname/lastname and linked services name) 8833 $sql = "SELECT t.id, t.token, u.id AS userid, u.firstname, u.lastname, s.name, t.iprestriction, t.validuntil, s.id AS serviceid 8834 FROM {external_tokens} t, {user} u, {external_services} s 8835 WHERE t.creatorid=? AND t.tokentype = ? AND s.id = t.externalserviceid AND t.userid = u.id"; 8836 $tokens = $DB->get_records_sql($sql, array($USER->id, EXTERNAL_TOKEN_PERMANENT)); 8837 if (!empty($tokens)) { 8838 foreach ($tokens as $token) { 8839 //TODO: retrieve context 8840 8841 $delete = "<a href=\"".$tokenpageurl."&action=delete&tokenid=".$token->id."\">"; 8842 $delete .= get_string('delete')."</a>"; 8843 8844 $validuntil = ''; 8845 if (!empty($token->validuntil)) { 8846 $validuntil = userdate($token->validuntil, get_string('strftimedatetime', 'langconfig')); 8847 } 8848 8849 $iprestriction = ''; 8850 if (!empty($token->iprestriction)) { 8851 $iprestriction = $token->iprestriction; 8852 } 8853 8854 $userprofilurl = new moodle_url('/user/profile.php?id='.$token->userid); 8855 $useratag = html_writer::start_tag('a', array('href' => $userprofilurl)); 8856 $useratag .= $token->firstname." ".$token->lastname; 8857 $useratag .= html_writer::end_tag('a'); 8858 8859 //check user missing capabilities 8860 require_once($CFG->dirroot . '/webservice/lib.php'); 8861 $webservicemanager = new webservice(); 8862 $usermissingcaps = $webservicemanager->get_missing_capabilities_by_users( 8863 array(array('id' => $token->userid)), $token->serviceid); 8864 8865 if (!is_siteadmin($token->userid) and 8866 array_key_exists($token->userid, $usermissingcaps)) { 8867 $missingcapabilities = implode(', ', 8868 $usermissingcaps[$token->userid]); 8869 if (!empty($missingcapabilities)) { 8870 $useratag .= html_writer::tag('div', 8871 get_string('usermissingcaps', 'webservice', 8872 $missingcapabilities) 8873 . ' ' . $OUTPUT->help_icon('missingcaps', 'webservice'), 8874 array('class' => 'missingcaps')); 8875 } 8876 } 8877 8878 $table->data[] = array($token->token, $useratag, $token->name, $iprestriction, $validuntil, $delete); 8879 } 8880 8881 $return .= html_writer::table($table); 8882 } else { 8883 $return .= get_string('notoken', 'webservice'); 8884 } 8885 8886 $return .= $OUTPUT->box_end(); 8887 // add a token to the table 8888 $return .= "<a href=\"".$tokenpageurl."&action=create\">"; 8889 $return .= get_string('add')."</a>"; 8890 8891 return highlight($query, $return); 8892 } 8893 } 8894 8895 8896 /** 8897 * Colour picker 8898 * 8899 * @copyright 2010 Sam Hemelryk 8900 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8901 */ 8902 class admin_setting_configcolourpicker extends admin_setting { 8903 8904 /** 8905 * Information for previewing the colour 8906 * 8907 * @var array|null 8908 */ 8909 protected $previewconfig = null; 8910 8911 /** 8912 * Use default when empty. 8913 */ 8914 protected $usedefaultwhenempty = true; 8915 8916 /** 8917 * 8918 * @param string $name 8919 * @param string $visiblename 8920 * @param string $description 8921 * @param string $defaultsetting 8922 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor'); 8923 */ 8924 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig = null, 8925 $usedefaultwhenempty = true) { 8926 $this->previewconfig = $previewconfig; 8927 $this->usedefaultwhenempty = $usedefaultwhenempty; 8928 parent::__construct($name, $visiblename, $description, $defaultsetting); 8929 } 8930 8931 /** 8932 * Return the setting 8933 * 8934 * @return mixed returns config if successful else null 8935 */ 8936 public function get_setting() { 8937 return $this->config_read($this->name); 8938 } 8939 8940 /** 8941 * Saves the setting 8942 * 8943 * @param string $data 8944 * @return bool 8945 */ 8946 public function write_setting($data) { 8947 $data = $this->validate($data); 8948 if ($data === false) { 8949 return get_string('validateerror', 'admin'); 8950 } 8951 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 8952 } 8953 8954 /** 8955 * Validates the colour that was entered by the user 8956 * 8957 * @param string $data 8958 * @return string|false 8959 */ 8960 protected function validate($data) { 8961 /** 8962 * List of valid HTML colour names 8963 * 8964 * @var array 8965 */ 8966 $colornames = array( 8967 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 8968 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 8969 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 8970 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 8971 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 8972 'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta', 8973 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 8974 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 8975 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 8976 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 8977 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 8978 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green', 8979 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 8980 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 8981 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 8982 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen', 8983 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 8984 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 8985 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 8986 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 8987 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 8988 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 8989 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 8990 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 8991 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 8992 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red', 8993 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 8994 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 8995 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 8996 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 8997 'whitesmoke', 'yellow', 'yellowgreen' 8998 ); 8999 9000 if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $data)) { 9001 if (strpos($data, '#')!==0) { 9002 $data = '#'.$data; 9003 } 9004 return $data; 9005 } else if (in_array(strtolower($data), $colornames)) { 9006 return $data; 9007 } else if (preg_match('/rgb\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\)/i', $data)) { 9008 return $data; 9009 } else if (preg_match('/rgba\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\, ?\d(\.\d)?\)/i', $data)) { 9010 return $data; 9011 } else if (preg_match('/hsl\(\d{0,3}\, ?\d{0,3}%, ?\d{0,3}%\)/i', $data)) { 9012 return $data; 9013 } else if (preg_match('/hsla\(\d{0,3}\, ?\d{0,3}%,\d{0,3}%\, ?\d(\.\d)?\)/i', $data)) { 9014 return $data; 9015 } else if (($data == 'transparent') || ($data == 'currentColor') || ($data == 'inherit')) { 9016 return $data; 9017 } else if (empty($data)) { 9018 if ($this->usedefaultwhenempty){ 9019 return $this->defaultsetting; 9020 } else { 9021 return ''; 9022 } 9023 } else { 9024 return false; 9025 } 9026 } 9027 9028 /** 9029 * Generates the HTML for the setting 9030 * 9031 * @global moodle_page $PAGE 9032 * @global core_renderer $OUTPUT 9033 * @param string $data 9034 * @param string $query 9035 */ 9036 public function output_html($data, $query = '') { 9037 global $PAGE, $OUTPUT; 9038 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig)); 9039 $content = html_writer::start_tag('div', array('class'=>'form-colourpicker defaultsnext')); 9040 $content .= html_writer::tag('div', $OUTPUT->pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', array('class'=>'loadingicon')), array('class'=>'admin_colourpicker clearfix')); 9041 $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$data, 'size'=>'12')); 9042 if (!empty($this->previewconfig)) { 9043 $content .= html_writer::empty_tag('input', array('type'=>'button','id'=>$this->get_id().'_preview', 'value'=>get_string('preview'), 'class'=>'admin_colourpicker_preview')); 9044 } 9045 $content .= html_writer::end_tag('div'); 9046 return format_admin_setting($this, $this->visiblename, $content, $this->description, true, '', $this->get_defaultsetting(), $query); 9047 } 9048 } 9049 9050 9051 /** 9052 * Class used for uploading of one file into file storage, 9053 * the file name is stored in config table. 9054 * 9055 * Please note you need to implement your own '_pluginfile' callback function, 9056 * this setting only stores the file, it does not deal with file serving. 9057 * 9058 * @copyright 2013 Petr Skoda {@link http://skodak.org} 9059 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9060 */ 9061 class admin_setting_configstoredfile extends admin_setting { 9062 /** @var array file area options - should be one file only */ 9063 protected $options; 9064 /** @var string name of the file area */ 9065 protected $filearea; 9066 /** @var int intemid */ 9067 protected $itemid; 9068 /** @var string used for detection of changes */ 9069 protected $oldhashes; 9070 9071 /** 9072 * Create new stored file setting. 9073 * 9074 * @param string $name low level setting name 9075 * @param string $visiblename human readable setting name 9076 * @param string $description description of setting 9077 * @param mixed $filearea file area for file storage 9078 * @param int $itemid itemid for file storage 9079 * @param array $options file area options 9080 */ 9081 public function __construct($name, $visiblename, $description, $filearea, $itemid = 0, array $options = null) { 9082 parent::__construct($name, $visiblename, $description, ''); 9083 $this->filearea = $filearea; 9084 $this->itemid = $itemid; 9085 $this->options = (array)$options; 9086 } 9087 9088 /** 9089 * Applies defaults and returns all options. 9090 * @return array 9091 */ 9092 protected function get_options() { 9093 global $CFG; 9094 9095 require_once("$CFG->libdir/filelib.php"); 9096 require_once("$CFG->dirroot/repository/lib.php"); 9097 $defaults = array( 9098 'mainfile' => '', 'subdirs' => 0, 'maxbytes' => -1, 'maxfiles' => 1, 9099 'accepted_types' => '*', 'return_types' => FILE_INTERNAL, 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 9100 'context' => context_system::instance()); 9101 foreach($this->options as $k => $v) { 9102 $defaults[$k] = $v; 9103 } 9104 9105 return $defaults; 9106 } 9107 9108 public function get_setting() { 9109 return $this->config_read($this->name); 9110 } 9111 9112 public function write_setting($data) { 9113 global $USER; 9114 9115 // Let's not deal with validation here, this is for admins only. 9116 $current = $this->get_setting(); 9117 if (empty($data) && $current === null) { 9118 // This will be the case when applying default settings (installation). 9119 return ($this->config_write($this->name, '') ? '' : get_string('errorsetting', 'admin')); 9120 } else if (!is_number($data)) { 9121 // Draft item id is expected here! 9122 return get_string('errorsetting', 'admin'); 9123 } 9124 9125 $options = $this->get_options(); 9126 $fs = get_file_storage(); 9127 $component = is_null($this->plugin) ? 'core' : $this->plugin; 9128 9129 $this->oldhashes = null; 9130 if ($current) { 9131 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current); 9132 if ($file = $fs->get_file_by_hash($hash)) { 9133 $this->oldhashes = $file->get_contenthash().$file->get_pathnamehash(); 9134 } 9135 unset($file); 9136 } 9137 9138 if ($fs->file_exists($options['context']->id, $component, $this->filearea, $this->itemid, '/', '.')) { 9139 // Make sure the settings form was not open for more than 4 days and draft areas deleted in the meantime. 9140 // But we can safely ignore that if the destination area is empty, so that the user is not prompt 9141 // with an error because the draft area does not exist, as he did not use it. 9142 $usercontext = context_user::instance($USER->id); 9143 if (!$fs->file_exists($usercontext->id, 'user', 'draft', $data, '/', '.') && $current !== '') { 9144 return get_string('errorsetting', 'admin'); 9145 } 9146 } 9147 9148 file_save_draft_area_files($data, $options['context']->id, $component, $this->filearea, $this->itemid, $options); 9149 $files = $fs->get_area_files($options['context']->id, $component, $this->filearea, $this->itemid, 'sortorder,filepath,filename', false); 9150 9151 $filepath = ''; 9152 if ($files) { 9153 /** @var stored_file $file */ 9154 $file = reset($files); 9155 $filepath = $file->get_filepath().$file->get_filename(); 9156 } 9157 9158 return ($this->config_write($this->name, $filepath) ? '' : get_string('errorsetting', 'admin')); 9159 } 9160 9161 public function post_write_settings($original) { 9162 $options = $this->get_options(); 9163 $fs = get_file_storage(); 9164 $component = is_null($this->plugin) ? 'core' : $this->plugin; 9165 9166 $current = $this->get_setting(); 9167 $newhashes = null; 9168 if ($current) { 9169 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current); 9170 if ($file = $fs->get_file_by_hash($hash)) { 9171 $newhashes = $file->get_contenthash().$file->get_pathnamehash(); 9172 } 9173 unset($file); 9174 } 9175 9176 if ($this->oldhashes === $newhashes) { 9177 $this->oldhashes = null; 9178 return false; 9179 } 9180 $this->oldhashes = null; 9181 9182 $callbackfunction = $this->updatedcallback; 9183 if (!empty($callbackfunction) and function_exists($callbackfunction)) { 9184 $callbackfunction($this->get_full_name()); 9185 } 9186 return true; 9187 } 9188 9189 public function output_html($data, $query = '') { 9190 global $PAGE, $CFG; 9191 9192 $options = $this->get_options(); 9193 $id = $this->get_id(); 9194 $elname = $this->get_full_name(); 9195 $draftitemid = file_get_submitted_draft_itemid($elname); 9196 $component = is_null($this->plugin) ? 'core' : $this->plugin; 9197 file_prepare_draft_area($draftitemid, $options['context']->id, $component, $this->filearea, $this->itemid, $options); 9198 9199 // Filemanager form element implementation is far from optimal, we need to rework this if we ever fix it... 9200 require_once("$CFG->dirroot/lib/form/filemanager.php"); 9201 9202 $fmoptions = new stdClass(); 9203 $fmoptions->mainfile = $options['mainfile']; 9204 $fmoptions->maxbytes = $options['maxbytes']; 9205 $fmoptions->maxfiles = $options['maxfiles']; 9206 $fmoptions->client_id = uniqid(); 9207 $fmoptions->itemid = $draftitemid; 9208 $fmoptions->subdirs = $options['subdirs']; 9209 $fmoptions->target = $id; 9210 $fmoptions->accepted_types = $options['accepted_types']; 9211 $fmoptions->return_types = $options['return_types']; 9212 $fmoptions->context = $options['context']; 9213 $fmoptions->areamaxbytes = $options['areamaxbytes']; 9214 9215 $fm = new form_filemanager($fmoptions); 9216 $output = $PAGE->get_renderer('core', 'files'); 9217 $html = $output->render($fm); 9218 9219 $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />'; 9220 $html .= '<input value="" id="'.$id.'" type="hidden" />'; 9221 9222 return format_admin_setting($this, $this->visiblename, 9223 '<div class="form-filemanager">'.$html.'</div>', $this->description, true, '', '', $query); 9224 } 9225 } 9226 9227 9228 /** 9229 * Administration interface for user specified regular expressions for device detection. 9230 * 9231 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9232 */ 9233 class admin_setting_devicedetectregex extends admin_setting { 9234 9235 /** 9236 * Calls parent::__construct with specific args 9237 * 9238 * @param string $name 9239 * @param string $visiblename 9240 * @param string $description 9241 * @param mixed $defaultsetting 9242 */ 9243 public function __construct($name, $visiblename, $description, $defaultsetting = '') { 9244 global $CFG; 9245 parent::__construct($name, $visiblename, $description, $defaultsetting); 9246 } 9247 9248 /** 9249 * Return the current setting(s) 9250 * 9251 * @return array Current settings array 9252 */ 9253 public function get_setting() { 9254 global $CFG; 9255 9256 $config = $this->config_read($this->name); 9257 if (is_null($config)) { 9258 return null; 9259 } 9260 9261 return $this->prepare_form_data($config); 9262 } 9263 9264 /** 9265 * Save selected settings 9266 * 9267 * @param array $data Array of settings to save 9268 * @return bool 9269 */ 9270 public function write_setting($data) { 9271 if (empty($data)) { 9272 $data = array(); 9273 } 9274 9275 if ($this->config_write($this->name, $this->process_form_data($data))) { 9276 return ''; // success 9277 } else { 9278 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br'); 9279 } 9280 } 9281 9282 /** 9283 * Return XHTML field(s) for regexes 9284 * 9285 * @param array $data Array of options to set in HTML 9286 * @return string XHTML string for the fields and wrapping div(s) 9287 */ 9288 public function output_html($data, $query='') { 9289 global $OUTPUT; 9290 9291 $out = html_writer::start_tag('table', array('class' => 'generaltable')); 9292 $out .= html_writer::start_tag('thead'); 9293 $out .= html_writer::start_tag('tr'); 9294 $out .= html_writer::tag('th', get_string('devicedetectregexexpression', 'admin')); 9295 $out .= html_writer::tag('th', get_string('devicedetectregexvalue', 'admin')); 9296 $out .= html_writer::end_tag('tr'); 9297 $out .= html_writer::end_tag('thead'); 9298 $out .= html_writer::start_tag('tbody'); 9299 9300 if (empty($data)) { 9301 $looplimit = 1; 9302 } else { 9303 $looplimit = (count($data)/2)+1; 9304 } 9305 9306 for ($i=0; $i<$looplimit; $i++) { 9307 $out .= html_writer::start_tag('tr'); 9308 9309 $expressionname = 'expression'.$i; 9310 9311 if (!empty($data[$expressionname])){ 9312 $expression = $data[$expressionname]; 9313 } else { 9314 $expression = ''; 9315 } 9316 9317 $out .= html_writer::tag('td', 9318 html_writer::empty_tag('input', 9319 array( 9320 'type' => 'text', 9321 'class' => 'form-text', 9322 'name' => $this->get_full_name().'[expression'.$i.']', 9323 'value' => $expression, 9324 ) 9325 ), array('class' => 'c'.$i) 9326 ); 9327 9328 $valuename = 'value'.$i; 9329 9330 if (!empty($data[$valuename])){ 9331 $value = $data[$valuename]; 9332 } else { 9333 $value= ''; 9334 } 9335 9336 $out .= html_writer::tag('td', 9337 html_writer::empty_tag('input', 9338 array( 9339 'type' => 'text', 9340 'class' => 'form-text', 9341 'name' => $this->get_full_name().'[value'.$i.']', 9342 'value' => $value, 9343 ) 9344 ), array('class' => 'c'.$i) 9345 ); 9346 9347 $out .= html_writer::end_tag('tr'); 9348 } 9349 9350 $out .= html_writer::end_tag('tbody'); 9351 $out .= html_writer::end_tag('table'); 9352 9353 return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', null, $query); 9354 } 9355 9356 /** 9357 * Converts the string of regexes 9358 * 9359 * @see self::process_form_data() 9360 * @param $regexes string of regexes 9361 * @return array of form fields and their values 9362 */ 9363 protected function prepare_form_data($regexes) { 9364 9365 $regexes = json_decode($regexes); 9366 9367 $form = array(); 9368 9369 $i = 0; 9370 9371 foreach ($regexes as $value => $regex) { 9372 $expressionname = 'expression'.$i; 9373 $valuename = 'value'.$i; 9374 9375 $form[$expressionname] = $regex; 9376 $form[$valuename] = $value; 9377 $i++; 9378 } 9379 9380 return $form; 9381 } 9382 9383 /** 9384 * Converts the data from admin settings form into a string of regexes 9385 * 9386 * @see self::prepare_form_data() 9387 * @param array $data array of admin form fields and values 9388 * @return false|string of regexes 9389 */ 9390 protected function process_form_data(array $form) { 9391 9392 $count = count($form); // number of form field values 9393 9394 if ($count % 2) { 9395 // we must get five fields per expression 9396 return false; 9397 } 9398 9399 $regexes = array(); 9400 for ($i = 0; $i < $count / 2; $i++) { 9401 $expressionname = "expression".$i; 9402 $valuename = "value".$i; 9403 9404 $expression = trim($form['expression'.$i]); 9405 $value = trim($form['value'.$i]); 9406 9407 if (empty($expression)){ 9408 continue; 9409 } 9410 9411 $regexes[$value] = $expression; 9412 } 9413 9414 $regexes = json_encode($regexes); 9415 9416 return $regexes; 9417 } 9418 } 9419 9420 /** 9421 * Multiselect for current modules 9422 * 9423 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9424 */ 9425 class admin_setting_configmultiselect_modules extends admin_setting_configmultiselect { 9426 private $excludesystem; 9427 9428 /** 9429 * Calls parent::__construct - note array $choices is not required 9430 * 9431 * @param string $name setting name 9432 * @param string $visiblename localised setting name 9433 * @param string $description setting description 9434 * @param array $defaultsetting a plain array of default module ids 9435 * @param bool $excludesystem If true, excludes modules with 'system' archetype 9436 */ 9437 public function __construct($name, $visiblename, $description, $defaultsetting = array(), 9438 $excludesystem = true) { 9439 parent::__construct($name, $visiblename, $description, $defaultsetting, null); 9440 $this->excludesystem = $excludesystem; 9441 } 9442 9443 /** 9444 * Loads an array of current module choices 9445 * 9446 * @return bool always return true 9447 */ 9448 public function load_choices() { 9449 if (is_array($this->choices)) { 9450 return true; 9451 } 9452 $this->choices = array(); 9453 9454 global $CFG, $DB; 9455 $records = $DB->get_records('modules', array('visible'=>1), 'name'); 9456 foreach ($records as $record) { 9457 // Exclude modules if the code doesn't exist 9458 if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) { 9459 // Also exclude system modules (if specified) 9460 if (!($this->excludesystem && 9461 plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) === 9462 MOD_ARCHETYPE_SYSTEM)) { 9463 $this->choices[$record->id] = $record->name; 9464 } 9465 } 9466 } 9467 return true; 9468 } 9469 } 9470 9471 /** 9472 * Admin setting to show if a php extension is enabled or not. 9473 * 9474 * @copyright 2013 Damyon Wiese 9475 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9476 */ 9477 class admin_setting_php_extension_enabled extends admin_setting { 9478 9479 /** @var string The name of the extension to check for */ 9480 private $extension; 9481 9482 /** 9483 * Calls parent::__construct with specific arguments 9484 */ 9485 public function __construct($name, $visiblename, $description, $extension) { 9486 $this->extension = $extension; 9487 $this->nosave = true; 9488 parent::__construct($name, $visiblename, $description, ''); 9489 } 9490 9491 /** 9492 * Always returns true, does nothing 9493 * 9494 * @return true 9495 */ 9496 public function get_setting() { 9497 return true; 9498 } 9499 9500 /** 9501 * Always returns true, does nothing 9502 * 9503 * @return true 9504 */ 9505 public function get_defaultsetting() { 9506 return true; 9507 } 9508 9509 /** 9510 * Always returns '', does not write anything 9511 * 9512 * @return string Always returns '' 9513 */ 9514 public function write_setting($data) { 9515 // Do not write any setting. 9516 return ''; 9517 } 9518 9519 /** 9520 * Outputs the html for this setting. 9521 * @return string Returns an XHTML string 9522 */ 9523 public function output_html($data, $query='') { 9524 global $OUTPUT; 9525 9526 $o = ''; 9527 if (!extension_loaded($this->extension)) { 9528 $warning = $OUTPUT->pix_icon('i/warning', '', '', array('role' => 'presentation')) . ' ' . $this->description; 9529 9530 $o .= format_admin_setting($this, $this->visiblename, $warning); 9531 } 9532 return $o; 9533 } 9534 } 9535 9536 /** 9537 * Server timezone setting. 9538 * 9539 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 9540 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9541 * @author Petr Skoda <petr.skoda@totaralms.com> 9542 */ 9543 class admin_setting_servertimezone extends admin_setting_configselect { 9544 /** 9545 * Constructor. 9546 */ 9547 public function __construct() { 9548 $default = core_date::get_default_php_timezone(); 9549 if ($default === 'UTC') { 9550 // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most. 9551 $default = 'Europe/London'; 9552 } 9553 9554 parent::__construct('timezone', 9555 new lang_string('timezone', 'core_admin'), 9556 new lang_string('configtimezone', 'core_admin'), $default, null); 9557 } 9558 9559 /** 9560 * Lazy load timezone options. 9561 * @return bool true if loaded, false if error 9562 */ 9563 public function load_choices() { 9564 global $CFG; 9565 if (is_array($this->choices)) { 9566 return true; 9567 } 9568 9569 $current = isset($CFG->timezone) ? $CFG->timezone : null; 9570 $this->choices = core_date::get_list_of_timezones($current, false); 9571 if ($current == 99) { 9572 // Do not show 99 unless it is current value, we want to get rid of it over time. 9573 $this->choices['99'] = new lang_string('timezonephpdefault', 'core_admin', 9574 core_date::get_default_php_timezone()); 9575 } 9576 9577 return true; 9578 } 9579 } 9580 9581 /** 9582 * Forced user timezone setting. 9583 * 9584 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 9585 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9586 * @author Petr Skoda <petr.skoda@totaralms.com> 9587 */ 9588 class admin_setting_forcetimezone extends admin_setting_configselect { 9589 /** 9590 * Constructor. 9591 */ 9592 public function __construct() { 9593 parent::__construct('forcetimezone', 9594 new lang_string('forcetimezone', 'core_admin'), 9595 new lang_string('helpforcetimezone', 'core_admin'), '99', null); 9596 } 9597 9598 /** 9599 * Lazy load timezone options. 9600 * @return bool true if loaded, false if error 9601 */ 9602 public function load_choices() { 9603 global $CFG; 9604 if (is_array($this->choices)) { 9605 return true; 9606 } 9607 9608 $current = isset($CFG->forcetimezone) ? $CFG->forcetimezone : null; 9609 $this->choices = core_date::get_list_of_timezones($current, true); 9610 $this->choices['99'] = new lang_string('timezonenotforced', 'core_admin'); 9611 9612 return true; 9613 } 9614 } 9615 9616 9617 /** 9618 * Search setup steps info. 9619 * 9620 * @package core 9621 * @copyright 2016 David Monllao {@link http://www.davidmonllao.com} 9622 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 9623 */ 9624 class admin_setting_searchsetupinfo extends admin_setting { 9625 9626 /** 9627 * Calls parent::__construct with specific arguments 9628 */ 9629 public function __construct() { 9630 $this->nosave = true; 9631 parent::__construct('searchsetupinfo', '', '', ''); 9632 } 9633 9634 /** 9635 * Always returns true, does nothing 9636 * 9637 * @return true 9638 */ 9639 public function get_setting() { 9640 return true; 9641 } 9642 9643 /** 9644 * Always returns true, does nothing 9645 * 9646 * @return true 9647 */ 9648 public function get_defaultsetting() { 9649 return true; 9650 } 9651 9652 /** 9653 * Always returns '', does not write anything 9654 * 9655 * @param array $data 9656 * @return string Always returns '' 9657 */ 9658 public function write_setting($data) { 9659 // Do not write any setting. 9660 return ''; 9661 } 9662 9663 /** 9664 * Builds the HTML to display the control 9665 * 9666 * @param string $data Unused 9667 * @param string $query 9668 * @return string 9669 */ 9670 public function output_html($data, $query='') { 9671 global $CFG, $OUTPUT; 9672 9673 $return = ''; 9674 $brtag = html_writer::empty_tag('br'); 9675 9676 // Available search areas. 9677 $searchareas = \core_search\manager::get_search_areas_list(); 9678 $anyenabled = false; 9679 $anyindexed = false; 9680 foreach ($searchareas as $areaid => $searcharea) { 9681 list($componentname, $varname) = $searcharea->get_config_var_name(); 9682 if (!$anyenabled) { 9683 $anyenabled = get_config($componentname, $varname . '_enabled'); 9684 } 9685 if (!$anyindexed) { 9686 $anyindexed = get_config($componentname, $varname . '_indexingstart'); 9687 } 9688 if ($anyenabled && $anyindexed) { 9689 break; 9690 } 9691 } 9692 9693 $return .= $OUTPUT->heading(get_string('searchsetupinfo', 'admin'), 3, 'main'); 9694 9695 $table = new html_table(); 9696 $table->head = array(get_string('step', 'search'), get_string('status')); 9697 $table->colclasses = array('leftalign step', 'leftalign status'); 9698 $table->id = 'searchsetup'; 9699 $table->attributes['class'] = 'admintable generaltable'; 9700 $table->data = array(); 9701 9702 $return .= $brtag . get_string('searchsetupdescription', 'search') . $brtag . $brtag; 9703 9704 // Select a search engine. 9705 $row = array(); 9706 $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#admin-searchengine'); 9707 $row[0] = '1. ' . html_writer::tag('a', get_string('selectsearchengine', 'admin'), 9708 array('href' => $url)); 9709 9710 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 9711 if (!empty($CFG->searchengine)) { 9712 $status = html_writer::tag('span', get_string('pluginname', 'search_' . $CFG->searchengine), 9713 array('class' => 'statusok')); 9714 9715 } 9716 $row[1] = $status; 9717 $table->data[] = $row; 9718 9719 // Available areas. 9720 $row = array(); 9721 $url = new moodle_url('/admin/searchareas.php'); 9722 $row[0] = '2. ' . html_writer::tag('a', get_string('enablesearchareas', 'admin'), 9723 array('href' => $url)); 9724 9725 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 9726 if ($anyenabled) { 9727 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok')); 9728 9729 } 9730 $row[1] = $status; 9731 $table->data[] = $row; 9732 9733 // Setup search engine. 9734 $row = array(); 9735 if (empty($CFG->searchengine)) { 9736 $row[0] = '3. ' . get_string('setupsearchengine', 'admin'); 9737 $row[1] = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 9738 } else { 9739 $url = new moodle_url('/admin/settings.php?section=search' . $CFG->searchengine); 9740 $row[0] = '3. ' . html_writer::tag('a', get_string('setupsearchengine', 'admin'), 9741 array('href' => $url)); 9742 // Check the engine status. 9743 $searchengine = \core_search\manager::search_engine_instance(); 9744 try { 9745 $serverstatus = $searchengine->is_server_ready(); 9746 } catch (\moodle_exception $e) { 9747 $serverstatus = $e->getMessage(); 9748 } 9749 if ($serverstatus === true) { 9750 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok')); 9751 } else { 9752 $status = html_writer::tag('span', $serverstatus, array('class' => 'statuscritical')); 9753 } 9754 $row[1] = $status; 9755 } 9756 $table->data[] = $row; 9757 9758 // Indexed data. 9759 $row = array(); 9760 $url = new moodle_url('/admin/searchareas.php'); 9761 $row[0] = '4. ' . html_writer::tag('a', get_string('indexdata', 'admin'), array('href' => $url)); 9762 if ($anyindexed) { 9763 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok')); 9764 } else { 9765 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 9766 } 9767 $row[1] = $status; 9768 $table->data[] = $row; 9769 9770 // Enable global search. 9771 $row = array(); 9772 $url = new moodle_url("/admin/search.php?query=enableglobalsearch"); 9773 $row[0] = '5. ' . html_writer::tag('a', get_string('enableglobalsearch', 'admin'), 9774 array('href' => $url)); 9775 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical')); 9776 if (\core_search\manager::is_global_search_enabled()) { 9777 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok')); 9778 } 9779 $row[1] = $status; 9780 $table->data[] = $row; 9781 9782 $return .= html_writer::table($table); 9783 9784 return highlight($query, $return); 9785 } 9786 9787 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |