MDL-8669 broken auth signup code
[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
12/**
ead29342 13 * Upgrade plugins
88a7228a 14 *
15 * @uses $db
16 * @uses $CFG
ead29342 17 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
18 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
19 * @param string $return The url to prompt the user to continue to
eef868d1 20 */
ead29342 21function upgrade_plugins($type, $dir, $return) {
e69ef14b 22 global $CFG, $db;
173cc1c3 23
ead29342 24 if (!$plugs = get_list_of_plugins($dir) ) {
25 error('No '.$type.' plugins installed!');
173cc1c3 26 }
27
583fad99 28 $updated_plugins = false;
29 $strpluginsetup = get_string('pluginsetup');
30
ead29342 31 foreach ($plugs as $plug) {
173cc1c3 32
ead29342 33 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
173cc1c3 34
ead29342 35 unset($plugin);
173cc1c3 36
bbbf2d40 37 if (is_readable($fullplug .'/version.php')) {
ead29342 38 include_once($fullplug .'/version.php'); // defines $plugin with version etc
173cc1c3 39 } else {
40 continue; // Nothing to do.
41 }
42
e79a09a2 43 $oldupgrade = false;
44 $newupgrade = false;
7c006e34 45 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
46 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
e79a09a2 47 $oldupgrade = true;
48 }
db8bd7a6 49 if (is_readable($fullplug . '/db/upgrade.php')) {
7c006e34 50 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
e79a09a2 51 $newupgrade = true;
52 }
53
ead29342 54 if (!isset($plugin)) {
173cc1c3 55 continue;
56 }
57
ead29342 58 if (!empty($plugin->requires)) {
59 if ($plugin->requires > $CFG->version) {
acdd790f 60 $info = new object();
ead29342 61 $info->pluginname = $plug;
62 $info->pluginversion = $plugin->version;
173cc1c3 63 $info->currentmoodle = $CFG->version;
ead29342 64 $info->requiremoodle = $plugin->requires;
583fad99 65 if (!$updated_plugins) {
eef868d1 66 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
371a32e3 67 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
583fad99 68 }
69 upgrade_log_start();
ead29342 70 notify(get_string('pluginrequirementsnotmet', 'error', $info));
583fad99 71 $updated_plugins = true;
173cc1c3 72 continue;
73 }
74 }
75
ead29342 76 $plugin->name = $plug; // The name MUST match the directory
173cc1c3 77
ead29342 78 $pluginversion = $type.'_'.$plug.'_version';
173cc1c3 79
ead29342 80 if (!isset($CFG->$pluginversion)) {
81 set_config($pluginversion, 0);
173cc1c3 82 }
eef868d1 83
ead29342 84 if ($CFG->$pluginversion == $plugin->version) {
173cc1c3 85 // do nothing
ead29342 86 } else if ($CFG->$pluginversion < $plugin->version) {
583fad99 87 if (!$updated_plugins) {
eef868d1 88 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
371a32e3 89 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 90 }
e79a09a2 91 $updated_plugins = true;
583fad99 92 upgrade_log_start();
ead29342 93 print_heading($plugin->name .' plugin needs upgrading');
e79a09a2 94 $db->debug = true;
95 @set_time_limit(0); // To allow slow databases to complete the long SQL
96
d87a9d73 97 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
e79a09a2 98 /// Both old .sql files and new install.xml are supported
99 /// but we priorize install.xml (XMLDB) if present
100 $status = false;
db8bd7a6 101 if (file_exists($fullplug . '/db/install.xml')) {
450cf307 102 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
e79a09a2 103 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
104 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
eef868d1 105 } else {
7c006e34 106 $status = true;
d87a9d73 107 }
e79a09a2 108
109 $db->debug = false;
eef868d1 110 /// Continue with the instalation, roles and other stuff
e79a09a2 111 if ($status) {
112 // OK so far, now update the plugins record
113 set_config($pluginversion, $plugin->version);
ae628043 114 if (!update_capabilities($type.'/'.$plug)) {
e79a09a2 115 error('Could not set up the capabilities for '.$module->name.'!');
116 }
117 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
118 } else {
119 notify('Installing '. $plugin->name .' FAILED!');
120 }
d87a9d73 121 } else { // Upgrade existing install
e79a09a2 122 /// Run de old and new upgrade functions for the module
123 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
124 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
125
126 /// First, the old function if exists
127 $oldupgrade_status = true;
128 if ($oldupgrade && function_exists($oldupgrade_function)) {
129 $db->debug = true;
130 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
131 } else if ($oldupgrade) {
132 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
133 $fullplug . '/db/' . $CFG->dbtype . '.php');
134 }
135
136 /// Then, the new function if exists and the old one was ok
137 $newupgrade_status = true;
138 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
139 $db->debug = true;
140 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
141 } else if ($newupgrade) {
142 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
143 $fullplug . '/db/upgrade.php');
144 }
145
146 $db->debug=false;
147 /// Now analyze upgrade results
148 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
149 // OK so far, now update the plugins record
150 set_config($pluginversion, $plugin->version);
ae628043 151 if (!update_capabilities($type.'/'.$plug)) {
e79a09a2 152 error('Could not update '.$plugin->name.' capabilities!');
d87a9d73 153 }
e79a09a2 154 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
155 } else {
156 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
173cc1c3 157 }
158 }
d87a9d73 159 echo '<hr />';
173cc1c3 160 } else {
583fad99 161 upgrade_log_start();
ead29342 162 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
173cc1c3 163 }
164 }
165
583fad99 166 upgrade_log_finish();
167
168 if ($updated_plugins) {
173cc1c3 169 print_continue($return);
acdd790f 170 print_footer('none');
173cc1c3 171 die;
172 }
173}
174
88a7228a 175/**
176 * Find and check all modules and load them up or upgrade them if necessary
177 *
178 * @uses $db
179 * @uses $CFG
180 * @param string $return The url to prompt the user to continue to
181 * @todo Finish documenting this function
eef868d1 182 */
173cc1c3 183function upgrade_activity_modules($return) {
173cc1c3 184
e69ef14b 185 global $CFG, $db;
173cc1c3 186
88a7228a 187 if (!$mods = get_list_of_plugins('mod') ) {
188 error('No modules installed!');
173cc1c3 189 }
190
583fad99 191 $updated_modules = false;
192 $strmodulesetup = get_string('modulesetup');
193
173cc1c3 194 foreach ($mods as $mod) {
195
88a7228a 196 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
173cc1c3 197 continue;
198 }
199
88a7228a 200 $fullmod = $CFG->dirroot .'/mod/'. $mod;
173cc1c3 201
202 unset($module);
203
88a7228a 204 if ( is_readable($fullmod .'/version.php')) {
205 include_once($fullmod .'/version.php'); // defines $module with version etc
173cc1c3 206 } else {
88a7228a 207 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
173cc1c3 208 continue;
209 }
210
d6eb06b6 211 $oldupgrade = false;
212 $newupgrade = false;
7c006e34 213 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
214 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
d6eb06b6 215 $oldupgrade = true;
216 }
db8bd7a6 217 if ( is_readable($fullmod . '/db/upgrade.php')) {
7c006e34 218 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
d6eb06b6 219 $newupgrade = true;
173cc1c3 220 }
221
222 if (!isset($module)) {
223 continue;
224 }
225
226 if (!empty($module->requires)) {
227 if ($module->requires > $CFG->version) {
acdd790f 228 $info = new object();
173cc1c3 229 $info->modulename = $mod;
230 $info->moduleversion = $module->version;
231 $info->currentmoodle = $CFG->version;
232 $info->requiremoodle = $module->requires;
583fad99 233 if (!$updated_modules) {
eef868d1 234 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
371a32e3 235 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
583fad99 236 }
237 upgrade_log_start();
173cc1c3 238 notify(get_string('modulerequirementsnotmet', 'error', $info));
583fad99 239 $updated_modules = true;
173cc1c3 240 continue;
241 }
242 }
243
244 $module->name = $mod; // The name MUST match the directory
eef868d1 245
88a7228a 246 if ($currmodule = get_record('modules', 'name', $module->name)) {
173cc1c3 247 if ($currmodule->version == $module->version) {
248 // do nothing
249 } else if ($currmodule->version < $module->version) {
d6eb06b6 250 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
251 if (!$oldupgrade && !$newupgrade) {
252 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
253 $fullmod . '/db/upgrade.php were not readable');
254 continue;
255 }
583fad99 256 if (!$updated_modules) {
eef868d1 257 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
371a32e3 258 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 259 }
583fad99 260 upgrade_log_start();
88a7228a 261 print_heading($module->name .' module needs upgrading');
d6eb06b6 262
263 /// Run de old and new upgrade functions for the module
264 $oldupgrade_function = $module->name . '_upgrade';
265 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
266
267 /// First, the old function if exists
268 $oldupgrade_status = true;
269 if ($oldupgrade && function_exists($oldupgrade_function)) {
270 $db->debug = true;
271 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
ba05965e 272 } else if ($oldupgrade) {
d6eb06b6 273 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
274 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
d6eb06b6 275 }
276
277 /// Then, the new function if exists and the old one was ok
278 $newupgrade_status = true;
ba05965e 279 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
d6eb06b6 280 $db->debug = true;
281 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
ba05965e 282 } else if ($newupgrade) {
d6eb06b6 283 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
284 $mod . ': ' . $fullmod . '/db/upgrade.php');
d6eb06b6 285 }
286
e79a09a2 287 $db->debug=false;
d6eb06b6 288 /// Now analyze upgrade results
668896e5 289 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
d6eb06b6 290 // OK so far, now update the modules record
291 $module->id = $currmodule->id;
292 if (! update_record('modules', $module)) {
293 error('Could not update '. $module->name .' record in modules table!');
173cc1c3 294 }
d6eb06b6 295 remove_dir($CFG->dataroot . '/cache', true); // flush cache
296 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
297 echo '<hr />';
298 } else {
d6eb06b6 299 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
173cc1c3 300 }
bbbf2d40 301
d6eb06b6 302 /// Update the capabilities table?
bbbf2d40 303 if (!update_capabilities('mod/'.$module->name)) {
304 error('Could not update '.$module->name.' capabilities!');
305 }
306
173cc1c3 307 $updated_modules = true;
eef868d1 308
173cc1c3 309 } else {
583fad99 310 upgrade_log_start();
88a7228a 311 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
173cc1c3 312 }
eef868d1 313
173cc1c3 314 } else { // module not installed yet, so install it
583fad99 315 if (!$updated_modules) {
eef868d1 316 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
371a32e3 317 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 318 }
583fad99 319 upgrade_log_start();
173cc1c3 320 print_heading($module->name);
321 $updated_modules = true;
322 $db->debug = true;
323 @set_time_limit(0); // To allow slow databases to complete the long SQL
d6eb06b6 324
325 /// Both old .sql files and new install.xml are supported
326 /// but we priorize install.xml (XMLDB) if present
db8bd7a6 327 if (file_exists($fullmod . '/db/install.xml')) {
d6eb06b6 328 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
329 } else {
330 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
331 }
332
e79a09a2 333 $db->debug = false;
d6eb06b6 334 /// Continue with the instalation, roles and other stuff
335 if ($status) {
88a7228a 336 if ($module->id = insert_record('modules', $module)) {
bbbf2d40 337 if (!update_capabilities('mod/'.$module->name)) {
338 error('Could not set up the capabilities for '.$module->name.'!');
339 }
a8f68426 340 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
88a7228a 341 echo '<hr />';
173cc1c3 342 } else {
88a7228a 343 error($module->name .' module could not be added to the module list!');
173cc1c3 344 }
eef868d1 345 } else {
88a7228a 346 error($module->name .' tables could NOT be set up successfully!');
173cc1c3 347 }
348 }
e5bd4e58 349
350 /// Check submodules of this module if necessary
351
352 include_once($fullmod.'/lib.php'); // defines upgrading function
353
354 $submoduleupgrade = $module->name.'_upgrade_submodules';
355 if (function_exists($submoduleupgrade)) {
356 $submoduleupgrade();
357 }
358
359
360 /// Run any defaults or final code that is necessary for this module
361
a5c0990e 362 if ( is_readable($fullmod .'/defaults.php')) {
363 // Insert default values for any important configuration variables
9e6e7502 364 unset($defaults);
eef868d1 365 include_once($fullmod .'/defaults.php');
f9a2e515 366 if (!empty($defaults)) {
367 foreach ($defaults as $name => $value) {
368 if (!isset($CFG->$name)) {
369 set_config($name, $value);
370 }
a5c0990e 371 }
372 }
373 }
173cc1c3 374 }
375
583fad99 376 upgrade_log_finish(); // finish logging if started
377
378 if ($updated_modules) {
173cc1c3 379 print_continue($return);
acdd790f 380 print_footer('none');
173cc1c3 381 die;
382 }
383}
384
eef868d1 385/**
f3221af9 386 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
80be7ee3 387 *
388 * @param string $name ?
389 * @param bool $value ?
390 * @param int $staleafter ?
391 * @param bool $clobberstale ?
392 * @todo Finish documenting this function
f3221af9 393 */
394function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
395
396 if (empty($name)) {
397 mtrace("Tried to get a cron lock for a null fieldname");
398 return false;
399 }
400
401 if (empty($value)) {
402 set_config($name,0);
403 return true;
404 }
405
406 if ($config = get_record('config','name',$name)) {
407 if (empty($config->value)) {
408 set_config($name,time());
409 } else {
410 // check for stale.
411 if ((time() - $staleafter) > $config->value) {
412 mtrace("STALE LOCKFILE FOR $name - was $config->value");
413 if (!empty($clobberstale)) {
414 set_config($name,time());
415 return true;
416 }
417 } else {
418 return false; // was not stale - ie, we're ok to still be running.
419 }
420 }
421 }
422 else {
423 set_config($name,time());
424 }
425 return true;
426}
a597f8a8 427
fb06b255 428function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
a597f8a8 429 static $starttime;
430 static $lasttime;
431
26ea4888 432 if ($total < 2) { // No need to show anything
433 return;
434 }
435
a597f8a8 436 if (empty($starttime)) {
437 $starttime = $lasttime = time();
438 $lasttime = $starttime - $updatetime;
439 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
72da5046 440 echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
441 echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
a597f8a8 442 echo '</div>';
72da5046 443 echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
a597f8a8 444 echo '</td></tr></table>';
445 echo '</div>';
446 }
447
a597f8a8 448 $now = time();
449
450 if ($done && (($now - $lasttime) >= $updatetime)) {
451 $elapsedtime = $now - $starttime;
452 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
453 $percentage = format_float((float)$done / (float)$total, 2);
454 $width = (int)(500 * $percentage);
455
fb06b255 456 if ($projectedtime > 10) {
457 $projectedtext = ' Ending: '.format_time($projectedtime);
458 } else {
459 $projectedtext = '';
460 }
461
a597f8a8 462 echo '<script>';
aae37b63 463 echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
464 echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
a597f8a8 465 echo '</script>';
466
467 $lasttime = $now;
468 sleep($sleeptime);
469 }
470}
583fad99 471
371a32e3 472function upgrade_get_javascript() {
473 global $CFG;
474
475 if (!empty($_SESSION['installautopilot'])) {
476 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
477 } else {
478 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
479 }
480 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
481
482 return $linktoscrolltoerrors;
483}
ad6226fb 484
485function create_admin_user() {
486 global $CFG, $USER;
487
488 if (empty($CFG->rolesactive)) { // No admin user yet.
489
490 $user = new object();
491 $user->auth = 'manual';
492 $user->firstname = get_string('admin');
493 $user->lastname = get_string('user');
494 $user->username = 'admin';
495 $user->password = hash_internal_user_password('admin');
496 $user->email = 'root@localhost';
497 $user->confirmed = 1;
498 $user->mnethostid = $CFG->mnet_localhost_id;
499 $user->lang = $CFG->lang;
500 $user->maildisplay = 1;
501 $user->timemodified = time();
502
503 if (!$user->id = insert_record('user', $user)) {
504 error('SERIOUS ERROR: Could not create admin user record !!!');
505 }
506
507 if (!$user = get_record('user', 'id', $user->id)) { // Double check.
508 error('User ID was incorrect (can\'t find it)');
509 }
510
511 // Assign the default admin roles to the new user.
512 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
513 error('No admin role could be found');
514 }
84c8ede0 515 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
ad6226fb 516 foreach ($adminroles as $adminrole) {
517 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
518 }
519
520 set_config('rolesactive', 1);
521
522 // Log the user in.
523 $USER = get_complete_user_data('username', 'admin');
524 $USER->newadminuser = 1;
525 load_all_capabilities();
526
527 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
528 } else {
529 error('Can not create admin!');
530 }
531}
532
583fad99 533////////////////////////////////////////////////
534/// upgrade logging functions
535////////////////////////////////////////////////
536
537$upgradeloghandle = false;
26c91c73 538$upgradelogbuffer = '';
539// I did not find out how to use static variable in callback function,
540// the problem was that I could not flush the static buffer :-(
541global $upgradeloghandle, $upgradelogbuffer;
583fad99 542
543/**
544 * Check if upgrade is already running.
545 *
546 * If anything goes wrong due to missing call to upgrade_log_finish()
547 * just restart the browser.
548 *
549 * @param string warning message indicating upgrade is already running
550 * @param int page reload timeout
551 */
552function upgrade_check_running($message, $timeout) {
553 if (!empty($_SESSION['upgraderunning'])) {
554 print_header();
555 redirect(me(), $message, $timeout);
556 }
557}
558
559/**
560 * Start logging of output into file (if not disabled) and
561 * prevent aborting and concurrent execution of upgrade script.
562 *
563 * Please note that you can not write into session variables after calling this function!
564 *
565 * This function may be called repeatedly.
566 */
567function upgrade_log_start() {
426a369b 568 global $CFG, $upgradeloghandle;
583fad99 569
570 if (!empty($_SESSION['upgraderunning'])) {
571 return; // logging already started
572 }
573
574 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
575 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
426a369b 576 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
577 session_write_close(); // from now on user can reload page - will be displayed warning
578 }
583fad99 579 make_upload_directory('upgradelogs');
580 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
dedb2304 581 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
583fad99 582}
583
584/**
585 * Terminate logging of output, flush all data, allow script aborting
586 * and reopen session for writing. Function error() does terminate the logging too.
587 *
588 * Please make sure that each upgrade_log_start() is properly terminated by
589 * this function or error().
590 *
591 * This function may be called repeatedly.
592 */
593function upgrade_log_finish() {
426a369b 594 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 595
596 if (empty($_SESSION['upgraderunning'])) {
597 return; // logging already terminated
598 }
599
600 @ob_end_flush();
26c91c73 601 if ($upgradelogbuffer !== '') {
602 @fwrite($upgradeloghandle, $upgradelogbuffer);
40896537 603 $upgradelogbuffer = '';
26c91c73 604 }
605 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
606 @fclose($upgradeloghandle);
40896537 607 $upgradeloghandle = false;
26c91c73 608 }
426a369b 609 if (empty($CFG->dbsessions)) {
610 @session_start(); // ignore header errors, we only need to reopen session
611 }
583fad99 612 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
613 if (connection_aborted()) {
614 die;
615 }
616 @ignore_user_abort(false);
617}
618
619/**
620 * Callback function for logging into files. Not more than one file is created per minute,
621 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
622 *
623 * This function must not output any characters or throw warnigns and errors!
624 */
625function upgrade_log_callback($string) {
26c91c73 626 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 627
628 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
629 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
26c91c73 630 $upgradelogbuffer .= $string;
631 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
632 @fwrite($upgradeloghandle, $upgradelogbuffer);
633 $upgradelogbuffer = '';
634 }
583fad99 635 } else {
636 $upgradeloghandle = 'error';
637 }
638 }
639 return $string;
640}
641
57e35f32 642/**
643 * Try to verify that dataroot is not accessible from web.
644 * It is not 100% correct but might help to reduce number of vulnerable sites.
645 *
646 * Protection from httpd.conf and .htaccess is not detected properly.
647 */
648function is_dataroot_insecure() {
649 global $CFG;
650
651 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
652
653 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
654 $rp = strrev(trim($rp, '/'));
655 $rp = explode('/', $rp);
656 foreach($rp as $r) {
657 if (strpos($siteroot, '/'.$r.'/') === 0) {
658 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
659 } else {
660 break; // probably alias root
661 }
662 }
663
664 $siteroot = strrev($siteroot);
665 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
666
667 if (strpos($dataroot, $siteroot) === 0) {
668 return true;
669 }
670 return false;
671}
6e4dc10f 672
673/// =============================================================================================================
674/// administration tree classes and functions
675
676
677// n.b. documentation is still in progress for this code
678
679/// INTRODUCTION
680
681/// This file performs the following tasks:
682/// -it defines the necessary objects and interfaces to build the Moodle
683/// admin hierarchy
eef868d1 684/// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
6e4dc10f 685/// and admin_externalpage_print_footer() functions used on admin pages
686
687/// ADMIN_SETTING OBJECTS
688
eef868d1 689/// Moodle settings are represented by objects that inherit from the admin_setting
6e4dc10f 690/// class. These objects encapsulate how to read a setting, how to write a new value
691/// to a setting, and how to appropriately display the HTML to modify the setting.
692
693/// ADMIN_SETTINGPAGE OBJECTS
694
695/// The admin_setting objects are then grouped into admin_settingpages. The latter
696/// appear in the Moodle admin tree block. All interaction with admin_settingpage
697/// objects is handled by the admin/settings.php file.
698
699/// ADMIN_EXTERNALPAGE OBJECTS
700
701/// There are some settings in Moodle that are too complex to (efficiently) handle
702/// with admin_settingpages. (Consider, for example, user management and displaying
703/// lists of users.) In this case, we use the admin_externalpage object. This object
704/// places a link to an external PHP file in the admin tree block.
705
706/// If you're using an admin_externalpage object for some settings, you can take
707/// advantage of the admin_externalpage_* functions. For example, suppose you wanted
708/// to add a foo.php file into admin. First off, you add the following line to
709/// admin/settings/first.php (at the end of the file) or to some other file in
710/// admin/settings:
711
eef868d1 712/// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
6e4dc10f 713/// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
714
715/// Next, in foo.php, your file structure would resemble the following:
716
717/// require_once('.../config.php');
718/// require_once($CFG->libdir.'/adminlib.php');
719/// $adminroot = admin_get_root();
720/// admin_externalpage_setup('foo', $adminroot);
721/// // functionality like processing form submissions goes here
722/// admin_externalpage_print_header($adminroot);
723/// // your HTML goes here
724/// admin_externalpage_print_footer($adminroot);
725
726/// The admin_externalpage_setup() function call ensures the user is logged in,
727/// and makes sure that they have the proper role permission to access the page.
728
729/// The admin_externalpage_print_header() function prints the header (it figures
730/// out what category and subcategories the page is classified under) and ensures
731/// that you're using the admin pagelib (which provides the admin tree block and
732/// the admin bookmarks block).
733
734/// The admin_externalpage_print_footer() function properly closes the tables
735/// opened up by the admin_externalpage_print_header() function and prints the
736/// standard Moodle footer.
737
738/// ADMIN_CATEGORY OBJECTS
739
740/// Above and beyond all this, we have admin_category objects. These objects
741/// appear as folders in the admin tree block. They contain admin_settingpage's,
742/// admin_externalpage's, and other admin_category's.
743
744/// OTHER NOTES
745
746/// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
747/// from part_of_admin_tree (a pseudointerface). This interface insists that
748/// a class has a check_access method for access permissions, a locate method
749/// used to find a specific node in the admin tree, and a path method used
750/// to determine the path to a specific node in the $ADMIN tree.
751
752/// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
753/// interface ensures that the class implements a recursive add function which
754/// accepts a part_of_admin_tree object and searches for the proper place to
755/// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
756
757/// Please note that the $this->name field of any part_of_admin_tree must be
758/// UNIQUE throughout the ENTIRE admin tree.
759
760/// The $this->name field of an admin_setting object (which is *not* part_of_
761/// admin_tree) must be unique on the respective admin_settingpage where it is
762/// used.
763
764
765/// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
766include_once($CFG->dirroot . '/backup/lib.php');
767
768/// CLASS DEFINITIONS /////////////////////////////////////////////////////////
769
770/**
771 * Pseudointerface for anything appearing in the admin tree
772 *
773 * The pseudointerface that is implemented by anything that appears in the admin tree
774 * block. It forces inheriting classes to define a method for checking user permissions
775 * and methods for finding something in the admin tree.
776 *
777 * @author Vincenzo K. Marcovecchio
778 * @package admin
779 */
780class part_of_admin_tree {
781
782 /**
783 * Finds a named part_of_admin_tree.
784 *
785 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
786 * and not parentable_part_of_admin_tree, then this function should only check if
787 * $this->name matches $name. If it does, it should return a reference to $this,
788 * otherwise, it should return a reference to NULL.
789 *
790 * If a class inherits parentable_part_of_admin_tree, this method should be called
791 * recursively on all child objects (assuming, of course, the parent object's name
792 * doesn't match the search criterion).
793 *
794 * @param string $name The internal name of the part_of_admin_tree we're searching for.
795 * @return mixed An object reference or a NULL reference.
796 */
eef868d1 797 function &locate($name) {
798 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
799 return;
6e4dc10f 800 }
4672d955 801
802 /**
803 * Removes named part_of_admin_tree.
804 *
805 * @param string $name The internal name of the part_of_admin_tree we want to remove.
a8a66c96 806 * @return bool success.
4672d955 807 */
808 function prune($name) {
eef868d1 809 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
4672d955 810 return;
eef868d1 811 }
4672d955 812
6e4dc10f 813 /**
814 * Verifies current user's access to this part_of_admin_tree.
815 *
816 * Used to check if the current user has access to this part of the admin tree or
817 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
818 * then this method is usually just a call to has_capability() in the site context.
819 *
820 * If a class inherits parentable_part_of_admin_tree, this method should return the
821 * logical OR of the return of check_access() on all child objects.
822 *
823 * @return bool True if the user has access, false if she doesn't.
824 */
eef868d1 825 function check_access() {
826 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
827 return;
6e4dc10f 828 }
eef868d1 829
a8a66c96 830 /**
831 * Mostly usefull for removing of some parts of the tree in admin tree block.
832 *
833 * @return True is hidden from normal list view
834 */
835 function is_hidden() {
836 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
837 return;
838 }
839
6e4dc10f 840 /**
841 * Determines the path to $name in the admin tree.
842 *
843 * Used to determine the path to $name in the admin tree. If a class inherits only
844 * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
845 * check if $this->name matches $name. If it does, $name is pushed onto the $path
846 * array (at the end), and $path should be returned. If it doesn't, NULL should be
847 * returned.
848 *
849 * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
850 * return NULL on failure. Instead, it pushes $this->name onto $path, and then
851 * recursively calls path() on its child objects. If any are non-NULL, it should
852 * return $path (being certain that the last element of $path is equal to $name).
853 * If they are all NULL, it returns NULL.
854 *
855 * @param string $name The internal name of the part_of_admin_tree we're searching for.
856 * @param array $path Not used on external calls. Defaults to empty array.
857 * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
858 */
eef868d1 859 function path($name, $path = array()) {
860 trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING);
861 return;
6e4dc10f 862 }
863}
864
865/**
866 * Pseudointerface implemented by any part_of_admin_tree that has children.
867 *
868 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
869 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
eef868d1 870 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
6e4dc10f 871 * include an add method for adding other part_of_admin_tree objects as children.
872 *
873 * @author Vincenzo K. Marcovecchio
874 * @package admin
875 */
876class parentable_part_of_admin_tree extends part_of_admin_tree {
eef868d1 877
6e4dc10f 878 /**
879 * Adds a part_of_admin_tree object to the admin tree.
880 *
881 * Used to add a part_of_admin_tree object to this object or a child of this
882 * object. $something should only be added if $destinationname matches
883 * $this->name. If it doesn't, add should be called on child objects that are
884 * also parentable_part_of_admin_tree's.
885 *
886 * @param string $destinationname The internal name of the new parent for $something.
887 * @param part_of_admin_tree &$something The object to be added.
888 * @return bool True on success, false on failure.
889 */
eef868d1 890 function add($destinationname, &$something) {
891 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
892 return;
6e4dc10f 893 }
eef868d1 894
6e4dc10f 895}
896
897/**
898 * The object used to represent folders (a.k.a. categories) in the admin tree block.
eef868d1 899 *
6e4dc10f 900 * Each admin_category object contains a number of part_of_admin_tree objects.
901 *
902 * @author Vincenzo K. Marcovecchio
903 * @package admin
904 */
905class admin_category extends parentable_part_of_admin_tree {
906
907 /**
908 * @var mixed An array of part_of_admin_tree objects that are this object's children
909 */
910 var $children;
eef868d1 911
6e4dc10f 912 /**
913 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
914 */
915 var $name;
eef868d1 916
6e4dc10f 917 /**
918 * @var string The displayed name for this category. Usually obtained through get_string()
919 */
920 var $visiblename;
eef868d1 921
a8a66c96 922 /**
923 * @var bool Should this category be hidden in admin tree block?
924 */
925 var $hidden;
926
6e4dc10f 927 // constructor for an empty admin category
928 // $name is the internal name of the category. it MUST be unique in the entire hierarchy
929 // $visiblename is the displayed name of the category. use a get_string for this
930
931 /**
932 * Constructor for an empty admin category
933 *
934 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
935 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
a8a66c96 936 * @param bool $hidden hide category in admin tree block
6e4dc10f 937 * @return mixed Returns the new object.
938 */
a8a66c96 939 function admin_category($name, $visiblename, $hidden = false) {
6e4dc10f 940 $this->children = array();
941 $this->name = $name;
942 $this->visiblename = $visiblename;
a8a66c96 943 $this->hidden = $hidden;
6e4dc10f 944 }
eef868d1 945
6e4dc10f 946 /**
947 * Finds the path to the part_of_admin_tree called $name.
948 *
949 * @param string $name The internal name that we're searching for.
950 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
951 * @return mixed An array of internal names that leads to $name, or NULL if not found.
952 */
953 function path($name, $path = array()) {
eef868d1 954
6e4dc10f 955 $path[count($path)] = $this->name;
eef868d1 956
6e4dc10f 957 if ($this->name == $name) {
958 return $path;
959 }
eef868d1 960
6e4dc10f 961 foreach($this->children as $child) {
962 if ($return = $child->path($name, $path)) {
963 return $return;
964 }
965 }
eef868d1 966
6e4dc10f 967 return NULL;
eef868d1 968
6e4dc10f 969 }
970
971 /**
972 * Returns a reference to the part_of_admin_tree object with internal name $name.
973 *
974 * @param string $name The internal name of the object we want.
975 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
976 */
977 function &locate($name) {
eef868d1 978
6e4dc10f 979 if ($this->name == $name) {
980 return $this;
981 }
eef868d1 982
6e4dc10f 983 foreach($this->children as $child) {
984 if ($return =& $child->locate($name)) {
985 return $return;
986 }
987 }
988 $return = NULL;
989 return $return;
990 }
991
4672d955 992 /**
993 * Removes part_of_admin_tree object with internal name $name.
994 *
995 * @param string $name The internal name of the object we want to remove.
a8a66c96 996 * @return bool success
4672d955 997 */
998 function prune($name) {
999
1000 if ($this->name == $name) {
1001 return false; //can not remove itself
1002 }
1003
1004 foreach($this->children as $precedence => $child) {
1005 if ($child->name == $name) {
1006 // found it!
eef868d1 1007 unset($this->children[$precedence]);
4672d955 1008 return true;
1009 }
1010 if ($this->children[$precedence]->prune($name)) {
1011 return true;
1012 }
1013 }
1014 return false;
1015 }
1016
6e4dc10f 1017 /**
1018 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1019 *
1020 * @param string $destinationame The internal name of the immediate parent that we want for &$something.
1021 * @param mixed &$something A part_of_admin_tree object to be added.
1022 * @param int $precedence The precedence of &$something when displayed. Smaller numbers mean it'll be displayed higher up in the admin menu. Defaults to '', meaning "next available position".
1023 * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
1024 */
1025 function add($destinationname, &$something, $precedence = '') {
eef868d1 1026
6e4dc10f 1027 if (!is_a($something, 'part_of_admin_tree')) {
1028 return false;
1029 }
1030
1031 if ($destinationname == $this->name) {
1032 if ($precedence === '') {
1033 $this->children[] = $something;
1034 } else {
1035 if (isset($this->children[$precedence])) { // this should never, ever be triggered in a release version of moodle.
1036 echo ('<font style="color: red;">There is a precedence conflict in the category ' . $this->name . '. The object named ' . $something->name . ' is overwriting the object named ' . $this->children[$precedence]->name . '.</font><br />');
1037 }
1038 $this->children[$precedence] = $something;
1039 }
1040 return true;
1041 }
eef868d1 1042
6e4dc10f 1043 unset($entries);
eef868d1 1044
6e4dc10f 1045 $entries = array_keys($this->children);
eef868d1 1046
6e4dc10f 1047 foreach($entries as $entry) {
1048 $child =& $this->children[$entry];
1049 if (is_a($child, 'parentable_part_of_admin_tree')) {
1050 if ($child->add($destinationname, $something, $precedence)) {
1051 return true;
1052 }
1053 }
1054 }
eef868d1 1055
6e4dc10f 1056 return false;
eef868d1 1057
6e4dc10f 1058 }
eef868d1 1059
6e4dc10f 1060 /**
1061 * Checks if the user has access to anything in this category.
1062 *
1063 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1064 */
1065 function check_access() {
eef868d1 1066
6e4dc10f 1067 $return = false;
1068 foreach ($this->children as $child) {
1069 $return = $return || $child->check_access();
1070 }
eef868d1 1071
6e4dc10f 1072 return $return;
eef868d1 1073
6e4dc10f 1074 }
eef868d1 1075
a8a66c96 1076 /**
1077 * Is this category hidden in admin tree block?
1078 *
1079 * @return bool True if hidden
1080 */
1081 function is_hidden() {
1082 return $this->hidden;
1083 }
6e4dc10f 1084}
1085
1086/**
1087 * Links external PHP pages into the admin tree.
1088 *
1089 * See detailed usage example at the top of this document (adminlib.php)
1090 *
1091 * @author Vincenzo K. Marcovecchio
1092 * @package admin
1093 */
1094class admin_externalpage extends part_of_admin_tree {
1095
eef868d1 1096 /**
6e4dc10f 1097 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1098 */
1099 var $name;
eef868d1 1100
6e4dc10f 1101 /**
1102 * @var string The displayed name for this external page. Usually obtained through get_string().
1103 */
1104 var $visiblename;
eef868d1 1105
6e4dc10f 1106 /**
1107 * @var string The external URL that we should link to when someone requests this external page.
1108 */
1109 var $url;
eef868d1 1110
6e4dc10f 1111 /**
1112 * @var string The role capability/permission a user must have to access this external page.
1113 */
2ce38b70 1114 var $req_capability;
eef868d1 1115
84c8ede0 1116 /**
1117 * @var object The context in which capability/permission should be checked, default is site context.
1118 */
1119 var $context;
1120
a8a66c96 1121 /**
1122 * @var bool hidden in admin tree block.
1123 */
1124 var $hidden;
1125
6e4dc10f 1126 /**
1127 * Constructor for adding an external page into the admin tree.
1128 *
1129 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1130 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1131 * @param string $url The external URL that we should link to when someone requests this external page.
38d2d43b 1132 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
6e4dc10f 1133 */
01e85af9 1134 function admin_externalpage($name, $visiblename, $url, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
6e4dc10f 1135 $this->name = $name;
1136 $this->visiblename = $visiblename;
1137 $this->url = $url;
38d2d43b 1138 if (is_array($req_capability)) {
1139 $this->req_capability = $req_capability;
1140 } else {
1141 $this->req_capability = array($req_capability);
1142 }
a8a66c96 1143 $this->hidden = $hidden;
84c8ede0 1144 $this->context = $context;
6e4dc10f 1145 }
eef868d1 1146
6e4dc10f 1147 /**
1148 * Finds the path to the part_of_admin_tree called $name.
1149 *
1150 * @param string $name The internal name that we're searching for.
1151 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1152 * @return mixed An array of internal names that leads to $name, or NULL if not found.
1153 */
1154 function path($name, $path = array()) {
1155 if ($name == $this->name) {
1156 array_push($path, $this->name);
1157 return $path;
1158 } else {
1159 return NULL;
1160 }
1161 }
eef868d1 1162
6e4dc10f 1163 /**
1164 * Returns a reference to the part_of_admin_tree object with internal name $name.
1165 *
1166 * @param string $name The internal name of the object we want.
1167 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1168 */
1169 function &locate($name) {
1170 $return = ($this->name == $name ? $this : NULL);
1171 return $return;
1172 }
4672d955 1173
1174 function prune($name) {
1175 return false;
1176 }
1177
6e4dc10f 1178 /**
2ce38b70 1179 * Determines if the current user has access to this external page based on $this->req_capability.
6e4dc10f 1180 *
1181 * @uses CONTEXT_SYSTEM
1182 * @uses SITEID
1183 * @return bool True if user has access, false otherwise.
1184 */
1185 function check_access() {
1186 if (!get_site()) {
1187 return true; // no access check before site is fully set up
1188 }
84c8ede0 1189 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1190 foreach($this->req_capability as $cap) {
1191 if (has_capability($cap, $context)) {
1192 return true;
1193 }
1194 }
1195 return false;
6e4dc10f 1196 }
1197
a8a66c96 1198 /**
1199 * Is this external page hidden in admin tree block?
1200 *
1201 * @return bool True if hidden
1202 */
1203 function is_hidden() {
1204 return $this->hidden;
1205 }
1206
6e4dc10f 1207}
1208
1209/**
1210 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1211 *
1212 * @author Vincenzo K. Marcovecchio
1213 * @package admin
1214 */
1215class admin_settingpage extends part_of_admin_tree {
1216
eef868d1 1217 /**
6e4dc10f 1218 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1219 */
1220 var $name;
eef868d1 1221
6e4dc10f 1222 /**
1223 * @var string The displayed name for this external page. Usually obtained through get_string().
1224 */
1225 var $visiblename;
1226 /**
1227 * @var mixed An array of admin_setting objects that are part of this setting page.
1228 */
1229 var $settings;
eef868d1 1230
6e4dc10f 1231 /**
1232 * @var string The role capability/permission a user must have to access this external page.
1233 */
2ce38b70 1234 var $req_capability;
eef868d1 1235
84c8ede0 1236 /**
1237 * @var object The context in which capability/permission should be checked, default is site context.
1238 */
1239 var $context;
1240
a8a66c96 1241 /**
1242 * @var bool hidden in admin tree block.
1243 */
1244 var $hidden;
1245
6e4dc10f 1246 // see admin_category
1247 function path($name, $path = array()) {
1248 if ($name == $this->name) {
1249 array_push($path, $this->name);
1250 return $path;
1251 } else {
1252 return NULL;
1253 }
1254 }
eef868d1 1255
6e4dc10f 1256 // see admin_category
1257 function &locate($name) {
1258 $return = ($this->name == $name ? $this : NULL);
1259 return $return;
1260 }
4672d955 1261
1262 function prune($name) {
1263 return false;
1264 }
1265
6e4dc10f 1266 // see admin_externalpage
01e85af9 1267 function admin_settingpage($name, $visiblename, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
6e4dc10f 1268 global $CFG;
1269 $this->settings = new stdClass();
1270 $this->name = $name;
1271 $this->visiblename = $visiblename;
38d2d43b 1272 if (is_array($req_capability)) {
1273 $this->req_capability = $req_capability;
1274 } else {
1275 $this->req_capability = array($req_capability);
1276 }
a8a66c96 1277 $this->hidden = false;
84c8ede0 1278 $this->context = $context;
6e4dc10f 1279 }
eef868d1 1280
6e4dc10f 1281 // 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
1282 // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1283 // &$setting is the admin_setting object you want to add
1284 // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1285 function add(&$setting) {
1286 if (is_a($setting, 'admin_setting')) {
1287 $this->settings->{$setting->name} =& $setting;
1288 return true;
1289 }
1290 return false;
1291 }
eef868d1 1292
6e4dc10f 1293 // see admin_externalpage
1294 function check_access() {
1295 if (!get_site()) {
1296 return true; // no access check before site is fully set up
1297 }
84c8ede0 1298 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1299 foreach($this->req_capability as $cap) {
1300 if (has_capability($cap, $context)) {
1301 return true;
1302 }
1303 }
1304 return false;
6e4dc10f 1305 }
eef868d1 1306
6e4dc10f 1307 // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1308 // returns a string of the html
1309 function output_html() {
15a16922 1310 $return = '<fieldset>' . "\n";
6153cf58 1311 $return .= '<div class="clearer"><!-- --></div>' . "\n";
6e4dc10f 1312 foreach($this->settings as $setting) {
15a16922 1313 $return .= $setting->output_html();
6e4dc10f 1314 }
6153cf58 1315 $return .= '</fieldset>';
6e4dc10f 1316 return $return;
1317 }
1318
1319 // writes settings (the ones that have been added to this admin_settingpage) to the database, or wherever else they're supposed to be written to
1320 // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1321 // $data should be the result from data_submitted()
1322 // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1323 function write_settings($data) {
1324 $return = '';
1325 foreach($this->settings as $setting) {
1326 if (isset($data['s_' . $setting->name])) {
1327 $return .= $setting->write_setting($data['s_' . $setting->name]);
1328 } else {
1329 $return .= $setting->write_setting('');
1330 }
1331 }
1332 return $return;
1333 }
1334
a8a66c96 1335 /**
1336 * Is this settigns page hidden in admin tree block?
1337 *
1338 * @return bool True if hidden
1339 */
1340 function is_hidden() {
1341 return $this->hidden;
1342 }
1343
6e4dc10f 1344}
1345
1346
1347// read & write happens at this level; no authentication
1348class admin_setting {
1349
1350 var $name;
1351 var $visiblename;
1352 var $description;
1353 var $defaultsetting;
1354
1355 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1356 $this->name = $name;
1357 $this->visiblename = $visiblename;
1358 $this->description = $description;
1359 $this->defaultsetting = $defaultsetting;
1360 }
eef868d1 1361
6e4dc10f 1362 function get_setting() {
1363 return NULL; // has to be overridden
1364 }
eef868d1 1365
6e4dc10f 1366 function write_setting($data) {
1367 return; // has to be overridden
1368 }
eef868d1 1369
6e4dc10f 1370 function output_html() {
1371 return; // has to be overridden
1372 }
eef868d1 1373
6e4dc10f 1374}
1375
1376
1377class admin_setting_configtext extends admin_setting {
1378
1379 var $paramtype;
1380
50999a0b 1381 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
6e4dc10f 1382 $this->paramtype = $paramtype;
1383 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1384 }
1385
cc73de71 1386 // returns a string or NULL
6e4dc10f 1387 function get_setting() {
1388 global $CFG;
c8218a42 1389 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
6e4dc10f 1390 }
eef868d1 1391
cc73de71 1392 // $data is a string
6e4dc10f 1393 function write_setting($data) {
9e24fbd1 1394 if (!$this->validate($data)) {
1395 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
c235598d 1396 }
6e4dc10f 1397 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1398 }
1399
c235598d 1400 function validate($data) {
9e24fbd1 1401 if (is_string($this->paramtype)) {
1402 return preg_match($this->paramtype, $data);
1403 } else if ($this->paramtype === PARAM_RAW) {
1404 return true;
1405 } else {
1406 $cleaned = clean_param($data, $this->paramtype);
1407 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1408 }
c235598d 1409 }
1410
6e4dc10f 1411 function output_html() {
c8218a42 1412 if ($this->get_setting() === NULL) {
1413 $current = $this->defaultsetting;
1414 } else {
1415 $current = $this->get_setting();
1416 }
9e24fbd1 1417 return format_admin_setting($this->name, $this->visiblename,
5259d5d8 1418 '<input type="text" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.s($current).'" />',
6153cf58 1419 $this->description);
6e4dc10f 1420 }
1421
1422}
1423
1424class admin_setting_configcheckbox extends admin_setting {
1425
1426 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1427 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1428 }
1429
1430 function get_setting() {
1431 global $CFG;
1432 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1433 }
eef868d1 1434
6e4dc10f 1435 function write_setting($data) {
1436 if ($data == '1') {
1437 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1438 } else {
1439 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1440 }
1441 }
1442
1443 function output_html() {
c8218a42 1444 if ($this->get_setting() === NULL) {
1445 $current = $this->defaultsetting;
1446 } else {
1447 $current = $this->get_setting();
1448 }
9e24fbd1 1449 return format_admin_setting($this->name, $this->visiblename,
3c6f7a78 1450 '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($current == true ? 'checked="checked"' : '') . ' />',
6153cf58 1451 $this->description);
6e4dc10f 1452 }
1453
1454}
1455
1456class admin_setting_configselect extends admin_setting {
1457
1458 var $choices;
eef868d1 1459
6e4dc10f 1460 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1461 $this->choices = $choices;
1462 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1463 }
1464
1465 function get_setting() {
1466 global $CFG;
1467 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1468 }
eef868d1 1469
6e4dc10f 1470 function write_setting($data) {
1471 // check that what we got was in the original choices
1472 // or that the data is the default setting - needed during install when choices can not be constructed yet
1473 if ($data != $this->defaultsetting and ! in_array($data, array_keys($this->choices))) {
1474 return 'Error setting ' . $this->visiblename . '<br />';
1475 }
eef868d1 1476
6e4dc10f 1477 return (set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1478 }
eef868d1 1479
6e4dc10f 1480 function output_html() {
c8218a42 1481 if ($this->get_setting() === NULL) {
1482 $current = $this->defaultsetting;
1483 } else {
1484 $current = $this->get_setting();
1485 }
afee9864 1486 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'">';
6e4dc10f 1487 foreach ($this->choices as $key => $value) {
a1069b07 1488 // the string cast is needed because key may be integer - 0 is equal to most strings!
1489 $return .= '<option value="'.$key.'"'.((string)$key==$current ? ' selected="selected"' : '').'>'.$value.'</option>';
6e4dc10f 1490 }
6153cf58 1491 $return .= '</select>';
1492
fc52aa6e 1493 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
6e4dc10f 1494 }
1495
1496}
1497
1498// this is a liiitle bit messy. we're using two selects, but we're returning them as an array named after $name (so we only use $name2
1499// internally for the setting)
1500class admin_setting_configtime extends admin_setting {
1501
1502 var $name2;
1503 var $choices;
1504 var $choices2;
6e4dc10f 1505
1506 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1507 $this->name2 = $minutesname;
1508 $this->choices = array();
1509 for ($i = 0; $i < 24; $i++) {
1510 $this->choices[$i] = $i;
1511 }
1512 $this->choices2 = array();
1513 for ($i = 0; $i < 60; $i += 5) {
1514 $this->choices2[$i] = $i;
1515 }
1516 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1517 }
1518
1519 function get_setting() {
1520 global $CFG;
cc73de71 1521 return (isset($CFG->{$this->name}) && isset($CFG->{$this->name2}) ? array('h' => $CFG->{$this->name}, 'm' => $CFG->{$this->name2}) : NULL);
6e4dc10f 1522 }
eef868d1 1523
6e4dc10f 1524 function write_setting($data) {
1525 // check that what we got was in the original choices
1526 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
1527 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1528 }
eef868d1 1529
6e4dc10f 1530 return (set_config($this->name, $data['h']) && set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1531 }
eef868d1 1532
6e4dc10f 1533 function output_html() {
cc73de71 1534 if ($this->get_setting() === NULL) {
1535 $currentsetting = $this->defaultsetting;
1536 } else {
1537 $currentsetting = $this->get_setting();
6e4dc10f 1538 }
2e0c11dd 1539 $return = '<div class="form-group">'.
1540 '<select class="form-select" id="id_s_'.$this->name.'h" name="s_' . $this->name .'[h]">';
6e4dc10f 1541 foreach ($this->choices as $key => $value) {
cc73de71 1542 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
6e4dc10f 1543 }
2e0c11dd 1544 $return .= '</select>:<select class="form-select" id="id_s_'.$this->name.'m" name="s_' . $this->name . '[m]">';
6e4dc10f 1545 foreach ($this->choices2 as $key => $value) {
cc73de71 1546 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
eef868d1 1547 }
2e0c11dd 1548 $return .= '</select></div>';
fbe31d22 1549 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1550 }
1551
1552}
1553
1554class admin_setting_configmultiselect extends admin_setting_configselect {
1555
1556 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1557 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1558 }
1559
1560 function get_setting() {
1561 global $CFG;
d7933a55 1562 if (isset($CFG->{$this->name})) {
1563 if ($CFG->{$this->name}) {
1564 return explode(',', $CFG->{$this->name});
1565 } else {
1566 return array();
1567 }
1568 } else {
1569 return NULL;
1570 }
6e4dc10f 1571 }
eef868d1 1572
6e4dc10f 1573 function write_setting($data) {
d7933a55 1574 if (empty($data)) {
1575 $data = array();
1576 }
6e4dc10f 1577 foreach ($data as $datum) {
1578 if (! in_array($datum, array_keys($this->choices))) {
1579 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1580 }
1581 }
eef868d1 1582
6e4dc10f 1583 return (set_config($this->name, implode(',',$data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1584 }
eef868d1 1585
6e4dc10f 1586 function output_html() {
cc73de71 1587 if ($this->get_setting() === NULL) {
1588 $currentsetting = $this->defaultsetting;
0b0f7c00 1589 if (!$currentsetting) {
1590 $currentsetting = array();
1591 }
cc73de71 1592 } else {
1593 $currentsetting = $this->get_setting();
6e4dc10f 1594 }
afee9864 1595 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'[]" size="10" multiple="multiple">';
6e4dc10f 1596 foreach ($this->choices as $key => $value) {
1597 $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ? ' selected="selected"' : '') . '>' . $value . '</option>';
1598 }
6153cf58 1599 $return .= '</select>';
fc52aa6e 1600 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
6e4dc10f 1601 }
1602
1603}
1604
1605class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
eef868d1 1606
6e4dc10f 1607 function admin_setting_special_adminseesall() {
1608 $name = 'calendar_adminseesall';
1609 $visiblename = get_string('adminseesall', 'admin');
1610 $description = get_string('helpadminseesall', 'admin');
1611 parent::admin_setting($name, $visiblename, $description, 0);
1612 }
1613
1614 function write_setting($data) {
1615 global $SESSION;
1616 unset($SESSION->cal_courses_shown);
1617 parent::write_setting($data);
1618 }
1619}
1620
1621class admin_setting_sitesetselect extends admin_setting_configselect {
1622
1623 var $id;
1624
1625 function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1626
1627 $this->id = SITEID;
1628 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
eef868d1 1629
6e4dc10f 1630 }
eef868d1 1631
6e4dc10f 1632 function get_setting() {
1633 $site = get_site();
1634 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1635 }
eef868d1 1636
6e4dc10f 1637 function write_setting($data) {
1638 if (!in_array($data, array_keys($this->choices))) {
1639 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1640 }
1641 $record = new stdClass();
1642 $record->id = $this->id;
1643 $temp = $this->name;
1644 $record->$temp = $data;
1645 $record->timemodified = time();
1646 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1647 }
eef868d1 1648
6e4dc10f 1649}
1650
1651
e0f6e995 1652class admin_setting_courselist_frontpage extends admin_setting_configselect {
6e4dc10f 1653
e0f6e995 1654 function admin_setting_courselist_frontpage($loggedin) {
6e4dc10f 1655 global $CFG;
1656 require_once($CFG->dirroot . '/course/lib.php');
1657 $name = 'frontpage' . ($loggedin ? 'loggedin' : '');
1658 $visiblename = get_string('frontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1659 $description = get_string('configfrontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1660 $choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
1661 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
1662 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
1663 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
1664 '' => get_string('none'));
9fec4e33 1665 if (!$loggedin and count_records("course") > FRONTPAGECOURSELIMIT) {
6e4dc10f 1666 unset($choices[FRONTPAGECOURSELIST]);
1667 }
4672d955 1668 $defaults = FRONTPAGECOURSELIST.',,,';
e0f6e995 1669 parent::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
6e4dc10f 1670 }
eef868d1 1671
6e4dc10f 1672 function get_setting() {
1673 global $CFG;
1c1e7af4 1674 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : ',1,,');
6e4dc10f 1675 }
eef868d1 1676
6e4dc10f 1677 function write_setting($data) {
1678 if (empty($data)) {
1679 $data = array();
e0f6e995 1680 } if (!is_array($data)) {
1681 $data = explode(',', $data);
6e4dc10f 1682 }
1683 foreach($data as $datum) {
1684 if (! in_array($datum, array_keys($this->choices))) {
1685 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1686 }
1687 }
1688 return (set_config($this->name, implode(',', $data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1689 }
eef868d1 1690
6e4dc10f 1691 function output_html() {
cc73de71 1692 if ($this->get_setting() === NULL) {
1693 $currentsetting = $this->defaultsetting;
1694 } else {
1695 $currentsetting = $this->get_setting();
6e4dc10f 1696 }
1697 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1698 if (!isset($currentsetting[$i])) {
1699 $currentsetting[$i] = 0;
1700 }
1701 }
0a7e84c3 1702 $return = '<div class="form-group">';
6e4dc10f 1703 for ($i = 0; $i < count($this->choices) - 1; $i++) {
a1d52643 1704 $return .='<select class="form-select" id="id_s_'.$this->name.$i.'" name="s_' . $this->name .'[]">';
6e4dc10f 1705 foreach ($this->choices as $key => $value) {
1706 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1707 }
1708 $return .= '</select>';
1709 if ($i !== count($this->choices) - 2) {
975211bb 1710 $return .= '<br />';
6e4dc10f 1711 }
1712 }
0a7e84c3 1713 $return .= '</div>';
1714
fbe31d22 1715 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1716 }
1717}
1718
1719class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
1720
1721 var $id;
1722
1723 function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1724
1725 $this->id = SITEID;
1726 parent::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
eef868d1 1727
6e4dc10f 1728 }
eef868d1 1729
6e4dc10f 1730 function get_setting() {
1731 $site = get_site();
1732 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1733 }
eef868d1 1734
6e4dc10f 1735 function write_setting($data) {
1736 $record = new stdClass();
1737 $record->id = $this->id;
1738 $temp = $this->name;
1739 $record->$temp = ($data == '1' ? 1 : 0);
1740 $record->timemodified = time();
1741 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1742 }
eef868d1 1743
6e4dc10f 1744}
1745
1746class admin_setting_sitesettext extends admin_setting_configtext {
1747
1748 var $id;
1749
b89639f9 1750 function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting) {
6e4dc10f 1751
1752 $this->id = SITEID;
b89639f9 1753 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting);
eef868d1 1754
6e4dc10f 1755 }
eef868d1 1756
6e4dc10f 1757 function get_setting() {
1758 $site = get_site();
1759 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1760 }
90cfbd0a 1761
b89639f9 1762 function validate($data) {
1763 $cleaned = clean_param($data, PARAM_NOTAGS);
1764 if ($cleaned == '') {
1765 return false; // can not be empty
1766 }
1767 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1768 }
1769
6e4dc10f 1770 function write_setting($data) {
b89639f9 1771 $data = trim($data);
9e24fbd1 1772 if (!$this->validate($data)) {
1773 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
90cfbd0a 1774 }
eef868d1 1775
6e4dc10f 1776 $record = new stdClass();
1777 $record->id = $this->id;
87fa8a17 1778 $record->{$this->name} = addslashes($data);
6e4dc10f 1779 $record->timemodified = time();
23a97d83 1780 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 1781 }
90cfbd0a 1782
6e4dc10f 1783}
1784
1785class admin_setting_special_frontpagedesc extends admin_setting {
1786
1787 var $id;
eef868d1 1788
6e4dc10f 1789 function admin_setting_special_frontpagedesc() {
1790 $this->id = SITEID;
1791 $name = 'summary';
1792 $visiblename = get_string('frontpagedescription');
1793 $description = get_string('frontpagedescriptionhelp');
1794 parent::admin_setting($name, $visiblename, $description, '');
1795 }
1796
1797 function output_html() {
eef868d1 1798
fa040029 1799 global $CFG;
1800
cc73de71 1801 if ($this->get_setting() === NULL) {
1802 $currentsetting = $this->defaultsetting;
1803 } else {
1804 $currentsetting = $this->get_setting();
1805 }
eef868d1 1806
fa040029 1807 $CFG->adminusehtmleditor = can_use_html_editor();
eef868d1 1808
fa040029 1809 $return = print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, 's_' . $this->name, $currentsetting, 0, true);
eef868d1 1810
fbe31d22 1811 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1812 }
eef868d1 1813
6e4dc10f 1814 function get_setting() {
eef868d1 1815
6e4dc10f 1816 $site = get_site();
1817 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
eef868d1 1818
6e4dc10f 1819 }
eef868d1 1820
6e4dc10f 1821 function write_setting($data) {
eef868d1 1822
6e4dc10f 1823 $data = addslashes(clean_param($data, PARAM_CLEANHTML));
eef868d1 1824
6e4dc10f 1825 $record = new stdClass();
1826 $record->id = $this->id;
1827 $temp = $this->name;
1828 $record->$temp = $data;
1829 $record->timemodified = time();
eef868d1 1830
6e4dc10f 1831 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
eef868d1 1832
6e4dc10f 1833 }
1834
1835}
1836
1837
1838class admin_setting_special_editorfontlist extends admin_setting {
1839
1840 var $items;
1841
1842 function admin_setting_special_editorfontlist() {
1843 global $CFG;
1844 $name = 'editorfontlist';
1845 $visiblename = get_string('editorfontlist', 'admin');
1846 $description = get_string('configeditorfontlist', 'admin');
6e4dc10f 1847 $defaults = array('k0' => 'Trebuchet',
1848 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1849 'k1' => 'Arial',
1850 'v1' => 'arial,helvetica,sans-serif',
1851 'k2' => 'Courier New',
1852 'v2' => 'courier new,courier,monospace',
1853 'k3' => 'Georgia',
1854 'v3' => 'georgia,times new roman,times,serif',
1855 'k4' => 'Tahoma',
1856 'v4' => 'tahoma,arial,helvetica,sans-serif',
1857 'k5' => 'Times New Roman',
1858 'v5' => 'times new roman,times,serif',
1859 'k6' => 'Verdana',
1860 'v6' => 'verdana,arial,helvetica,sans-serif',
1861 'k7' => 'Impact',
1862 'v7' => 'impact',
1863 'k8' => 'Wingdings',
1864 'v8' => 'wingdings');
1865 parent::admin_setting($name, $visiblename, $description, $defaults);
1866 }
eef868d1 1867
6e4dc10f 1868 function get_setting() {
cc73de71 1869 global $CFG;
1870 if (isset($CFG->editorfontlist)) {
1871 $i = 0;
1872 $currentsetting = array();
1873 $items = explode(';', $CFG->editorfontlist);
1874 foreach ($items as $item) {
1875 $item = explode(':', $item);
1876 $currentsetting['k' . $i] = $item[0];
1877 $currentsetting['v' . $i] = $item[1];
1878 $i++;
1879 }
1880 return $currentsetting;
1881 } else {
1882 return NULL;
1883 }
6e4dc10f 1884 }
eef868d1 1885
6e4dc10f 1886 function write_setting($data) {
eef868d1 1887
6e4dc10f 1888 // there miiight be an easier way to do this :)
1889 // if this is changed, make sure the $defaults array above is modified so that this
1890 // function processes it correctly
eef868d1 1891
6e4dc10f 1892 $keys = array();
1893 $values = array();
eef868d1 1894
6e4dc10f 1895 foreach ($data as $key => $value) {
1896 if (substr($key,0,1) == 'k') {
1897 $keys[substr($key,1)] = $value;
1898 } elseif (substr($key,0,1) == 'v') {
1899 $values[substr($key,1)] = $value;
1900 }
1901 }
eef868d1 1902
6e4dc10f 1903 $result = '';
1904 for ($i = 0; $i < count($keys); $i++) {
1905 if (($keys[$i] !== '') && ($values[$i] !== '')) {
1906 $result .= clean_param($keys[$i],PARAM_NOTAGS) . ':' . clean_param($values[$i], PARAM_NOTAGS) . ';';
1907 }
1908 }
eef868d1 1909
6e4dc10f 1910 $result = substr($result, 0, -1); // trim the last semicolon
eef868d1 1911
6e4dc10f 1912 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1913 }
eef868d1 1914
6e4dc10f 1915 function output_html() {
eef868d1 1916
cc73de71 1917 if ($this->get_setting() === NULL) {
1918 $currentsetting = $this->defaultsetting;
1919 } else {
1920 $currentsetting = $this->get_setting();
6e4dc10f 1921 }
eef868d1 1922
1beed35f 1923 $return = '<div class="form-group">';
cc73de71 1924 for ($i = 0; $i < count($currentsetting) / 2; $i++) {
3c6f7a78 1925 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" />';
6e4dc10f 1926 $return .= '&nbsp;&nbsp;';
3c6f7a78 1927 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" /><br />';
6e4dc10f 1928 }
3c6f7a78 1929 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="" />';
6e4dc10f 1930 $return .= '&nbsp;&nbsp;';
3c6f7a78 1931 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="" /><br />';
1932 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . ($i + 1) . ']" value="" />';
6e4dc10f 1933 $return .= '&nbsp;&nbsp;';
3c6f7a78 1934 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . ($i + 1) . ']" value="" />';
1beed35f 1935 $return .= '</div>';
6153cf58 1936
60a9a6ea 1937 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1938 }
eef868d1 1939
6e4dc10f 1940}
1941
1942class admin_setting_special_editordictionary extends admin_setting_configselect {
1943
1944 function admin_setting_special_editordictionary() {
1945 $name = 'editordictionary';
1946 $visiblename = get_string('editordictionary','admin');
1947 $description = get_string('configeditordictionary', 'admin');
1948 $choices = $this->editor_get_dictionaries();
1949 if (! is_array($choices)) {
1950 $choices = array('');
1951 }
eef868d1 1952
6e4dc10f 1953 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
1954 }
1955
1956 // function borrowed from the old moodle/admin/editor.php, slightly modified
1957 function editor_get_dictionaries () {
1958 /// Get all installed dictionaries in the system
1959
1960 global $CFG;
eef868d1 1961
6e4dc10f 1962// error_reporting(E_ALL); // for debug, final version shouldn't have this...
1963 clearstatcache();
1964
1965 // If aspellpath isn't set don't even bother ;-)
1966 if (empty($CFG->aspellpath)) {
1967 return 'Empty aspell path!';
1968 }
1969
1970 // Do we have access to popen function?
1971 if (!function_exists('popen')) {
1972 return 'Popen function disabled!';
1973 }
eef868d1 1974
6e4dc10f 1975 $cmd = $CFG->aspellpath;
1976 $output = '';
1977 $dictionaries = array();
1978 $dicts = array();
1979
1980 if(!($handle = @popen(escapeshellarg($cmd) .' dump dicts', 'r'))) {
1981 return 'Couldn\'t create handle!';
1982 }
1983
1984 while(!feof($handle)) {
1985 $output .= fread($handle, 1024);
1986 }
1987 @pclose($handle);
1988
1989 $dictionaries = explode(chr(10), $output);
1990
1991 // Get rid of possible empty values
1992 if (is_array($dictionaries)) {
1993
1994 $cnt = count($dictionaries);
1995
1996 for ($i = 0; $i < $cnt; $i++) {
1997 if (!empty($dictionaries[$i])) {
2c41b2d7 1998 $dicts[$dictionaries[$i]] = $dictionaries[$i];
6e4dc10f 1999 }
2000 }
2001 }
2002
2003 if (count($dicts) >= 1) {
2004 return $dicts;
2005 }
2006
2007 return 'Error! Check your aspell installation!';
2008 }
2009
eef868d1 2010
6e4dc10f 2011
2012}
2013
2014
2015class admin_setting_special_editorhidebuttons extends admin_setting {
2016
2017 var $name;
2018 var $visiblename;
2019 var $description;
2020 var $items;
2021
2022 function admin_setting_special_editorhidebuttons() {
2023 $this->name = 'editorhidebuttons';
2024 $this->visiblename = get_string('editorhidebuttons', 'admin');
2025 $this->description = get_string('confeditorhidebuttons', 'admin');
2026 $this->defaultsetting = array();
2027 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2028 $this->items = array('fontname' => '',
2029 'fontsize' => '',
2030 'formatblock' => '',
2031 'bold' => 'ed_format_bold.gif',
2032 'italic' => 'ed_format_italic.gif',
2033 'underline' => 'ed_format_underline.gif',
2034 'strikethrough' => 'ed_format_strike.gif',
2035 'subscript' => 'ed_format_sub.gif',
2036 'superscript' => 'ed_format_sup.gif',
2037 'copy' => 'ed_copy.gif',
2038 'cut' => 'ed_cut.gif',
2039 'paste' => 'ed_paste.gif',
2040 'clean' => 'ed_wordclean.gif',
2041 'undo' => 'ed_undo.gif',
2042 'redo' => 'ed_redo.gif',
2043 'justifyleft' => 'ed_align_left.gif',
2044 'justifycenter' => 'ed_align_center.gif',
2045 'justifyright' => 'ed_align_right.gif',
2046 'justifyfull' => 'ed_align_justify.gif',
2047 'lefttoright' => 'ed_left_to_right.gif',
2048 'righttoleft' => 'ed_right_to_left.gif',
2049 'insertorderedlist' => 'ed_list_num.gif',
2050 'insertunorderedlist' => 'ed_list_bullet.gif',
2051 'outdent' => 'ed_indent_less.gif',
2052 'indent' => 'ed_indent_more.gif',
2053 'forecolor' => 'ed_color_fg.gif',
2054 'hilitecolor' => 'ed_color_bg.gif',
2055 'inserthorizontalrule' => 'ed_hr.gif',
2056 'createanchor' => 'ed_anchor.gif',
2057 'createlink' => 'ed_link.gif',
2058 'unlink' => 'ed_unlink.gif',
2059 'insertimage' => 'ed_image.gif',
2060 'inserttable' => 'insert_table.gif',
2061 'insertsmile' => 'em.icon.smile.gif',
2062 'insertchar' => 'icon_ins_char.gif',
2063 'spellcheck' => 'spell-check.gif',
2064 'htmlmode' => 'ed_html.gif',
2065 'popupeditor' => 'fullscreen_maximize.gif',
2066 'search_replace' => 'ed_replace.gif');
2067 }
2068
2069 function get_setting() {
2070 global $CFG;
2071 return (isset($CFG->{$this->name}) ? explode(' ', $CFG->{$this->name}) : NULL);
2072 }
2073
2074 function write_setting($data) {
2075 $result = array();
2076 if (empty($data)) { $data = array(); }
2077 foreach ($data as $key => $value) {
2078 if (!in_array($key, array_keys($this->items))) {
2079 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2080 }
2081 if ($value == '1') {
2082 $result[] = $key;
2083 }
2084 }
2085 return (set_config($this->name, implode(' ',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2086 }
2087
2088 function output_html() {
eef868d1 2089
6e4dc10f 2090 global $CFG;
eef868d1 2091
6e4dc10f 2092 // checkboxes with input name="$this->name[$key]" value="1"
2093 // we do 15 fields per column
eef868d1 2094
cc73de71 2095 if ($this->get_setting() === NULL) {
2096 $currentsetting = $this->defaultsetting;
2097 } else {
2098 $currentsetting = $this->get_setting();
6e4dc10f 2099 }
eef868d1 2100
1beed35f 2101 $return = '<div class="form-group">';
2102 $return .= '<table><tr><td valign="top" align="right">';
eef868d1 2103
6e4dc10f 2104 $count = 0;
eef868d1 2105
6e4dc10f 2106 foreach($this->items as $key => $value) {
8ddbd7a6 2107 if ($count % 15 == 0 and $count != 0) {
2108 $return .= '</td><td valign="top" align="right">';
6e4dc10f 2109 }
eef868d1 2110
6e4dc10f 2111 $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;';
afee9864 2112 $return .= '<input type="checkbox" class="form-checkbox" value="1" id="id_s_'.$this->name.$key.'" name="s_' . $this->name . '[' . $key . ']"' . (in_array($key,$currentsetting) ? ' checked="checked"' : '') . ' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
6e4dc10f 2113 $count++;
2114 if ($count % 15 != 0) {
2115 $return .= '<br /><br />';
2116 }
2117 }
eef868d1 2118
2119 $return .= '</td></tr>';
6e4dc10f 2120 $return .= '</table>';
1beed35f 2121 $return .= '</div>';
6e4dc10f 2122
60a9a6ea 2123 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 2124 }
2125
2126}
2127
2128class admin_setting_backupselect extends admin_setting_configselect {
2129
2130 function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
2131 parent::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
2132 }
2133
2134 function get_setting() {
2135 $backup_config = backup_get_config();
2136 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2137 }
eef868d1 2138
6e4dc10f 2139 function write_setting($data) {
2140 // check that what we got was in the original choices
2141 if (! in_array($data, array_keys($this->choices))) {
2142 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2143 }
eef868d1 2144
6e4dc10f 2145 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2146 }
2147
2148}
2149
2150class admin_setting_special_backupsaveto extends admin_setting_configtext {
2151
2152 function admin_setting_special_backupsaveto() {
2153 $name = 'backup_sche_destination';
2154 $visiblename = get_string('saveto');
2155 $description = get_string('backupsavetohelp');
348d6827 2156 parent::admin_setting_configtext($name, $visiblename, $description, '');
6e4dc10f 2157 }
eef868d1 2158
6e4dc10f 2159 function get_setting() {
2160 $backup_config = backup_get_config();
2161 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2162 }
eef868d1 2163
6e4dc10f 2164 function write_setting($data) {
348d6827 2165 $data = trim($data);
2166 if (!empty($data) and !is_dir($data)) {
6e4dc10f 2167 return get_string('pathnotexists') . '<br />';
2168 }
2169 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2170 }
2171
2172}
2173
2174class admin_setting_backupcheckbox extends admin_setting_configcheckbox {
2175
2176 function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2177 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2178 }
2179
2180 function write_setting($data) {
2181 if ($data == '1') {
2182 return (backup_set_config($this->name, 1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2183 } else {
2184 return (backup_set_config($this->name, 0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2185 }
2186 }
eef868d1 2187
6e4dc10f 2188 function get_setting() {
2189 $backup_config = backup_get_config();
2190 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2191 }
2192
2193}
2194
2195class admin_setting_special_backuptime extends admin_setting_configtime {
2196
2197 function admin_setting_special_backuptime() {
2198 $name = 'backup_sche_hour';
2199 $name2 = 'backup_sche_minute';
2200 $visiblename = get_string('executeat');
2201 $description = get_string('backupexecuteathelp');
2202 $default = array('h' => 0, 'm' => 0);
2203 parent::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2204 }
eef868d1 2205
6e4dc10f 2206 function get_setting() {
2207 $backup_config = backup_get_config();
9fd9df20 2208 return (isset($backup_config->{$this->name}) && isset($backup_config->{$this->name}) ? array('h'=>$backup_config->{$this->name}, 'm'=>$backup_config->{$this->name2}) : NULL);
6e4dc10f 2209 }
eef868d1 2210
6e4dc10f 2211 function write_setting($data) {
2212 // check that what we got was in the original choices
2213 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
2214 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2215 }
eef868d1 2216
2217 return (backup_set_config($this->name, $data['h']) && backup_set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 2218 }
eef868d1 2219
6e4dc10f 2220}
2221
2222class admin_setting_special_backupdays extends admin_setting {
2223
2224 function admin_setting_special_backupdays() {
2225 $name = 'backup_sche_weekdays';
2226 $visiblename = get_string('schedule');
2227 $description = get_string('backupschedulehelp');
6727c175 2228 $default = array('u' => 0, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 0);
2229 parent::admin_setting($name, $visiblename, $description, $default);
6e4dc10f 2230 }
eef868d1 2231
6e4dc10f 2232 function get_setting() {
2233 $backup_config = backup_get_config();
cc73de71 2234 if (isset($backup_config->{$this->name})) {
2235 $currentsetting = $backup_config->{$this->name};
2236 return array('u' => substr($currentsetting, 0, 1),
2237 'm' => substr($currentsetting, 1, 1),
2238 't' => substr($currentsetting, 2, 1),
2239 'w' => substr($currentsetting, 3, 1),
2240 'r' => substr($currentsetting, 4, 1),
2241 'f' => substr($currentsetting, 5, 1),
2242 's' => substr($currentsetting, 6, 1));
2243 } else {
2244 return NULL;
2245 }
6e4dc10f 2246 }
eef868d1 2247
6e4dc10f 2248 function output_html() {
eef868d1 2249
cc73de71 2250 if ($this->get_setting() === NULL) {
2251 $currentsetting = $this->defaultsetting;
2252 } else {
2253 $currentsetting = $this->get_setting();
6e4dc10f 2254 }
eef868d1 2255
cc73de71 2256 // rewrite for simplicity
eef868d1 2257 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
cc73de71 2258 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
eef868d1 2259
60a9a6ea 2260 $return = '<table><tr><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2261 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2262 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2263 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2264 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'u" name="s_'. $this->name .'[u]" value="1" ' . (substr($currentsetting,0,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2265 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'m" name="s_'. $this->name .'[m]" value="1" ' . (substr($currentsetting,1,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2266 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'t" name="s_'. $this->name .'[t]" value="1" ' . (substr($currentsetting,2,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2267 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'w" name="s_'. $this->name .'[w]" value="1" ' . (substr($currentsetting,3,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2268 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'r" name="s_'. $this->name .'[r]" value="1" ' . (substr($currentsetting,4,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2269 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'f" name="s_'. $this->name .'[f]" value="1" ' . (substr($currentsetting,5,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2270 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'s" name="s_'. $this->name .'[s]" value="1" ' . (substr($currentsetting,6,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
6153cf58 2271 '</tr></table>';
2272
60a9a6ea 2273 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
eef868d1 2274
6e4dc10f 2275 }
eef868d1 2276
6e4dc10f 2277 // we're using the array trick (see http://ca.php.net/manual/en/faq.html.php#faq.html.arrays) to get the data passed to use without having to modify
2278 // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2279 // they MUST go into an array named $this->name, or else we won't receive them here
2280 function write_setting($data) {
2281 $week = 'umtwrfs';
2282 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
9fd9df20 2283 if (!empty($data)) {
2284 foreach($data as $key => $value) {
2285 if ($value == '1') {
2286 $result[strpos($week, $key)] = 1;
2287 }
2288 }
6e4dc10f 2289 }
2290 return (backup_set_config($this->name, implode('',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2291 }
2292}
2293
ee437bbc 2294class admin_setting_special_debug extends admin_setting_configselect {
6e4dc10f 2295
2296 function admin_setting_special_debug() {
2297 $name = 'debug';
2298 $visiblename = get_string('debug', 'admin');
2299 $description = get_string('configdebug', 'admin');
7eb0b60a 2300 $choices = array( DEBUG_NONE => get_string('debugnone', 'admin'),
2301 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
2302 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
38d2d43b 2303 DEBUG_ALL => get_string('debugall', 'admin'),
2304 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')
ee437bbc 2305 );
2306 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
6e4dc10f 2307 }
2308
ee437bbc 2309 function get_setting() {
2310 global $CFG;
cc73de71 2311 if (isset($CFG->debug)) {
cc73de71 2312 return $CFG->debug;
2313 } else {
2314 return NULL;
ee437bbc 2315 }
6e4dc10f 2316 }
2317
ee437bbc 2318 function write_setting($data) {
2319 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 2320 }
2321
2322}
2323
2324
2325class admin_setting_special_calendar_weekend extends admin_setting {
2326
2327 function admin_setting_special_calendar_weekend() {
2328 $name = 'calendar_weekend';
2329 $visiblename = get_string('calendar_weekend', 'admin');
2330 $description = get_string('helpweekenddays', 'admin');
b91b1f92 2331 $default = array('u' => 1, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 1);
2332 parent::admin_setting($name, $visiblename, $description, $default);
6e4dc10f 2333 }
2334
2335 function get_setting() {
2336 global $CFG;
2337 if (isset($CFG->{$this->name})) {
b91b1f92 2338 $currentsetting = decbin($CFG->{$this->name});
2339 $currentsetting = str_pad($currentsetting, 7, '0', STR_PAD_LEFT);
2340 return array('u' => substr($currentsetting, 0, 1),
2341 'm' => substr($currentsetting, 1, 1),
2342 't' => substr($currentsetting, 2, 1),
2343 'w' => substr($currentsetting, 3, 1),
2344 'r' => substr($currentsetting, 4, 1),
2345 'f' => substr($currentsetting, 5, 1),
2346 's' => substr($currentsetting, 6, 1));
6e4dc10f 2347 } else {
2348 return NULL;
2349 }
2350 }
eef868d1 2351
6e4dc10f 2352 function write_setting($data) {
2353 $week = 'umtwrfs';
2354 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
b91b1f92 2355 if (!empty($data)) {
2356 foreach($data as $key => $value) {
2357 if ($value == '1') {
2358 $result[strpos($week, $key)] = 1;
2359 }
2360 }
6e4dc10f 2361 }
2362 return (set_config($this->name, bindec(implode('',$result))) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2363 }
eef868d1 2364
6e4dc10f 2365 function output_html() {
2366
cc73de71 2367 if ($this->get_setting() === NULL) {
2368 $currentsetting = $this->defaultsetting;
2369 } else {
2370 $currentsetting = $this->get_setting();
6e4dc10f 2371 }
cc73de71 2372
b91b1f92 2373 // rewrite for simplicity
2374 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2375 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
3b904bc9 2376
038bf621 2377 $return = '<table><tr><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2378 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2379 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2380 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2381 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'u" name="s_'. $this->name .'[u]" value="1" ' . (substr($currentsetting,0,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2382 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'m" name="s_'. $this->name .'[m]" value="1" ' . (substr($currentsetting,1,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2383 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'t" name="s_'. $this->name .'[t]" value="1" ' . (substr($currentsetting,2,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2384 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'w" name="s_'. $this->name .'[w]" value="1" ' . (substr($currentsetting,3,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2385 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'r" name="s_'. $this->name .'[r]" value="1" ' . (substr($currentsetting,4,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2386 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'f" name="s_'. $this->name .'[f]" value="1" ' . (substr($currentsetting,5,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2387 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'s" name="s_'. $this->name .'[s]" value="1" ' . (substr($currentsetting,6,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
6153cf58 2388 '</tr></table>';
2389
038bf621 2390 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
eef868d1 2391
6e4dc10f 2392 }
2393
2394}
2395
73afaf5b 2396/*
2397 * this is used in config->appearance->gradeconfig
5a412dbf 2398 */
0909d44e 2399class admin_setting_special_gradebookroles extends admin_setting {
5a412dbf 2400
0909d44e 2401 function admin_setting_special_gradebookroles() {
2402 $name = 'gradebookroles';
73afaf5b 2403 $visiblename = get_string('gradebookroles', 'admin');
2404 $description = get_string('configgradebookroles', 'admin');
7aa3e196 2405 $default = array(5=>'1'); // The student role in a default install
8a2cb2fa 2406 parent::admin_setting($name, $visiblename, $description, $default);
5a412dbf 2407 }
2408
2409 function get_setting() {
2410 global $CFG;
8a2cb2fa 2411 if (!empty($CFG->{$this->name})) {
60f7d402 2412 $result = explode(',', $CFG->{$this->name});
2413 foreach ($result as $roleid) {
2414 $array[$roleid] = 1;
2415 }
2416 return $array;
5a412dbf 2417 } else {
3fae9f57 2418 return null;
5a412dbf 2419 }
2420 }
2421
2422 function write_setting($data) {
2423 if (!empty($data)) {
2424 $str = '';
0909d44e 2425 foreach ($data as $key => $value) {
5a412dbf 2426 if ($value) {
2427 $str .= $key.',';
2428 }
2429 }
2430 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2431 } else {
73afaf5b 2432 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2433 }
5a412dbf 2434 }
2435
2436 function output_html() {
2437
2438 if ($this->get_setting() === NULL) {
2439 $currentsetting = $this->defaultsetting;
2440 } else {
2441 $currentsetting = $this->get_setting();
2442 }
5a412dbf 2443 // from to process which roles to display
2444 if ($roles = get_records('role')) {
73afaf5b 2445 $return = '<div class="form-group">';
2446 $first = true;
2447 foreach ($roles as $roleid=>$role) {
60f7d402 2448 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
fb132873 2449 $checked = ' checked="checked"';
5a412dbf 2450 } else {
73afaf5b 2451 $checked = '';
5a412dbf 2452 }
73afaf5b 2453 if ($first) {
2454 $first = false;
2455 } else {
2456 $return .= '<br />';
2457 }
4eb777c2 2458 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1"'.$checked.' />&nbsp;'.$role->name;
5a412dbf 2459 }
73afaf5b 2460 $return .= '</div>';
5a412dbf 2461 }
73afaf5b 2462
60a9a6ea 2463 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
5a412dbf 2464
2465 }
2466
2467}
6e4dc10f 2468
d42c64ba 2469/*
2470 * this is used in config->appearance->coursemanager
2471 * (which roles to show on course decription page)
2472 */
2473class admin_setting_special_coursemanager extends admin_setting {
2474
2475 function admin_setting_special_coursemanager() {
2476 $name = 'coursemanager';
2477 $visiblename = get_string('coursemanager', 'admin');
2478 $description = get_string('configcoursemanager', 'admin');
2479 $default = array(3=>'1'); // The teahcer role in a default install
2480 parent::admin_setting($name, $visiblename, $description, $default);
2481 }
2482
2483 function get_setting() {
2484
2485 global $CFG;
2486 if (!empty($CFG->{$this->name})) {
2487 $result = explode(',', $CFG->{$this->name});
2488 foreach ($result as $roleid) {
2489 $array[$roleid] = 1;
2490 }
2491 return $array;
2492 } else {
2493 return null;
2494 }
2495 }
2496
2497 function write_setting($data) {
2498
2499 if (!empty($data)) {
2500 $str = '';
2501 foreach ($data as $key => $value) {
2502 if ($value) {
2503 $str .= $key.',';
2504 }
2505 }
2506 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2507 } else {
2508 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2509 }
2510 }
2511
2512 function output_html() {
2513
2514 if ($this->get_setting() === NULL) {
2515 $currentsetting = $this->defaultsetting;
2516 } else {
2517 $currentsetting = $this->get_setting();
2518 }
2519 // from to process which roles to display
2520 if ($roles = get_records('role')) {
2521 $return = '<div class="form-group">';
2522 $first = true;
2523 foreach ($roles as $roleid=>$role) {
2524 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2525 $checked = 'checked="checked"';
2526 } else {
2527 $checked = '';
2528 }
2529 if ($first) {
2530 $first = false;
2531 } else {
2532 $return .= '<br />';
2533 }
7203167d 2534 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1" '.$checked.' />&nbsp;'.$role->name;
d42c64ba 2535 }
2536 $return .= '</div>';
2537 }
60a9a6ea 2538 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
d42c64ba 2539 }
2540}
2541
6e4dc10f 2542class admin_setting_special_perfdebug extends admin_setting_configcheckbox {
2543
2544 function admin_setting_special_perfdebug() {
2545 $name = 'perfdebug';
2546 $visiblename = get_string('perfdebug', 'admin');
2547 $description = get_string('configperfdebug', 'admin');
2548 parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2549 }
2550
2551 function write_setting($data) {
d42c64ba 2552
6e4dc10f 2553 if ($data == '1') {
2554 return (set_config($this->name,15) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2555 } else {
2556 return (set_config($this->name,7) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2557 }
2558 }
2559
2560 function output_html() {
d42c64ba 2561
cc73de71 2562 if ($this->get_setting() === NULL) {
2563 $currentsetting = $this->defaultsetting;
2564 } else {
2565 $currentsetting = $this->get_setting();
2566 }
eef868d1 2567
3c6f7a78 2568 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 15 ? 'checked="checked"' : '') . ' />';
fc52aa6e 2569 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
6e4dc10f 2570 }
2571
2572}
2573
47b8b9eb 2574class admin_setting_special_debugdisplay extends admin_setting_configcheckbox {
2575
2576 function admin_setting_special_debugdisplay() {
2577 $name = 'debugdisplay';
2578 $visiblename = get_string('debugdisplay', 'admin');
2579 $description = get_string('configdebugdisplay', 'admin');
6349a3ba 2580 $default = ini_get('display_errors');
2581 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
47b8b9eb 2582 }
2583
2584 function write_setting($data) {
2585
2586 if ($data == '1') {
2587 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2588 } else {
2589 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2590 }
2591 }
2592
2593 function output_html() {
2594
2595 if ($this->get_setting() === NULL) {
6349a3ba 2596 $currentsetting = $this->defaultsetting;
47b8b9eb 2597 } else {
2598 $currentsetting = $this->get_setting();
2599 }
2600
2601 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 1 ? 'checked="checked"' : '') . ' />';
2602 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2603 }
2604
2605}
2606
2607
6e4dc10f 2608// Code for a function that helps externalpages print proper headers and footers
2609// N.B.: THIS FUNCTION HANDLES AUTHENTICATION
2610function admin_externalpage_setup($section, $adminroot) {
2611
2612 global $CFG, $PAGE, $USER;
eef868d1 2613
6e4dc10f 2614 require_once($CFG->libdir . '/blocklib.php');
02cc05a7 2615 require_once($CFG->dirroot . '/'.$CFG->admin.'/pagelib.php');
eef868d1 2616
02cc05a7 2617 page_map_class(PAGE_ADMIN, 'page_admin');
6e4dc10f 2618
e9a20759 2619 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
6e4dc10f 2620
02cc05a7 2621 $PAGE->init_extra($section); // hack alert!
6e4dc10f 2622
2623 $root = $adminroot->locate($PAGE->section);
2624
2625 if ($site = get_site()) {
2626 require_login();
2627 } else {
6859360c 2628 redirect($CFG->wwwroot . '/'.$CFG->admin.'/index.php');
6e4dc10f 2629 die;
2630 }
2631
2632 if (!is_a($root, 'admin_externalpage')) {
2633 error(get_string('sectionerror','admin'));
2634 die;
2635 }
2636
2637 // this eliminates our need to authenticate on the actual pages
2638 if (!($root->check_access())) {
2639 error(get_string('accessdenied', 'admin'));
2640 die;
2641 }
eef868d1 2642
6e4dc10f 2643 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
eef868d1 2644
6e4dc10f 2645 if (!isset($USER->adminediting)) {
2646 $USER->adminediting = false;
2647 }
eef868d1 2648
6e4dc10f 2649 if ($PAGE->user_allowed_editing()) {
2650 if ($adminediting == 1) {
2651 $USER->adminediting = true;
2652 } elseif ($adminediting == 0) {
2653 $USER->adminediting = false;
2654 }
2655 }
eef868d1 2656
6e4dc10f 2657}
2658
2659function admin_externalpage_print_header($adminroot) {
2660
ce821fda 2661 global $CFG, $PAGE, $SITE, $THEME;
eef868d1 2662
b1ce7811 2663 if (!empty($SITE->fullname)) {
2664 $pageblocks = blocks_setup($PAGE);
6e4dc10f 2665
e524c0ed 2666 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
2667 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
b1ce7811 2668 BLOCK_L_MAX_WIDTH);
b1ce7811 2669 $PAGE->print_header();
5577ceb3 2670 echo '<table id="layout-table" summary=""><tr>';
b1ce7811 2671 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
ce821fda 2672 if (!empty($THEME->roundcorners)) {
2673 echo '<div class="bt"><div></div></div>';
2674 echo '<div class="i1"><div class="i2"><div class="i3">';
2675 }
b1ce7811 2676 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
ce821fda 2677 if (!empty($THEME->roundcorners)) {
2678 echo '</div></div></div>';
2679 echo '<div class="bb"><div></div></div>';
2680 }
b1ce7811 2681 echo '</td>';
a06c8c2c 2682 echo '<td id="middle-column">';
ce821fda 2683 if (!empty($THEME->roundcorners)) {
2684 echo '<div class="bt"><div></div></div>';
2685 echo '<div class="i1"><div class="i2"><div class="i3">';
2686 }
b1ce7811 2687 } else {
2688 print_header();
2689 }
6e4dc10f 2690}
2691
2692function admin_externalpage_print_footer($adminroot) {
2693
ce821fda 2694 global $CFG, $PAGE, $SITE, $THEME;
b1ce7811 2695
2696 if (!empty($SITE->fullname)) {
2697 $pageblocks = blocks_setup($PAGE);
e524c0ed 2698 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
2699 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
b1ce7811 2700 BLOCK_R_MAX_WIDTH);
ce821fda 2701 if (!empty($THEME->roundcorners)) {
2702 echo '</div></div></div>';
2703 echo '<div class="bb"><div></div></div>';
2704 }
b1ce7811 2705 echo '</td>';
d5271d3d 2706 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
ec3938f3 2707 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2708 if (!empty($THEME->roundcorners)) {
2709 echo '<div class="bt"><div></div></div>';
2710 echo '<div class="i1"><div class="i2"><div class="i3">';
2711 }
2712 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
2713 if (!empty($THEME->roundcorners)) {
2714 echo '</div></div></div>';
2715 echo '<div class="bb"><div></div></div>';
2716 }
2717 echo '</td>';
ce821fda 2718 }
ec3938f3 2719 echo '</tr></table>';
b1ce7811 2720 }
6e4dc10f 2721 print_footer();
6e4dc10f 2722}
2723
2724function admin_get_root() {
2725 global $CFG;
2726
2727 static $ADMIN;
2728
2729 if (!isset($ADMIN)) {
2730 // start the admin tree!
2058a0a1 2731 $ADMIN = new admin_category('root', get_string("administration"));
6e4dc10f 2732 // we process this file first to get categories up and running
6859360c 2733 include($CFG->dirroot . '/'.$CFG->admin.'/settings/top.php');
6e4dc10f 2734
2735 // now we process all other files in admin/settings to build the
2736 // admin tree
6859360c 2737 foreach (glob($CFG->dirroot . '/'.$CFG->admin.'/settings/*.php') as $file) {
2738 if ($file != $CFG->dirroot . '/'.$CFG->admin.'/settings/top.php') {
6e4dc10f 2739 include_once($file);
2740 }
2741 }
2742 }
eef868d1 2743
6e4dc10f 2744 return $ADMIN;
2745}
2746
2747/// settings utiliti functions
2748
2749// n.b. this function unconditionally applies default settings
2750function apply_default_settings(&$node) {
2751
2752 global $CFG;
2753
2754 if (is_a($node, 'admin_category')) {
2755 $entries = array_keys($node->children);
2756 foreach ($entries as $entry) {
2757 apply_default_settings($node->children[$entry]);
2758 }
2759 return;
eef868d1 2760 }
6e4dc10f 2761
eef868d1 2762 if (is_a($node, 'admin_settingpage')) {
6e4dc10f 2763 foreach ($node->settings as $setting) {
2764 $CFG->{$setting->name} = $setting->defaultsetting;
2765 $setting->write_setting($setting->defaultsetting);
2766 unset($setting); // needed to prevent odd (imho) reference behaviour
2767 // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2768 }
2769 return;
2770 }
2771
2772 return;
2773
2774}
2775
2776// n.b. this function unconditionally applies default settings
2777function apply_default_exception_settings($defaults) {
2778
2779 global $CFG;
2780
2781 foreach($defaults as $key => $value) {
2782 $CFG->$key = $value;
2783 set_config($key, $value);
2784 }
2785
2786}
2787
fbe31d22 2788function format_admin_setting($name, $title='', $form='', $description='', $label=true) {
2789
2790 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
2791 if ($label) {
2792 $labelfor = 'for = "id_s_'.$name.'"';
2793 } else {
2794 $labelfor = '';
2795 }
2796
2797 $str = "\n".
fc52aa6e 2798 '<div class="form-item" id="admin-'.$name.'">'."\n".
fbe31d22 2799 '<label '.$labelfor.'>'.$title."\n".
6153cf58 2800 ' <span class="form-shortname">'.$name.'</span>'."\n".
2801 '</label>'."\n".
2802 $form."\n".
edb6cba4 2803 '<div class="description">'.$description.'</div>'."\n".
23586aca 2804 '</div>'.
2805 "\n\n";
fbe31d22 2806
2807 return $str;
2c8766df 2808}
2809
d210e12e 2810/*
2811 * Try to upgrade the given language pack (or current language)
2812 * If it doesn't work, fail silently and return false
2813 */
2814function upgrade_language_pack($lang='') {
2815 global $CFG;
2816
2817 if (empty($lang)) {
2818 $lang = current_language();
2819 }
2820
2821 if ($lang == 'en_utf8') {
2822 return true; // Nothing to do
2823 }
2824
2825 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
2826
2827 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
2828 @mkdir ($CFG->dataroot.'/lang/');
2829
2830 require_once($CFG->libdir.'/componentlib.class.php');
2831
2832 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
2833 $status = $cd->install(); //returns ERROR | UPTODATE | INSTALLED
2834
2835 if ($status == INSTALLED) {
2836 debugging('Downloading successful: '.$lang);
2837 @unlink($CFG->dataroot.'/cache/languages');
2838 return true;
2839 }
2840 }
2841
2842 return false;
2843}
2844
6153cf58 2845?>