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