libdir.'/ddllib.php'); require_once($CFG->libdir.'/xmlize.php'); require_once($CFG->libdir.'/messagelib.php'); // Messagelib functions define('INSECURE_DATAROOT_WARNING', 1); define('INSECURE_DATAROOT_ERROR', 2); /** * Delete all plugin tables * @name string name of plugin, used as table prefix * @file string path to install.xml file * @feedback boolean */ function drop_plugin_tables($name, $file, $feedback=true) { global $CFG, $DB; // first try normal delete if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) { return true; } // then try to find all tables that start with name and are not in any xml file $used_tables = get_used_table_names(); $tables = $DB->get_tables(); /// Iterate over, fixing id fields as necessary foreach ($tables as $table) { if (in_array($table, $used_tables)) { continue; } if (strpos($table, $name) !== 0) { continue; } // found orphan table --> delete it if ($DB->get_manager()->table_exists($table)) { $xmldb_table = new xmldb_table($table); $DB->get_manager()->drop_table($xmldb_table); } } return true; } /** * Returns names of all known tables == tables that moodle knowns about. * @return array of lowercase table names */ function get_used_table_names() { $table_names = array(); $dbdirs = get_db_directories(); foreach ($dbdirs as $dbdir) { $file = $dbdir.'/install.xml'; $xmldb_file = new xmldb_file($file); if (!$xmldb_file->fileExists()) { continue; } $loaded = $xmldb_file->loadXMLStructure(); $structure = $xmldb_file->getStructure(); if ($loaded and $tables = $structure->getTables()) { foreach($tables as $table) { $table_names[] = strtolower($table->name); } } } return $table_names; } /** * Lists all plugin types * @return array of strings - name=>location */ function get_plugin_types() { global $CFG; return array('mod' => 'mod', 'qtype' => 'question/type', 'block' => 'blocks', 'auth' => 'auth', 'enrol' => 'enrol', 'format' => 'course/format', 'gradeexport' => 'grade/export', 'gradeimport' => 'grade/import', 'gradereport' => 'grade/report', 'message' => 'message/output', 'coursereport' => 'course/report', 'report' => $CFG->admin.'/report', 'portfolio' => 'portfolio/type', // following types a very ugly hacks - we should not make exceptions like this - all plugins should be equal; // these plugins may cause problems such as when wanting to uninstall them 'quizreport' => 'mod/quiz/report', 'assignment_type' => 'mod/assignment/type', ); } /** * Returns list of all directories where we expect install.xml files * @return array of paths */ function get_db_directories() { global $CFG; $dbdirs = array(); /// First, the main one (lib/db) $dbdirs[] = $CFG->libdir.'/db'; /// Now, activity modules (mod/xxx/db) if ($plugins = get_list_of_plugins('mod')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/mod/'.$plugin.'/db'; } } /// Now, assignment submodules (mod/assignment/type/xxx/db) if ($plugins = get_list_of_plugins('mod/assignment/type')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/mod/assignment/type/'.$plugin.'/db'; } } /// Now, question types (question/type/xxx/db) if ($plugins = get_list_of_plugins('question/type')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/question/type/'.$plugin.'/db'; } } /// Now, blocks (blocks/xxx/db) if ($plugins = get_list_of_plugins('blocks', 'db')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/blocks/'.$plugin.'/db'; } } /// Now, course formats (course/format/xxx/db) if ($plugins = get_list_of_plugins('course/format', 'db')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/course/format/'.$plugin.'/db'; } } /// Now, enrolment plugins (enrol/xxx/db) if ($plugins = get_list_of_plugins('enrol', 'db')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/enrol/'.$plugin.'/db'; } } /// Now admin report plugins (admin/report/xxx/db) if ($plugins = get_list_of_plugins($CFG->admin.'/report', 'db')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/'.$CFG->admin.'/report/'.$plugin.'/db'; } } /// Now quiz report plugins (mod/quiz/report/xxx/db) if ($plugins = get_list_of_plugins('mod/quiz/report', 'db')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot.'/mod/quiz/report/'.$plugin.'/db'; } } if ($plugins = get_list_of_plugins('portfolio/type', 'db')) { foreach ($plugins as $plugin) { $dbdirs[] = $CFG->dirroot . '/portfolio/type/' . $plugin . '/db'; } } /// Local database changes, if the local folder exists. if (file_exists($CFG->dirroot . '/local')) { $dbdirs[] = $CFG->dirroot.'/local/db'; } return $dbdirs; } /** * Try to obtain or release the cron lock. * * @param string $name name of lock * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly * @param bool $ignorecurrent ignore current lock state, usually entend previous lock * @return bool true if lock obtained */ function set_cron_lock($name, $until, $ignorecurrent=false) { global $DB; if (empty($name)) { debugging("Tried to get a cron lock for a null fieldname"); return false; } // remove lock by force == remove from config table if (is_null($until)) { set_config($name, null); return true; } if (!$ignorecurrent) { // read value from db - other processes might have changed it $value = $DB->get_field('config', 'value', array('name'=>$name)); if ($value and $value > time()) { //lock active return false; } } set_config($name, $until); return true; } /** * Test if and critical warnings are present * @return bool */ function admin_critical_warnings_present() { global $SESSION; if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { return 0; } if (!isset($SESSION->admin_critical_warning)) { $SESSION->admin_critical_warning = 0; if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) { $SESSION->admin_critical_warning = 1; } } return $SESSION->admin_critical_warning; } /** * Detects if float support at least 10 deciman digits * and also if float-->string conversion works as expected. * @return bool true if problem found */ function is_float_problem() { $num1 = 2009010200.01; $num2 = 2009010200.02; return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1); } /** * Try to verify that dataroot is not accessible from web. * It is not 100% correct but might help to reduce number of vulnerable sites. * * Protection from httpd.conf and .htaccess is not detected properly. * @param bool $fetchtest try to test public access by fetching file * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING migth be problematic */ function is_dataroot_insecure($fetchtest=false) { global $CFG; $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1); $rp = strrev(trim($rp, '/')); $rp = explode('/', $rp); foreach($rp as $r) { if (strpos($siteroot, '/'.$r.'/') === 0) { $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory } else { break; // probably alias root } } $siteroot = strrev($siteroot); $dataroot = str_replace('\\', '/', $CFG->dataroot.'/'); if (strpos($dataroot, $siteroot) !== 0) { return false; } if (!$fetchtest) { return INSECURE_DATAROOT_WARNING; } // now try all methods to fetch a test file using http protocol $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches); $httpdocroot = $matches[1]; $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot)); if (make_upload_directory('diag', false) === false) { return INSECURE_DATAROOT_WARNING; } $testfile = $CFG->dataroot.'/diag/public.txt'; if (!file_exists($testfile)) { file_put_contents($testfile, 'test file, do not delete'); } $teststr = trim(file_get_contents($testfile)); if (empty($teststr)) { // hmm, strange return INSECURE_DATAROOT_WARNING; } $testurl = $datarooturl.'/diag/public.txt'; if (extension_loaded('curl') and !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and ($ch = @curl_init($testurl)) !== false) { curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); $data = curl_exec($ch); if (!curl_errno($ch)) { $data = trim($data); if ($data === $teststr) { curl_close($ch); return INSECURE_DATAROOT_ERROR; } } curl_close($ch); } if ($data = @file_get_contents($testurl)) { $data = trim($data); if ($data === $teststr) { return INSECURE_DATAROOT_ERROR; } } preg_match('|https?://([^/]+)|i', $testurl, $matches); $sitename = $matches[1]; $error = 0; if ($fp = @fsockopen($sitename, 80, $error)) { preg_match('|https?://[^/]+(.*)|i', $testurl, $matches); $localurl = $matches[1]; $out = "GET $localurl HTTP/1.1\r\n"; $out .= "Host: $sitename\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); $data = ''; $incoming = false; while (!feof($fp)) { if ($incoming) { $data .= fgets($fp, 1024); } else if (@fgets($fp, 1024) === "\r\n") { $incoming = true; } } fclose($fp); $data = trim($data); if ($data === $teststr) { return INSECURE_DATAROOT_ERROR; } } return INSECURE_DATAROOT_WARNING; } /// ============================================================================================================= /// administration tree classes and functions // n.b. documentation is still in progress for this code /// INTRODUCTION /// This file performs the following tasks: /// -it defines the necessary objects and interfaces to build the Moodle /// admin hierarchy /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(), /// and admin_externalpage_print_footer() functions used on admin pages /// ADMIN_SETTING OBJECTS /// Moodle settings are represented by objects that inherit from the admin_setting /// class. These objects encapsulate how to read a setting, how to write a new value /// to a setting, and how to appropriately display the HTML to modify the setting. /// ADMIN_SETTINGPAGE OBJECTS /// The admin_setting objects are then grouped into admin_settingpages. The latter /// appear in the Moodle admin tree block. All interaction with admin_settingpage /// objects is handled by the admin/settings.php file. /// ADMIN_EXTERNALPAGE OBJECTS /// There are some settings in Moodle that are too complex to (efficiently) handle /// with admin_settingpages. (Consider, for example, user management and displaying /// lists of users.) In this case, we use the admin_externalpage object. This object /// places a link to an external PHP file in the admin tree block. /// If you're using an admin_externalpage object for some settings, you can take /// advantage of the admin_externalpage_* functions. For example, suppose you wanted /// to add a foo.php file into admin. First off, you add the following line to /// admin/settings/first.php (at the end of the file) or to some other file in /// admin/settings: /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'), /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission')); /// Next, in foo.php, your file structure would resemble the following: /// require_once('.../config.php'); /// require_once($CFG->libdir.'/adminlib.php'); /// admin_externalpage_setup('foo'); /// // functionality like processing form submissions goes here /// admin_externalpage_print_header(); /// // your HTML goes here /// admin_externalpage_print_footer(); /// The admin_externalpage_setup() function call ensures the user is logged in, /// and makes sure that they have the proper role permission to access the page. /// The admin_externalpage_print_header() function prints the header (it figures /// out what category and subcategories the page is classified under) and ensures /// that you're using the admin pagelib (which provides the admin tree block and /// the admin bookmarks block). /// The admin_externalpage_print_footer() function properly closes the tables /// opened up by the admin_externalpage_print_header() function and prints the /// standard Moodle footer. /// ADMIN_CATEGORY OBJECTS /// Above and beyond all this, we have admin_category objects. These objects /// appear as folders in the admin tree block. They contain admin_settingpage's, /// admin_externalpage's, and other admin_category's. /// OTHER NOTES /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit /// from part_of_admin_tree (a pseudointerface). This interface insists that /// a class has a check_access method for access permissions, a locate method /// used to find a specific node in the admin tree and find parent path. /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo- /// interface ensures that the class implements a recursive add function which /// accepts a part_of_admin_tree object and searches for the proper place to /// put it. parentable_part_of_admin_tree implies part_of_admin_tree. /// Please note that the $this->name field of any part_of_admin_tree must be /// UNIQUE throughout the ENTIRE admin tree. /// The $this->name field of an admin_setting object (which is *not* part_of_ /// admin_tree) must be unique on the respective admin_settingpage where it is /// used. /// CLASS DEFINITIONS ///////////////////////////////////////////////////////// /** * Pseudointerface for anything appearing in the admin tree * * The pseudointerface that is implemented by anything that appears in the admin tree * block. It forces inheriting classes to define a method for checking user permissions * and methods for finding something in the admin tree. * * @author Vincenzo K. Marcovecchio * @package admin */ interface part_of_admin_tree { /** * Finds a named part_of_admin_tree. * * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree * and not parentable_part_of_admin_tree, then this function should only check if * $this->name matches $name. If it does, it should return a reference to $this, * otherwise, it should return a reference to NULL. * * If a class inherits parentable_part_of_admin_tree, this method should be called * recursively on all child objects (assuming, of course, the parent object's name * doesn't match the search criterion). * * @param string $name The internal name of the part_of_admin_tree we're searching for. * @return mixed An object reference or a NULL reference. */ public function locate($name); /** * Removes named part_of_admin_tree. * * @param string $name The internal name of the part_of_admin_tree we want to remove. * @return bool success. */ public function prune($name); /** * Search using query * @param strin query * @return mixed array-object structure of found settings and pages */ public function search($query); /** * Verifies current user's access to this part_of_admin_tree. * * Used to check if the current user has access to this part of the admin tree or * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree, * then this method is usually just a call to has_capability() in the site context. * * If a class inherits parentable_part_of_admin_tree, this method should return the * logical OR of the return of check_access() on all child objects. * * @return bool True if the user has access, false if she doesn't. */ public function check_access(); /** * Mostly usefull for removing of some parts of the tree in admin tree block. * * @return True is hidden from normal list view */ public function is_hidden(); } /** * Pseudointerface implemented by any part_of_admin_tree that has children. * * The pseudointerface implemented by any part_of_admin_tree that can be a parent * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods * include an add method for adding other part_of_admin_tree objects as children. * * @author Vincenzo K. Marcovecchio * @package admin */ interface parentable_part_of_admin_tree extends part_of_admin_tree { /** * Adds a part_of_admin_tree object to the admin tree. * * Used to add a part_of_admin_tree object to this object or a child of this * object. $something should only be added if $destinationname matches * $this->name. If it doesn't, add should be called on child objects that are * also parentable_part_of_admin_tree's. * * @param string $destinationname The internal name of the new parent for $something. * @param part_of_admin_tree $something The object to be added. * @return bool True on success, false on failure. */ public function add($destinationname, $something); } /** * The object used to represent folders (a.k.a. categories) in the admin tree block. * * Each admin_category object contains a number of part_of_admin_tree objects. * * @author Vincenzo K. Marcovecchio * @package admin */ class admin_category implements parentable_part_of_admin_tree { /** * @var mixed An array of part_of_admin_tree objects that are this object's children */ public $children; /** * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */ public $name; /** * @var string The displayed name for this category. Usually obtained through get_string() */ public $visiblename; /** * @var bool Should this category be hidden in admin tree block? */ public $hidden; /** * paths */ public $path; public $visiblepath; /** * Constructor for an empty admin category * * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects * @param string $visiblename The displayed named for this category. Usually obtained through get_string() * @param bool $hidden hide category in admin tree block */ public function __construct($name, $visiblename, $hidden=false) { $this->children = array(); $this->name = $name; $this->visiblename = $visiblename; $this->hidden = $hidden; } /** * Returns a reference to the part_of_admin_tree object with internal name $name. * * @param string $name The internal name of the object we want. * @param bool $findpath initialize path and visiblepath arrays * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL. */ public function locate($name, $findpath=false) { if ($this->name == $name) { if ($findpath) { $this->visiblepath[] = $this->visiblename; $this->path[] = $this->name; } return $this; } $return = NULL; foreach($this->children as $childid=>$unused) { if ($return = $this->children[$childid]->locate($name, $findpath)) { break; } } if (!is_null($return) and $findpath) { $return->visiblepath[] = $this->visiblename; $return->path[] = $this->name; } return $return; } /** * Search using query * @param strin query * @return mixed array-object structure of found settings and pages */ public function search($query) { $result = array(); foreach ($this->children as $child) { $subsearch = $child->search($query); if (!is_array($subsearch)) { debugging('Incorrect search result from '.$child->name); continue; } $result = array_merge($result, $subsearch); } return $result; } /** * Removes part_of_admin_tree object with internal name $name. * * @param string $name The internal name of the object we want to remove. * @return bool success */ public function prune($name) { if ($this->name == $name) { return false; //can not remove itself } foreach($this->children as $precedence => $child) { if ($child->name == $name) { // found it! unset($this->children[$precedence]); return true; } if ($this->children[$precedence]->prune($name)) { return true; } } return false; } /** * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object. * * @param string $destinationame The internal name of the immediate parent that we want for $something. * @param mixed $something A part_of_admin_tree or setting instanceto be added. * @return bool True if successfully added, false if $something can not be added. */ public function add($parentname, $something) { $parent = $this->locate($parentname); if (is_null($parent)) { debugging('parent does not exist!'); return false; } if ($something instanceof part_of_admin_tree) { if (!($parent instanceof parentable_part_of_admin_tree)) { debugging('error - parts of tree can be inserted only into parentable parts'); return false; } $parent->children[] = $something; return true; } else { debugging('error - can not add this element'); return false; } } /** * Checks if the user has access to anything in this category. * * @return bool True if the user has access to atleast one child in this category, false otherwise. */ public function check_access() { foreach ($this->children as $child) { if ($child->check_access()) { return true; } } return false; } /** * Is this category hidden in admin tree block? * * @return bool True if hidden */ public function is_hidden() { return $this->hidden; } } class admin_root extends admin_category { /** list of errors */ public $errors; /** search query */ public $search; /** full tree flag - true means all settings required, false onlypages required */ public $fulltree; /** flag indicating loaded tree */ public $loaded; /** site custom defaults overriding defaults in setings files */ public $custom_defaults; public function __construct($fulltree) { global $CFG; parent::__construct('root', get_string('administration'), false); $this->errors = array(); $this->search = ''; $this->fulltree = $fulltree; $this->loaded = false; // load custom defaults if found $this->custom_defaults = null; $defaultsfile = "$CFG->dirroot/local/defaults.php"; if (is_readable($defaultsfile)) { $defaults = array(); include($defaultsfile); if (is_array($defaults) and count($defaults)) { $this->custom_defaults = $defaults; } } } public function purge_children($requirefulltree) { $this->children = array(); $this->fulltree = ($requirefulltree || $this->fulltree); $this->loaded = false; } } /** * Links external PHP pages into the admin tree. * * See detailed usage example at the top of this document (adminlib.php) * * @author Vincenzo K. Marcovecchio * @package admin */ class admin_externalpage implements part_of_admin_tree { /** * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */ public $name; /** * @var string The displayed name for this external page. Usually obtained through get_string(). */ public $visiblename; /** * @var string The external URL that we should link to when someone requests this external page. */ public $url; /** * @var string The role capability/permission a user must have to access this external page. */ public $req_capability; /** * @var object The context in which capability/permission should be checked, default is site context. */ public $context; /** * @var bool hidden in admin tree block. */ public $hidden; /** * visible path */ public $path; public $visiblepath; /** * Constructor for adding an external page into the admin tree. * * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects. * @param string $visiblename The displayed name for this external page. Usually obtained through get_string(). * @param string $url The external URL that we should link to when someone requests this external page. * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'. * @param boolean $hidden Is this external page hidden in admin tree block? Default false. * @param context $context The context the page relates to. Not sure what happens * if you specify something other than system or front page. Defaults to system. */ public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) { $this->name = $name; $this->visiblename = $visiblename; $this->url = $url; if (is_array($req_capability)) { $this->req_capability = $req_capability; } else { $this->req_capability = array($req_capability); } $this->hidden = $hidden; $this->context = $context; } /** * Returns a reference to the part_of_admin_tree object with internal name $name. * * @param string $name The internal name of the object we want. * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL. */ public function locate($name, $findpath=false) { if ($this->name == $name) { if ($findpath) { $this->visiblepath = array($this->visiblename); $this->path = array($this->name); } return $this; } else { $return = NULL; return $return; } } public function prune($name) { return false; } /** * Search using query * @param strin query * @return mixed array-object structure of found settings and pages */ public function search($query) { $textlib = textlib_get_instance(); $found = false; if (strpos(strtolower($this->name), $query) !== false) { $found = true; } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) { $found = true; } if ($found) { $result = new object(); $result->page = $this; $result->settings = array(); return array($this->name => $result); } else { return array(); } } /** * Determines if the current user has access to this external page based on $this->req_capability. * @return bool True if user has access, false otherwise. */ public function check_access() { global $CFG; $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context; foreach($this->req_capability as $cap) { if (is_valid_capability($cap) and has_capability($cap, $context)) { return true; } } return false; } /** * Is this external page hidden in admin tree block? * * @return bool True if hidden */ public function is_hidden() { return $this->hidden; } } /** * Used to group a number of admin_setting objects into a page and add them to the admin tree. * * @author Vincenzo K. Marcovecchio * @package admin */ class admin_settingpage implements part_of_admin_tree { /** * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */ public $name; /** * @var string The displayed name for this external page. Usually obtained through get_string(). */ public $visiblename; /** * @var mixed An array of admin_setting objects that are part of this setting page. */ public $settings; /** * @var string The role capability/permission a user must have to access this external page. */ public $req_capability; /** * @var object The context in which capability/permission should be checked, default is site context. */ public $context; /** * @var bool hidden in admin tree block. */ public $hidden; /** * paths */ public $path; public $visiblepath; // see admin_externalpage public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) { $this->settings = new object(); $this->name = $name; $this->visiblename = $visiblename; if (is_array($req_capability)) { $this->req_capability = $req_capability; } else { $this->req_capability = array($req_capability); } $this->hidden = $hidden; $this->context = $context; } // see admin_category public function locate($name, $findpath=false) { if ($this->name == $name) { if ($findpath) { $this->visiblepath = array($this->visiblename); $this->path = array($this->name); } return $this; } else { $return = NULL; return $return; } } public function search($query) { $found = array(); foreach ($this->settings as $setting) { if ($setting->is_related($query)) { $found[] = $setting; } } if ($found) { $result = new object(); $result->page = $this; $result->settings = $found; return array($this->name => $result); } $textlib = textlib_get_instance(); $found = false; if (strpos(strtolower($this->name), $query) !== false) { $found = true; } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) { $found = true; } if ($found) { $result = new object(); $result->page = $this; $result->settings = array(); return array($this->name => $result); } else { return array(); } } public function prune($name) { return false; } /** * 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 * n.b. each admin_setting in an admin_settingpage must have a unique internal name * @param object $setting is the admin_setting object you want to add * @return true if successful, false if not */ public function add($setting) { if (!($setting instanceof admin_setting)) { debugging('error - not a setting instance'); return false; } $this->settings->{$setting->name} = $setting; return true; } // see admin_externalpage public function check_access() { global $CFG; $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context; foreach($this->req_capability as $cap) { if (is_valid_capability($cap) and has_capability($cap, $context)) { return true; } } return false; } /** * outputs this page as html in a table (suitable for inclusion in an admin pagetype) * returns a string of the html */ public function output_html() { $adminroot = admin_get_root(); $return = '
'."\n".'
'."\n"; foreach($this->settings as $setting) { $fullname = $setting->get_full_name(); if (array_key_exists($fullname, $adminroot->errors)) { $data = $adminroot->errors[$fullname]->data; } else { $data = $setting->get_setting(); // do not use defaults if settings not available - upgrdesettings handles the defaults! } $return .= $setting->output_html($data); } $return .= '
'; return $return; } /** * Is this settigns page hidden in admin tree block? * * @return bool True if hidden */ public function is_hidden() { return $this->hidden; } } /** * Admin settings class. Only exists on setting pages. * Read & write happens at this level; no authentication. */ abstract class admin_setting { public $name; public $visiblename; public $description; public $defaultsetting; public $updatedcallback; public $plugin; // null means main config table /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised name * @param string $description localised long description * @param mixed $defaultsetting string or array depending on implementation */ public function __construct($name, $visiblename, $description, $defaultsetting) { $this->parse_setting_name($name); $this->visiblename = $visiblename; $this->description = $description; $this->defaultsetting = $defaultsetting; } /** * Set up $this->name and possibly $this->plugin based on whether $name looks * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking * on the names, that is, output a developer debug warning if the name * contains anything other than [a-zA-Z0-9_]+. * * @param string $name the setting name passed in to the constructor. */ private function parse_setting_name($name) { $bits = explode('/', $name); if (count($bits) > 2) { throw new moodle_exception('invalidadminsettingname', '', '', $name); } $this->name = array_pop($bits); if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) { throw new moodle_exception('invalidadminsettingname', '', '', $name); } if (!empty($bits)) { $this->plugin = array_pop($bits); if ($this->plugin === 'moodle') { $this->plugin = null; } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) { throw new moodle_exception('invalidadminsettingname', '', '', $name); } } } public function get_full_name() { return 's_'.$this->plugin.'_'.$this->name; } public function get_id() { return 'id_s_'.$this->plugin.'_'.$this->name; } public function config_read($name) { global $CFG; if (!empty($this->plugin)) { $value = get_config($this->plugin, $name); return $value === false ? NULL : $value; } else { if (isset($CFG->$name)) { return $CFG->$name; } else { return NULL; } } } /** * * @param $name * @param $value * @return Write setting to confix table */ public function config_write($name, $value) { global $DB, $USER, $CFG; // make sure it is a real change $oldvalue = get_config($this->plugin, $name); $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise $value = is_null($value) ? null : (string)$value; if ($oldvalue === $value) { return true; } // store change set_config($name, $value, $this->plugin); // log change $log = new object(); $log->userid = empty($CFG->rolesactive) ? 0 :$USER->id; // 0 as user id during install $log->timemodified = time(); $log->plugin = $this->plugin; $log->name = $name; $log->value = $value; $log->oldvalue = $oldvalue; $DB->insert_record('config_log', $log); return true; // BC only } /** * Returns current value of this setting * @return mixed array or string depending on instance, NULL means not set yet */ public abstract function get_setting(); /** * Returns default setting if exists * @return mixed array or string depending on instance; NULL means no default, user must supply */ public function get_defaultsetting() { $adminroot = admin_get_root(false, false); if (!empty($adminroot->custom_defaults)) { $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin; if (isset($adminroot->custom_defaults[$plugin])) { if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid valie here ;-) return $adminroot->custom_defaults[$plugin][$this->name]; } } } return $this->defaultsetting; } /** * Store new setting * @param mixed string or array, must not be NULL * @return '' if ok, string error message otherwise */ public abstract function write_setting($data); /** * Return part of form with setting * @param mixed data array or string depending on setting * @return string */ public function output_html($data, $query='') { // should be overridden return; } /** * function called if setting updated - cleanup, cache reset, etc. */ public function set_updatedcallback($functionname) { $this->updatedcallback = $functionname; } /** * Is setting related to query text - used when searching * @param string $query * @return bool */ public function is_related($query) { if (strpos(strtolower($this->name), $query) !== false) { return true; } $textlib = textlib_get_instance(); if (strpos($textlib->strtolower($this->visiblename), $query) !== false) { return true; } if (strpos($textlib->strtolower($this->description), $query) !== false) { return true; } $current = $this->get_setting(); if (!is_null($current)) { if (is_string($current)) { if (strpos($textlib->strtolower($current), $query) !== false) { return true; } } } $default = $this->get_defaultsetting(); if (!is_null($default)) { if (is_string($default)) { if (strpos($textlib->strtolower($default), $query) !== false) { return true; } } } return false; } } /** * No setting - just heading and text. */ class admin_setting_heading extends admin_setting { /** * not a setting, just text * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $heading heading * @param string $information text in box */ public function __construct($name, $heading, $information) { parent::__construct($name, $heading, $information, ''); } public function get_setting() { return true; } public function get_defaultsetting() { return true; } public function write_setting($data) { // do not write any setting return ''; } public function output_html($data, $query='') { $return = ''; if ($this->visiblename != '') { $return .= print_heading(''.highlightfast($query, $this->visiblename).'', '', 3, 'main', true); } if ($this->description != '') { $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true); } return $return; } } /** * The most flexibly setting, user is typing text */ class admin_setting_configtext extends admin_setting { public $paramtype; public $size; /** * config text contructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param string $defaultsetting * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex * @param int $size default field size */ public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) { $this->paramtype = $paramtype; if (!is_null($size)) { $this->size = $size; } else { $this->size = ($paramtype == PARAM_INT) ? 5 : 30; } parent::__construct($name, $visiblename, $description, $defaultsetting); } public function get_setting() { return $this->config_read($this->name); } public function write_setting($data) { if ($this->paramtype === PARAM_INT and $data === '') { // do not complain if '' used instead of 0 $data = 0; } // $data is a string $validated = $this->validate($data); if ($validated !== true) { return $validated; } return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); } /** * Validate data before storage * @param string data * @return mixed true if ok string if error found */ public function validate($data) { if (is_string($this->paramtype)) { if (preg_match($this->paramtype, $data)) { return true; } else { return get_string('validateerror', 'admin'); } } else if ($this->paramtype === PARAM_RAW) { return true; } else { $cleaned = clean_param($data, $this->paramtype); if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison return true; } else { return get_string('validateerror', 'admin'); } } } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); return format_admin_setting($this, $this->visiblename, '
', $this->description, true, '', $default, $query); } } /** * General text area without html editor. */ class admin_setting_configtextarea extends admin_setting_configtext { public $rows; public $cols; public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') { $this->rows = $rows; $this->cols = $cols; parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype); } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); $defaultinfo = $default; if (!is_null($default) and $default !== '') { $defaultinfo = "\n".$default; } return format_admin_setting($this, $this->visiblename, '
', $this->description, true, '', $defaultinfo, $query); } } /** * Password field, allows unmasking of password */ class admin_setting_configpasswordunmask extends admin_setting_configtext { /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param string $defaultsetting default password */ public function __construct($name, $visiblename, $description, $defaultsetting) { parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30); } public function output_html($data, $query='') { $id = $this->get_id(); $unmask = get_string('unmaskpassword', 'form'); $unmaskjs = ''; return format_admin_setting($this, $this->visiblename, '
'.$unmaskjs.'
', $this->description, true, '', NULL, $query); } } /** * Path to directory */ class admin_setting_configfile extends admin_setting_configtext { /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param string $defaultdirectory default directory location */ public function __construct($name, $visiblename, $description, $defaultdirectory) { parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50); } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); if ($data) { if (file_exists($data)) { $executable = ''; } else { $executable = ''; } } else { $executable = ''; } return format_admin_setting($this, $this->visiblename, '
'.$executable.'
', $this->description, true, '', $default, $query); } } /** * Path to executable file */ class admin_setting_configexecutable extends admin_setting_configfile { public function output_html($data, $query='') { $default = $this->get_defaultsetting(); if ($data) { if (file_exists($data) and is_executable($data)) { $executable = ''; } else { $executable = ''; } } else { $executable = ''; } return format_admin_setting($this, $this->visiblename, '
'.$executable.'
', $this->description, true, '', $default, $query); } } /** * Path to directory */ class admin_setting_configdirectory extends admin_setting_configfile { public function output_html($data, $query='') { $default = $this->get_defaultsetting(); if ($data) { if (file_exists($data) and is_dir($data)) { $executable = ''; } else { $executable = ''; } } else { $executable = ''; } return format_admin_setting($this, $this->visiblename, '
'.$executable.'
', $this->description, true, '', $default, $query); } } /** * Checkbox */ class admin_setting_configcheckbox extends admin_setting { public $yes; public $no; /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param string $defaultsetting * @param string $yes value used when checked * @param string $no value used when not checked */ public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') { parent::__construct($name, $visiblename, $description, $defaultsetting); $this->yes = (string)$yes; $this->no = (string)$no; } public function get_setting() { return $this->config_read($this->name); } public function write_setting($data) { if ((string)$data === $this->yes) { // convert to strings before comparison $data = $this->yes; } else { $data = $this->no; } return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); if (!is_null($default)) { if ((string)$default === $this->yes) { $defaultinfo = get_string('checkboxyes', 'admin'); } else { $defaultinfo = get_string('checkboxno', 'admin'); } } else { $defaultinfo = NULL; } if ((string)$data === $this->yes) { // convert to strings before comparison $checked = 'checked="checked"'; } else { $checked = ''; } return format_admin_setting($this, $this->visiblename, '
' .'
', $this->description, true, '', $defaultinfo, $query); } } /** * Multiple checkboxes, each represents different value, stored in csv format */ class admin_setting_configmulticheckbox extends admin_setting { public $choices; /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param array $defaultsetting array of selected * @param array $choices array of $value=>$label for each checkbox */ public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { $this->choices = $choices; parent::__construct($name, $visiblename, $description, $defaultsetting); } /** * This public function may be used in ancestors for lazy loading of choices * @return true if loaded, false if error */ public function load_choices() { /* if (is_array($this->choices)) { return true; } .... load choices here */ return true; } /** * Is setting related to query text - used when searching * @param string $query * @return bool */ public function is_related($query) { if (!$this->load_choices() or empty($this->choices)) { return false; } if (parent::is_related($query)) { return true; } $textlib = textlib_get_instance(); foreach ($this->choices as $desc) { if (strpos($textlib->strtolower($desc), $query) !== false) { return true; } } return false; } public function get_setting() { $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } if ($result === '') { return array(); } $enabled = explode(',', $result); $setting = array(); foreach ($enabled as $option) { $setting[$option] = 1; } return $setting; } public function write_setting($data) { if (!is_array($data)) { return ''; // ignore it } if (!$this->load_choices() or empty($this->choices)) { return ''; } unset($data['xxxxx']); $result = array(); foreach ($data as $key => $value) { if ($value and array_key_exists($key, $this->choices)) { $result[] = $key; } } return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin'); } public function output_html($data, $query='') { if (!$this->load_choices() or empty($this->choices)) { return ''; } $default = $this->get_defaultsetting(); if (is_null($default)) { $default = array(); } if (is_null($data)) { $data = array(); } $options = array(); $defaults = array(); foreach ($this->choices as $key=>$description) { if (!empty($data[$key])) { $checked = 'checked="checked"'; } else { $checked = ''; } if (!empty($default[$key])) { $defaults[] = $description; } $options[] = '' .''; } if (is_null($default)) { $defaultinfo = NULL; } else if (!empty($defaults)) { $defaultinfo = implode(', ', $defaults); } else { $defaultinfo = get_string('none'); } $return = '
'; $return .= ''; // something must be submitted even if nothing selected if ($options) { $return .= '
    '; foreach ($options as $option) { $return .= '
  • '.$option.'
  • '; } $return .= '
'; } $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query); } } /** * Multiple checkboxes 2, value stored as string 00101011 */ class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox { public function get_setting() { $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } if (!$this->load_choices()) { return NULL; } $result = str_pad($result, count($this->choices), '0'); $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY); $setting = array(); foreach ($this->choices as $key=>$unused) { $value = array_shift($result); if ($value) { $setting[$key] = 1; } } return $setting; } public function write_setting($data) { if (!is_array($data)) { return ''; // ignore it } if (!$this->load_choices() or empty($this->choices)) { return ''; } $result = ''; foreach ($this->choices as $key=>$unused) { if (!empty($data[$key])) { $result .= '1'; } else { $result .= '0'; } } return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'); } } /** * Select one value from list */ class admin_setting_configselect extends admin_setting { public $choices; /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param string $defaultsetting * @param array $choices array of $value=>$label for each selection */ public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { $this->choices = $choices; parent::__construct($name, $visiblename, $description, $defaultsetting); } /** * This function may be used in ancestors for lazy loading of choices * @return true if loaded, false if error */ public function load_choices() { /* if (is_array($this->choices)) { return true; } .... load choices here */ return true; } public function is_related($query) { if (parent::is_related($query)) { return true; } if (!$this->load_choices()) { return false; } $textlib = textlib_get_instance(); foreach ($this->choices as $key=>$value) { if (strpos($textlib->strtolower($key), $query) !== false) { return true; } if (strpos($textlib->strtolower($value), $query) !== false) { return true; } } return false; } public function get_setting() { return $this->config_read($this->name); } public function write_setting($data) { if (!$this->load_choices() or empty($this->choices)) { return ''; } if (!array_key_exists($data, $this->choices)) { return ''; // ignore it } return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); } /** * Ensure the options are loaded, and generate the HTML for the select * element and any warning message. Separating this out from output_html * makes it easier to subclass this class. * * @param string $data the option to show as selected. * @param string $current the currently selected option in the database, null if none. * @param string $default the default selected option. * @return array the HTML for the select element, and a warning message. */ public function output_select_html($data, $current, $default, $extraname = '') { if (!$this->load_choices() or empty($this->choices)) { return array('', ''); } $warning = ''; if (is_null($current)) { // first run } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) { // no warning } else if (!array_key_exists($current, $this->choices)) { $warning = get_string('warningcurrentsetting', 'admin', s($current)); if (!is_null($default) and $data == $current) { $data = $default; // use default instead of first value when showing the form } } $selecthtml = ''; return array($selecthtml, $warning); } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); $current = $this->get_setting(); list($selecthtml, $warning) = $this->output_select_html($data, $current, $default); if (!$selecthtml) { return ''; } if (!is_null($default) and array_key_exists($default, $this->choices)) { $defaultinfo = $this->choices[$default]; } else { $defaultinfo = NULL; } $return = '
' . $selecthtml . '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query); } } /** * Select multiple items from list */ class admin_setting_configmultiselect extends admin_setting_configselect { /** * Constructor * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised * @param string $description long localised info * @param array $defaultsetting array of selected items * @param array $choices array of $value=>$label for each list item */ public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); } public function get_setting() { $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } if ($result === '') { return array(); } return explode(',', $result); } public function write_setting($data) { if (!is_array($data)) { return ''; //ignore it } if (!$this->load_choices() or empty($this->choices)) { return ''; } unset($data['xxxxx']); $save = array(); foreach ($data as $value) { if (!array_key_exists($value, $this->choices)) { continue; // ignore it } $save[] = $value; } return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin')); } /** * Is setting related to query text - used when searching * @param string $query * @return bool */ public function is_related($query) { if (!$this->load_choices() or empty($this->choices)) { return false; } if (parent::is_related($query)) { return true; } $textlib = textlib_get_instance(); foreach ($this->choices as $desc) { if (strpos($textlib->strtolower($desc), $query) !== false) { return true; } } return false; } public function output_html($data, $query='') { if (!$this->load_choices() or empty($this->choices)) { return ''; } $choices = $this->choices; $default = $this->get_defaultsetting(); if (is_null($default)) { $default = array(); } if (is_null($data)) { $data = array(); } $defaults = array(); $size = min(10, count($this->choices)); $return = '
'; // something must be submitted even if nothing selected $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query); } } /** * Time selector * this is a liiitle bit messy. we're using two selects, but we're returning * them as an array named after $name (so we only use $name2 internally for the setting) */ class admin_setting_configtime extends admin_setting { public $name2; /** * Constructor * @param string $hoursname setting for hours * @param string $minutesname setting for hours * @param string $visiblename localised * @param string $description long localised info * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes */ public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) { $this->name2 = $minutesname; parent::__construct($hoursname, $visiblename, $description, $defaultsetting); } public function get_setting() { $result1 = $this->config_read($this->name); $result2 = $this->config_read($this->name2); if (is_null($result1) or is_null($result2)) { return NULL; } return array('h' => $result1, 'm' => $result2); } public function write_setting($data) { if (!is_array($data)) { return ''; } $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']); return ($result ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); if (is_array($default)) { $defaultinfo = $default['h'].':'.$default['m']; } else { $defaultinfo = NULL; } $return = '
'. ':
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query); } } class admin_setting_configiplist extends admin_setting_configtextarea { public function validate($data) { if(!empty($data)) { $ips = explode("\n", $data); } else { return true; } $result = true; foreach($ips as $ip) { $ip = trim($ip); if(preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) || preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) || preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) { $result = true; } else { $result = false; break; } } if($result){ return true; } else { return get_string('validateerror', 'admin'); } } } /** * An admin setting for selecting one or more users, who have a particular capability * in the system context. Warning, make sure the list will never be too long. There is * no paging or searching of this list. * * To correctly get a list of users from this config setting, you need to call the * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php. */ class admin_setting_users_with_capability extends admin_setting_configmultiselect { protected $capability; /** * Constructor. * * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. * @param string $visiblename localised name * @param string $description localised long description * @param array $defaultsetting array of usernames * @param string $capability string capability name. */ public function __construct($name, $visiblename, $description, $defaultsetting, $capability) { $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM), $capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname'); $choices = array( '$@NONE@$' => get_string('nobody'), '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($capability)), ); foreach ($users as $user) { $choices[$user->username] = fullname($user); } parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); } public function get_defaultsetting() { $this->load_choices(); $defaultsetting = parent::get_defaultsetting(); if (empty($defaultsetting)) { return array('$@NONE@$'); } else if (array_key_exists($defaultsetting, $this->choices)) { return $defaultsetting; } else { return ''; } } public function get_setting() { $result = parent::get_setting(); if (empty($result)) { $result = array('$@NONE@$'); } return $result; } public function write_setting($data) { // If all is selected, remove any explicit options. if (in_array('$@ALL@$', $data)) { $data = array('$@ALL@$'); } // None never needs to be writted to the DB. if (in_array('$@NONE@$', $data)) { unset($data[array_search('$@NONE@$', $data)]); } return parent::write_setting($data); } } /** * Special checkbox for calendar - resets SESSION vars. */ class admin_setting_special_adminseesall extends admin_setting_configcheckbox { public function __construct() { parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'), get_string('helpadminseesall', 'admin'), '0'); } public function write_setting($data) { global $SESSION; unset($SESSION->cal_courses_shown); return parent::write_setting($data); } } /** * Special select for settings that are altered in setup.php and can not be altered on the fly */ class admin_setting_special_selectsetup extends admin_setting_configselect { public function get_setting() { // read directly from db! return get_config(NULL, $this->name); } public function write_setting($data) { global $CFG; // do not change active CFG setting! $current = $CFG->{$this->name}; $result = parent::write_setting($data); $CFG->{$this->name} = $current; return $result; } } /** * Special select for frontpage - stores data in course table */ class admin_setting_sitesetselect extends admin_setting_configselect { public function get_setting() { $site = get_site(); return $site->{$this->name}; } public function write_setting($data) { global $DB; if (!in_array($data, array_keys($this->choices))) { return get_string('errorsetting', 'admin'); } $record = new stdClass(); $record->id = SITEID; $temp = $this->name; $record->$temp = $data; $record->timemodified = time(); return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin')); } } /** * Special select - lists on the frontpage - hacky */ class admin_setting_courselist_frontpage extends admin_setting { public $choices; public function __construct($loggedin) { global $CFG; require_once($CFG->dirroot.'/course/lib.php'); $name = 'frontpage'.($loggedin ? 'loggedin' : ''); $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin'); $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin'); $defaults = array(FRONTPAGECOURSELIST); parent::__construct($name, $visiblename, $description, $defaults); } public function load_choices() { global $DB; if (is_array($this->choices)) { return true; } $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'), FRONTPAGECOURSELIST => get_string('frontpagecourselist'), FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'), FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'), 'none' => get_string('none')); if ($this->name == 'frontpage' and $DB->count_records('course') > FRONTPAGECOURSELIMIT) { unset($this->choices[FRONTPAGECOURSELIST]); } return true; } public function get_setting() { $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } if ($result === '') { return array(); } return explode(',', $result); } public function write_setting($data) { if (!is_array($data)) { return ''; } $this->load_choices(); $save = array(); foreach($data as $datum) { if ($datum == 'none' or !array_key_exists($datum, $this->choices)) { continue; } $save[$datum] = $datum; // no duplicates } return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { $this->load_choices(); $currentsetting = array(); foreach ($data as $key) { if ($key != 'none' and array_key_exists($key, $this->choices)) { $currentsetting[] = $key; // already selected first } } $return = '
'; for ($i = 0; $i < count($this->choices) - 1; $i++) { if (!array_key_exists($i, $currentsetting)) { $currentsetting[$i] = 'none'; //none } $return .=''; if ($i !== count($this->choices) - 2) { $return .= '
'; } } $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); } } /** * Special checkbox for frontpage - stores data in course table */ class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox { public function get_setting() { $site = get_site(); return $site->{$this->name}; } public function write_setting($data) { global $DB; $record = new object(); $record->id = SITEID; $record->{$this->name} = ($data == '1' ? 1 : 0); $record->timemodified = time(); return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin')); } } /** * Special text for frontpage - stores data in course table. * Empty string means not set here. Manual setting is required. */ class admin_setting_sitesettext extends admin_setting_configtext { public function get_setting() { $site = get_site(); return $site->{$this->name} != '' ? $site->{$this->name} : NULL; } public function validate($data) { $cleaned = clean_param($data, PARAM_MULTILANG); if ($cleaned === '') { return get_string('required'); } if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison return true; } else { return get_string('validateerror', 'admin'); } } public function write_setting($data) { global $DB; $data = trim($data); $validated = $this->validate($data); if ($validated !== true) { return $validated; } $record = new object(); $record->id = SITEID; $record->{$this->name} = $data; $record->timemodified = time(); return ($DB->update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error')); } } /** * Special text editor for site description. */ class admin_setting_special_frontpagedesc extends admin_setting { public function __construct() { parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL); } public function get_setting() { $site = get_site(); return $site->{$this->name}; } public function write_setting($data) { global $DB; $record = new object(); $record->id = SITEID; $record->{$this->name} = $data; $record->timemodified = time(); return($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { global $CFG; $CFG->adminusehtmleditor = can_use_html_editor(); $return = '
'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); } } class admin_setting_special_editorfontlist extends admin_setting { public $items; public function __construct() { global $CFG; $name = 'editorfontlist'; $visiblename = get_string('editorfontlist', 'admin'); $description = get_string('configeditorfontlist', 'admin'); $defaults = array('k0' => 'Trebuchet', 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif', 'k1' => 'Arial', 'v1' => 'arial,helvetica,sans-serif', 'k2' => 'Courier New', 'v2' => 'courier new,courier,monospace', 'k3' => 'Georgia', 'v3' => 'georgia,times new roman,times,serif', 'k4' => 'Tahoma', 'v4' => 'tahoma,arial,helvetica,sans-serif', 'k5' => 'Times New Roman', 'v5' => 'times new roman,times,serif', 'k6' => 'Verdana', 'v6' => 'verdana,arial,helvetica,sans-serif', 'k7' => 'Impact', 'v7' => 'impact', 'k8' => 'Wingdings', 'v8' => 'wingdings'); parent::__construct($name, $visiblename, $description, $defaults); } public function get_setting() { global $CFG; $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } $i = 0; $currentsetting = array(); $items = explode(';', $result); foreach ($items as $item) { $item = explode(':', $item); $currentsetting['k'.$i] = $item[0]; $currentsetting['v'.$i] = $item[1]; $i++; } return $currentsetting; } public function write_setting($data) { // there miiight be an easier way to do this :) // if this is changed, make sure the $defaults array above is modified so that this // function processes it correctly $keys = array(); $values = array(); foreach ($data as $key => $value) { if (substr($key,0,1) == 'k') { $keys[substr($key,1)] = $value; } elseif (substr($key,0,1) == 'v') { $values[substr($key,1)] = $value; } } $result = array(); for ($i = 0; $i < count($keys); $i++) { if (($keys[$i] !== '') && ($values[$i] !== '')) { $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS); } } return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { $fullname = $this->get_full_name(); $return = '
'; for ($i = 0; $i < count($data) / 2; $i++) { $return .= ''; $return .= '  '; $return .= '
'; } $return .= ''; $return .= '  '; $return .= '
'; $return .= ''; $return .= '  '; $return .= ''; $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); } } class admin_setting_emoticons extends admin_setting { public $items; public function __construct() { global $CFG; $name = 'emoticons'; $visiblename = get_string('emoticons', 'admin'); $description = get_string('configemoticons', 'admin'); $defaults = array('k0' => ':-)', 'v0' => 'smiley', 'k1' => ':)', 'v1' => 'smiley', 'k2' => ':-D', 'v2' => 'biggrin', 'k3' => ';-)', 'v3' => 'wink', 'k4' => ':-/', 'v4' => 'mixed', 'k5' => 'V-.', 'v5' => 'thoughtful', 'k6' => ':-P', 'v6' => 'tongueout', 'k7' => 'B-)', 'v7' => 'cool', 'k8' => '^-)', 'v8' => 'approve', 'k9' => '8-)', 'v9' => 'wideeyes', 'k10' => ':o)', 'v10' => 'clown', 'k11' => ':-(', 'v11' => 'sad', 'k12' => ':(', 'v12' => 'sad', 'k13' => '8-.', 'v13' => 'shy', 'k14' => ':-I', 'v14' => 'blush', 'k15' => ':-X', 'v15' => 'kiss', 'k16' => '8-o', 'v16' => 'surprise', 'k17' => 'P-|', 'v17' => 'blackeye', 'k18' => '8-[', 'v18' => 'angry', 'k19' => 'xx-P', 'v19' => 'dead', 'k20' => '|-.', 'v20' => 'sleepy', 'k21' => '}-]', 'v21' => 'evil', 'k22' => '(h)', 'v22' => 'heart', 'k23' => '(heart)', 'v23' => 'heart', 'k24' => '(y)', 'v24' => 'yes', 'k25' => '(n)', 'v25' => 'no', 'k26' => '(martin)', 'v26' => 'martin', 'k27' => '( )', 'v27' => 'egg'); parent::__construct($name, $visiblename, $description, $defaults); } public function get_setting() { global $CFG; $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } $i = 0; $currentsetting = array(); $items = explode('{;}', $result); foreach ($items as $item) { $item = explode('{:}', $item); $currentsetting['k'.$i] = $item[0]; $currentsetting['v'.$i] = $item[1]; $i++; } return $currentsetting; } public function write_setting($data) { // there miiight be an easier way to do this :) // if this is changed, make sure the $defaults array above is modified so that this // function processes it correctly $keys = array(); $values = array(); foreach ($data as $key => $value) { if (substr($key,0,1) == 'k') { $keys[substr($key,1)] = $value; } elseif (substr($key,0,1) == 'v') { $values[substr($key,1)] = $value; } } $result = array(); for ($i = 0; $i < count($keys); $i++) { if (($keys[$i] !== '') && ($values[$i] !== '')) { $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS); } } return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'
'); } public function output_html($data, $query='') { $fullname = $this->get_full_name(); $return = '
'; for ($i = 0; $i < count($data) / 2; $i++) { $return .= ''; $return .= '  '; $return .= '
'; } $return .= ''; $return .= '  '; $return .= '
'; $return .= ''; $return .= '  '; $return .= ''; $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); } } class admin_setting_special_editorhidebuttons extends admin_setting { public $items; public function __construct() { parent::__construct('editorhidebuttons', get_string('editorhidebuttons', 'admin'), get_string('confeditorhidebuttons', 'admin'), array()); // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead $this->items = array('fontname' => '', 'fontsize' => '', 'formatblock' => '', 'bold' => 'ed_format_bold.gif', 'italic' => 'ed_format_italic.gif', 'underline' => 'ed_format_underline.gif', 'strikethrough' => 'ed_format_strike.gif', 'subscript' => 'ed_format_sub.gif', 'superscript' => 'ed_format_sup.gif', 'copy' => 'ed_copy.gif', 'cut' => 'ed_cut.gif', 'paste' => 'ed_paste.gif', 'clean' => 'ed_wordclean.gif', 'undo' => 'ed_undo.gif', 'redo' => 'ed_redo.gif', 'justifyleft' => 'ed_align_left.gif', 'justifycenter' => 'ed_align_center.gif', 'justifyright' => 'ed_align_right.gif', 'justifyfull' => 'ed_align_justify.gif', 'lefttoright' => 'ed_left_to_right.gif', 'righttoleft' => 'ed_right_to_left.gif', 'insertorderedlist' => 'ed_list_num.gif', 'insertunorderedlist' => 'ed_list_bullet.gif', 'outdent' => 'ed_indent_less.gif', 'indent' => 'ed_indent_more.gif', 'forecolor' => 'ed_color_fg.gif', 'hilitecolor' => 'ed_color_bg.gif', 'inserthorizontalrule' => 'ed_hr.gif', 'createanchor' => 'ed_anchor.gif', 'createlink' => 'ed_link.gif', 'unlink' => 'ed_unlink.gif', 'insertimage' => 'ed_image.gif', 'inserttable' => 'insert_table.gif', 'insertsmile' => 'em.icon.smile.gif', 'insertchar' => 'icon_ins_char.gif', 'spellcheck' => 'spell-check.gif', 'htmlmode' => 'ed_html.gif', 'popupeditor' => 'fullscreen_maximize.gif', 'search_replace' => 'ed_replace.gif'); } public function get_setting() { $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } if ($result === '') { return array(); } return explode(' ', $result); } public function write_setting($data) { if (!is_array($data)) { return ''; // ignore it } unset($data['xxxxx']); $result = array(); foreach ($data as $key => $value) { if (!isset($this->items[$key])) { return get_string('errorsetting', 'admin'); } if ($value == '1') { $result[] = $key; } } return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { global $CFG; // checkboxes with input name="$this->name[$key]" value="1" // we do 15 fields per column $return = '
'; $return .= ''; $return .= '
'; $return .= ''; // something must be submitted even if nothing selected $count = 0; foreach($this->items as $key => $value) { if ($count % 15 == 0 and $count != 0) { $return .= ''; } $return .= ''; $count++; if ($count % 15 != 0) { $return .= '

'; } } $return .= '
'; $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); } } /** * Special setting for limiting of the list of available languages. */ class admin_setting_langlist extends admin_setting_configtext { public function __construct() { parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS); } public function write_setting($data) { $return = parent::write_setting($data); get_list_of_languages(true);//refresh the list return $return; } } /** * Course category selection */ class admin_settings_coursecat_select extends admin_setting_configselect { public function __construct($name, $visiblename, $description, $defaultsetting) { parent::__construct($name, $visiblename, $description, $defaultsetting, NULL); } public function load_choices() { global $CFG; require_once($CFG->dirroot.'/course/lib.php'); if (is_array($this->choices)) { return true; } $this->choices = make_categories_options(); return true; } } class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 { public function __construct() { parent::__construct('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL); $this->plugin = 'backup'; } public function load_choices() { if (is_array($this->choices)) { return true; } $this->choices = array(); $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); foreach ($days as $day) { $this->choices[$day] = get_string($day, 'calendar'); } return true; } } /** * Special debug setting */ class admin_setting_special_debug extends admin_setting_configselect { public function __construct() { parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL); } public function load_choices() { if (is_array($this->choices)) { return true; } $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'), DEBUG_MINIMAL => get_string('debugminimal', 'admin'), DEBUG_NORMAL => get_string('debugnormal', 'admin'), DEBUG_ALL => get_string('debugall', 'admin'), DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')); return true; } } class admin_setting_special_calendar_weekend extends admin_setting { public function __construct() { $name = 'calendar_weekend'; $visiblename = get_string('calendar_weekend', 'admin'); $description = get_string('helpweekenddays', 'admin'); $default = array ('0', '6'); // Saturdays and Sundays parent::__construct($name, $visiblename, $description, $default); } public function get_setting() { $result = $this->config_read($this->name); if (is_null($result)) { return NULL; } if ($result === '') { return array(); } $settings = array(); for ($i=0; $i<7; $i++) { if ($result & (1 << $i)) { $settings[] = $i; } } return $settings; } public function write_setting($data) { if (!is_array($data)) { return ''; } unset($data['xxxxx']); $result = 0; foreach($data as $index) { $result |= 1 << $index; } return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin')); } public function output_html($data, $query='') { // The order matters very much because of the implied numeric keys $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); $return = ''; $return .= ''; // something must be submitted even if nothing selected foreach($days as $index => $day) { $return .= ''; } $return .= ''; foreach($days as $index => $day) { $return .= ''; } $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query); } } /** * Admin setting that allows a user to pick appropriate roles for something. */ class admin_setting_pickroles extends admin_setting_configmulticheckbox { private $types; /** * @param string $name Name of config variable * @param string $visiblename Display name * @param string $description Description * @param array $types Array of capabilities (usually moodle/legacy:something) * which identify roles that will be enabled by default. Default is the * student role */ public function __construct($name, $visiblename, $description, $types) { parent::__construct($name, $visiblename, $description, NULL, NULL); $this->types = $types; } public function load_choices() { global $CFG, $DB; if (empty($CFG->rolesactive)) { return false; } if (is_array($this->choices)) { return true; } if ($roles = get_all_roles()) { $this->choices = array(); foreach($roles as $role) { $this->choices[$role->id] = format_string($role->name); } return true; } else { return false; } } public function get_defaultsetting() { global $CFG; if (empty($CFG->rolesactive)) { return null; } $result = array(); foreach($this->types as $capability) { if ($caproles = get_roles_with_capability($capability, CAP_ALLOW)) { foreach ($caproles as $caprole) { $result[$caprole->id] = 1; } } } return $result; } } /** * Text field with an advanced checkbox, that controls a additional "fix_$name" setting. */ class admin_setting_text_with_advanced extends admin_setting_configtext { public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype) { parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype); } public function get_setting() { $value = parent::get_setting(); $fix = $this->config_read('fix_' . $this->name); if (is_null($value) or is_null($fix)) { return NULL; } return array('value' => $value, 'fix' => $fix); } public function write_setting($data) { $error = parent::write_setting($data['value']); if (!$error) { if (empty($data['fix'])) { $ok = $this->config_write('fix_' . $this->name, 0); } else { $ok = $this->config_write('fix_' . $this->name, 1); } if (!$ok) { $error = get_string('errorsetting', 'admin'); } } return $error; } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); $defaultinfo = array(); if (isset($this->choices[$default['value']])) { $defaultinfo[] = $default['value']; } if (!empty($default['fix'])) { $defaultinfo[] = get_string('advanced'); } $defaultinfo = implode(', ', $defaultinfo); $fix = !empty($data['fix']); $return = '
' . '' . ' ' . '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query); } } /** * Dropdown menu with an advanced checkbox, that controls a additional "fix_$name" setting. */ class admin_setting_combo_with_advanced extends admin_setting_configselect { public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); } public function get_setting() { $value = parent::get_setting(); $fix = $this->config_read('fix_' . $this->name); if (is_null($value) or is_null($fix)) { return NULL; } return array('value' => $value, 'fix' => $fix); } public function write_setting($data) { $error = parent::write_setting($data['value']); if (!$error) { if (empty($data['fix'])) { $ok = $this->config_write('fix_' . $this->name, 0); } else { $ok = $this->config_write('fix_' . $this->name, 1); } if (!$ok) { $error = get_string('errorsetting', 'admin'); } } return $error; } public function output_html($data, $query='') { $default = $this->get_defaultsetting(); $current = $this->get_setting(); list($selecthtml, $warning) = $this->output_select_html($data['value'], $current['value'], $default['value'], '[value]'); if (!$selecthtml) { return ''; } if (!is_null($default) and array_key_exists($default['value'], $this->choices)) { $defaultinfo = array(); if (isset($this->choices[$default['value']])) { $defaultinfo[] = $this->choices[$default['value']]; } if (!empty($default['fix'])) { $defaultinfo[] = get_string('advanced'); } $defaultinfo = implode(', ', $defaultinfo); } else { $defaultinfo = ''; } $fix = !empty($data['fix']); $return = '
' . $selecthtml . ' ' . '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query); } } /** * Specialisation of admin_setting_combo_with_advanced for easy yes/no choices. */ class admin_setting_yesno_with_advanced extends admin_setting_combo_with_advanced { public function __construct($name, $visiblename, $description, $defaultsetting) { parent::__construct($name, $visiblename, $description, $defaultsetting, array(get_string('no'), get_string('yes'))); } } /** * Graded roles in gradebook */ class admin_setting_special_gradebookroles extends admin_setting_pickroles { public function __construct() { parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'), get_string('configgradebookroles', 'admin'), array('moodle/legacy:student')); } } class admin_setting_regradingcheckbox extends admin_setting_configcheckbox { public function write_setting($data) { global $CFG, $DB; $oldvalue = $this->config_read($this->name); $return = parent::write_setting($data); $newvalue = $this->config_read($this->name); if ($oldvalue !== $newvalue) { // force full regrading $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0)); } return $return; } } /** * Which roles to show on course decription page */ class admin_setting_special_coursemanager extends admin_setting_pickroles { public function __construct() { parent::__construct('coursemanager', get_string('coursemanager', 'admin'), get_string('configcoursemanager', 'admin'), array('moodle/legacy:editingteacher')); } } /** * Primary grade export plugin - has state tracking. */ class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox { public function __construct() { parent::__construct('gradeexport', get_string('gradeexport', 'admin'), get_string('configgradeexport', 'admin'), array(), NULL); } public function load_choices() { if (is_array($this->choices)) { return true; } $this->choices = array(); if ($plugins = get_list_of_plugins('grade/export')) { foreach($plugins as $plugin) { $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin); } } return true; } } /** * Grade category settings */ class admin_setting_gradecat_combo extends admin_setting { public $choices; public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { $this->choices = $choices; parent::__construct($name, $visiblename, $description, $defaultsetting); } public function get_setting() { global $CFG; $value = $this->config_read($this->name); $flag = $this->config_read($this->name.'_flag'); if (is_null($value) or is_null($flag)) { return NULL; } $flag = (int)$flag; $forced = (boolean)(1 & $flag); // first bit $adv = (boolean)(2 & $flag); // second bit return array('value' => $value, 'forced' => $forced, 'adv' => $adv); } public function write_setting($data) { global $CFG; $value = $data['value']; $forced = empty($data['forced']) ? 0 : 1; $adv = empty($data['adv']) ? 0 : 2; $flag = ($forced | $adv); //bitwise or if (!in_array($value, array_keys($this->choices))) { return 'Error setting '; } $oldvalue = $this->config_read($this->name); $oldflag = (int)$this->config_read($this->name.'_flag'); $oldforced = (1 & $oldflag); // first bit $result1 = $this->config_write($this->name, $value); $result2 = $this->config_write($this->name.'_flag', $flag); // force regrade if needed if ($oldforced != $forced or ($forced and $value != $oldvalue)) { require_once($CFG->libdir.'/gradelib.php'); grade_category::updated_forced_settings(); } if ($result1 and $result2) { return ''; } else { return get_string('errorsetting', 'admin'); } } public function output_html($data, $query='') { $value = $data['value']; $forced = !empty($data['forced']); $adv = !empty($data['adv']); $default = $this->get_defaultsetting(); if (!is_null($default)) { $defaultinfo = array(); if (isset($this->choices[$default['value']])) { $defaultinfo[] = $this->choices[$default['value']]; } if (!empty($default['forced'])) { $defaultinfo[] = get_string('force'); } if (!empty($default['adv'])) { $defaultinfo[] = get_string('advanced'); } $defaultinfo = implode(', ', $defaultinfo); } else { $defaultinfo = NULL; } $return = '
'; $return .= ''; $return .= '' .''; $return .= '' .''; $return .= '
'; return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query); } } /** * Selection of grade report in user profiles */ class admin_setting_grade_profilereport extends admin_setting_configselect { public function __construct() { parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null); } public function load_choices() { if (is_array($this->choices)) { return true; } $this->choices = array(); global $CFG; require_once($CFG->libdir.'/gradelib.php'); foreach (get_list_of_plugins('grade/report') as $plugin) { if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) { require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php'); $functionname = 'grade_report_'.$plugin.'_profilereport'; if (function_exists($functionname)) { $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin); } } } return true; } } /** * Special class for register auth selection */ class admin_setting_special_registerauth extends admin_setting_configselect { public function __construct() { parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null); } public function get_defaultsetting() { $this->load_choices(); $defaultsetting = parent::get_defaultsetting(); if (array_key_exists($defaultsetting, $this->choices)) { return $defaultsetting; } else { return ''; } } public function load_choices() { global $CFG; if (is_array($this->choices)) { return true; } $this->choices = array(); $this->choices[''] = get_string('disable'); $authsenabled = get_enabled_auth_plugins(true); foreach ($authsenabled as $auth) { $authplugin = get_auth_plugin($auth); if (!$authplugin->can_signup()) { continue; } // Get the auth title (from core or own auth lang files) $authtitle = $authplugin->get_title(); $this->choices[$auth] = $authtitle; } return true; } } /** * Module manage page */ class admin_page_managemods extends admin_externalpage { public function __construct() { global $CFG; parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php"); } public function search($query) { global $DB; if ($result = parent::search($query)) { return $result; } $found = false; if ($modules = $DB->get_records('modules')) { $textlib = textlib_get_instance(); foreach ($modules as $module) { if (strpos($module->name, $query) !== false) { $found = true; break; } $strmodulename = get_string('modulename', $module->name); if (strpos($textlib->strtolower($strmodulename), $query) !== false) { $found = true; break; } } } if ($found) { $result = new object(); $result->page = $this; $result->settings = array(); return array($this->name => $result); } else { return array(); } } } /** * Enrolment manage page */ class admin_enrolment_page extends admin_externalpage { public function __construct() { global $CFG; parent::__construct('enrolment', get_string('enrolments'), $CFG->wwwroot . '/'.$CFG->admin.'/enrol.php'); } public function search($query) { if ($result = parent::search($query)) { return $result; } $found = false; if ($modules = get_list_of_plugins('enrol')) { $textlib = textlib_get_instance(); foreach ($modules as $plugin) { if (strpos($plugin, $query) !== false) { $found = true; break; } $strmodulename = get_string('enrolname', "enrol_$plugin"); if (strpos($textlib->strtolower($strmodulename), $query) !== false) { $found = true; break; } } } //ugly harcoded hacks if (strpos('sendcoursewelcomemessage', $query) !== false) { $found = true; } else if (strpos($textlib->strtolower(get_string('sendcoursewelcomemessage', 'admin')), $query) !== false) { $found = true; } else if (strpos($textlib->strtolower(get_string('configsendcoursewelcomemessage', 'admin')), $query) !== false) { $found = true; } else if (strpos($textlib->strtolower(get_string('configenrolmentplugins', 'admin')), $query) !== false) { $found = true; } if ($found) { $result = new object(); $result->page = $this; $result->settings = array(); return array($this->name => $result); } else { return array(); } } } /** * Blocks manage page */ class admin_page_manageblocks extends admin_externalpage { public function __construct() { global $CFG; parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php"); } public function search($query) { global $CFG, $DB; if ($result = parent::search($query)) { return $result; } $found = false; if ($blocks = $DB->get_records('block')) { $textlib = textlib_get_instance(); foreach ($blocks as $block) { if (strpos($block->name, $query) !== false) { $found = true; break; } $strblockname = get_string('blockname', 'block_'.$block->name); if (strpos($textlib->strtolower($strblockname), $query) !== false) { $found = true; break; } } } if ($found) { $result = new object(); $result->page = $this; $result->settings = array(); return array($this->name => $result); } else { return array(); } } } /** * Question type manage page */ class admin_page_manageqtypes extends admin_externalpage { public function __construct() { global $CFG; parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'), "$CFG->wwwroot/$CFG->admin/qtypes.php"); } public function search($query) { global $CFG; if ($result = parent::search($query)) { return $result; } $found = false; $textlib = textlib_get_instance(); require_once($CFG->libdir . '/questionlib.php'); global $QTYPES; foreach ($QTYPES as $qtype) { if (strpos($textlib->strtolower($qtype->local_name()), $query) !== false) { $found = true; break; } } if ($found) { $result = new object(); $result->page = $this; $result->settings = array(); return array($this->name => $result); } else { return array(); } } } /** * Special class for authentication administration. */ class admin_setting_manageauths extends admin_setting { public function __construct() { parent::__construct('authsui', get_string('authsettings', 'admin'), '', ''); } public function get_setting() { return true; } public function get_defaultsetting() { return true; } public function write_setting($data) { // do not write any setting return ''; } public function is_related($query) { if (parent::is_related($query)) { return true; } $textlib = textlib_get_instance(); $authsavailable = get_list_of_plugins('auth'); foreach ($authsavailable as $auth) { if (strpos($auth, $query) !== false) { return true; } $authplugin = get_auth_plugin($auth); $authtitle = $authplugin->get_title(); if (strpos($textlib->strtolower($authtitle), $query) !== false) { return true; } } return false; } public function output_html($data, $query='') { global $CFG; // display strings $txt = get_strings(array('authenticationplugins', 'users', 'administration', 'settings', 'edit', 'name', 'enable', 'disable', 'up', 'down', 'none')); $txt->updown = "$txt->up/$txt->down"; $authsavailable = get_list_of_plugins('auth'); get_enabled_auth_plugins(true); // fix the list of enabled auths if (empty($CFG->auth)) { $authsenabled = array(); } else { $authsenabled = explode(',', $CFG->auth); } // construct the display array, with enabled auth plugins at the top, in order $displayauths = array(); $registrationauths = array(); $registrationauths[''] = $txt->disable; foreach ($authsenabled as $auth) { $authplugin = get_auth_plugin($auth); /// Get the auth title (from core or own auth lang files) $authtitle = $authplugin->get_title(); /// Apply titles $displayauths[$auth] = $authtitle; if ($authplugin->can_signup()) { $registrationauths[$auth] = $authtitle; } } foreach ($authsavailable as $auth) { if (array_key_exists($auth, $displayauths)) { continue; //already in the list } $authplugin = get_auth_plugin($auth); /// Get the auth title (from core or own auth lang files) $authtitle = $authplugin->get_title(); /// Apply titles $displayauths[$auth] = $authtitle; if ($authplugin->can_signup()) { $registrationauths[$auth] = $authtitle; } } $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true); $return .= print_box_start('generalbox authsui', '', true); $table = new object(); $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings); $table->align = array('left', 'center', 'center', 'center'); $table->width = '90%'; $table->data = array(); //add always enabled plugins first $displayname = "".$displayauths['manual'].""; $settings = "{$txt->settings}"; //$settings = "{$txt->settings}"; $table->data[] = array($displayname, '', '', $settings); $displayname = "".$displayauths['nologin'].""; $settings = "{$txt->settings}"; $table->data[] = array($displayname, '', '', $settings); // iterate through auth plugins and add to the display table $updowncount = 1; $authcount = count($authsenabled); $url = "auth.php?sesskey=" . sesskey(); foreach ($displayauths as $auth => $name) { if ($auth == 'manual' or $auth == 'nologin') { continue; } // hide/show link if (in_array($auth, $authsenabled)) { $hideshow = ""; $hideshow .= "pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" />"; // $hideshow = ""; $enabled = true; $displayname = "$name"; } else { $hideshow = ""; $hideshow .= "pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" />"; // $hideshow = ""; $enabled = false; $displayname = "$name"; } // up/down link (only if auth is enabled) $updown = ''; if ($enabled) { if ($updowncount > 1) { $updown .= ""; $updown .= "pixpath}/t/up.gif\" alt=\"up\" /> "; } else { $updown .= "pixpath}/spacer.gif\" class=\"icon\" alt=\"\" /> "; } if ($updowncount < $authcount) { $updown .= ""; $updown .= "pixpath}/t/down.gif\" alt=\"down\" />"; } else { $updown .= "pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />"; } ++ $updowncount; } // settings link if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) { $settings = "{$txt->settings}"; } else { $settings = "{$txt->settings}"; } // add a row to the table $table->data[] =array($displayname, $hideshow, $updown, $settings); } $return .= print_table($table, true); $return .= get_string('configauthenticationplugins', 'admin').'
'.get_string('tablenosave', 'filters'); $return .= print_box_end(true); return highlight($query, $return); } } /** * Special class for filter administration. */ class admin_setting_managefilters extends admin_setting { public function __construct() { parent::__construct('filtersui', get_string('filtersettings', 'admin'), '', ''); } public function get_setting() { return true; } public function get_defaultsetting() { return true; } public function write_setting($data) { // do not write any setting return ''; } public function is_related($query) { if (parent::is_related($query)) { return true; } $textlib = textlib_get_instance(); $filterlocations = array('mod','filter'); foreach ($filterlocations as $filterlocation) { $plugins = get_list_of_plugins($filterlocation); foreach ($plugins as $plugin) { if (strpos($plugin, $query) !== false) { return true; } $name = get_string('filtername', $plugin); if (strpos($textlib->strtolower($name), $query) !== false) { return true; } } } return false; } public function output_html($data, $query='') { global $CFG; $strname = get_string('name'); $strhide = get_string('disable'); $strshow = get_string('enable'); $strhideshow = "$strhide/$strshow"; $strsettings = get_string('settings'); $strup = get_string('up'); $strdown = get_string('down'); $strupdown = "$strup/$strdown"; // get a list of possible filters (and translate name if possible) // note filters can be in the dedicated filters area OR in their // associated modules $installedfilters = array(); $filtersettings_new = array(); $filterlocations = array('mod','filter'); foreach ($filterlocations as $filterlocation) { $plugins = get_list_of_plugins($filterlocation); foreach ($plugins as $plugin) { $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php"; $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php"; if (is_readable($pluginpath)) { $name = trim(get_string("filtername", $plugin)); if (empty($name) or ($name == '[[filtername]]')) { $textlib = textlib_get_instance(); $name = $textlib->strtotitle($plugin); } $installedfilters["$filterlocation/$plugin"] = $name; if (is_readable($settingspath_new)) { $filtersettings_new[] = "$filterlocation/$plugin"; } } } } // get all the currently selected filters if (!empty($CFG->textfilters)) { $oldactivefilters = explode(',', $CFG->textfilters); $oldactivefilters = array_unique($oldactivefilters); } else { $oldactivefilters = array(); } // take this opportunity to clean up filters $activefilters = array(); foreach ($oldactivefilters as $oldactivefilter) { if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) { $activefilters[] = $oldactivefilter; } } // construct the display array with installed filters // at the top in the right order $displayfilters = array(); foreach ($activefilters as $activefilter) { $name = $installedfilters[$activefilter]; $displayfilters[$activefilter] = $name; } foreach ($installedfilters as $key => $filter) { if (!array_key_exists($key, $displayfilters)) { $displayfilters[$key] = $filter; } } $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true); $return .= print_box_start('generalbox filtersui', '', true); $table = new object(); $table->head = array($strname, $strhideshow, $strupdown, $strsettings); $table->align = array('left', 'center', 'center', 'center'); $table->width = '90%'; $table->data = array(); $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey(); $imgurl = "$CFG->pixpath/t"; // iterate through filters adding to display table $updowncount = 1; $activefilterscount = count($activefilters); foreach ($displayfilters as $path => $name) { $upath = urlencode($path); // get hide/show link if (in_array($path, $activefilters)) { $hideshow = ""; $hideshow .= "pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" />"; $hidden = false; $displayname = "$name"; } else { $hideshow = ""; $hideshow .= "pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" />"; $hidden = true; $displayname = "$name"; } // get up/down link (only if not hidden) $updown = ''; if (!$hidden) { if ($updowncount>1) { $updown .= ""; $updown .= "\"$strup\" "; } else { $updown .= "pixpath/spacer.gif\" class=\"icon\" alt=\"\" /> "; } if ($updowncount<$activefilterscount) { $updown .= ""; $updown .= "\"$strdown\""; } else { $updown .= "pixpath/spacer.gif\" class=\"icon\" alt=\"\" />"; } ++$updowncount; } // settings link (if defined) $settings = ''; if (in_array($path, $filtersettings_new)) { $settings = "$strsettings"; } // write data into the table object $table->data[] = array($displayname, $hideshow, $updown, $settings); } $return .= print_table($table, true); $return .= get_string('tablenosave', 'filters'); $return .= print_box_end(true); return highlight($query, $return); } } class admin_setting_manageportfolio extends admin_setting { private $baseurl; public function __construct() { global $CFG; parent::__construct('manageportfolio', get_string('manageportfolio', 'portfolio'), '', ''); $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/portfolio.php?sesskey=' . sesskey(); } public function get_setting() { return true; } public function get_defaultsetting() { return true; } public function write_setting($data) { return ''; } public function is_related($query) { if (parent::is_related($query)) { return true; } $textlib = textlib_get_instance(); $portfolios= get_list_of_plugins('portfolio/type'); foreach ($portfolios as $p) { if (strpos($p, $query) !== false) { return true; } } foreach (portfolio_instances(false, false) as $instance) { $title = $instance->get('name'); if (strpos($textlib->strtolower($title), $query) !== false) { return true; } } return false; } public function output_html($data, $query='') { global $CFG; $output = print_simple_box_start(true); $namestr = get_string('name'); $pluginstr = get_string('plugin', 'portfolio'); $plugins = get_list_of_plugins('portfolio/type'); $instances = portfolio_instances(false, false); $alreadyplugins = array(); // to avoid notifications being sent out while admin is editing the page define('ADMIN_EDITING_PORTFOLIO', true); $insane = portfolio_plugin_sanity_check($plugins); $insaneinstances = portfolio_instance_sanity_check($instances); $output .= portfolio_report_insane($insane, null, true); $output .= portfolio_report_insane($insaneinstances, $instances, true); $table = new StdClass; $table->head = array($namestr, $pluginstr, ''); $table->data = array(); foreach ($instances as $i) { $row = ''; $row .= '' . get_string('edit') . '' . "\n"; $row .= '' . get_string('delete') . '' . "\n"; if (array_key_exists($i->get('plugin'), $insane) || array_key_exists($i->get('id'), $insaneinstances)) { $row .= '' . get_string('hidden', 'portfolio') . '' . "\n"; } else { $row .= ' ' . get_string($i->get('visible') ? 'hide' : 'show') . '' . "\n"; } $table->data[] = array($i->get('name'), $i->get_name() . ' (' . $i->get('plugin') . ')', $row); if (!in_array($i->get('plugin'), $alreadyplugins)) { $alreadyplugins[] = $i->get('plugin'); } } $output .= print_table($table, true); $instancehtml = '

' . get_string('addnewportfolio', 'portfolio') . ':

'; $addable = 0; foreach ($plugins as $p) { if (!portfolio_static_function($p, 'allows_multiple') && in_array($p, $alreadyplugins)) { continue; } if (array_key_exists($p, $insane)) { continue; } $instancehtml .= '' . portfolio_static_function($p, 'get_name') . ' (' . s($p) . ')' . '
' . "\n"; $addable++; } if ($addable) { $output .= $instancehtml; } $output .= print_simple_box_end(true); return highlight($query, $output); } } /** * Initialise admin page - this function does require login and permission * checks specified in page definition. * This function must be called on each admin page before other code. * @param string $section name of page * @param string $extrabutton extra HTML that is added after the blocks editing on/off button. * @param string $extraurlparams an array paramname => paramvalue, or parameters that need to be * added to the turn blocks editing on/off form, so this page reloads correctly. * @param string $actualurl if the actual page being viewed is not the normal one for this * page (e.g. admin/roles/allowassin.php, instead of admin/roles/manage.php, you can pass the alternate URL here. */ function admin_externalpage_setup($section, $extrabutton='', $extraurlparams=array(), $actualurl='') { global $CFG, $PAGE, $USER; require_once($CFG->libdir.'/blocklib.php'); require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php'); if ($site = get_site()) { require_login(); } else { redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php'); die; } $adminroot = admin_get_root(false, false); // settings not required for external pages $extpage = $adminroot->locate($section); if (empty($extpage) or !($extpage instanceof admin_externalpage)) { print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/"); die; } // this eliminates our need to authenticate on the actual pages if (!($extpage->check_access())) { print_error('accessdenied', 'admin'); die; } page_map_class(PAGE_ADMIN, 'page_admin'); $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number $PAGE->init_extra($section); // hack alert! $PAGE->set_extra_button($extrabutton); $PAGE->set_extra_url_params($extraurlparams, $actualurl); $adminediting = optional_param('adminedit', -1, PARAM_BOOL); if (!isset($USER->adminediting)) { $USER->adminediting = false; } if ($PAGE->user_allowed_editing()) { if ($adminediting == 1) { $USER->adminediting = true; } elseif ($adminediting == 0) { $USER->adminediting = false; } } } /** * Print header for admin page * @param string $focus focus element */ function admin_externalpage_print_header($focus='') { if (!is_string($focus)) { $focus = ''; // BC compatibility, there used to be adminroot parameter } global $CFG, $PAGE, $SITE, $THEME; define('ADMIN_EXT_HEADER_PRINTED', 'true'); if (!empty($SITE->fullname) and !empty($SITE->shortname)) { $pageblocks = blocks_setup($PAGE); $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]), BLOCK_L_MAX_WIDTH); $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), BLOCK_R_MAX_WIDTH); $PAGE->print_header('', $focus); echo ''; $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable; foreach ($lt as $column) { $lt1[] = $column; if ($column == 'middle') break; } foreach ($lt1 as $column) { switch ($column) { case 'left': echo ''; break; case 'middle': echo ''; } break; } } } else { $strinstallation = get_string('installation', 'install'); $strsettings = get_string('settings'); $navigation = build_navigation(array(array('name'=>$strsettings, 'link'=>null, 'type'=>'misc'))); print_header($strinstallation, $strinstallation, $navigation, "", "", false, " ", " "); } } /** * Print footer on admin page - please use normal print_footer() instead */ function admin_externalpage_print_footer() { global $CFG, $PAGE, $SITE, $THEME; define('ADMIN_EXT_FOOTER_PRINTED', 'true'); if (!empty($SITE->fullname)) { $pageblocks = blocks_setup($PAGE); $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]), BLOCK_L_MAX_WIDTH); $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), BLOCK_R_MAX_WIDTH); $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable; foreach ($lt as $column) { if ($column != 'middle') { array_shift($lt); } else if ($column == 'middle') { break; } } foreach ($lt as $column) { switch ($column) { case 'left': echo ''; break; case 'middle': print_container_end(); $THEME->open_header_containers--; // this is hacky workaround for the print_error()/notice() autoclosing problems on admin pages echo ''; break; case 'right': if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) { echo ''; } break; } } echo '
'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); print_container_end(); echo ''; print_container_start(true); $THEME->open_header_containers++; // this is hacky workaround for the print_error()/notice() autoclosing problems on admin pages break; case 'right': if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) { echo ''; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); print_container_end(); echo ''; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); print_container_end(); echo ''; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); print_container_end(); echo '
'; } print_footer(); } /** * Returns the reference to admin tree root * @return reference */ function admin_get_root($reload=false, $requirefulltree=true) { global $CFG, $DB; static $ADMIN = NULL; if (is_null($ADMIN)) { // create the admin tree! $ADMIN = new admin_root($requirefulltree); } if ($reload or ($requirefulltree and !$ADMIN->fulltree)) { $ADMIN->purge_children($requirefulltree); } if (!$ADMIN->loaded) { // we process this file first to create categories first and in correct order require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php'); // now we process all other files in admin/settings to build the admin tree foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) { if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') { continue; } if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') { // plugins are loaded last - they may insert pages anywhere continue; } require($file); } require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php'); if (file_exists($CFG->dirroot.'/local/settings.php')) { require($CFG->dirroot.'/local/settings.php'); } $ADMIN->loaded = true; } return $ADMIN; } /// settings utility functions /** * This function applies default settings. * @param object $node, NULL means complete tree * @param bool $uncoditional if true overrides all values with defaults * @return void */ function admin_apply_default_settings($node=NULL, $unconditional=true) { global $CFG; if (is_null($node)) { $node = admin_get_root(true, true); } if ($node instanceof admin_category) { $entries = array_keys($node->children); foreach ($entries as $entry) { admin_apply_default_settings($node->children[$entry], $unconditional); } } else if ($node instanceof admin_settingpage) { foreach ($node->settings as $setting) { if (!$unconditional and !is_null($setting->get_setting())) { //do not override existing defaults continue; } $defaultsetting = $setting->get_defaultsetting(); if (is_null($defaultsetting)) { // no value yet - default maybe applied after admin user creation or in upgradesettings continue; } $setting->write_setting($defaultsetting); } } } /** * Store changed settings, this function updates the errors variable in $ADMIN * @param object $formdata from form * @return int number of changed settings */ function admin_write_settings($formdata) { global $CFG, $SITE, $COURSE, $DB; $olddbsessions = !empty($CFG->dbsessions); $formdata = (array)$formdata; $data = array(); foreach ($formdata as $fullname=>$value) { if (strpos($fullname, 's_') !== 0) { continue; // not a config value } $data[$fullname] = $value; } $adminroot = admin_get_root(); $settings = admin_find_write_settings($adminroot, $data); $count = 0; foreach ($settings as $fullname=>$setting) { $original = serialize($setting->get_setting()); // comparison must work for arrays too $error = $setting->write_setting($data[$fullname]); if ($error !== '') { $adminroot->errors[$fullname] = new object(); $adminroot->errors[$fullname]->data = $data[$fullname]; $adminroot->errors[$fullname]->id = $setting->get_id(); $adminroot->errors[$fullname]->error = $error; } if ($original !== serialize($setting->get_setting())) { $count++; $callbackfunction = $setting->updatedcallback; if (function_exists($callbackfunction)) { $callbackfunction($fullname); } } } if ($olddbsessions != !empty($CFG->dbsessions)) { require_logout(); } // now update $SITE - it might have been changed $SITE = $DB->get_record('course', array('id'=>$SITE->id)); course_setup($SITE); // now reload all settings - some of them might depend on the changed admin_get_root(true); return $count; } /** * Internal recursive function - finds all settings from submitted form */ function admin_find_write_settings($node, $data) { $return = array(); if (empty($data)) { return $return; } if ($node instanceof admin_category) { $entries = array_keys($node->children); foreach ($entries as $entry) { $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data)); } } else if ($node instanceof admin_settingpage) { foreach ($node->settings as $setting) { $fullname = $setting->get_full_name(); if (array_key_exists($fullname, $data)) { $return[$fullname] = $setting; } } } return $return; } /** * Internal function - prints the search results */ function admin_search_settings_html($query) { global $CFG; $textlib = textlib_get_instance(); if ($textlib->strlen($query) < 2) { return ''; } $query = $textlib->strtolower($query); $adminroot = admin_get_root(); $findings = $adminroot->search($query); $return = ''; $savebutton = false; foreach ($findings as $found) { $page = $found->page; $settings = $found->settings; if ($page->is_hidden()) { // hidden pages are not displayed in search results continue; } if ($page instanceof admin_externalpage) { $return .= print_heading(get_string('searchresults','admin').' - '.highlight($query, $page->visiblename).'', '', 2, 'main', true); } else if ($page instanceof admin_settingpage) { $return .= print_heading(get_string('searchresults','admin').' - '.highlight($query, $page->visiblename).'', '', 2, 'main', true); } else { continue; } if (!empty($settings)) { $savebutton = true; $return .= '
'."\n"; foreach ($settings as $setting) { $return .= '
'."\n"; $fullname = $setting->get_full_name(); if (array_key_exists($fullname, $adminroot->errors)) { $data = $adminroot->errors[$fullname]->data; } else { $data = $setting->get_setting(); // do not use defaults if settings not available - upgrdesettings handles the defaults! } $return .= $setting->output_html($data, $query); } $return .= '
'; } } if ($savebutton) { $return .= '
'; } return $return; } /** * Internal function - returns arrays of html pages with uninitialised settings */ function admin_output_new_settings_by_page($node) { $return = array(); if ($node instanceof admin_category) { $entries = array_keys($node->children); foreach ($entries as $entry) { $return += admin_output_new_settings_by_page($node->children[$entry]); } } else if ($node instanceof admin_settingpage) { $newsettings = array(); foreach ($node->settings as $setting) { if (is_null($setting->get_setting())) { $newsettings[] = $setting; } } if (count($newsettings) > 0) { $adminroot = admin_get_root(); $page = print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true); $page .= '
'."\n"; foreach ($newsettings as $setting) { $fullname = $setting->get_full_name(); if (array_key_exists($fullname, $adminroot->errors)) { $data = $adminroot->errors[$fullname]->data; } else { $data = $setting->get_setting(); if (is_null($data)) { $data = $setting->get_defaultsetting(); } } $page .= '
'."\n"; $page .= $setting->output_html($data); } $page .= '
'; $return[$node->name] = $page; } } return $return; } /** * Format admin settings * @param string $object setting * @param string $title label element * @param string $form form fragment, html code - not highlighed automaticaly * @param string $description * @param bool $label link label to id * @param string $warning warning text * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string * @param string $query search query to be highlighted */ function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') { global $CFG; $name = $setting->name; $fullname = $setting->get_full_name(); // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate if ($label) { $labelfor = 'for = "'.$setting->get_id().'"'; } else { $labelfor = ''; } if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) { $override = '
'.get_string('configoverride', 'admin').'
'; } else { $override = ''; } if ($warning !== '') { $warning = '
'.$warning.'
'; } if (is_null($defaultinfo)) { $defaultinfo = ''; } else { if ($defaultinfo === '') { $defaultinfo = get_string('emptysettingvalue', 'admin'); } $defaultinfo = highlight($query, nl2br(s($defaultinfo))); $defaultinfo = '
'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'
'; } $str = '
'.$form.$defaultinfo.'
'.highlight($query, $description).'
'; $adminroot = admin_get_root(); if (array_key_exists($fullname, $adminroot->errors)) { $str = '
'.$adminroot->errors[$fullname]->error.''.$str.'
'; } return $str; } /** * Based on find_new_settings{@link ()} in upgradesettings.php * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any. * * @param string $node The node at which to start searching. * @return boolen true if any settings haven't been initialised, false if they all have */ function any_new_admin_settings($node) { if ($node instanceof admin_category) { $entries = array_keys($node->children); foreach ($entries as $entry) { if (any_new_admin_settings($node->children[$entry])){ return true; } } } else if ($node instanceof admin_settingpage) { foreach ($node->settings as $setting) { if ($setting->get_setting() === NULL) { return true; } } } return false; } /** * Moved from admin/replace.php so that we can use this in cron * @param string $search - string to look for * @param string $replace - string to replace * @return bool - success or fail */ function db_replace($search, $replace) { global $DB, $CFG; /// Turn off time limits, sometimes upgrades can be slow. @set_time_limit(0); @ob_implicit_flush(true); while(@ob_end_flush()); if (!$tables = $DB->get_tables() ) { // No tables yet at all. return false; } foreach ($tables as $table) { if (in_array($table, array('config'))) { // Don't process these continue; } if ($columns = $DB->get_columns($table)) { $DB->set_debug(true); foreach ($columns as $column => $data) { if (in_array($data->meta_type, array('C', 'X'))) { // Text stuff only $DB->execute("UPDATE {".$table."} SET $column = REPLACE($column, ?, ?)", array($search, $replace)); } } $DB->set_debug(false); } } return true; } /** * Prints tables of detected plugins, one table per plugin type, * and prints whether they are part of the standard Moodle * distribution or not. */ function print_plugin_tables() { global $DB; $plugins_standard = array(); $plugins_standard['mod'] = array('assignment', 'chat', 'choice', 'data', 'feedback', 'forum', 'glossary', 'hotpot', 'label', 'lesson', 'quiz', 'resource', 'scorm', 'survey', 'wiki'); $plugins_standard['blocks'] = array('activity_modules', 'admin', 'admin_bookmarks', 'admin_tree', 'blog_menu', 'blog_tags', 'calendar_month', 'calendar_upcoming', 'course_list', 'course_summary', 'glossary_random', 'html', 'loancalc', 'login', 'mentees', 'messages', 'mnet_hosts', 'news_items', 'online_users', 'participants', 'quiz_results', 'recent_activity', 'rss_client', 'search', 'search_forums', 'section_links', 'site_main_menu', 'social_activities', 'tag_flickr', 'tag_youtube', 'tags'); $plugins_standard['filter'] = array('activitynames', 'algebra', 'censor', 'emailprotect', 'filter', 'mediaplugin', 'multilang', 'tex', 'tidy'); $plugins_installed = array(); $installed_mods = $DB->get_records('modules', null, 'name'); $installed_blocks = $DB->get_records('block', null, 'name'); foreach($installed_mods as $mod) { $plugins_installed['mod'][] = $mod->name; } foreach($installed_blocks as $block) { $plugins_installed['blocks'][] = $block->name; } $plugins_installed['filter'] = array(); $plugins_ondisk = array(); $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db'); $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db'); $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db'); $strstandard = get_string('standard'); $strnonstandard = get_string('nonstandard'); $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')'; $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')'; $html = ''; $html .= ''; foreach ($plugins_ondisk as $cat => $list_ondisk) { $strcaption = get_string($cat); if ($cat == 'mod') { $strcaption = get_string('activitymodule'); } elseif ($cat == 'filter') { $strcaption = get_string('managefilters'); } $html .= ''; } $html .= '
' . "\n"; $html .= '\n" . '\n" . '\n\n"; $row = 1; foreach ($list_ondisk as $k => $plugin) { $status = 'ok'; $standard = 'standard'; $note = ''; if (!in_array($plugin, $plugins_standard[$cat])) { $standard = 'nonstandard'; $status = 'warning'; } // Get real name and full path of plugin $plugin_name = "[[$plugin]]"; $plugin_path = "$cat/$plugin"; $plugin_name = get_plugin_name($plugin, $cat); // Determine if the plugin is about to be installed if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) { $note = $strabouttobeinstalled; $plugin_name = $plugin; } $html .= "\n" . "\n" . "\n" . "\n\n"; $row++; // If the plugin was both on disk and in the db, unset the value from the installed plugins list if ($key = array_search($plugin, $plugins_installed[$cat])) { unset($plugins_installed[$cat][$key]); } } // If there are plugins left in the plugins_installed list, it means they are missing from disk foreach ($plugins_installed[$cat] as $k => $missing_plugin) { // Make sure the plugin really is missing from disk if (!in_array($missing_plugin, $plugins_ondisk[$cat])) { $standard = 'standard'; $status = 'warning'; if (!in_array($missing_plugin, $plugins_standard[$cat])) { $standard = 'nonstandard'; } $plugin_name = $missing_plugin; $html .= "\n" . "\n" . "\n" . "\n\n"; $row++; } } $html .= '
' . $strcaption . '
' . get_string('directory') . "' . get_string('name') . "' . get_string('status') . "
$plugin_path$plugin_name" . ${'str' . $standard} . " $note
?$plugin_name" . ${'str' . $standard} . " $strmissingfromdisk

'; echo $html; } class admin_setting_managerepository extends admin_setting { private $baseurl; public function __construct() { global $CFG; parent::__construct('managerepository', get_string('managerepository', 'repository'), '', ''); $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey(); } public function get_setting() { return true; } public function get_defaultsetting() { return true; } public function get_full_name() { return 's_managerepository'; } public function write_setting($data) { $url = $this->baseurl . '&new=' . $data; return ''; // TODO // Should not use redirect and exit here // Find a better way to do this. // redirect($url); // exit; } public function is_related($query) { if (parent::is_related($query)) { return true; } $textlib = textlib_get_instance(); $repositories= get_list_of_plugins('repository'); foreach ($repositories as $p) { if (strpos($p, $query) !== false) { return true; } } foreach (repository::get_types() as $instance) { $title = $instance->get_typename(); if (strpos($textlib->strtolower($title), $query) !== false) { return true; } } return false; } public function output_html($data, $query='') { global $CFG, $USER; $output = print_box_start('generalbox','',true); $namestr = get_string('name'); $settingsstr = get_string('settings'); $updownstr = get_string('updown', 'repository'); $hiddenstr = get_string('hiddenshow', 'repository'); $deletestr = get_string('delete'); $plugins = get_list_of_plugins('repository'); $instances = repository::get_types(); $instancesnumber = count($instances); $alreadyplugins = array(); $table = new StdClass; $table->head = array($namestr, $updownstr, $hiddenstr, $deletestr, $settingsstr); $table->align = array('left', 'center', 'center','center','center'); $table->data = array(); $updowncount=1; foreach ($instances as $i) { $settings = ''; //display edit link only if you can config the type or if it has multiple instances (e.g. has instance config) $typeoptionnames = repository::static_function($i->get_typename(), 'get_type_option_names'); $instanceoptionnames = repository::static_function($i->get_typename(), 'get_instance_option_names'); if ( !empty($typeoptionnames) || !empty($instanceoptionnames)) { $settings .= '' . $settingsstr .'' . "\n"; } $delete = '' . $deletestr . '' . "\n"; $hidetitle = $i->get_visible() ? get_string('clicktohide', 'repository') : get_string('clicktoshow', 'repository'); $hiddenshow = ' ' .'' . $hidetitle . '' .'' . "\n"; // display up/down link $updown = ''; if ($updowncount > 1) { $updown .= "baseurl&move=up&type=".$i->get_typename()."\">"; $updown .= "pixpath}/t/up.gif\" alt=\"up\" /> "; } else { $updown .= "pixpath}/spacer.gif\" class=\"icon\" alt=\"\" /> "; } if ($updowncount < count($instances)) { $updown .= "baseurl&move=down&type=".$i->get_typename()."\">"; $updown .= "pixpath}/t/down.gif\" alt=\"down\" />"; } else { $updown .= "pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />"; } $updowncount++; $table->data[] = array($i->get_readablename(), $updown, $hiddenshow, $delete, $settings); //display a grey row if the type is defined as not visible if (!$i->get_visible()){ $table->rowclass[] = 'dimmed_text'; } else{ $table->rowclass[] = ''; } if (!in_array($i->get_typename(), $alreadyplugins)) { $alreadyplugins[] = $i->get_typename(); } } $output .= print_table($table, true); $instancehtml = '

'; $instancehtml .= get_string('addplugin', 'repository'); $instancehtml .= '

'; $instancehtml .= '
'; if ($addable) { $output .= $instancehtml; } $output .= print_box_end(true); return highlight($query, $output); } }