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