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