MDL-15094 added some overlook conversions - thanks to Eloy's script ;-)
[moodle.git] / lib / adminlib.php
CommitLineData
a4e10845 1<?php
88a7228a 2
3/**
4 * adminlib.php - Contains functions that only administrators will ever need to use
5 *
a4e10845 6 * @author Martin Dougiamas and many others
88a7228a 7 * @version $Id$
8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9 * @package moodlecore
10 */
11
8ddcdd86 12function upgrade_main_savepoint($result, $version) {
13 global $CFG;
14
15 if ($result) {
16 if ($CFG->version >= $version) {
17 // something really wrong is going on in main upgrade script
2f137aa1 18 print_error('cannotdowngrade', 'debug', '', array($CFG->version, $version));
8ddcdd86 19 }
20 set_config('version', $version);
21 } else {
22 notify ("Upgrade savepoint: Error during main upgrade to version $version");
23 }
24}
25
26function upgrade_mod_savepoint($result, $version, $type) {
27 //TODO
28}
29
30function upgrade_plugin_savepoint($result, $version, $type, $dir) {
31 //TODO
32}
33
34function upgrade_backup_savepoint($result, $version) {
35 //TODO
36}
37
38function upgrade_blocks_savepoint($result, $version, $type) {
39 //TODO
40}
41
88a7228a 42/**
ead29342 43 * Upgrade plugins
88a7228a 44 *
88a7228a 45 * @uses $CFG
ead29342 46 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
47 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
48 * @param string $return The url to prompt the user to continue to
eef868d1 49 */
ead29342 50function upgrade_plugins($type, $dir, $return) {
f33e1ed4 51 global $CFG, $interactive, $DB;
173cc1c3 52
15999a93 53/// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
54 $embedded = defined('HEADER_PRINTED');
55
bb7053f3 56 $plugs = get_list_of_plugins($dir);
583fad99 57 $updated_plugins = false;
58 $strpluginsetup = get_string('pluginsetup');
59
ead29342 60 foreach ($plugs as $plug) {
173cc1c3 61
ead29342 62 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
173cc1c3 63
ead29342 64 unset($plugin);
173cc1c3 65
bbbf2d40 66 if (is_readable($fullplug .'/version.php')) {
ead29342 67 include_once($fullplug .'/version.php'); // defines $plugin with version etc
173cc1c3 68 } else {
69 continue; // Nothing to do.
70 }
71
e79a09a2 72 $newupgrade = false;
db8bd7a6 73 if (is_readable($fullplug . '/db/upgrade.php')) {
7c006e34 74 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
e79a09a2 75 $newupgrade = true;
76 }
77
ead29342 78 if (!isset($plugin)) {
173cc1c3 79 continue;
80 }
81
ead29342 82 if (!empty($plugin->requires)) {
83 if ($plugin->requires > $CFG->version) {
acdd790f 84 $info = new object();
ead29342 85 $info->pluginname = $plug;
86 $info->pluginversion = $plugin->version;
173cc1c3 87 $info->currentmoodle = $CFG->version;
ead29342 88 $info->requiremoodle = $plugin->requires;
15999a93 89 if (!$updated_plugins && !$embedded) {
0be6f678 90 print_header($strpluginsetup, $strpluginsetup,
91 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
371a32e3 92 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
583fad99 93 }
94 upgrade_log_start();
ead29342 95 notify(get_string('pluginrequirementsnotmet', 'error', $info));
583fad99 96 $updated_plugins = true;
173cc1c3 97 continue;
98 }
99 }
100
ead29342 101 $plugin->name = $plug; // The name MUST match the directory
173cc1c3 102
ead29342 103 $pluginversion = $type.'_'.$plug.'_version';
173cc1c3 104
ead29342 105 if (!isset($CFG->$pluginversion)) {
106 set_config($pluginversion, 0);
173cc1c3 107 }
eef868d1 108
ead29342 109 if ($CFG->$pluginversion == $plugin->version) {
173cc1c3 110 // do nothing
ead29342 111 } else if ($CFG->$pluginversion < $plugin->version) {
15999a93 112 if (!$updated_plugins && !$embedded) {
0be6f678 113 print_header($strpluginsetup, $strpluginsetup,
114 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
371a32e3 115 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 116 }
e79a09a2 117 $updated_plugins = true;
583fad99 118 upgrade_log_start();
05b42119 119 print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
2f13f94c 120 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 121 $DB->set_debug(true);
2f13f94c 122 }
e79a09a2 123 @set_time_limit(0); // To allow slow databases to complete the long SQL
124
d87a9d73 125 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
e79a09a2 126 /// Both old .sql files and new install.xml are supported
127 /// but we priorize install.xml (XMLDB) if present
128 $status = false;
db8bd7a6 129 if (file_exists($fullplug . '/db/install.xml')) {
f33e1ed4 130 $status = $DB->get_manager()->install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
eef868d1 131 } else {
7c006e34 132 $status = true;
d87a9d73 133 }
2f13f94c 134 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 135 $DB->set_debug(false);
2f13f94c 136 }
eef868d1 137 /// Continue with the instalation, roles and other stuff
e79a09a2 138 if ($status) {
3f59a54e 139 /// OK so far, now update the plugins record
e79a09a2 140 set_config($pluginversion, $plugin->version);
3f59a54e 141
142 /// Install capabilities
ae628043 143 if (!update_capabilities($type.'/'.$plug)) {
2f137aa1 144 print_error('cannotsetupcapforplugin', '', '', $plugin->name);
e79a09a2 145 }
3f59a54e 146 /// Install events
0856223c 147 events_update_definition($type.'/'.$plug);
3f59a54e 148
149 /// Run local install function if there is one
150 if (is_readable($fullplug .'/lib.php')) {
9ba38673 151 include_once($fullplug .'/lib.php');
3f59a54e 152 $installfunction = $plugin->name.'_install';
153 if (function_exists($installfunction)) {
154 if (! $installfunction() ) {
155 notify('Encountered a problem running install function for '.$module->name.'!');
156 }
157 }
158 }
9ba38673 159
e79a09a2 160 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
161 } else {
162 notify('Installing '. $plugin->name .' FAILED!');
163 }
d87a9d73 164 } else { // Upgrade existing install
e79a09a2 165 /// Run de old and new upgrade functions for the module
e79a09a2 166 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
167
e79a09a2 168 /// Then, the new function if exists and the old one was ok
169 $newupgrade_status = true;
47c53a54 170 if ($newupgrade && function_exists($newupgrade_function)) {
2f13f94c 171 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 172 $DB->set_debug(true);
2f13f94c 173 }
e79a09a2 174 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
175 } else if ($newupgrade) {
176 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
177 $fullplug . '/db/upgrade.php');
178 }
2f13f94c 179 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 180 $DB->set_debug(false);
2f13f94c 181 }
e79a09a2 182 /// Now analyze upgrade results
47c53a54 183 if ($newupgrade_status) { // No upgrading failed
e79a09a2 184 // OK so far, now update the plugins record
185 set_config($pluginversion, $plugin->version);
ae628043 186 if (!update_capabilities($type.'/'.$plug)) {
2f137aa1 187 print_error('cannotupdateplugincap', '', '', $plugin->name);
d87a9d73 188 }
0856223c 189 events_update_definition($type.'/'.$plug);
e79a09a2 190 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
191 } else {
192 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
173cc1c3 193 }
194 }
2f13f94c 195 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
196 echo '<hr />';
197 }
173cc1c3 198 } else {
583fad99 199 upgrade_log_start();
2f137aa1 200 print_error('cannotdowngrade', 'debug', '', array($CFG->pluginversion, $plugin->version));
173cc1c3 201 }
202 }
203
583fad99 204 upgrade_log_finish();
205
15999a93 206 if ($updated_plugins && !$embedded) {
2f13f94c 207 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
173cc1c3 208 print_continue($return);
acdd790f 209 print_footer('none');
173cc1c3 210 die;
2f13f94c 211 } else if (CLI_UPGRADE && ($interactive > CLI_SEMI )) {
212 console_write(STDOUT,'askcontinue');
213 if (read_boolean()){
214 return ;
215 }else {
216 console_write(STDERR,'','',false);
217 }
218 }
173cc1c3 219 }
220}
221
88a7228a 222/**
223 * Find and check all modules and load them up or upgrade them if necessary
224 *
88a7228a 225 * @uses $CFG
226 * @param string $return The url to prompt the user to continue to
227 * @todo Finish documenting this function
eef868d1 228 */
173cc1c3 229function upgrade_activity_modules($return) {
173cc1c3 230
f33e1ed4 231 global $CFG, $interactive, $DB;
173cc1c3 232
88a7228a 233 if (!$mods = get_list_of_plugins('mod') ) {
2f137aa1 234 print_error('nomodules', 'debug');
173cc1c3 235 }
236
583fad99 237 $updated_modules = false;
238 $strmodulesetup = get_string('modulesetup');
239
173cc1c3 240 foreach ($mods as $mod) {
241
88a7228a 242 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
173cc1c3 243 continue;
244 }
245
88a7228a 246 $fullmod = $CFG->dirroot .'/mod/'. $mod;
173cc1c3 247
248 unset($module);
249
88a7228a 250 if ( is_readable($fullmod .'/version.php')) {
251 include_once($fullmod .'/version.php'); // defines $module with version etc
173cc1c3 252 } else {
88a7228a 253 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
173cc1c3 254 continue;
255 }
256
d6eb06b6 257 $newupgrade = false;
db8bd7a6 258 if ( is_readable($fullmod . '/db/upgrade.php')) {
7c006e34 259 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
d6eb06b6 260 $newupgrade = true;
173cc1c3 261 }
262
263 if (!isset($module)) {
264 continue;
265 }
266
267 if (!empty($module->requires)) {
268 if ($module->requires > $CFG->version) {
acdd790f 269 $info = new object();
173cc1c3 270 $info->modulename = $mod;
271 $info->moduleversion = $module->version;
272 $info->currentmoodle = $CFG->version;
273 $info->requiremoodle = $module->requires;
583fad99 274 if (!$updated_modules) {
0be6f678 275 print_header($strmodulesetup, $strmodulesetup,
276 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
371a32e3 277 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
583fad99 278 }
279 upgrade_log_start();
173cc1c3 280 notify(get_string('modulerequirementsnotmet', 'error', $info));
583fad99 281 $updated_modules = true;
173cc1c3 282 continue;
283 }
284 }
285
286 $module->name = $mod; // The name MUST match the directory
eef868d1 287
11e4a24b 288 include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
289
f33e1ed4 290 if ($currmodule = $DB->get_record('modules', array('name'=>$module->name))) {
173cc1c3 291 if ($currmodule->version == $module->version) {
292 // do nothing
293 } else if ($currmodule->version < $module->version) {
d6eb06b6 294 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
47c53a54 295 if (!$newupgrade) {
296 notify('Upgrade file ' . $mod . ': ' . $fullmod . '/db/upgrade.php is not readable');
d6eb06b6 297 continue;
298 }
583fad99 299 if (!$updated_modules) {
0be6f678 300 print_header($strmodulesetup, $strmodulesetup,
301 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
371a32e3 302 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 303 }
583fad99 304 upgrade_log_start();
2f13f94c 305
88a7228a 306 print_heading($module->name .' module needs upgrading');
d6eb06b6 307
308 /// Run de old and new upgrade functions for the module
d6eb06b6 309 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
310
d6eb06b6 311 /// Then, the new function if exists and the old one was ok
312 $newupgrade_status = true;
47c53a54 313 if ($newupgrade && function_exists($newupgrade_function)) {
2f13f94c 314 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 315 $DB->set_debug(true);
2f13f94c 316 }
d6eb06b6 317 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
47c53a54 318 } else if ($newupgrade) {
d6eb06b6 319 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
320 $mod . ': ' . $fullmod . '/db/upgrade.php');
d6eb06b6 321 }
2f13f94c 322 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 323 $DB->set_debug(false);
2f13f94c 324 }
d6eb06b6 325 /// Now analyze upgrade results
47c53a54 326 if ($newupgrade_status) { // No upgrading failed
d6eb06b6 327 // OK so far, now update the modules record
328 $module->id = $currmodule->id;
f33e1ed4 329 if (!$DB->update_record('modules', $module)) {
2f137aa1 330 print_error('cannotupdatemod', '', '', $module->name);
173cc1c3 331 }
d6eb06b6 332 remove_dir($CFG->dataroot . '/cache', true); // flush cache
333 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
2f13f94c 334 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE) {
d6eb06b6 335 echo '<hr />';
2f13f94c 336 }
d6eb06b6 337 } else {
d6eb06b6 338 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
173cc1c3 339 }
bbbf2d40 340
d6eb06b6 341 /// Update the capabilities table?
bbbf2d40 342 if (!update_capabilities('mod/'.$module->name)) {
2f137aa1 343 print_error('cannotupdatemodcap', '', '', $module->name);
bbbf2d40 344 }
0856223c 345 events_update_definition('mod/'.$module->name);
bbbf2d40 346
173cc1c3 347 $updated_modules = true;
eef868d1 348
173cc1c3 349 } else {
583fad99 350 upgrade_log_start();
2f137aa1 351 print_error('cannotdowngrade', 'debug', '', array($currmodule->version, $module->version));
173cc1c3 352 }
eef868d1 353
173cc1c3 354 } else { // module not installed yet, so install it
583fad99 355 if (!$updated_modules) {
2f13f94c 356 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
0be6f678 357 print_header($strmodulesetup, $strmodulesetup,
358 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
371a32e3 359 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 360 }
2f13f94c 361 }
583fad99 362 upgrade_log_start();
173cc1c3 363 print_heading($module->name);
364 $updated_modules = true;
2f13f94c 365 // To avoid unnecessary output from the SQL queries in the CLI version
366 if (!defined('CLI_UPGRADE')|| !CLI_UPGRADE ) {
f33e1ed4 367 $DB->set_debug(true);
2f13f94c 368 }
173cc1c3 369 @set_time_limit(0); // To allow slow databases to complete the long SQL
d6eb06b6 370
371 /// Both old .sql files and new install.xml are supported
372 /// but we priorize install.xml (XMLDB) if present
db8bd7a6 373 if (file_exists($fullmod . '/db/install.xml')) {
f33e1ed4 374 $status = $DB->get_manager()->install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
d6eb06b6 375 }
2f13f94c 376 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
f33e1ed4 377 $DB->set_debug(false);
2f13f94c 378 }
11e4a24b 379
380 /// Continue with the installation, roles and other stuff
d6eb06b6 381 if ($status) {
f33e1ed4 382 if ($module->id = $DB->insert_record('modules', $module)) {
11e4a24b 383
9ba38673 384 /// Capabilities
bbbf2d40 385 if (!update_capabilities('mod/'.$module->name)) {
2f137aa1 386 print_error('cannotsetupcapformod', '', '', $module->name);
bbbf2d40 387 }
9ba38673 388
11e4a24b 389 /// Events
0856223c 390 events_update_definition('mod/'.$module->name);
11e4a24b 391
392 /// Run local install function if there is one
393 $installfunction = $module->name.'_install';
394 if (function_exists($installfunction)) {
395 if (! $installfunction() ) {
396 notify('Encountered a problem running install function for '.$module->name.'!');
397 }
398 }
399
a8f68426 400 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
2f13f94c 401 if (!defined('CLI_UPGRADE')|| !CLI_UPGRADE ) {
88a7228a 402 echo '<hr />';
2f13f94c 403 }
173cc1c3 404 } else {
5a2a5331 405 print_error($module->name .' module could not be added to the module list!');
173cc1c3 406 }
eef868d1 407 } else {
5a2a5331 408 print_error($module->name .' tables could NOT be set up successfully!');
173cc1c3 409 }
410 }
e5bd4e58 411
412 /// Check submodules of this module if necessary
413
e5bd4e58 414 $submoduleupgrade = $module->name.'_upgrade_submodules';
415 if (function_exists($submoduleupgrade)) {
416 $submoduleupgrade();
417 }
418
e5bd4e58 419 /// Run any defaults or final code that is necessary for this module
420
a5c0990e 421 if ( is_readable($fullmod .'/defaults.php')) {
422 // Insert default values for any important configuration variables
9e6e7502 423 unset($defaults);
220a90c5 424 include($fullmod .'/defaults.php'); // include here means execute, not library include
f9a2e515 425 if (!empty($defaults)) {
426 foreach ($defaults as $name => $value) {
427 if (!isset($CFG->$name)) {
428 set_config($name, $value);
429 }
a5c0990e 430 }
431 }
432 }
173cc1c3 433 }
434
583fad99 435 upgrade_log_finish(); // finish logging if started
436
437 if ($updated_modules) {
2f13f94c 438 if (!defined('CLI_UPGRADE')|| !CLI_UPGRADE ) {
173cc1c3 439 print_continue($return);
acdd790f 440 print_footer('none');
173cc1c3 441 die;
2f13f94c 442 } else if ( CLI_UPGRADE && ($interactive > CLI_SEMI) ) {
443 console_write(STDOUT,'askcontinue');
444 if (read_boolean()){
445 return ;
446 }else {
447 console_write(STDERR,'','',false);
448 }
449 }
173cc1c3 450 }
451}
452
eef868d1 453/**
61460dd6 454 * Try to obtain or release the cron lock.
80be7ee3 455 *
61460dd6 456 * @param string $name name of lock
457 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly
458 * @param bool $ignorecurrent ignore current lock state, usually entend previous lock
459 * @return bool true if lock obtained
f3221af9 460 */
61460dd6 461function set_cron_lock($name, $until, $ignorecurrent=false) {
f33e1ed4 462 global $DB;
f3221af9 463 if (empty($name)) {
61460dd6 464 debugging("Tried to get a cron lock for a null fieldname");
f3221af9 465 return false;
466 }
467
61460dd6 468 // remove lock by force == remove from config table
469 if (is_null($until)) {
470 set_config($name, null);
f3221af9 471 return true;
472 }
473
61460dd6 474 if (!$ignorecurrent) {
475 // read value from db - other processes might have changed it
f33e1ed4 476 $value = $DB->get_field('config', 'value', array('name'=>$name));
61460dd6 477
478 if ($value and $value > time()) {
479 //lock active
480 return false;
f3221af9 481 }
482 }
61460dd6 483
484 set_config($name, $until);
f3221af9 485 return true;
486}
a597f8a8 487
fb06b255 488function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
67784b2f 489 static $thisbarid;
a597f8a8 490 static $starttime;
491 static $lasttime;
492
26ea4888 493 if ($total < 2) { // No need to show anything
494 return;
495 }
496
67784b2f 497 // Are we done?
498 if ($done >= $total) {
499 $done = $total;
500 if (!empty($thisbarid)) {
501 $donetext .= ' ('.$done.'/'.$total.') '.get_string('success');
502 print_progress_redraw($thisbarid, $done, $total, 500, $donetext);
503 $thisbarid = $starttime = $lasttime = NULL;
504 }
505 return;
506 }
507
a597f8a8 508 if (empty($starttime)) {
509 $starttime = $lasttime = time();
510 $lasttime = $starttime - $updatetime;
67784b2f 511 $thisbarid = uniqid();
a597f8a8 512 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
67784b2f 513 echo '<div id="bar'.$thisbarid.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
514 echo '<div id="slider'.$thisbarid.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
a597f8a8 515 echo '</div>';
67784b2f 516 echo '<div id="text'.$thisbarid.'" align="center" style="width:500px;"></div>';
a597f8a8 517 echo '</td></tr></table>';
518 echo '</div>';
519 }
520
a597f8a8 521 $now = time();
522
523 if ($done && (($now - $lasttime) >= $updatetime)) {
524 $elapsedtime = $now - $starttime;
525 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
76317c73 526 $percentage = round((float)$done / (float)$total, 2);
a597f8a8 527 $width = (int)(500 * $percentage);
528
fb06b255 529 if ($projectedtime > 10) {
530 $projectedtext = ' Ending: '.format_time($projectedtime);
531 } else {
532 $projectedtext = '';
533 }
534
67784b2f 535 $donetext .= ' ('.$done.'/'.$total.') '.$projectedtext;
536 print_progress_redraw($thisbarid, $done, $total, $width, $donetext);
a597f8a8 537
538 $lasttime = $now;
a597f8a8 539 }
540}
583fad99 541
67784b2f 542// Don't call this function directly, it's called from print_progress.
543function print_progress_redraw($thisbarid, $done, $total, $width, $donetext='') {
544 if (empty($thisbarid)) {
545 return;
546 }
547 echo '<script>';
294ce987 548 echo 'document.getElementById("text'.$thisbarid.'").innerHTML = "'.addslashes_js($donetext).'";'."\n";
67784b2f 549 echo 'document.getElementById("slider'.$thisbarid.'").style.width = \''.$width.'px\';'."\n";
550 echo '</script>';
551}
552
371a32e3 553function upgrade_get_javascript() {
554 global $CFG;
555
556 if (!empty($_SESSION['installautopilot'])) {
557 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
558 } else {
559 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
560 }
561 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
562
563 return $linktoscrolltoerrors;
564}
ad6226fb 565
2f13f94c 566function create_admin_user($user_input=NULL) {
f33e1ed4 567 global $CFG, $USER, $DB;
ad6226fb 568
569 if (empty($CFG->rolesactive)) { // No admin user yet.
570
571 $user = new object();
572 $user->auth = 'manual';
573 $user->firstname = get_string('admin');
574 $user->lastname = get_string('user');
575 $user->username = 'admin';
576 $user->password = hash_internal_user_password('admin');
577 $user->email = 'root@localhost';
578 $user->confirmed = 1;
579 $user->mnethostid = $CFG->mnet_localhost_id;
580 $user->lang = $CFG->lang;
581 $user->maildisplay = 1;
582 $user->timemodified = time();
583
2f13f94c 584 if ($user_input) {
585 $user = $user_input;
586 }
f33e1ed4 587 if (!$user->id = $DB->insert_record('user', $user)) {
2f137aa1 588 print_error('cannotcreateadminuser', 'debug');
ad6226fb 589 }
590
f33e1ed4 591 if (!$user = $DB->get_record('user', array('id'=>$user->id))) { // Double check.
2f137aa1 592 print_error('invaliduserid');
ad6226fb 593 }
594
595 // Assign the default admin roles to the new user.
596 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
2f137aa1 597 print_error('noadminrole', 'debug');
ad6226fb 598 }
84c8ede0 599 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
ad6226fb 600 foreach ($adminroles as $adminrole) {
601 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
602 }
603
604 set_config('rolesactive', 1);
605
606 // Log the user in.
607 $USER = get_complete_user_data('username', 'admin');
608 $USER->newadminuser = 1;
609 load_all_capabilities();
610
2f13f94c 611 if (!defined('CLI_UPGRADE')||!CLI_UPGRADE) {
ad6226fb 612 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
2f13f94c 613 }
ad6226fb 614 } else {
2f137aa1 615 print_error('cannotcreateadminuser', 'debug');
ad6226fb 616 }
617}
618
583fad99 619////////////////////////////////////////////////
620/// upgrade logging functions
621////////////////////////////////////////////////
622
623$upgradeloghandle = false;
26c91c73 624$upgradelogbuffer = '';
625// I did not find out how to use static variable in callback function,
626// the problem was that I could not flush the static buffer :-(
627global $upgradeloghandle, $upgradelogbuffer;
583fad99 628
629/**
630 * Check if upgrade is already running.
631 *
632 * If anything goes wrong due to missing call to upgrade_log_finish()
633 * just restart the browser.
634 *
635 * @param string warning message indicating upgrade is already running
636 * @param int page reload timeout
637 */
638function upgrade_check_running($message, $timeout) {
639 if (!empty($_SESSION['upgraderunning'])) {
640 print_header();
641 redirect(me(), $message, $timeout);
642 }
643}
644
645/**
646 * Start logging of output into file (if not disabled) and
647 * prevent aborting and concurrent execution of upgrade script.
648 *
649 * Please note that you can not write into session variables after calling this function!
650 *
651 * This function may be called repeatedly.
652 */
653function upgrade_log_start() {
426a369b 654 global $CFG, $upgradeloghandle;
583fad99 655
656 if (!empty($_SESSION['upgraderunning'])) {
657 return; // logging already started
658 }
659
660 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
661 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
426a369b 662 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
663 session_write_close(); // from now on user can reload page - will be displayed warning
664 }
583fad99 665 make_upload_directory('upgradelogs');
666 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
dedb2304 667 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
583fad99 668}
669
670/**
671 * Terminate logging of output, flush all data, allow script aborting
5a2a5331 672 * and reopen session for writing. Function print_error() does terminate the logging too.
583fad99 673 *
674 * Please make sure that each upgrade_log_start() is properly terminated by
5a2a5331 675 * this function or print_error().
583fad99 676 *
677 * This function may be called repeatedly.
678 */
679function upgrade_log_finish() {
426a369b 680 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 681
682 if (empty($_SESSION['upgraderunning'])) {
683 return; // logging already terminated
684 }
685
686 @ob_end_flush();
26c91c73 687 if ($upgradelogbuffer !== '') {
688 @fwrite($upgradeloghandle, $upgradelogbuffer);
40896537 689 $upgradelogbuffer = '';
26c91c73 690 }
691 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
692 @fclose($upgradeloghandle);
40896537 693 $upgradeloghandle = false;
26c91c73 694 }
426a369b 695 if (empty($CFG->dbsessions)) {
696 @session_start(); // ignore header errors, we only need to reopen session
697 }
583fad99 698 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
699 if (connection_aborted()) {
700 die;
701 }
702 @ignore_user_abort(false);
703}
704
705/**
706 * Callback function for logging into files. Not more than one file is created per minute,
707 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
708 *
709 * This function must not output any characters or throw warnigns and errors!
710 */
711function upgrade_log_callback($string) {
26c91c73 712 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 713
714 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
715 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
26c91c73 716 $upgradelogbuffer .= $string;
717 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
718 @fwrite($upgradeloghandle, $upgradelogbuffer);
719 $upgradelogbuffer = '';
720 }
583fad99 721 } else {
722 $upgradeloghandle = 'error';
723 }
724 }
725 return $string;
726}
727
57e35f32 728/**
729 * Try to verify that dataroot is not accessible from web.
730 * It is not 100% correct but might help to reduce number of vulnerable sites.
731 *
732 * Protection from httpd.conf and .htaccess is not detected properly.
733 */
734function is_dataroot_insecure() {
735 global $CFG;
736
737 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
738
739 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
740 $rp = strrev(trim($rp, '/'));
741 $rp = explode('/', $rp);
742 foreach($rp as $r) {
743 if (strpos($siteroot, '/'.$r.'/') === 0) {
744 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
745 } else {
746 break; // probably alias root
747 }
748 }
749
750 $siteroot = strrev($siteroot);
751 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
752
753 if (strpos($dataroot, $siteroot) === 0) {
754 return true;
755 }
756 return false;
757}
6e4dc10f 758
759/// =============================================================================================================
760/// administration tree classes and functions
761
762
763// n.b. documentation is still in progress for this code
764
765/// INTRODUCTION
766
767/// This file performs the following tasks:
768/// -it defines the necessary objects and interfaces to build the Moodle
769/// admin hierarchy
eef868d1 770/// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
6e4dc10f 771/// and admin_externalpage_print_footer() functions used on admin pages
772
773/// ADMIN_SETTING OBJECTS
774
eef868d1 775/// Moodle settings are represented by objects that inherit from the admin_setting
6e4dc10f 776/// class. These objects encapsulate how to read a setting, how to write a new value
777/// to a setting, and how to appropriately display the HTML to modify the setting.
778
779/// ADMIN_SETTINGPAGE OBJECTS
780
781/// The admin_setting objects are then grouped into admin_settingpages. The latter
782/// appear in the Moodle admin tree block. All interaction with admin_settingpage
783/// objects is handled by the admin/settings.php file.
784
785/// ADMIN_EXTERNALPAGE OBJECTS
786
787/// There are some settings in Moodle that are too complex to (efficiently) handle
788/// with admin_settingpages. (Consider, for example, user management and displaying
789/// lists of users.) In this case, we use the admin_externalpage object. This object
790/// places a link to an external PHP file in the admin tree block.
791
792/// If you're using an admin_externalpage object for some settings, you can take
793/// advantage of the admin_externalpage_* functions. For example, suppose you wanted
794/// to add a foo.php file into admin. First off, you add the following line to
795/// admin/settings/first.php (at the end of the file) or to some other file in
796/// admin/settings:
797
eef868d1 798/// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
6e4dc10f 799/// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
800
801/// Next, in foo.php, your file structure would resemble the following:
802
803/// require_once('.../config.php');
804/// require_once($CFG->libdir.'/adminlib.php');
1ae083e4 805/// admin_externalpage_setup('foo');
6e4dc10f 806/// // functionality like processing form submissions goes here
1ae083e4 807/// admin_externalpage_print_header();
6e4dc10f 808/// // your HTML goes here
1ae083e4 809/// admin_externalpage_print_footer();
6e4dc10f 810
811/// The admin_externalpage_setup() function call ensures the user is logged in,
812/// and makes sure that they have the proper role permission to access the page.
813
814/// The admin_externalpage_print_header() function prints the header (it figures
815/// out what category and subcategories the page is classified under) and ensures
816/// that you're using the admin pagelib (which provides the admin tree block and
817/// the admin bookmarks block).
818
819/// The admin_externalpage_print_footer() function properly closes the tables
820/// opened up by the admin_externalpage_print_header() function and prints the
821/// standard Moodle footer.
822
823/// ADMIN_CATEGORY OBJECTS
824
825/// Above and beyond all this, we have admin_category objects. These objects
826/// appear as folders in the admin tree block. They contain admin_settingpage's,
827/// admin_externalpage's, and other admin_category's.
828
829/// OTHER NOTES
830
831/// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
832/// from part_of_admin_tree (a pseudointerface). This interface insists that
833/// a class has a check_access method for access permissions, a locate method
220a90c5 834/// used to find a specific node in the admin tree and find parent path.
6e4dc10f 835
836/// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
837/// interface ensures that the class implements a recursive add function which
838/// accepts a part_of_admin_tree object and searches for the proper place to
839/// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
840
841/// Please note that the $this->name field of any part_of_admin_tree must be
842/// UNIQUE throughout the ENTIRE admin tree.
843
844/// The $this->name field of an admin_setting object (which is *not* part_of_
845/// admin_tree) must be unique on the respective admin_settingpage where it is
846/// used.
847
848
6e4dc10f 849/// CLASS DEFINITIONS /////////////////////////////////////////////////////////
850
851/**
852 * Pseudointerface for anything appearing in the admin tree
853 *
854 * The pseudointerface that is implemented by anything that appears in the admin tree
855 * block. It forces inheriting classes to define a method for checking user permissions
856 * and methods for finding something in the admin tree.
857 *
858 * @author Vincenzo K. Marcovecchio
859 * @package admin
860 */
861class part_of_admin_tree {
862
863 /**
864 * Finds a named part_of_admin_tree.
865 *
866 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
867 * and not parentable_part_of_admin_tree, then this function should only check if
868 * $this->name matches $name. If it does, it should return a reference to $this,
869 * otherwise, it should return a reference to NULL.
870 *
871 * If a class inherits parentable_part_of_admin_tree, this method should be called
872 * recursively on all child objects (assuming, of course, the parent object's name
873 * doesn't match the search criterion).
874 *
875 * @param string $name The internal name of the part_of_admin_tree we're searching for.
876 * @return mixed An object reference or a NULL reference.
877 */
eef868d1 878 function &locate($name) {
879 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
880 return;
6e4dc10f 881 }
4672d955 882
883 /**
884 * Removes named part_of_admin_tree.
885 *
886 * @param string $name The internal name of the part_of_admin_tree we want to remove.
a8a66c96 887 * @return bool success.
4672d955 888 */
889 function prune($name) {
eef868d1 890 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
4672d955 891 return;
eef868d1 892 }
4672d955 893
220a90c5 894 /**
895 * Search using query
896 * @param strin query
897 * @return mixed array-object structure of found settings and pages
898 */
899 function search($query) {
900 trigger_error('Admin class does not implement method <strong>search()</strong>', E_USER_WARNING);
901 return;
902 }
903
6e4dc10f 904 /**
905 * Verifies current user's access to this part_of_admin_tree.
906 *
907 * Used to check if the current user has access to this part of the admin tree or
908 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
909 * then this method is usually just a call to has_capability() in the site context.
910 *
911 * If a class inherits parentable_part_of_admin_tree, this method should return the
912 * logical OR of the return of check_access() on all child objects.
913 *
914 * @return bool True if the user has access, false if she doesn't.
915 */
eef868d1 916 function check_access() {
917 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
918 return;
6e4dc10f 919 }
eef868d1 920
a8a66c96 921 /**
922 * Mostly usefull for removing of some parts of the tree in admin tree block.
923 *
924 * @return True is hidden from normal list view
925 */
926 function is_hidden() {
927 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
928 return;
929 }
6e4dc10f 930}
931
932/**
933 * Pseudointerface implemented by any part_of_admin_tree that has children.
934 *
935 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
936 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
eef868d1 937 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
6e4dc10f 938 * include an add method for adding other part_of_admin_tree objects as children.
939 *
940 * @author Vincenzo K. Marcovecchio
941 * @package admin
942 */
943class parentable_part_of_admin_tree extends part_of_admin_tree {
eef868d1 944
6e4dc10f 945 /**
946 * Adds a part_of_admin_tree object to the admin tree.
947 *
948 * Used to add a part_of_admin_tree object to this object or a child of this
949 * object. $something should only be added if $destinationname matches
950 * $this->name. If it doesn't, add should be called on child objects that are
951 * also parentable_part_of_admin_tree's.
952 *
953 * @param string $destinationname The internal name of the new parent for $something.
954 * @param part_of_admin_tree &$something The object to be added.
955 * @return bool True on success, false on failure.
956 */
220a90c5 957 function add($destinationname, $something) {
eef868d1 958 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
959 return;
6e4dc10f 960 }
eef868d1 961
6e4dc10f 962}
963
964/**
965 * The object used to represent folders (a.k.a. categories) in the admin tree block.
eef868d1 966 *
6e4dc10f 967 * Each admin_category object contains a number of part_of_admin_tree objects.
968 *
969 * @author Vincenzo K. Marcovecchio
970 * @package admin
971 */
972class admin_category extends parentable_part_of_admin_tree {
973
974 /**
975 * @var mixed An array of part_of_admin_tree objects that are this object's children
976 */
977 var $children;
eef868d1 978
6e4dc10f 979 /**
980 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
981 */
982 var $name;
eef868d1 983
6e4dc10f 984 /**
985 * @var string The displayed name for this category. Usually obtained through get_string()
986 */
987 var $visiblename;
eef868d1 988
a8a66c96 989 /**
990 * @var bool Should this category be hidden in admin tree block?
991 */
992 var $hidden;
993
220a90c5 994 /**
995 * paths
996 */
997 var $path;
998 var $visiblepath;
6e4dc10f 999
1000 /**
1001 * Constructor for an empty admin category
1002 *
1003 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
1004 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
a8a66c96 1005 * @param bool $hidden hide category in admin tree block
6e4dc10f 1006 */
220a90c5 1007 function admin_category($name, $visiblename, $hidden=false) {
1008 $this->children = array();
1009 $this->name = $name;
6e4dc10f 1010 $this->visiblename = $visiblename;
220a90c5 1011 $this->hidden = $hidden;
6e4dc10f 1012 }
eef868d1 1013
6e4dc10f 1014 /**
220a90c5 1015 * Returns a reference to the part_of_admin_tree object with internal name $name.
6e4dc10f 1016 *
220a90c5 1017 * @param string $name The internal name of the object we want.
1018 * @param bool $findpath initialize path and visiblepath arrays
1019 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
6e4dc10f 1020 */
220a90c5 1021 function &locate($name, $findpath=false) {
6e4dc10f 1022 if ($this->name == $name) {
220a90c5 1023 if ($findpath) {
1024 $this->visiblepath[] = $this->visiblename;
1025 $this->path[] = $this->name;
1026 }
1027 return $this;
6e4dc10f 1028 }
eef868d1 1029
220a90c5 1030 $return = NULL;
1031 foreach($this->children as $childid=>$unused) {
1032 if ($return =& $this->children[$childid]->locate($name, $findpath)) {
1033 break;
6e4dc10f 1034 }
1035 }
eef868d1 1036
220a90c5 1037 if (!is_null($return) and $findpath) {
1038 $return->visiblepath[] = $this->visiblename;
1039 $return->path[] = $this->name;
1040 }
eef868d1 1041
220a90c5 1042 return $return;
6e4dc10f 1043 }
1044
1045 /**
220a90c5 1046 * Search using query
1047 * @param strin query
1048 * @return mixed array-object structure of found settings and pages
6e4dc10f 1049 */
220a90c5 1050 function search($query) {
1051 $result = array();
1052 foreach ($this->children as $child) {
3cea9c55 1053 $subsearch = $child->search($query);
1054 if (!is_array($subsearch)) {
1055 debugging('Incorrect search result from '.$child->name);
1056 continue;
1057 }
1058 $result = array_merge($result, $subsearch);
6e4dc10f 1059 }
220a90c5 1060 return $result;
6e4dc10f 1061 }
1062
4672d955 1063 /**
1064 * Removes part_of_admin_tree object with internal name $name.
1065 *
1066 * @param string $name The internal name of the object we want to remove.
a8a66c96 1067 * @return bool success
4672d955 1068 */
1069 function prune($name) {
1070
1071 if ($this->name == $name) {
1072 return false; //can not remove itself
1073 }
1074
1075 foreach($this->children as $precedence => $child) {
1076 if ($child->name == $name) {
1077 // found it!
eef868d1 1078 unset($this->children[$precedence]);
4672d955 1079 return true;
1080 }
1081 if ($this->children[$precedence]->prune($name)) {
1082 return true;
1083 }
1084 }
1085 return false;
1086 }
1087
6e4dc10f 1088 /**
1089 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1090 *
220a90c5 1091 * @param string $destinationame The internal name of the immediate parent that we want for $something.
1092 * @param mixed $something A part_of_admin_tree or setting instanceto be added.
1093 * @return bool True if successfully added, false if $something can not be added.
6e4dc10f 1094 */
220a90c5 1095 function add($parentname, $something) {
1096 $parent =& $this->locate($parentname);
1097 if (is_null($parent)) {
1098 debugging('parent does not exist!');
6e4dc10f 1099 return false;
1100 }
1101
220a90c5 1102 if (is_a($something, 'part_of_admin_tree')) {
1103 if (!is_a($parent, 'parentable_part_of_admin_tree')) {
1104 debugging('error - parts of tree can be inserted only into parentable parts');
1105 return false;
6e4dc10f 1106 }
220a90c5 1107 $parent->children[] = $something;
6e4dc10f 1108 return true;
eef868d1 1109
220a90c5 1110 } else {
1111 debugging('error - can not add this element');
1112 return false;
6e4dc10f 1113 }
eef868d1 1114
6e4dc10f 1115 }
eef868d1 1116
6e4dc10f 1117 /**
1118 * Checks if the user has access to anything in this category.
1119 *
1120 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1121 */
1122 function check_access() {
6e4dc10f 1123 foreach ($this->children as $child) {
220a90c5 1124 if ($child->check_access()) {
1125 return true;
1126 }
6e4dc10f 1127 }
220a90c5 1128 return false;
6e4dc10f 1129 }
eef868d1 1130
a8a66c96 1131 /**
1132 * Is this category hidden in admin tree block?
1133 *
1134 * @return bool True if hidden
1135 */
1136 function is_hidden() {
1137 return $this->hidden;
1138 }
6e4dc10f 1139}
1140
220a90c5 1141class admin_root extends admin_category {
1142 /**
1143 * list of errors
1144 */
1145 var $errors;
1146
1147 /**
1148 * search query
1149 */
1150 var $search;
1151
1152 /**
1153 * full tree flag - true means all settings required, false onlypages required
1154 */
1155 var $fulltree;
1156
1157
1158 function admin_root() {
1159 parent::admin_category('root', get_string('administration'), false);
1160 $this->errors = array();
1161 $this->search = '';
1162 $this->fulltree = true;
1163 }
1164}
1165
6e4dc10f 1166/**
1167 * Links external PHP pages into the admin tree.
1168 *
1169 * See detailed usage example at the top of this document (adminlib.php)
1170 *
1171 * @author Vincenzo K. Marcovecchio
1172 * @package admin
1173 */
1174class admin_externalpage extends part_of_admin_tree {
1175
eef868d1 1176 /**
6e4dc10f 1177 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1178 */
1179 var $name;
eef868d1 1180
6e4dc10f 1181 /**
1182 * @var string The displayed name for this external page. Usually obtained through get_string().
1183 */
1184 var $visiblename;
eef868d1 1185
6e4dc10f 1186 /**
1187 * @var string The external URL that we should link to when someone requests this external page.
1188 */
1189 var $url;
eef868d1 1190
6e4dc10f 1191 /**
1192 * @var string The role capability/permission a user must have to access this external page.
1193 */
2ce38b70 1194 var $req_capability;
eef868d1 1195
84c8ede0 1196 /**
1197 * @var object The context in which capability/permission should be checked, default is site context.
1198 */
1199 var $context;
1200
a8a66c96 1201 /**
1202 * @var bool hidden in admin tree block.
1203 */
1204 var $hidden;
1205
220a90c5 1206 /**
1207 * visible path
1208 */
1209 var $path;
1210 var $visiblepath;
1211
6e4dc10f 1212 /**
1213 * Constructor for adding an external page into the admin tree.
1214 *
1215 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1216 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1217 * @param string $url The external URL that we should link to when someone requests this external page.
38d2d43b 1218 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
6e4dc10f 1219 */
220a90c5 1220 function admin_externalpage($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1221 $this->name = $name;
6e4dc10f 1222 $this->visiblename = $visiblename;
220a90c5 1223 $this->url = $url;
38d2d43b 1224 if (is_array($req_capability)) {
1225 $this->req_capability = $req_capability;
1226 } else {
1227 $this->req_capability = array($req_capability);
1228 }
220a90c5 1229 $this->hidden = $hidden;
84c8ede0 1230 $this->context = $context;
6e4dc10f 1231 }
eef868d1 1232
6e4dc10f 1233 /**
1234 * Returns a reference to the part_of_admin_tree object with internal name $name.
1235 *
1236 * @param string $name The internal name of the object we want.
1237 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1238 */
220a90c5 1239 function &locate($name, $findpath=false) {
1240 if ($this->name == $name) {
1241 if ($findpath) {
1242 $this->visiblepath = array($this->visiblename);
1243 $this->path = array($this->name);
1244 }
1245 return $this;
1246 } else {
1247 $return = NULL;
1248 return $return;
1249 }
6e4dc10f 1250 }
4672d955 1251
1252 function prune($name) {
1253 return false;
1254 }
1255
220a90c5 1256 /**
1257 * Search using query
1258 * @param strin query
1259 * @return mixed array-object structure of found settings and pages
1260 */
1261 function search($query) {
1262 $textlib = textlib_get_instance();
1263
1264 $found = false;
1265 if (strpos(strtolower($this->name), $query) !== false) {
1266 $found = true;
1267 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1268 $found = true;
1269 }
1270 if ($found) {
1271 $result = new object();
1272 $result->page = $this;
1273 $result->settings = array();
1274 return array($this->name => $result);
1275 } else {
1276 return array();
1277 }
1278 }
1279
6e4dc10f 1280 /**
2ce38b70 1281 * Determines if the current user has access to this external page based on $this->req_capability.
6e4dc10f 1282 * @return bool True if user has access, false otherwise.
1283 */
1284 function check_access() {
1285 if (!get_site()) {
1286 return true; // no access check before site is fully set up
1287 }
84c8ede0 1288 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1289 foreach($this->req_capability as $cap) {
1290 if (has_capability($cap, $context)) {
1291 return true;
1292 }
1293 }
1294 return false;
6e4dc10f 1295 }
1296
a8a66c96 1297 /**
1298 * Is this external page hidden in admin tree block?
1299 *
1300 * @return bool True if hidden
1301 */
1302 function is_hidden() {
1303 return $this->hidden;
1304 }
1305
6e4dc10f 1306}
1307
1308/**
1309 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1310 *
1311 * @author Vincenzo K. Marcovecchio
1312 * @package admin
1313 */
1314class admin_settingpage extends part_of_admin_tree {
1315
eef868d1 1316 /**
6e4dc10f 1317 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1318 */
1319 var $name;
eef868d1 1320
6e4dc10f 1321 /**
1322 * @var string The displayed name for this external page. Usually obtained through get_string().
1323 */
1324 var $visiblename;
1325 /**
1326 * @var mixed An array of admin_setting objects that are part of this setting page.
1327 */
1328 var $settings;
eef868d1 1329
6e4dc10f 1330 /**
1331 * @var string The role capability/permission a user must have to access this external page.
1332 */
2ce38b70 1333 var $req_capability;
eef868d1 1334
84c8ede0 1335 /**
1336 * @var object The context in which capability/permission should be checked, default is site context.
1337 */
1338 var $context;
1339
a8a66c96 1340 /**
1341 * @var bool hidden in admin tree block.
1342 */
1343 var $hidden;
1344
220a90c5 1345 /**
1346 * paths
1347 */
1348 var $path;
1349 var $visiblepath;
1350
1351 // see admin_externalpage
1352 function admin_settingpage($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1353 $this->settings = new object();
1354 $this->name = $name;
1355 $this->visiblename = $visiblename;
1356 if (is_array($req_capability)) {
1357 $this->req_capability = $req_capability;
6e4dc10f 1358 } else {
220a90c5 1359 $this->req_capability = array($req_capability);
6e4dc10f 1360 }
220a90c5 1361 $this->hidden = $hidden;
1362 $this->context = $context;
6e4dc10f 1363 }
eef868d1 1364
6e4dc10f 1365 // see admin_category
220a90c5 1366 function &locate($name, $findpath=false) {
1367 if ($this->name == $name) {
1368 if ($findpath) {
1369 $this->visiblepath = array($this->visiblename);
1370 $this->path = array($this->name);
1371 }
1372 return $this;
1373 } else {
1374 $return = NULL;
1375 return $return;
1376 }
6e4dc10f 1377 }
4672d955 1378
220a90c5 1379 function search($query) {
1380 $found = array();
4672d955 1381
220a90c5 1382 foreach ($this->settings as $setting) {
1383 if ($setting->is_related($query)) {
1384 $found[] = $setting;
1385 }
1386 }
1387
1388 if ($found) {
1389 $result = new object();
1390 $result->page = $this;
1391 $result->settings = $found;
1392 return array($this->name => $result);
1393 }
1394
1395 $textlib = textlib_get_instance();
1396
1397 $found = false;
1398 if (strpos(strtolower($this->name), $query) !== false) {
1399 $found = true;
1400 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1401 $found = true;
1402 }
1403 if ($found) {
1404 $result = new object();
1405 $result->page = $this;
1406 $result->settings = array();
1407 return array($this->name => $result);
38d2d43b 1408 } else {
220a90c5 1409 return array();
38d2d43b 1410 }
6e4dc10f 1411 }
eef868d1 1412
220a90c5 1413 function prune($name) {
6e4dc10f 1414 return false;
1415 }
eef868d1 1416
220a90c5 1417 /**
1418 * 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
1419 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1420 * @param object $setting is the admin_setting object you want to add
1421 * @return true if successful, false if not
1422 */
1423 function add($setting) {
1424 if (!is_a($setting, 'admin_setting')) {
1425 debugging('error - not a setting instance');
1426 return false;
1427 }
1428
1429 $this->settings->{$setting->name} = $setting;
1430 return true;
1431 }
1432
6e4dc10f 1433 // see admin_externalpage
1434 function check_access() {
1435 if (!get_site()) {
1436 return true; // no access check before site is fully set up
1437 }
84c8ede0 1438 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1439 foreach($this->req_capability as $cap) {
1440 if (has_capability($cap, $context)) {
1441 return true;
1442 }
1443 }
1444 return false;
6e4dc10f 1445 }
eef868d1 1446
220a90c5 1447 /**
1448 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1449 * returns a string of the html
1450 */
6e4dc10f 1451 function output_html() {
220a90c5 1452 $adminroot =& admin_get_root();
1453 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
6e4dc10f 1454 foreach($this->settings as $setting) {
220a90c5 1455 $fullname = $setting->get_full_name();
1456 if (array_key_exists($fullname, $adminroot->errors)) {
1457 $data = $adminroot->errors[$fullname]->data;
6e4dc10f 1458 } else {
220a90c5 1459 $data = $setting->get_setting();
1460 if (is_null($data)) {
1461 $data = $setting->get_defaultsetting();
1462 }
6e4dc10f 1463 }
220a90c5 1464 $return .= $setting->output_html($data);
6e4dc10f 1465 }
220a90c5 1466 $return .= '</fieldset>';
6e4dc10f 1467 return $return;
1468 }
1469
a8a66c96 1470 /**
1471 * Is this settigns page hidden in admin tree block?
1472 *
1473 * @return bool True if hidden
1474 */
1475 function is_hidden() {
1476 return $this->hidden;
1477 }
1478
6e4dc10f 1479}
1480
1481
220a90c5 1482/**
1483 * Admin settings class. Only exists on setting pages.
1484 * Read & write happens at this level; no authentication.
1485 */
6e4dc10f 1486class admin_setting {
1487
1488 var $name;
1489 var $visiblename;
1490 var $description;
1491 var $defaultsetting;
220a90c5 1492 var $updatedcallback;
1493 var $plugin; // null means main config table
6e4dc10f 1494
220a90c5 1495 /**
1496 * Constructor
1497 * @param $name string unique ascii name
1498 * @param $visiblename string localised name
1499 * @param strin $description localised long description
1500 * @param mixed $defaultsetting string or array depending on implementation
1501 */
6e4dc10f 1502 function admin_setting($name, $visiblename, $description, $defaultsetting) {
220a90c5 1503 $this->name = $name;
1504 $this->visiblename = $visiblename;
1505 $this->description = $description;
6e4dc10f 1506 $this->defaultsetting = $defaultsetting;
1507 }
eef868d1 1508
220a90c5 1509 function get_full_name() {
1510 return 's_'.$this->plugin.'_'.$this->name;
1511 }
1512
1513 function get_id() {
1514 return 'id_s_'.$this->plugin.'_'.$this->name;
1515 }
1516
1517 function config_read($name) {
1518 global $CFG;
1519 if ($this->plugin === 'backup') {
1520 require_once($CFG->dirroot.'/backup/lib.php');
1521 $backupconfig = backup_get_config();
1522 if (isset($backupconfig->$name)) {
1523 return $backupconfig->$name;
1524 } else {
1525 return NULL;
1526 }
1527
1528 } else if (!empty($this->plugin)) {
1529 $value = get_config($this->plugin, $name);
1530 return $value === false ? NULL : $value;
1531
1532 } else {
1533 if (isset($CFG->$name)) {
1534 return $CFG->$name;
1535 } else {
1536 return NULL;
1537 }
1538 }
1539 }
1540
1541 function config_write($name, $value) {
1542 global $CFG;
1543 if ($this->plugin === 'backup') {
1544 require_once($CFG->dirroot.'/backup/lib.php');
1545 return (boolean)backup_set_config($name, $value);
1546 } else {
1547 return (boolean)set_config($name, $value, $this->plugin);
1548 }
1549 }
1550
1551 /**
1552 * Returns current value of this setting
1553 * @return mixed array or string depending on instance, NULL means not set yet
1554 */
6e4dc10f 1555 function get_setting() {
220a90c5 1556 // has to be overridden
1557 return NULL;
6e4dc10f 1558 }
eef868d1 1559
220a90c5 1560 /**
1561 * Returns default setting if exists
1562 * @return mixed array or string depending on instance; NULL means no default, user must supply
1563 */
8e5da17a 1564 function get_defaultsetting() {
1565 return $this->defaultsetting;
1566 }
1567
220a90c5 1568 /**
1569 * Store new setting
1570 * @param mixed string or array, must not be NULL
1571 * @return '' if ok, string error message otherwise
1572 */
6e4dc10f 1573 function write_setting($data) {
220a90c5 1574 // should be overridden
1575 return '';
6e4dc10f 1576 }
eef868d1 1577
220a90c5 1578 /**
1579 * Return part of form with setting
1580 * @param mixed data array or string depending on setting
1581 * @return string
1582 */
587c7040 1583 function output_html($data, $query='') {
220a90c5 1584 // should be overridden
1585 return;
1586 }
1587
1588 /**
1589 * function called if setting updated - cleanup, cache reset, etc.
1590 */
1591 function set_updatedcallback($functionname) {
1592 $this->updatedcallback = $functionname;
1593 }
1594
1595 /**
1596 * Is setting related to query text - used when searching
1597 * @param string $query
1598 * @return bool
1599 */
1600 function is_related($query) {
1601 if (strpos(strtolower($this->name), $query) !== false) {
1602 return true;
1603 }
1604 $textlib = textlib_get_instance();
1605 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1606 return true;
1607 }
1608 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1609 return true;
1610 }
587c7040 1611 $current = $this->get_setting();
1612 if (!is_null($current)) {
1613 if (is_string($current)) {
1614 if (strpos($textlib->strtolower($current), $query) !== false) {
1615 return true;
1616 }
1617 }
1618 }
1619 $default = $this->get_defaultsetting();
1620 if (!is_null($default)) {
1621 if (is_string($default)) {
1622 if (strpos($textlib->strtolower($default), $query) !== false) {
1623 return true;
1624 }
1625 }
1626 }
220a90c5 1627 return false;
6e4dc10f 1628 }
220a90c5 1629}
eef868d1 1630
220a90c5 1631/**
1632 * No setting - just heading and text.
1633 */
1634class admin_setting_heading extends admin_setting {
1635 /**
1636 * not a setting, just text
1637 * @param string $name of setting
1638 * @param string $heading heading
1639 * @param string $information text in box
1640 */
1641 function admin_setting_heading($name, $heading, $information) {
1642 parent::admin_setting($name, $heading, $information, '');
1643 }
1644
1645 function get_setting() {
1646 return true;
1647 }
1648
1649 function get_defaultsetting() {
1650 return true;
1651 }
1652
1653 function write_setting($data) {
1654 // do not write any setting
1655 return '';
1656 }
1657
587c7040 1658 function output_html($data, $query='') {
220a90c5 1659 $return = '';
1660 if ($this->visiblename != '') {
587c7040 1661 $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
220a90c5 1662 }
1663 if ($this->description != '') {
587c7040 1664 $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
220a90c5 1665 }
1666 return $return;
1667 }
1668}
6e4dc10f 1669
220a90c5 1670/**
1671 * The most flexibly setting, user is typing text
1672 */
6e4dc10f 1673class admin_setting_configtext extends admin_setting {
1674
1675 var $paramtype;
f7633b0f 1676 var $size;
6e4dc10f 1677
220a90c5 1678 /**
1679 * config text contructor
1680 * @param string $name of setting
1681 * @param string $visiblename localised
1682 * @param string $description long localised info
1683 * @param string $defaultsetting
1684 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
f7633b0f 1685 * @param int $size default field size
220a90c5 1686 */
f7633b0f 1687 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
6e4dc10f 1688 $this->paramtype = $paramtype;
f7633b0f 1689 if (!is_null($size)) {
1690 $this->size = $size;
1691 } else {
1692 $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
1693 }
6e4dc10f 1694 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1695 }
1696
1697 function get_setting() {
220a90c5 1698 return $this->config_read($this->name);
6e4dc10f 1699 }
eef868d1 1700
6e4dc10f 1701 function write_setting($data) {
8cad6cca 1702 if ($this->paramtype === PARAM_INT and $data === '') {
1703 // do not complain if '' used instead of 0
1704 $data = 0;
1705 }
220a90c5 1706 // $data is a string
e33fbf87 1707 $validated = $this->validate($data);
1708 if ($validated !== true) {
1709 return $validated;
c235598d 1710 }
220a90c5 1711 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 1712 }
1713
e33fbf87 1714 /**
1715 * Validate data before storage
1716 * @param string data
1717 * @return mixed true if ok string if error found
1718 */
c235598d 1719 function validate($data) {
9e24fbd1 1720 if (is_string($this->paramtype)) {
e33fbf87 1721 if (preg_match($this->paramtype, $data)) {
1722 return true;
1723 } else {
1724 return get_string('validateerror', 'admin');
1725 }
1726
9e24fbd1 1727 } else if ($this->paramtype === PARAM_RAW) {
1728 return true;
e33fbf87 1729
9e24fbd1 1730 } else {
294ce987 1731 $cleaned = clean_param($data, $this->paramtype);
e33fbf87 1732 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
1733 return true;
1734 } else {
1735 return get_string('validateerror', 'admin');
1736 }
9e24fbd1 1737 }
c235598d 1738 }
1739
587c7040 1740 function output_html($data, $query='') {
220a90c5 1741 $default = $this->get_defaultsetting();
1742
220a90c5 1743 return format_admin_setting($this, $this->visiblename,
f7633b0f 1744 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
587c7040 1745 $this->description, true, '', $default, $query);
6e4dc10f 1746 }
6e4dc10f 1747}
1748
220a90c5 1749/**
1750 * General text area without html editor.
1751 */
1752class admin_setting_configtextarea extends admin_setting_configtext {
1753 var $rows;
1754 var $cols;
eba8cd63 1755
28764710 1756 function admin_setting_configtextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
220a90c5 1757 $this->rows = $rows;
1758 $this->cols = $cols;
eba8cd63 1759 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1760 }
1761
587c7040 1762 function output_html($data, $query='') {
220a90c5 1763 $default = $this->get_defaultsetting();
1764
587c7040 1765 $defaultinfo = $default;
1766 if (!is_null($default) and $default !== '') {
1767 $defaultinfo = "\n".$default;
1768 }
220a90c5 1769
1770 return format_admin_setting($this, $this->visiblename,
8c37106d 1771 '<div class="form-textarea form-textarea-advanced" ><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'">'. s($data) .'</textarea></div>',
587c7040 1772 $this->description, true, '', $defaultinfo, $query);
220a90c5 1773 }
1774}
1775
1776/**
1777 * Password field, allows unmasking of password
1778 */
1779class admin_setting_configpasswordunmask extends admin_setting_configtext {
1780 /**
1781 * Constructor
1782 * @param string $name of setting
1783 * @param string $visiblename localised
1784 * @param string $description long localised info
1785 * @param string $defaultsetting default password
1786 */
1787 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
f7633b0f 1788 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
220a90c5 1789 }
1790
587c7040 1791 function output_html($data, $query='') {
220a90c5 1792 $id = $this->get_id();
1793 $unmask = get_string('unmaskpassword', 'form');
1794 $unmaskjs = '<script type="text/javascript">
eba8cd63 1795//<![CDATA[
220a90c5 1796document.write(\'<span class="unmask"><input id="'.$id.'unmask" value="1" type="checkbox" onclick="unmaskPassword(\\\''.$id.'\\\')"/><label for="'.$id.'unmask">'.addslashes_js($unmask).'<\/label><\/span>\');
eba8cd63 1797//]]>
1798</script>';
220a90c5 1799 return format_admin_setting($this, $this->visiblename,
f7633b0f 1800 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
587c7040 1801 $this->description, true, '', NULL, $query);
220a90c5 1802 }
1803}
1804
1805/**
e9c0fa35 1806 * Path to directory
220a90c5 1807 */
e9c0fa35 1808class admin_setting_configfile extends admin_setting_configtext {
220a90c5 1809 /**
1810 * Constructor
1811 * @param string $name of setting
1812 * @param string $visiblename localised
1813 * @param string $description long localised info
e9c0fa35 1814 * @param string $defaultdirectory default directory location
220a90c5 1815 */
e9c0fa35 1816 function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
f7633b0f 1817 parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
220a90c5 1818 }
1819
587c7040 1820 function output_html($data, $query='') {
220a90c5 1821 $default = $this->get_defaultsetting();
1822
220a90c5 1823 if ($data) {
e9c0fa35 1824 if (file_exists($data)) {
220a90c5 1825 $executable = '<span class="pathok">&#x2714;</span>';
1826 } else {
1827 $executable = '<span class="patherror">&#x2718;</span>';
1828 }
1829 } else {
1830 $executable = '';
1831 }
1832
1833 return format_admin_setting($this, $this->visiblename,
f7633b0f 1834 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
587c7040 1835 $this->description, true, '', $default, $query);
eba8cd63 1836 }
220a90c5 1837}
1838
1839/**
e9c0fa35 1840 * Path to executable file
220a90c5 1841 */
e9c0fa35 1842class admin_setting_configexecutable extends admin_setting_configfile {
1843
1844 function output_html($data, $query='') {
1845 $default = $this->get_defaultsetting();
1846
1847 if ($data) {
1848 if (file_exists($data) and is_executable($data)) {
1849 $executable = '<span class="pathok">&#x2714;</span>';
1850 } else {
1851 $executable = '<span class="patherror">&#x2718;</span>';
1852 }
1853 } else {
1854 $executable = '';
1855 }
1856
1857 return format_admin_setting($this, $this->visiblename,
f7633b0f 1858 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
e9c0fa35 1859 $this->description, true, '', $default, $query);
220a90c5 1860 }
e9c0fa35 1861}
220a90c5 1862
e9c0fa35 1863/**
1864 * Path to directory
1865 */
1866class admin_setting_configdirectory extends admin_setting_configfile {
587c7040 1867 function output_html($data, $query='') {
220a90c5 1868 $default = $this->get_defaultsetting();
1869
220a90c5 1870 if ($data) {
1871 if (file_exists($data) and is_dir($data)) {
1872 $executable = '<span class="pathok">&#x2714;</span>';
1873 } else {
1874 $executable = '<span class="patherror">&#x2718;</span>';
1875 }
1876 } else {
1877 $executable = '';
1878 }
9ba38673 1879
220a90c5 1880 return format_admin_setting($this, $this->visiblename,
f7633b0f 1881 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
587c7040 1882 $this->description, true, '', $default, $query);
220a90c5 1883 }
eba8cd63 1884}
1885
220a90c5 1886/**
1887 * Checkbox
1888 */
6e4dc10f 1889class admin_setting_configcheckbox extends admin_setting {
220a90c5 1890 var $yes;
1891 var $no;
6e4dc10f 1892
220a90c5 1893 /**
1894 * Constructor
1895 * @param string $name of setting
1896 * @param string $visiblename localised
1897 * @param string $description long localised info
1898 * @param string $defaultsetting
1899 * @param string $yes value used when checked
1900 * @param string $no value used when not checked
1901 */
1902 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
6e4dc10f 1903 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
220a90c5 1904 $this->yes = (string)$yes;
1905 $this->no = (string)$no;
6e4dc10f 1906 }
1907
1908 function get_setting() {
220a90c5 1909 return $this->config_read($this->name);
6e4dc10f 1910 }
eef868d1 1911
6e4dc10f 1912 function write_setting($data) {
220a90c5 1913 if ((string)$data === $this->yes) { // convert to strings before comparison
1914 $data = $this->yes;
6e4dc10f 1915 } else {
220a90c5 1916 $data = $this->no;
6e4dc10f 1917 }
220a90c5 1918 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 1919 }
1920
587c7040 1921 function output_html($data, $query='') {
220a90c5 1922 $default = $this->get_defaultsetting();
1923
1924 if (!is_null($default)) {
1925 if ((string)$default === $this->yes) {
587c7040 1926 $defaultinfo = get_string('checkboxyes', 'admin');
220a90c5 1927 } else {
587c7040 1928 $defaultinfo = get_string('checkboxno', 'admin');
220a90c5 1929 }
c8218a42 1930 } else {
587c7040 1931 $defaultinfo = NULL;
c8218a42 1932 }
220a90c5 1933
1934 if ((string)$data === $this->yes) { // convert to strings before comparison
1935 $checked = 'checked="checked"';
1936 } else {
1937 $checked = '';
1938 }
1939
1940 return format_admin_setting($this, $this->visiblename,
587c7040 1941 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
1942 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
1943 $this->description, true, '', $defaultinfo, $query);
6e4dc10f 1944 }
6e4dc10f 1945}
1946
220a90c5 1947/**
1948 * Multiple checkboxes, each represents different value, stored in csv format
1949 */
1950class admin_setting_configmulticheckbox extends admin_setting {
6e4dc10f 1951 var $choices;
eef868d1 1952
220a90c5 1953 /**
1954 * Constructor
1955 * @param string $name of setting
1956 * @param string $visiblename localised
1957 * @param string $description long localised info
1958 * @param array $defaultsetting array of selected
1959 * @param array $choices array of $value=>$label for each checkbox
1960 */
1961 function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
6e4dc10f 1962 $this->choices = $choices;
1963 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1964 }
1965
0a784551 1966 /**
1967 * This function may be used in ancestors for lazy loading of choices
220a90c5 1968 * @return true if loaded, false if error
0a784551 1969 */
1970 function load_choices() {
1971 /*
220a90c5 1972 if (is_array($this->choices)) {
1973 return true;
0a784551 1974 }
1975 .... load choices here
1976 */
220a90c5 1977 return true;
1978 }
1979
1980 /**
1981 * Is setting related to query text - used when searching
1982 * @param string $query
1983 * @return bool
1984 */
1985 function is_related($query) {
1986 if (!$this->load_choices() or empty($this->choices)) {
1987 return false;
1988 }
1989 if (parent::is_related($query)) {
1990 return true;
1991 }
1992
1993 $textlib = textlib_get_instance();
1994 foreach ($this->choices as $desc) {
1995 if (strpos($textlib->strtolower($desc), $query) !== false) {
1996 return true;
1997 }
1998 }
1999 return false;
0a784551 2000 }
2001
6e4dc10f 2002 function get_setting() {
220a90c5 2003 $result = $this->config_read($this->name);
2004 if (is_null($result)) {
2005 return NULL;
2006 }
2007 if ($result === '') {
2008 return array();
2009 }
2010 return explode(',', $result);
6e4dc10f 2011 }
eef868d1 2012
6e4dc10f 2013 function write_setting($data) {
220a90c5 2014 if (!is_array($data)) {
2015 return ''; // ignore it
2016 }
2017 if (!$this->load_choices() or empty($this->choices)) {
2018 return '';
2019 }
2020 unset($data['xxxxx']);
2021 $result = array();
2022 foreach ($data as $key => $value) {
2023 if ($value and array_key_exists($key, $this->choices)) {
2024 $result[] = $key;
2025 }
2026 }
2027 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
6e4dc10f 2028 }
eef868d1 2029
587c7040 2030 function output_html($data, $query='') {
220a90c5 2031 if (!$this->load_choices() or empty($this->choices)) {
2032 return '';
2033 }
2034 $default = $this->get_defaultsetting();
2035 if (is_null($default)) {
2036 $default = array();
2037 }
2038 if (is_null($data)) {
2039 foreach ($default as $key=>$value) {
2040 if ($value) {
2041 $current[] = $value;
2042 }
2043 }
2044 }
2045
2046 $options = array();
2047 $defaults = array();
2048 foreach($this->choices as $key=>$description) {
2049 if (in_array($key, $data)) {
2050 $checked = 'checked="checked"';
2051 } else {
2052 $checked = '';
2053 }
2054 if (!empty($default[$key])) {
2055 $defaults[] = $description;
2056 }
2057
2058 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
587c7040 2059 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
220a90c5 2060 }
2061
587c7040 2062 if (is_null($default)) {
2063 $defaultinfo = NULL;
2064 } else if (!empty($defaults)) {
2065 $defaultinfo = implode(', ', $defaults);
c8218a42 2066 } else {
587c7040 2067 $defaultinfo = get_string('none');
c8218a42 2068 }
220a90c5 2069
2070 $return = '<div class="form-multicheckbox">';
2071 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2072 if ($options) {
2073 $return .= '<ul>';
2074 foreach ($options as $option) {
2075 $return .= '<li>'.$option.'</li>';
2076 }
2077 $return .= '</ul>';
6e4dc10f 2078 }
587c7040 2079 $return .= '</div>';
6153cf58 2080
587c7040 2081 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2082
6e4dc10f 2083 }
6e4dc10f 2084}
2085
220a90c5 2086/**
2087 * Multiple checkboxes 2, value stored as string 00101011
2088 */
2089class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2090 function get_setting() {
2091 $result = $this->config_read($this->name);
2092 if (is_null($result)) {
2093 return NULL;
2094 }
2095 if (!$this->load_choices()) {
2096 return NULL;
2097 }
2098 $result = str_pad($result, count($this->choices), '0');
2099 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2100 $setting = array();
2101 foreach ($this->choices as $key=>$unused) {
2102 $value = array_shift($result);
2103 if ($value) {
2104 $setting[] = $key;
2105 }
2106 }
2107 return $setting;
2108 }
6e4dc10f 2109
220a90c5 2110 function write_setting($data) {
2111 if (!is_array($data)) {
2112 return ''; // ignore it
2113 }
2114 if (!$this->load_choices() or empty($this->choices)) {
2115 return '';
2116 }
2117 $result = '';
2118 foreach ($this->choices as $key=>$unused) {
2119 if (!empty($data[$key])) {
2120 $result .= '1';
2121 } else {
2122 $result .= '0';
2123 }
2124 }
2125 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2126 }
2127}
2128
2129/**
2130 * Select one value from list
2131 */
2132class admin_setting_configselect extends admin_setting {
6e4dc10f 2133 var $choices;
6e4dc10f 2134
220a90c5 2135 /**
2136 * Constructor
2137 * @param string $name of setting
2138 * @param string $visiblename localised
2139 * @param string $description long localised info
2140 * @param string $defaultsetting
2141 * @param array $choices array of $value=>$label for each selection
2142 */
2143 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
2144 $this->choices = $choices;
2145 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2146 }
2147
2148 /**
2149 * This function may be used in ancestors for lazy loading of choices
2150 * @return true if loaded, false if error
2151 */
2152 function load_choices() {
2153 /*
2154 if (is_array($this->choices)) {
2155 return true;
6e4dc10f 2156 }
220a90c5 2157 .... load choices here
2158 */
2159 return true;
6e4dc10f 2160 }
2161
407d8134 2162 function is_related($query) {
2163 if (parent::is_related($query)) {
2164 return true;
2165 }
2166 if (!$this->load_choices()) {
2167 return false;
2168 }
2169 $textlib = textlib_get_instance();
2170 foreach ($this->choices as $key=>$value) {
2171 if (strpos($textlib->strtolower($key), $query) !== false) {
2172 return true;
2173 }
2174 if (strpos($textlib->strtolower($value), $query) !== false) {
2175 return true;
2176 }
2177 }
2178 return false;
2179 }
2180
6e4dc10f 2181 function get_setting() {
220a90c5 2182 return $this->config_read($this->name);
6e4dc10f 2183 }
eef868d1 2184
6e4dc10f 2185 function write_setting($data) {
220a90c5 2186 if (!$this->load_choices() or empty($this->choices)) {
2187 return '';
2188 }
2189 if (!array_key_exists($data, $this->choices)) {
2190 return ''; // ignore it
2191 }
eef868d1 2192
220a90c5 2193 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2194 }
eef868d1 2195
587c7040 2196 function output_html($data, $query='') {
220a90c5 2197 if (!$this->load_choices() or empty($this->choices)) {
2198 return '';
2199 }
2200 $default = $this->get_defaultsetting();
2201
2202 if (!is_null($default) and array_key_exists($default, $this->choices)) {
587c7040 2203 $defaultinfo = $this->choices[$default];
cc73de71 2204 } else {
587c7040 2205 $defaultinfo = NULL;
6e4dc10f 2206 }
220a90c5 2207
9c305ba1 2208 $current = $this->get_setting();
2209 $warning = '';
2210 if (is_null($current)) {
2211 //first run
2212 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2213 // no warning
2214 } else if (!array_key_exists($current, $this->choices)) {
2215 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2216 if (!is_null($default) and $data==$current) {
2217 $data = $default; // use default instead of first value when showing the form
2218 }
2219 }
2220
587c7040 2221 $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
6e4dc10f 2222 foreach ($this->choices as $key => $value) {
220a90c5 2223 // the string cast is needed because key may be integer - 0 is equal to most strings!
2224 $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
eef868d1 2225 }
587c7040 2226 $return .= '</select></div>';
220a90c5 2227
587c7040 2228 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
6e4dc10f 2229 }
2230
2231}
2232
220a90c5 2233/**
2234 * Select multiple items from list
2235 */
6e4dc10f 2236class admin_setting_configmultiselect extends admin_setting_configselect {
220a90c5 2237 /**
2238 * Constructor
2239 * @param string $name of setting
2240 * @param string $visiblename localised
2241 * @param string $description long localised info
2242 * @param array $defaultsetting array of selected items
2243 * @param array $choices array of $value=>$label for each list item
2244 */
6e4dc10f 2245 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
2246 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
2247 }
2248
2249 function get_setting() {
220a90c5 2250 $result = $this->config_read($this->name);
2251 if (is_null($result)) {
d7933a55 2252 return NULL;
2253 }
220a90c5 2254 if ($result === '') {
2255 return array();
2256 }
2257 return explode(',', $result);
6e4dc10f 2258 }
eef868d1 2259
6e4dc10f 2260 function write_setting($data) {
220a90c5 2261 if (!is_array($data)) {
2262 return ''; //ignore it
2263 }
2264 if (!$this->load_choices() or empty($this->choices)) {
2265 return '';
2266 }
2267
a7ad48fd 2268 unset($data['xxxxx']);
2269
220a90c5 2270 $save = array();
2271 foreach ($data as $value) {
2272 if (!array_key_exists($value, $this->choices)) {
2273 continue; // ignore it
2274 }
2275 $save[] = $value;
2276 }
2277
2278 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2279 }
2280
2281 /**
2282 * Is setting related to query text - used when searching
2283 * @param string $query
2284 * @return bool
2285 */
2286 function is_related($query) {
2287 if (!$this->load_choices() or empty($this->choices)) {
2288 return false;
2289 }
2290 if (parent::is_related($query)) {
2291 return true;
2292 }
2293
2294 $textlib = textlib_get_instance();
2295 foreach ($this->choices as $desc) {
2296 if (strpos($textlib->strtolower($desc), $query) !== false) {
2297 return true;
2298 }
2299 }
2300 return false;
2301 }
2302
587c7040 2303 function output_html($data, $query='') {
220a90c5 2304 if (!$this->load_choices() or empty($this->choices)) {
2305 return '';
2306 }
2307 $choices = $this->choices;
2308 $default = $this->get_defaultsetting();
2309 if (is_null($default)) {
2310 $default = array();
2311 }
2312 if (is_null($data)) {
d7933a55 2313 $data = array();
2314 }
220a90c5 2315
2316 $defaults = array();
a7ad48fd 2317 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2318 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="10" multiple="multiple">';
220a90c5 2319 foreach ($this->choices as $key => $description) {
2320 if (in_array($key, $data)) {
2321 $selected = 'selected="selected"';
2322 } else {
2323 $selected = '';
2324 }
2325 if (in_array($key, $default)) {
2326 $defaults[] = $description;
6e4dc10f 2327 }
220a90c5 2328
2329 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2330 }
2331
587c7040 2332 if (is_null($default)) {
2333 $defaultinfo = NULL;
2334 } if (!empty($defaults)) {
2335 $defaultinfo = implode(', ', $defaults);
220a90c5 2336 } else {
587c7040 2337 $defaultinfo = get_string('none');
6e4dc10f 2338 }
eef868d1 2339
587c7040 2340 $return .= '</select></div>';
2341 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
6e4dc10f 2342 }
220a90c5 2343}
eef868d1 2344
220a90c5 2345/**
2346 * Time selector
2347 * this is a liiitle bit messy. we're using two selects, but we're returning
2348 * them as an array named after $name (so we only use $name2 internally for the setting)
2349 */
2350class admin_setting_configtime extends admin_setting {
2351 var $name2;
2352
2353 /**
2354 * Constructor
2355 * @param string $hoursname setting for hours
2356 * @param string $minutesname setting for hours
2357 * @param string $visiblename localised
2358 * @param string $description long localised info
2359 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2360 */
2361 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2362 $this->name2 = $minutesname;
2363 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
2364 }
2365
2366 function get_setting() {
2367 $result1 = $this->config_read($this->name);
2368 $result2 = $this->config_read($this->name2);
2369 if (is_null($result1) or is_null($result2)) {
2370 return NULL;
2371 }
2372
2373 return array('h' => $result1, 'm' => $result2);
2374 }
2375
2376 function write_setting($data) {
2377 if (!is_array($data)) {
2378 return '';
2379 }
2380
2381 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2382 return ($result ? '' : get_string('errorsetting', 'admin'));
2383 }
2384
587c7040 2385 function output_html($data, $query='') {
220a90c5 2386 $default = $this->get_defaultsetting();
2387
2388 if (is_array($default)) {
587c7040 2389 $defaultinfo = $default['h'].':'.$default['m'];
cc73de71 2390 } else {
587c7040 2391 $defaultinfo = NULL;
6e4dc10f 2392 }
220a90c5 2393
587c7040 2394 $return = '<div class="form-time defaultsnext">'.
220a90c5 2395 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2396 for ($i = 0; $i < 24; $i++) {
2397 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
6e4dc10f 2398 }
220a90c5 2399 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2400 for ($i = 0; $i < 60; $i += 5) {
2401 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2402 }
587c7040 2403 $return .= '</select></div>';
2404 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
6e4dc10f 2405 }
2406
2407}
2408
220a90c5 2409/**
2410 * Special checkbox for calendar - resets SESSION vars.
2411 */
6e4dc10f 2412class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
6e4dc10f 2413 function admin_setting_special_adminseesall() {
220a90c5 2414 parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
2415 get_string('helpadminseesall', 'admin'), '0');
6e4dc10f 2416 }
2417
2418 function write_setting($data) {
2419 global $SESSION;
2420 unset($SESSION->cal_courses_shown);
220a90c5 2421 return parent::write_setting($data);
6e4dc10f 2422 }
2423}
2424
392e7363 2425/**
2426 * Special select for settings that are altered in setup.php and can not be altered on the fly
2427 */
2428class admin_setting_special_selectsetup extends admin_setting_configselect {
2429 function get_setting() {
2430 // read directly from db!
2431 return get_config(NULL, $this->name);
2432 }
2433
2434 function write_setting($data) {
2435 global $CFG;
2436 // do not change active CFG setting!
2437 $current = $CFG->{$this->name};
2438 $result = parent::write_setting($data);
2439 $CFG->{$this->name} = $current;
2440 return $result;
2441 }
2442}
2443
220a90c5 2444/**
2445 * Special select for frontpage - stores data in course table
2446 */
6e4dc10f 2447class admin_setting_sitesetselect extends admin_setting_configselect {
6e4dc10f 2448 function get_setting() {
2449 $site = get_site();
220a90c5 2450 return $site->{$this->name};
6e4dc10f 2451 }
eef868d1 2452
6e4dc10f 2453 function write_setting($data) {
f33e1ed4 2454 global $DB;
6e4dc10f 2455 if (!in_array($data, array_keys($this->choices))) {
220a90c5 2456 return get_string('errorsetting', 'admin');
6e4dc10f 2457 }
2458 $record = new stdClass();
220a90c5 2459 $record->id = SITEID;
2460 $temp = $this->name;
2461 $record->$temp = $data;
6e4dc10f 2462 $record->timemodified = time();
f33e1ed4 2463 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2464 }
6e4dc10f 2465}
2466
220a90c5 2467/**
2468 * Special select - lists on the frontpage - hacky
2469 */
2470class admin_setting_courselist_frontpage extends admin_setting {
2471 var $choices;
6e4dc10f 2472
e0f6e995 2473 function admin_setting_courselist_frontpage($loggedin) {
6e4dc10f 2474 global $CFG;
220a90c5 2475 require_once($CFG->dirroot.'/course/lib.php');
2476 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2477 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2478 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2479 $defaults = array(FRONTPAGECOURSELIST);
2480 parent::admin_setting($name, $visiblename, $description, $defaults);
6e4dc10f 2481 }
eef868d1 2482
220a90c5 2483 function load_choices() {
c7da4357 2484 global $DB;
220a90c5 2485 if (is_array($this->choices)) {
2486 return true;
2487 }
2488 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2489 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2490 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2491 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2492 'none' => get_string('none'));
c7da4357 2493 if ($this->name == 'frontpage' and $DB->count_records('course') > FRONTPAGECOURSELIMIT) {
220a90c5 2494 unset($this->choices[FRONTPAGECOURSELIST]);
2495 }
2496 return true;
2497 }
6e4dc10f 2498 function get_setting() {
220a90c5 2499 $result = $this->config_read($this->name);
2500 if (is_null($result)) {
2501 return NULL;
2502 }
2503 if ($result === '') {
2504 return array();
2505 }
2506 return explode(',', $result);
6e4dc10f 2507 }
eef868d1 2508
6e4dc10f 2509 function write_setting($data) {
220a90c5 2510 if (!is_array($data)) {
2511 return '';
6e4dc10f 2512 }
220a90c5 2513 $this->load_choices();
2514 $save = array();
6e4dc10f 2515 foreach($data as $datum) {
220a90c5 2516 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2517 continue;
6e4dc10f 2518 }
220a90c5 2519 $save[$datum] = $datum; // no duplicates
6e4dc10f 2520 }
220a90c5 2521 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2522 }
eef868d1 2523
587c7040 2524 function output_html($data, $query='') {
220a90c5 2525 $this->load_choices();
2526 $currentsetting = array();
2527 foreach ($data as $key) {
2528 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2529 $currentsetting[] = $key; // already selected first
6e4dc10f 2530 }
2531 }
220a90c5 2532
0a7e84c3 2533 $return = '<div class="form-group">';
6e4dc10f 2534 for ($i = 0; $i < count($this->choices) - 1; $i++) {
220a90c5 2535 if (!array_key_exists($i, $currentsetting)) {
2536 $currentsetting[$i] = 'none'; //none
2537 }
2538 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
6e4dc10f 2539 foreach ($this->choices as $key => $value) {
220a90c5 2540 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
6e4dc10f 2541 }
2542 $return .= '</select>';
2543 if ($i !== count($this->choices) - 2) {
975211bb 2544 $return .= '<br />';
6e4dc10f 2545 }
2546 }
0a7e84c3 2547 $return .= '</div>';
2548
587c7040 2549 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
6e4dc10f 2550 }
2551}
2552
220a90c5 2553/**
2554 * Special checkbox for frontpage - stores data in course table
2555 */
6e4dc10f 2556class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
6e4dc10f 2557 function get_setting() {
2558 $site = get_site();
8e5da17a 2559 return $site->{$this->name};
6e4dc10f 2560 }
eef868d1 2561
6e4dc10f 2562 function write_setting($data) {
f33e1ed4 2563 global $DB;
220a90c5 2564 $record = new object();
2565 $record->id = SITEID;
2566 $record->{$this->name} = ($data == '1' ? 1 : 0);
2567 $record->timemodified = time();
f33e1ed4 2568 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2569 }
6e4dc10f 2570}
2571
220a90c5 2572/**
2573 * Special text for frontpage - stores data in course table.
2574 * Empty string means not set here. Manual setting is required.
2575 */
6e4dc10f 2576class admin_setting_sitesettext extends admin_setting_configtext {
6e4dc10f 2577 function get_setting() {
2578 $site = get_site();
8e5da17a 2579 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
6e4dc10f 2580 }
90cfbd0a 2581
b89639f9 2582 function validate($data) {
294ce987 2583 $cleaned = clean_param($data, PARAM_MULTILANG);
e33fbf87 2584 if ($cleaned === '') {
2585 return get_string('required');
2586 }
2587 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2588 return true;
2589 } else {
2590 return get_string('validateerror', 'admin');
b89639f9 2591 }
b89639f9 2592 }
2593
6e4dc10f 2594 function write_setting($data) {
f33e1ed4 2595 global $DB;
b89639f9 2596 $data = trim($data);
e33fbf87 2597 $validated = $this->validate($data);
2598 if ($validated !== true) {
2599 return $validated;
90cfbd0a 2600 }
eef868d1 2601
220a90c5 2602 $record = new object();
2603 $record->id = SITEID;
f33e1ed4 2604 $record->{$this->name} = $data;
220a90c5 2605 $record->timemodified = time();
f33e1ed4 2606 return ($DB->update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
6e4dc10f 2607 }
6e4dc10f 2608}
2609
220a90c5 2610/**
2611 * Special text editor for site description.
2612 */
6e4dc10f 2613class admin_setting_special_frontpagedesc extends admin_setting {
6e4dc10f 2614 function admin_setting_special_frontpagedesc() {
220a90c5 2615 parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
6e4dc10f 2616 }
eef868d1 2617
6e4dc10f 2618 function get_setting() {
6e4dc10f 2619 $site = get_site();
c626c2f4 2620 return $site->{$this->name};
2621 }
eef868d1 2622
6e4dc10f 2623 function write_setting($data) {
f33e1ed4 2624 global $DB;
c626c2f4 2625 $record = new object();
220a90c5 2626 $record->id = SITEID;
f33e1ed4 2627 $record->{$this->name} = $data;
c626c2f4 2628 $record->timemodified = time();
f33e1ed4 2629 return($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2630 }
2631
587c7040 2632 function output_html($data, $query='') {
0d6ec706 2633 global $CFG, $htmlEditorObject;
6e4dc10f 2634
220a90c5 2635 $CFG->adminusehtmleditor = can_use_html_editor();
8c37106d 2636 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'</div>';
220a90c5 2637
587c7040 2638 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
220a90c5 2639 }
2640}
6e4dc10f 2641
2642class admin_setting_special_editorfontlist extends admin_setting {
2643
2644 var $items;
2645
2646 function admin_setting_special_editorfontlist() {
2647 global $CFG;
2648 $name = 'editorfontlist';
2649 $visiblename = get_string('editorfontlist', 'admin');
2650 $description = get_string('configeditorfontlist', 'admin');
6e4dc10f 2651 $defaults = array('k0' => 'Trebuchet',
2652 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
2653 'k1' => 'Arial',
2654 'v1' => 'arial,helvetica,sans-serif',
2655 'k2' => 'Courier New',
2656 'v2' => 'courier new,courier,monospace',
2657 'k3' => 'Georgia',
2658 'v3' => 'georgia,times new roman,times,serif',
2659 'k4' => 'Tahoma',
2660 'v4' => 'tahoma,arial,helvetica,sans-serif',
2661 'k5' => 'Times New Roman',
2662 'v5' => 'times new roman,times,serif',
2663 'k6' => 'Verdana',
2664 'v6' => 'verdana,arial,helvetica,sans-serif',
2665 'k7' => 'Impact',
2666 'v7' => 'impact',
2667 'k8' => 'Wingdings',
2668 'v8' => 'wingdings');
2669 parent::admin_setting($name, $visiblename, $description, $defaults);
2670 }
eef868d1 2671
6e4dc10f 2672 function get_setting() {
cc73de71 2673 global $CFG;
220a90c5 2674 $result = $this->config_read($this->name);
2675 if (is_null($result)) {
cc73de71 2676 return NULL;
2677 }
220a90c5 2678 $i = 0;
2679 $currentsetting = array();
2680 $items = explode(';', $result);
2681 foreach ($items as $item) {
2682 $item = explode(':', $item);
2683 $currentsetting['k'.$i] = $item[0];
2684 $currentsetting['v'.$i] = $item[1];
2685 $i++;
2686 }
2687 return $currentsetting;
6e4dc10f 2688 }
eef868d1 2689
6e4dc10f 2690 function write_setting($data) {
eef868d1 2691
6e4dc10f 2692 // there miiight be an easier way to do this :)
2693 // if this is changed, make sure the $defaults array above is modified so that this
2694 // function processes it correctly
eef868d1 2695
6e4dc10f 2696 $keys = array();
2697 $values = array();
eef868d1 2698
6e4dc10f 2699 foreach ($data as $key => $value) {
2700 if (substr($key,0,1) == 'k') {
2701 $keys[substr($key,1)] = $value;
2702 } elseif (substr($key,0,1) == 'v') {
2703 $values[substr($key,1)] = $value;
2704 }
2705 }
eef868d1 2706
220a90c5 2707 $result = array();
6e4dc10f 2708 for ($i = 0; $i < count($keys); $i++) {
2709 if (($keys[$i] !== '') && ($values[$i] !== '')) {
220a90c5 2710 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
6e4dc10f 2711 }
2712 }
eef868d1 2713
220a90c5 2714 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2715 }
eef868d1 2716
587c7040 2717 function output_html($data, $query='') {
220a90c5 2718 $fullname = $this->get_full_name();
1beed35f 2719 $return = '<div class="form-group">';
220a90c5 2720 for ($i = 0; $i < count($data) / 2; $i++) {
2721 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
6e4dc10f 2722 $return .= '&nbsp;&nbsp;';
220a90c5 2723 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
6e4dc10f 2724 }
220a90c5 2725 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
6e4dc10f 2726 $return .= '&nbsp;&nbsp;';
220a90c5 2727 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2728 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
6e4dc10f 2729 $return .= '&nbsp;&nbsp;';
220a90c5 2730 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
1beed35f 2731 $return .= '</div>';
6153cf58 2732
587c7040 2733 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
6e4dc10f 2734 }
eef868d1 2735
6e4dc10f 2736}
2737
93c61c18 2738class admin_setting_emoticons extends admin_setting {
2739
2740 var $items;
2741
2742 function admin_setting_emoticons() {
2743 global $CFG;
2744 $name = 'emoticons';
2745 $visiblename = get_string('emoticons', 'admin');
2746 $description = get_string('configemoticons', 'admin');
2747 $defaults = array('k0' => ':-)',
2748 'v0' => 'smiley',
2749 'k1' => ':)',
2750 'v1' => 'smiley',
2751 'k2' => ':-D',
2752 'v2' => 'biggrin',
2753 'k3' => ';-)',
2754 'v3' => 'wink',
2755 'k4' => ':-/',
2756 'v4' => 'mixed',
2757 'k5' => 'V-.',
2758 'v5' => 'thoughtful',
2759 'k6' => ':-P',
2760 'v6' => 'tongueout',
2761 'k7' => 'B-)',
2762 'v7' => 'cool',
2763 'k8' => '^-)',
2764 'v8' => 'approve',
2765 'k9' => '8-)',
2766 'v9' => 'wideeyes',
2767 'k10' => ':o)',
2768 'v10' => 'clown',
2769 'k11' => ':-(',
2770 'v11' => 'sad',
2771 'k12' => ':(',
2772 'v12' => 'sad',
2773 'k13' => '8-.',
2774 'v13' => 'shy',
2775 'k14' => ':-I',
2776 'v14' => 'blush',
2777 'k15' => ':-X',
2778 'v15' => 'kiss',
2779 'k16' => '8-o',
2780 'v16' => 'surprise',
2781 'k17' => 'P-|',
2782 'v17' => 'blackeye',
2783 'k18' => '8-[',
2784 'v18' => 'angry',
2785 'k19' => 'xx-P',
2786 'v19' => 'dead',
2787 'k20' => '|-.',
2788 'v20' => 'sleepy',
2789 'k21' => '}-]',
2790 'v21' => 'evil',
2791 'k22' => '(h)',
2792 'v22' => 'heart',
2793 'k23' => '(heart)',
2794 'v23' => 'heart',
2795 'k24' => '(y)',
2796 'v24' => 'yes',
2797 'k25' => '(n)',
2798 'v25' => 'no',
2799 'k26' => '(martin)',
2800 'v26' => 'martin',
2801 'k27' => '( )',
2802 'v27' => 'egg');
2803 parent::admin_setting($name, $visiblename, $description, $defaults);
2804 }
2805
2806 function get_setting() {
2807 global $CFG;
220a90c5 2808 $result = $this->config_read($this->name);
2809 if (is_null($result)) {
93c61c18 2810 return NULL;
2811 }
220a90c5 2812 $i = 0;
2813 $currentsetting = array();
2814 $items = explode('{;}', $result);
2815 foreach ($items as $item) {
2816 $item = explode('{:}', $item);
2817 $currentsetting['k'.$i] = $item[0];
2818 $currentsetting['v'.$i] = $item[1];
2819 $i++;
2820 }
2821 return $currentsetting;
93c61c18 2822 }
2823
2824 function write_setting($data) {
2825
2826 // there miiight be an easier way to do this :)
2827 // if this is changed, make sure the $defaults array above is modified so that this
2828 // function processes it correctly
2829
2830 $keys = array();
2831 $values = array();
2832
2833 foreach ($data as $key => $value) {
2834 if (substr($key,0,1) == 'k') {
2835 $keys[substr($key,1)] = $value;
2836 } elseif (substr($key,0,1) == 'v') {
2837 $values[substr($key,1)] = $value;
2838 }
2839 }
2840
220a90c5 2841 $result = array();
93c61c18 2842 for ($i = 0; $i < count($keys); $i++) {
2843 if (($keys[$i] !== '') && ($values[$i] !== '')) {
220a90c5 2844 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
93c61c18 2845 }
2846 }
2847
220a90c5 2848 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
93c61c18 2849 }
2850
587c7040 2851 function output_html($data, $query='') {
220a90c5 2852 $fullname = $this->get_full_name();
93c61c18 2853 $return = '<div class="form-group">';
220a90c5 2854 for ($i = 0; $i < count($data) / 2; $i++) {
2855 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
93c61c18 2856 $return .= '&nbsp;&nbsp;';
220a90c5 2857 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
93c61c18 2858 }
220a90c5 2859 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
93c61c18 2860 $return .= '&nbsp;&nbsp;';
220a90c5 2861 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2862 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
93c61c18 2863 $return .= '&nbsp;&nbsp;';
220a90c5 2864 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
93c61c18 2865 $return .= '</div>';
2866
587c7040 2867 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
93c61c18 2868 }
2869
2870}
2871
220a90c5 2872/**
2873 * Setting for spellchecker language selection.
2874 */
6e4dc10f 2875class admin_setting_special_editordictionary extends admin_setting_configselect {
2876
2877 function admin_setting_special_editordictionary() {
2878 $name = 'editordictionary';
2879 $visiblename = get_string('editordictionary','admin');
2880 $description = get_string('configeditordictionary', 'admin');
220a90c5 2881 parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
6e4dc10f 2882 }
2883
220a90c5 2884 function load_choices() {
2885 // function borrowed from the old moodle/admin/editor.php, slightly modified
2886 // Get all installed dictionaries in the system
2887 if (is_array($this->choices)) {
2888 return true;
2889 }
2890
2891 $this->choices = array();
6e4dc10f 2892
2893 global $CFG;
eef868d1 2894
6e4dc10f 2895 clearstatcache();
2896
2897 // If aspellpath isn't set don't even bother ;-)
2898 if (empty($CFG->aspellpath)) {
220a90c5 2899 $this->choices['error'] = 'Empty aspell path!';
2900 return true;
6e4dc10f 2901 }
2902
2903 // Do we have access to popen function?
2904 if (!function_exists('popen')) {
220a90c5 2905 $this->choices['error'] = 'Popen function disabled!';
2906 return true;
6e4dc10f 2907 }
eef868d1 2908
6e4dc10f 2909 $cmd = $CFG->aspellpath;
2910 $output = '';
2911 $dictionaries = array();
6e4dc10f 2912
220a90c5 2913 if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
2914 $this->choices['error'] = 'Couldn\'t create handle!';
6e4dc10f 2915 }
2916
2917 while(!feof($handle)) {
2918 $output .= fread($handle, 1024);
2919 }
2920 @pclose($handle);
2921
2922 $dictionaries = explode(chr(10), $output);
220a90c5 2923 foreach ($dictionaries as $dict) {
2924 if (empty($dict)) {
2925 continue;
6e4dc10f 2926 }
220a90c5 2927 $this->choices[$dict] = $dict;
6e4dc10f 2928 }
2929
220a90c5 2930 if (empty($this->choices)) {
2931 $this->choices['error'] = 'Error! Check your aspell installation!';
6e4dc10f 2932 }
220a90c5 2933 return true;
6e4dc10f 2934 }
6e4dc10f 2935}
2936
2937
2938class admin_setting_special_editorhidebuttons extends admin_setting {
6e4dc10f 2939 var $items;
2940
2941 function admin_setting_special_editorhidebuttons() {
220a90c5 2942 parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
2943 get_string('confeditorhidebuttons', 'admin'), array());
6e4dc10f 2944 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2945 $this->items = array('fontname' => '',
2946 'fontsize' => '',
2947 'formatblock' => '',
2948 'bold' => 'ed_format_bold.gif',
2949 'italic' => 'ed_format_italic.gif',
2950 'underline' => 'ed_format_underline.gif',
2951 'strikethrough' => 'ed_format_strike.gif',
2952 'subscript' => 'ed_format_sub.gif',
2953 'superscript' => 'ed_format_sup.gif',
2954 'copy' => 'ed_copy.gif',
2955 'cut' => 'ed_cut.gif',
2956 'paste' => 'ed_paste.gif',
2957 'clean' => 'ed_wordclean.gif',
2958 'undo' => 'ed_undo.gif',
2959 'redo' => 'ed_redo.gif',
2960 'justifyleft' => 'ed_align_left.gif',
2961 'justifycenter' => 'ed_align_center.gif',
2962 'justifyright' => 'ed_align_right.gif',
2963 'justifyfull' => 'ed_align_justify.gif',
2964 'lefttoright' => 'ed_left_to_right.gif',
2965 'righttoleft' => 'ed_right_to_left.gif',
2966 'insertorderedlist' => 'ed_list_num.gif',
2967 'insertunorderedlist' => 'ed_list_bullet.gif',
2968 'outdent' => 'ed_indent_less.gif',
2969 'indent' => 'ed_indent_more.gif',
2970 'forecolor' => 'ed_color_fg.gif',
2971 'hilitecolor' => 'ed_color_bg.gif',
2972 'inserthorizontalrule' => 'ed_hr.gif',
2973 'createanchor' => 'ed_anchor.gif',
2974 'createlink' => 'ed_link.gif',
2975 'unlink' => 'ed_unlink.gif',
2976 'insertimage' => 'ed_image.gif',
2977 'inserttable' => 'insert_table.gif',
2978 'insertsmile' => 'em.icon.smile.gif',
2979 'insertchar' => 'icon_ins_char.gif',
2980 'spellcheck' => 'spell-check.gif',
2981 'htmlmode' => 'ed_html.gif',
2982 'popupeditor' => 'fullscreen_maximize.gif',
2983 'search_replace' => 'ed_replace.gif');
2984 }
2985
2986 function get_setting() {
220a90c5 2987 $result = $this->config_read($this->name);
2988 if (is_null($result)) {
2989 return NULL;
2990 }
2991 if ($result === '') {
2992 return array();
2993 }
5ac776ac 2994 return explode(' ', $result);
6e4dc10f 2995 }
2996
2997 function write_setting($data) {
220a90c5 2998 if (!is_array($data)) {
2999 return ''; // ignore it
3000 }
3001 unset($data['xxxxx']);
6e4dc10f 3002 $result = array();
220a90c5 3003
6e4dc10f 3004 foreach ($data as $key => $value) {
5ac776ac 3005 if (!isset($this->items[$key])) {
220a90c5 3006 return get_string('errorsetting', 'admin');
6e4dc10f 3007 }
3008 if ($value == '1') {
3009 $result[] = $key;
3010 }
3011 }
220a90c5 3012 return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 3013 }
3014
587c7040 3015 function output_html($data, $query='') {
eef868d1 3016
6e4dc10f 3017 global $CFG;
eef868d1 3018
6e4dc10f 3019 // checkboxes with input name="$this->name[$key]" value="1"
3020 // we do 15 fields per column
eef868d1 3021
1beed35f 3022 $return = '<div class="form-group">';
3023 $return .= '<table><tr><td valign="top" align="right">';
220a90c5 3024 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
eef868d1 3025
6e4dc10f 3026 $count = 0;
eef868d1 3027
6e4dc10f 3028 foreach($this->items as $key => $value) {
8ddbd7a6 3029 if ($count % 15 == 0 and $count != 0) {
3030 $return .= '</td><td valign="top" align="right">';
6e4dc10f 3031 }
eef868d1 3032
5ac776ac 3033 $return .= '<label for="'.$this->get_id().$key.'">';
220a90c5 3034 $return .= ($value == '' ? get_string($key,'editor') : '<img width="18" height="18" src="'.$CFG->wwwroot.'/lib/editor/htmlarea/images/'.$value.'" alt="'.get_string($key,'editor').'" title="'.get_string($key,'editor').'" />').'&nbsp;';
3035 $return .= '<input type="checkbox" class="form-checkbox" value="1" id="'.$this->get_id().$key.'" name="'.$this->get_full_name().'['.$key.']"'.(in_array($key,$data) ? ' checked="checked"' : '').' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
5ac776ac 3036 $return .= '</label>';
6e4dc10f 3037 $count++;
3038 if ($count % 15 != 0) {
3039 $return .= '<br /><br />';
3040 }
3041 }
eef868d1 3042
3043 $return .= '</td></tr>';
6e4dc10f 3044 $return .= '</table>';
1beed35f 3045 $return .= '</div>';
6e4dc10f 3046
587c7040 3047 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
6e4dc10f 3048 }
6e4dc10f 3049}
3050
220a90c5 3051/**
3052 * Special setting for limiting of the list of available languages.
3053 */
4642650f 3054class admin_setting_langlist extends admin_setting_configtext {
3055 function admin_setting_langlist() {
3056 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3057 }
3058
3059 function write_setting($data) {
3060 $return = parent::write_setting($data);
3061 get_list_of_languages(true);//refresh the list
3062 return $return;
3063 }
3064}
3065
220a90c5 3066/**
3067 * Course category selection
3068 */
3069class admin_settings_coursecat_select extends admin_setting_configselect {
3070 function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
3071 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
3072 }
6153cf58 3073
220a90c5 3074 function load_choices() {
3075 global $CFG;
3076 require_once($CFG->dirroot.'/course/lib.php');
3077 if (is_array($this->choices)) {
3078 return true;
3079 }
3080 $this->choices = make_categories_options();
3081 return true;
3082 }
3083}
eef868d1 3084
220a90c5 3085class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3086 function admin_setting_special_backupdays() {
3087 parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
3088 $this->plugin = 'backup';
6e4dc10f 3089 }
eef868d1 3090
220a90c5 3091 function load_choices() {
3092 if (is_array($this->choices)) {
3093 return true;
3094 }
3095 $this->choices = array();
3096 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3097 foreach ($days as $day) {
3098 $this->choices[$day] = get_string($day, 'calendar');
6e4dc10f 3099 }
220a90c5 3100 return true;
6e4dc10f 3101 }
3102}
3103
220a90c5 3104/**
3105 * Special debug setting
3106 */
ee437bbc 3107class admin_setting_special_debug extends admin_setting_configselect {
6e4dc10f 3108 function admin_setting_special_debug() {
220a90c5 3109 parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
6e4dc10f 3110 }
3111
220a90c5 3112 function load_choices() {
3113 if (is_array($this->choices)) {
3114 return true;
ee437bbc 3115 }
220a90c5 3116 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3117 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3118 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3119 DEBUG_ALL => get_string('debugall', 'admin'),
3120 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3121 return true;
6e4dc10f 3122 }
6e4dc10f 3123}
3124
3125
3126class admin_setting_special_calendar_weekend extends admin_setting {
6e4dc10f 3127 function admin_setting_special_calendar_weekend() {
3128 $name = 'calendar_weekend';
3129 $visiblename = get_string('calendar_weekend', 'admin');
3130 $description = get_string('helpweekenddays', 'admin');
5eaa6aa0 3131 $default = array ('0', '6'); // Saturdays and Sundays
b91b1f92 3132 parent::admin_setting($name, $visiblename, $description, $default);
6e4dc10f 3133 }
3134
3135 function get_setting() {
220a90c5 3136 $result = $this->config_read($this->name);
3137 if (is_null($result)) {
3138 return NULL;
3139 }
3140 if ($result === '') {
3141 return array();
3142 }
3143 $settings = array();
3144 for ($i=0; $i<7; $i++) {
3145 if ($result & (1 << $i)) {
3146 $setting[] = $i;
3147 }
3148 }
3149 return $setting;
6e4dc10f 3150 }
eef868d1 3151
6e4dc10f 3152 function write_setting($data) {
220a90c5 3153 if (!is_array($data)) {
3154 return '';
3155 }
3156 unset($data['xxxxx']);
4af8d5d3 3157 $result = 0;
220a90c5 3158 foreach($data as $index) {
3159 $result |= 1 << $index;
6e4dc10f 3160 }
220a90c5 3161 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 3162 }
eef868d1 3163
587c7040 3164 function output_html($data, $query='') {
4af8d5d3 3165 // The order matters very much because of the implied numeric keys
3166 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3167 $return = '<table><thead><tr>';
220a90c5 3168 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
4af8d5d3 3169 foreach($days as $index => $day) {
220a90c5 3170 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
4af8d5d3 3171 }
3172 $return .= '</tr></thead><tbody><tr>';
3173 foreach($days as $index => $day) {
220a90c5 3174 $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>';
4af8d5d3 3175 }
3176 $return .= '</tr></tbody></table>';
6153cf58 3177
587c7040 3178 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
eef868d1 3179
6e4dc10f 3180 }
6e4dc10f 3181}
3182
220a90c5 3183
3d5c00b3 3184/**
220a90c5 3185 * Graded roles in gradebook
5a412dbf 3186 */
220a90c5 3187class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
0909d44e 3188 function admin_setting_special_gradebookroles() {
220a90c5 3189 parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
3190 get_string('configgradebookroles', 'admin'), NULL, NULL);
5a412dbf 3191 }
3192
220a90c5 3193 function load_choices() {
f33e1ed4 3194 global $CFG, $DB;
220a90c5 3195 if (empty($CFG->rolesactive)) {
3196 return false;
3197 }
3198 if (is_array($this->choices)) {
3199 return true;
3200 }
f33e1ed4 3201 if ($roles = $DB->get_records('role')) {
220a90c5 3202 $this->choices = array();
3203 foreach($roles as $role) {
3204 $this->choices[$role->id] = format_string($role->name);
60f7d402 3205 }
220a90c5 3206 return true;
5a412dbf 3207 } else {
220a90c5 3208 return false;
5a412dbf 3209 }
3210 }
3211
220a90c5 3212 function get_defaultsetting() {
3213 global $CFG;
3214 if (empty($CFG->rolesactive)) {
3215 return NULL;
3216 }
3217 $result = array();
3218 if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
3219 foreach ($studentroles as $studentrole) {
3220 $result[$studentrole->id] = '1';
5a412dbf 3221 }
73afaf5b 3222 }
220a90c5 3223 return $result;
5a412dbf 3224 }
220a90c5 3225}
5a412dbf 3226
91f9a62c 3227class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
3228 function write_setting($data) {
f33e1ed4 3229 global $CFG, $DB;
91f9a62c 3230
3231 $oldvalue = $this->config_read($this->name);
3232 $return = parent::write_setting($data);
3233 $newvalue = $this->config_read($this->name);
3234
3235 if ($oldvalue !== $newvalue) {
3236 // force full regrading
f33e1ed4 3237 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
91f9a62c 3238 }
3239
3240 return $return;
3241 }
3242}
3243
220a90c5 3244/**
3245 * Which roles to show on course decription page
3246 */
3247class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
3248 function admin_setting_special_coursemanager() {
3249 parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
3250 get_string('configcoursemanager', 'admin'), NULL, NULL);
3251 }
5a412dbf 3252
220a90c5 3253 function load_choices() {
f33e1ed4 3254 global $DB;
220a90c5 3255 if (is_array($this->choices)) {
3256 return true;
5a412dbf 3257 }
95dff9da 3258 if ($roles = $DB->get_records('role',null,'sortorder')) {
220a90c5 3259 $this->choices = array();
3260 foreach($roles as $role) {
3261 $this->choices[$role->id] = format_string($role->name);
5a412dbf 3262 }
220a90c5 3263 return true;
5a412dbf 3264 }
220a90c5 3265 return false;
3266 }
73afaf5b 3267
220a90c5 3268 function get_defaultsetting() {
3269 global $CFG;
3270 if (empty($CFG->rolesactive)) {
3271 return NULL;
3272 }
3273 $result = array();
3274 if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
3275 foreach ($teacherroles as $teacherrole) {
3276 $result[$teacherrole->id] = '1';
3277 }
3278 }
3279 return $result;
3280 }
3281}
5a412dbf 3282
220a90c5 3283/**
3284 * Primary grade export plugin - has state tracking.
3285 */
3286class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
3287 function admin_setting_special_gradeexport() {
3288 parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
3289 get_string('configgradeexport', 'admin'), array(), NULL);
5a412dbf 3290 }
3291
220a90c5 3292 function load_choices() {
3293 if (is_array($this->choices)) {
3294 return true;
3295 }
3296 $this->choices = array();
3297
3298 if ($plugins = get_list_of_plugins('grade/export')) {
3299 foreach($plugins as $plugin) {
3300 $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
3301 }
3302 }
3303 return true;
3304 }
5a412dbf 3305}
6e4dc10f 3306
220a90c5 3307/**
3308 * Grade category settings
d42c64ba 3309 */
220a90c5 3310class admin_setting_gradecat_combo extends admin_setting {
d42c64ba 3311
220a90c5 3312 var $choices;
3313
3314 function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
3315 $this->choices = $choices;
3316 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
d42c64ba 3317 }
3318
3319 function get_setting() {
d42c64ba 3320 global $CFG;
220a90c5 3321
3322 $value = $this->config_read($this->name);
3323 $flag = $this->config_read($this->name.'_flag');
3324
3325 if (is_null($value) or is_null($flag)) {
3326 return NULL;
d42c64ba 3327 }
220a90c5 3328
3329 $flag = (int)$flag;
3330 $forced = (boolean)(1 & $flag); // first bit
3331 $adv = (boolean)(2 & $flag); // second bit
3332
3333 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);