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