/** * This file keeps track of upgrades to * the forum module * * Sometimes, changes between versions involve * alterations to database structures and other * major things that may break installations. * * The upgrade function in this file will attempt * to perform all the necessary actions to upgrade * your older installation to the current version. * * If there's something it cannot do itself, it * will tell you what you need to do. * * The commands in here will all be database-neutral, * using the methods of database_manager class * * Please do not forget to use upgrade_set_timeout() * before any action that may take longer time to finish. * * @package mod-forum * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ function xmldb_forum_upgrade($oldversion) { global $CFG, $DB, $OUTPUT; $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. // Moodle v2.2.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.3.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.4.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013020500) { // Define field displaywordcount to be added to forum. $table = new xmldb_table('forum'); $field = new xmldb_field('displaywordcount', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'completionposts'); // Conditionally launch add field displaywordcount. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013020500, 'forum'); } // Forcefully assign mod/forum:allowforcesubscribe to frontpage role, as we missed that when // capability was introduced. if ($oldversion < 2013021200) { // If capability mod/forum:allowforcesubscribe is defined then set it for frontpage role. if (get_capability_info('mod/forum:allowforcesubscribe')) { assign_legacy_capabilities('mod/forum:allowforcesubscribe', array('frontpage' => CAP_ALLOW)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013021200, 'forum'); } // Moodle v2.5.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013071000) { // Define table forum_digests to be created. $table = new xmldb_table('forum_digests'); // Adding fields to table forum_digests. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('forum', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('maildigest', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '-1'); // Adding keys to table forum_digests. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); $table->add_key('forum', XMLDB_KEY_FOREIGN, array('forum'), 'forum', array('id')); $table->add_key('forumdigest', XMLDB_KEY_UNIQUE, array('forum', 'userid', 'maildigest')); // Conditionally launch create table for forum_digests. if (!$dbman->table_exists($table)) { $dbman->create_table($table); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013071000, 'forum'); } // Moodle v2.6.0 release upgrade line. // Put any upgrade step following this. return true; }
/** * Checks if the plugin is instantiable by the current user in the specified context. * Checks capability addinstance. If the plugin doesn't have the capability, it cannot be instantiated. * * @param context $context Either course or dataform (module) context. * @return boolean */ public function is_instantiable($context) { $capability = 'dataformview/' . $this->name . ':addinstance'; if (!get_capability_info($capability)) { // If the capability does not exist, the plugin cannot be instantiated. return false; } return has_capability($capability, $context); }
/** * Check modifying capability record is not exposed to other code. */ public function test_capabilities_mutation() { $oldcap = get_capability_info('moodle/site:config'); $cap = get_capability_info('moodle/site:config'); unset($cap->name); $newcap = get_capability_info('moodle/site:config'); $this->assertFalse(isset($cap->name)); $this->assertTrue(isset($newcap->name)); $this->assertTrue(isset($oldcap->name)); }
function xmldb_block_demostudent_upgrade($oldversion = 0) { global $CFG; $result = true; // Assign moodle/course:viewhiddencourses capability to demostudent role. if ($oldversion < 2013100201) { if (get_capability_info('moodle/course:viewhiddencourses')) { $demostudentroleid = get_roleid_by_roleshortname('demostudent'); assign_capability('moodle/course:viewhiddencourses', CAP_ALLOW, $demostudentroleid, 1); } upgrade_plugin_savepoint(true, 2013100201, 'block', 'demostudent'); } return $result; }
/** * This file keeps track of upgrades to * the forum module * * Sometimes, changes between versions involve * alterations to database structures and other * major things that may break installations. * * The upgrade function in this file will attempt * to perform all the necessary actions to upgrade * your older installation to the current version. * * If there's something it cannot do itself, it * will tell you what you need to do. * * The commands in here will all be database-neutral, * using the methods of database_manager class * * Please do not forget to use upgrade_set_timeout() * before any action that may take longer time to finish. * * @package mod-forum * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ function xmldb_forum_upgrade($oldversion) { global $CFG, $DB, $OUTPUT; $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. // Moodle v2.2.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.3.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.4.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.5.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013020500) { // Define field displaywordcount to be added to forum. $table = new xmldb_table('forum'); $field = new xmldb_field('displaywordcount', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'completionposts'); // Conditionally launch add field displaywordcount. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013020500, 'forum'); } // Forcefully assign mod/forum:allowforcesubscribe to frontpage role, as we missed that when // capability was introduced. if ($oldversion < 2013021200) { // If capability mod/forum:allowforcesubscribe is defined then set it for frontpage role. if (get_capability_info('mod/forum:allowforcesubscribe')) { assign_legacy_capabilities('mod/forum:allowforcesubscribe', array('frontpage' => CAP_ALLOW)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013021200, 'forum'); } return true; }
/** * This file keeps track of upgrades to * the forum module * * Sometimes, changes between versions involve * alterations to database structures and other * major things that may break installations. * * The upgrade function in this file will attempt * to perform all the necessary actions to upgrade * your older installation to the current version. * * If there's something it cannot do itself, it * will tell you what you need to do. * * The commands in here will all be database-neutral, * using the methods of database_manager class * * Please do not forget to use upgrade_set_timeout() * before any action that may take longer time to finish. * * @package mod-forum * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ function xmldb_forum_upgrade($oldversion) { global $CFG, $DB, $OUTPUT; $dbman = $DB->get_manager(); // loads ddl manager and xmldb classes // Moodle v2.2.0 release upgrade line // Put any upgrade step following this // Moodle v2.3.0 release upgrade line // Put any upgrade step following this // Forcefully assign mod/forum:allowforcesubscribe to frontpage role, as we missed that when // capability was introduced. if ($oldversion < 2012061702) { // If capability mod/forum:allowforcesubscribe is defined then set it for frontpage role. if (get_capability_info('mod/forum:allowforcesubscribe')) { assign_legacy_capabilities('mod/forum:allowforcesubscribe', array('frontpage' => CAP_ALLOW)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2012061702, 'forum'); } return true; }
/** * Used by {@link optional_param()} and {@link required_param()} to * clean the variables and/or cast to specific types, based on * an options field. * <code> * $course->format = clean_param($course->format, PARAM_ALPHA); * $selectedgradeitem = clean_param($selectedgradeitem, PARAM_INT); * </code> * * @param mixed $param the variable we are cleaning * @param string $type expected format of param after cleaning. * @return mixed * @throws coding_exception */ function clean_param($param, $type) { global $CFG; if (is_array($param)) { throw new coding_exception('clean_param() can not process arrays, please use clean_param_array() instead.'); } else { if (is_object($param)) { if (method_exists($param, '__toString')) { $param = $param->__toString(); } else { throw new coding_exception('clean_param() can not process objects, please use clean_param_array() instead.'); } } } switch ($type) { case PARAM_RAW: // No cleaning at all. $param = fix_utf8($param); return $param; case PARAM_RAW_TRIMMED: // No cleaning, but strip leading and trailing whitespace. $param = fix_utf8($param); return trim($param); case PARAM_CLEAN: // General HTML cleaning, try to use more specific type if possible this is deprecated! // Please use more specific type instead. if (is_numeric($param)) { return $param; } $param = fix_utf8($param); // Sweep for scripts, etc. return clean_text($param); case PARAM_CLEANHTML: // Clean html fragment. $param = fix_utf8($param); // Sweep for scripts, etc. $param = clean_text($param, FORMAT_HTML); return trim($param); case PARAM_INT: // Convert to integer. return (int) $param; case PARAM_FLOAT: // Convert to float. return (double) $param; case PARAM_ALPHA: // Remove everything not `a-z`. return preg_replace('/[^a-zA-Z]/i', '', $param); case PARAM_ALPHAEXT: // Remove everything not `a-zA-Z_-` (originally allowed "/" too). return preg_replace('/[^a-zA-Z_-]/i', '', $param); case PARAM_ALPHANUM: // Remove everything not `a-zA-Z0-9`. return preg_replace('/[^A-Za-z0-9]/i', '', $param); case PARAM_ALPHANUMEXT: // Remove everything not `a-zA-Z0-9_-`. return preg_replace('/[^A-Za-z0-9_-]/i', '', $param); case PARAM_SEQUENCE: // Remove everything not `0-9,`. return preg_replace('/[^0-9,]/i', '', $param); case PARAM_BOOL: // Convert to 1 or 0. $tempstr = strtolower($param); if ($tempstr === 'on' or $tempstr === 'yes' or $tempstr === 'true') { $param = 1; } else { if ($tempstr === 'off' or $tempstr === 'no' or $tempstr === 'false') { $param = 0; } else { $param = empty($param) ? 0 : 1; } } return $param; case PARAM_NOTAGS: // Strip all tags. $param = fix_utf8($param); return strip_tags($param); case PARAM_TEXT: // Leave only tags needed for multilang. $param = fix_utf8($param); // If the multilang syntax is not correct we strip all tags because it would break xhtml strict which is required // for accessibility standards please note this cleaning does not strip unbalanced '>' for BC compatibility reasons. do { if (strpos($param, '</lang>') !== false) { // Old and future mutilang syntax. $param = strip_tags($param, '<lang>'); if (!preg_match_all('/<.*>/suU', $param, $matches)) { break; } $open = false; foreach ($matches[0] as $match) { if ($match === '</lang>') { if ($open) { $open = false; continue; } else { break 2; } } if (!preg_match('/^<lang lang="[a-zA-Z0-9_-]+"\\s*>$/u', $match)) { break 2; } else { $open = true; } } if ($open) { break; } return $param; } else { if (strpos($param, '</span>') !== false) { // Current problematic multilang syntax. $param = strip_tags($param, '<span>'); if (!preg_match_all('/<.*>/suU', $param, $matches)) { break; } $open = false; foreach ($matches[0] as $match) { if ($match === '</span>') { if ($open) { $open = false; continue; } else { break 2; } } if (!preg_match('/^<span(\\s+lang="[a-zA-Z0-9_-]+"|\\s+class="multilang"){2}\\s*>$/u', $match)) { break 2; } else { $open = true; } } if ($open) { break; } return $param; } } } while (false); // Easy, just strip all tags, if we ever want to fix orphaned '&' we have to do that in format_string(). return strip_tags($param); case PARAM_COMPONENT: // We do not want any guessing here, either the name is correct or not // please note only normalised component names are accepted. if (!preg_match('/^[a-z]+(_[a-z][a-z0-9_]*)?[a-z0-9]+$/', $param)) { return ''; } if (strpos($param, '__') !== false) { return ''; } if (strpos($param, 'mod_') === 0) { // Module names must not contain underscores because we need to differentiate them from invalid plugin types. if (substr_count($param, '_') != 1) { return ''; } } return $param; case PARAM_PLUGIN: case PARAM_AREA: // We do not want any guessing here, either the name is correct or not. if (!is_valid_plugin_name($param)) { return ''; } return $param; case PARAM_SAFEDIR: // Remove everything not a-zA-Z0-9_- . return preg_replace('/[^a-zA-Z0-9_-]/i', '', $param); case PARAM_SAFEPATH: // Remove everything not a-zA-Z0-9/_- . return preg_replace('/[^a-zA-Z0-9\\/_-]/i', '', $param); case PARAM_FILE: // Strip all suspicious characters from filename. $param = fix_utf8($param); $param = preg_replace('~[[:cntrl:]]|[&<>"`\\|\':\\\\/]~u', '', $param); if ($param === '.' || $param === '..') { $param = ''; } return $param; case PARAM_PATH: // Strip all suspicious characters from file path. $param = fix_utf8($param); $param = str_replace('\\', '/', $param); // Explode the path and clean each element using the PARAM_FILE rules. $breadcrumb = explode('/', $param); foreach ($breadcrumb as $key => $crumb) { if ($crumb === '.' && $key === 0) { // Special condition to allow for relative current path such as ./currentdirfile.txt. } else { $crumb = clean_param($crumb, PARAM_FILE); } $breadcrumb[$key] = $crumb; } $param = implode('/', $breadcrumb); // Remove multiple current path (./././) and multiple slashes (///). $param = preg_replace('~//+~', '/', $param); $param = preg_replace('~/(\\./)+~', '/', $param); return $param; case PARAM_HOST: // Allow FQDN or IPv4 dotted quad. $param = preg_replace('/[^\\.\\d\\w-]/', '', $param); // Match ipv4 dotted quad. if (preg_match('/(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/', $param, $match)) { // Confirm values are ok. if ($match[0] > 255 || $match[1] > 255 || $match[3] > 255 || $match[4] > 255) { // Hmmm, what kind of dotted quad is this? $param = ''; } } else { if (preg_match('/^[\\w\\d\\.-]+$/', $param) && !preg_match('/^[\\.-]/', $param) && !preg_match('/[\\.-]$/', $param)) { // All is ok - $param is respected. } else { // All is not ok... $param = ''; } } return $param; case PARAM_URL: // Allow safe ftp, http, mailto urls. $param = fix_utf8($param); include_once $CFG->dirroot . '/lib/validateurlsyntax.php'; if (!empty($param) && validateUrlSyntax($param, 's?H?S?F?E?u-P-a?I?p?f?q?r?')) { // All is ok, param is respected. } else { // Not really ok. $param = ''; } return $param; case PARAM_LOCALURL: // Allow http absolute, root relative and relative URLs within wwwroot. $param = clean_param($param, PARAM_URL); if (!empty($param)) { // Simulate the HTTPS version of the site. $httpswwwroot = str_replace('http://', 'https://', $CFG->wwwroot); if ($param === $CFG->wwwroot) { // Exact match; } else { if (!empty($CFG->loginhttps) && $param === $httpswwwroot) { // Exact match; } else { if (preg_match(':^/:', $param)) { // Root-relative, ok! } else { if (preg_match('/^' . preg_quote($CFG->wwwroot . '/', '/') . '/i', $param)) { // Absolute, and matches our wwwroot. } else { if (!empty($CFG->loginhttps) && preg_match('/^' . preg_quote($httpswwwroot . '/', '/') . '/i', $param)) { // Absolute, and matches our httpswwwroot. } else { // Relative - let's make sure there are no tricks. if (validateUrlSyntax('/' . $param, 's-u-P-a-p-f+q?r?')) { // Looks ok. } else { $param = ''; } } } } } } } return $param; case PARAM_PEM: $param = trim($param); // PEM formatted strings may contain letters/numbers and the symbols: // forward slash: / // plus sign: + // equal sign: = // , surrounded by BEGIN and END CERTIFICATE prefix and suffixes. if (preg_match('/^-----BEGIN CERTIFICATE-----([\\s\\w\\/\\+=]+)-----END CERTIFICATE-----$/', trim($param), $matches)) { list($wholething, $body) = $matches; unset($wholething, $matches); $b64 = clean_param($body, PARAM_BASE64); if (!empty($b64)) { return "-----BEGIN CERTIFICATE-----\n{$b64}\n-----END CERTIFICATE-----\n"; } else { return ''; } } return ''; case PARAM_BASE64: if (!empty($param)) { // PEM formatted strings may contain letters/numbers and the symbols // forward slash: / // plus sign: + // equal sign: =. if (0 >= preg_match('/^([\\s\\w\\/\\+=]+)$/', trim($param))) { return ''; } $lines = preg_split('/[\\s]+/', $param, -1, PREG_SPLIT_NO_EMPTY); // Each line of base64 encoded data must be 64 characters in length, except for the last line which may be less // than (or equal to) 64 characters long. for ($i = 0, $j = count($lines); $i < $j; $i++) { if ($i + 1 == $j) { if (64 < strlen($lines[$i])) { return ''; } continue; } if (64 != strlen($lines[$i])) { return ''; } } return implode("\n", $lines); } else { return ''; } case PARAM_TAG: $param = fix_utf8($param); // Please note it is not safe to use the tag name directly anywhere, // it must be processed with s(), urlencode() before embedding anywhere. // Remove some nasties. $param = preg_replace('~[[:cntrl:]]|[<>`]~u', '', $param); // Convert many whitespace chars into one. $param = preg_replace('/\\s+/u', ' ', $param); $param = core_text::substr(trim($param), 0, TAG_MAX_LENGTH); return $param; case PARAM_TAGLIST: $param = fix_utf8($param); $tags = explode(',', $param); $result = array(); foreach ($tags as $tag) { $res = clean_param($tag, PARAM_TAG); if ($res !== '') { $result[] = $res; } } if ($result) { return implode(',', $result); } else { return ''; } case PARAM_CAPABILITY: if (get_capability_info($param)) { return $param; } else { return ''; } case PARAM_PERMISSION: $param = (int) $param; if (in_array($param, array(CAP_INHERIT, CAP_ALLOW, CAP_PREVENT, CAP_PROHIBIT))) { return $param; } else { return CAP_INHERIT; } case PARAM_AUTH: $param = clean_param($param, PARAM_PLUGIN); if (empty($param)) { return ''; } else { if (exists_auth_plugin($param)) { return $param; } else { return ''; } } case PARAM_LANG: $param = clean_param($param, PARAM_SAFEDIR); if (get_string_manager()->translation_exists($param)) { return $param; } else { // Specified language is not installed or param malformed. return ''; } case PARAM_THEME: $param = clean_param($param, PARAM_PLUGIN); if (empty($param)) { return ''; } else { if (file_exists("{$CFG->dirroot}/theme/{$param}/config.php")) { return $param; } else { if (!empty($CFG->themedir) and file_exists("{$CFG->themedir}/{$param}/config.php")) { return $param; } else { // Specified theme is not installed. return ''; } } } case PARAM_USERNAME: $param = fix_utf8($param); $param = trim($param); // Convert uppercase to lowercase MDL-16919. $param = core_text::strtolower($param); if (empty($CFG->extendedusernamechars)) { $param = str_replace(" ", "", $param); // Regular expression, eliminate all chars EXCEPT: // alphanum, dash (-), underscore (_), at sign (@) and period (.) characters. $param = preg_replace('/[^-\\.@_a-z0-9]/', '', $param); } return $param; case PARAM_EMAIL: $param = fix_utf8($param); if (validate_email($param)) { return $param; } else { return ''; } case PARAM_STRINGID: if (preg_match('|^[a-zA-Z][a-zA-Z0-9\\.:/_-]*$|', $param)) { return $param; } else { return ''; } case PARAM_TIMEZONE: // Can be int, float(with .5 or .0) or string seperated by '/' and can have '-_'. $param = fix_utf8($param); $timezonepattern = '/^(([+-]?(0?[0-9](\\.[5|0])?|1[0-3](\\.0)?|1[0-2]\\.5))|(99)|[[:alnum:]]+(\\/?[[:alpha:]_-])+)$/'; if (preg_match($timezonepattern, $param)) { return $param; } else { return ''; } default: // Doh! throw error, switched parameters in optional_param or another serious problem. print_error("unknownparamtype", '', '', $type); } }
/** * Checks whether mod/...:view capability restricts the current user's access. * * @return bool True if the user access is restricted. */ public function is_user_access_restricted_by_capability() { $userid = $this->modinfo->get_user_id(); if ($userid == -1) { return null; } $capability = 'mod/' . $this->modname . ':view'; $capabilityinfo = get_capability_info($capability); if (!$capabilityinfo) { // Capability does not exist, no one is prevented from seeing the activity. return false; } // You are blocked if you don't have the capability. return !has_capability($capability, $this->get_context(), $userid); }
/** * Used by {@link optional_param()} and {@link required_param()} to * clean the variables and/or cast to specific types, based on * an options field. * <code> * $course->format = clean_param($course->format, PARAM_ALPHA); * $selectedgrade_item = clean_param($selectedgrade_item, PARAM_INT); * </code> * * @param mixed $param the variable we are cleaning * @param int $type expected format of param after cleaning. * @return mixed */ function clean_param($param, $type) { global $CFG; if (is_array($param)) { // Let's loop $newparam = array(); foreach ($param as $key => $value) { $newparam[$key] = clean_param($value, $type); } return $newparam; } switch ($type) { case PARAM_RAW: // no cleaning at all return $param; case PARAM_RAW_TRIMMED: // no cleaning, but strip leading and trailing whitespace. return trim($param); case PARAM_CLEAN: // General HTML cleaning, try to use more specific type if possible // this is deprecated!, please use more specific type instead if (is_numeric($param)) { return $param; } return clean_text($param); // Sweep for scripts, etc // Sweep for scripts, etc case PARAM_CLEANHTML: // clean html fragment $param = clean_text($param, FORMAT_HTML); // Sweep for scripts, etc return trim($param); case PARAM_INT: return (int) $param; // Convert to integer // Convert to integer case PARAM_FLOAT: case PARAM_NUMBER: return (double) $param; // Convert to float // Convert to float case PARAM_ALPHA: // Remove everything not a-z return preg_replace('/[^a-zA-Z]/i', '', $param); case PARAM_ALPHAEXT: // Remove everything not a-zA-Z_- (originally allowed "/" too) return preg_replace('/[^a-zA-Z_-]/i', '', $param); case PARAM_ALPHANUM: // Remove everything not a-zA-Z0-9 return preg_replace('/[^A-Za-z0-9]/i', '', $param); case PARAM_ALPHANUMEXT: // Remove everything not a-zA-Z0-9_- return preg_replace('/[^A-Za-z0-9_-]/i', '', $param); case PARAM_SEQUENCE: // Remove everything not 0-9, return preg_replace('/[^0-9,]/i', '', $param); case PARAM_BOOL: // Convert to 1 or 0 $tempstr = strtolower($param); if ($tempstr === 'on' or $tempstr === 'yes' or $tempstr === 'true') { $param = 1; } else { if ($tempstr === 'off' or $tempstr === 'no' or $tempstr === 'false') { $param = 0; } else { $param = empty($param) ? 0 : 1; } } return $param; case PARAM_NOTAGS: // Strip all tags return strip_tags($param); case PARAM_TEXT: // leave only tags needed for multilang // if the multilang syntax is not correct we strip all tags // because it would break xhtml strict which is required for accessibility standards // please note this cleaning does not strip unbalanced '>' for BC compatibility reasons do { if (strpos($param, '</lang>') !== false) { // old and future mutilang syntax $param = strip_tags($param, '<lang>'); if (!preg_match_all('/<.*>/suU', $param, $matches)) { break; } $open = false; foreach ($matches[0] as $match) { if ($match === '</lang>') { if ($open) { $open = false; continue; } else { break 2; } } if (!preg_match('/^<lang lang="[a-zA-Z0-9_-]+"\\s*>$/u', $match)) { break 2; } else { $open = true; } } if ($open) { break; } return $param; } else { if (strpos($param, '</span>') !== false) { // current problematic multilang syntax $param = strip_tags($param, '<span>'); if (!preg_match_all('/<.*>/suU', $param, $matches)) { break; } $open = false; foreach ($matches[0] as $match) { if ($match === '</span>') { if ($open) { $open = false; continue; } else { break 2; } } if (!preg_match('/^<span(\\s+lang="[a-zA-Z0-9_-]+"|\\s+class="multilang"){2}\\s*>$/u', $match)) { break 2; } else { $open = true; } } if ($open) { break; } return $param; } } } while (false); // easy, just strip all tags, if we ever want to fix orphaned '&' we have to do that in format_string() return strip_tags($param); case PARAM_SAFEDIR: // Remove everything not a-zA-Z0-9_- return preg_replace('/[^a-zA-Z0-9_-]/i', '', $param); case PARAM_SAFEPATH: // Remove everything not a-zA-Z0-9/_- return preg_replace('/[^a-zA-Z0-9\\/_-]/i', '', $param); case PARAM_FILE: // Strip all suspicious characters from filename $param = preg_replace('~[[:cntrl:]]|[&<>"`\\|\':\\\\/]~u', '', $param); $param = preg_replace('~\\.\\.+~', '', $param); if ($param === '.') { $param = ''; } return $param; case PARAM_PATH: // Strip all suspicious characters from file path $param = str_replace('\\', '/', $param); $param = preg_replace('~[[:cntrl:]]|[&<>"`\\|\':]~u', '', $param); $param = preg_replace('~\\.\\.+~', '', $param); $param = preg_replace('~//+~', '/', $param); return preg_replace('~/(\\./)+~', '/', $param); case PARAM_HOST: // allow FQDN or IPv4 dotted quad $param = preg_replace('/[^\\.\\d\\w-]/', '', $param); // only allowed chars // match ipv4 dotted quad if (preg_match('/(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/', $param, $match)) { // confirm values are ok if ($match[0] > 255 || $match[1] > 255 || $match[3] > 255 || $match[4] > 255) { // hmmm, what kind of dotted quad is this? $param = ''; } } elseif (preg_match('/^[\\w\\d\\.-]+$/', $param) && !preg_match('/^[\\.-]/', $param) && !preg_match('/[\\.-]$/', $param)) { // all is ok - $param is respected } else { // all is not ok... $param = ''; } return $param; case PARAM_URL: // allow safe ftp, http, mailto urls include_once $CFG->dirroot . '/lib/validateurlsyntax.php'; if (!empty($param) && validateUrlSyntax($param, 's?H?S?F?E?u-P-a?I?p?f?q?r?')) { // all is ok, param is respected } else { $param = ''; // not really ok } return $param; case PARAM_LOCALURL: // allow http absolute, root relative and relative URLs within wwwroot $param = clean_param($param, PARAM_URL); if (!empty($param)) { if (preg_match(':^/:', $param)) { // root-relative, ok! } elseif (preg_match('/^' . preg_quote($CFG->wwwroot, '/') . '/i', $param)) { // absolute, and matches our wwwroot } else { // relative - let's make sure there are no tricks if (validateUrlSyntax('/' . $param, 's-u-P-a-p-f+q?r?')) { // looks ok. } else { $param = ''; } } } return $param; case PARAM_PEM: $param = trim($param); // PEM formatted strings may contain letters/numbers and the symbols // forward slash: / // plus sign: + // equal sign: = // , surrounded by BEGIN and END CERTIFICATE prefix and suffixes if (preg_match('/^-----BEGIN CERTIFICATE-----([\\s\\w\\/\\+=]+)-----END CERTIFICATE-----$/', trim($param), $matches)) { list($wholething, $body) = $matches; unset($wholething, $matches); $b64 = clean_param($body, PARAM_BASE64); if (!empty($b64)) { return "-----BEGIN CERTIFICATE-----\n{$b64}\n-----END CERTIFICATE-----\n"; } else { return ''; } } return ''; case PARAM_BASE64: if (!empty($param)) { // PEM formatted strings may contain letters/numbers and the symbols // forward slash: / // plus sign: + // equal sign: = if (0 >= preg_match('/^([\\s\\w\\/\\+=]+)$/', trim($param))) { return ''; } $lines = preg_split('/[\\s]+/', $param, -1, PREG_SPLIT_NO_EMPTY); // Each line of base64 encoded data must be 64 characters in // length, except for the last line which may be less than (or // equal to) 64 characters long. for ($i = 0, $j = count($lines); $i < $j; $i++) { if ($i + 1 == $j) { if (64 < strlen($lines[$i])) { return ''; } continue; } if (64 != strlen($lines[$i])) { return ''; } } return implode("\n", $lines); } else { return ''; } case PARAM_TAG: // Please note it is not safe to use the tag name directly anywhere, // it must be processed with s(), urlencode() before embedding anywhere. // remove some nasties $param = preg_replace('~[[:cntrl:]]|[<>`]~u', '', $param); //convert many whitespace chars into one $param = preg_replace('/\\s+/', ' ', $param); $textlib = textlib_get_instance(); $param = $textlib->substr(trim($param), 0, TAG_MAX_LENGTH); return $param; case PARAM_TAGLIST: $tags = explode(',', $param); $result = array(); foreach ($tags as $tag) { $res = clean_param($tag, PARAM_TAG); if ($res !== '') { $result[] = $res; } } if ($result) { return implode(',', $result); } else { return ''; } case PARAM_CAPABILITY: if (get_capability_info($param)) { return $param; } else { return ''; } case PARAM_PERMISSION: $param = (int) $param; if (in_array($param, array(CAP_INHERIT, CAP_ALLOW, CAP_PREVENT, CAP_PROHIBIT))) { return $param; } else { return CAP_INHERIT; } case PARAM_AUTH: $param = clean_param($param, PARAM_SAFEDIR); if (exists_auth_plugin($param)) { return $param; } else { return ''; } case PARAM_LANG: $param = clean_param($param, PARAM_SAFEDIR); if (get_string_manager()->translation_exists($param)) { return $param; } else { return ''; // Specified language is not installed or param malformed } case PARAM_THEME: $param = clean_param($param, PARAM_SAFEDIR); if (file_exists("{$CFG->dirroot}/theme/{$param}/config.php")) { return $param; } else { if (!empty($CFG->themedir) and file_exists("{$CFG->themedir}/{$param}/config.php")) { return $param; } else { return ''; // Specified theme is not installed } } case PARAM_USERNAME: $param = str_replace(" ", "", $param); $param = moodle_strtolower($param); // Convert uppercase to lowercase MDL-16919 if (empty($CFG->extendedusernamechars)) { // regular expression, eliminate all chars EXCEPT: // alphanum, dash (-), underscore (_), at sign (@) and period (.) characters. $param = preg_replace('/[^-\\.@_a-z0-9]/', '', $param); } return $param; case PARAM_EMAIL: if (validate_email($param)) { return $param; } else { return ''; } case PARAM_STRINGID: if (preg_match('|^[a-zA-Z][a-zA-Z0-9\\.:/_-]*$|', $param)) { return $param; } else { return ''; } default: // throw error, switched parameters in optional_param or another serious problem print_error("unknownparamtype", '', '', $type); } }
/** * Returns true if the user can add a block to a page. * * @param moodle_page $page * @param string $capability the capability to check * @return boolean true if user can add a block, false otherwise. */ private function has_add_block_capability($page, $capability) { // Check if the capability exists. if (!get_capability_info($capability)) { // Debug warning that the capability does not exist, but no more than once per page. static $warned = array(); if (!isset($warned[$this->name()])) { debugging('The block ' . $this->name() . ' does not define the standard capability ' . $capability, DEBUG_DEVELOPER); $warned[$this->name()] = 1; } // If the capability does not exist, the block can always be added. return true; } else { return has_capability($capability, $page->context); } }
/** * Check whether a user has a particular capability in a given context. * * For example:: * $context = get_context_instance(CONTEXT_MODULE, $cm->id); * has_capability('mod/forum:replypost',$context) * * By default checks the capabilities of the current user, but you can pass a * different userid. By default will return true for admin users, but you can override that with the fourth argument. * * Guest and not-logged-in users can never get any dangerous capability - that is any write capability * or capabilities with XSS, config or data loss risks. * * @param string $capability the name of the capability to check. For example mod/forum:view * @param object $context the context to check the capability in. You normally get this with {@link get_context_instance}. * @param integer|object $user A user id or object. By default (null) checks the permissions of the current user. * @param boolean $doanything If false, ignores effect of admin role assignment * @return boolean true if the user has this capability. Otherwise false. */ function has_capability($capability, $context, $user = null, $doanything = true) { global $USER, $CFG, $DB, $SCRIPT, $ACCESSLIB_PRIVATE; if (during_initial_install()) { if ($SCRIPT === "/{$CFG->admin}/index.php" or $SCRIPT === "/{$CFG->admin}/cliupgrade.php") { // we are in an installer - roles can not work yet return true; } else { return false; } } if (strpos($capability, 'moodle/legacy:') === 0) { throw new coding_exception('Legacy capabilities can not be used any more!'); } // the original $CONTEXT here was hiding serious errors // for security reasons do not reuse previous context if (empty($context)) { debugging('Incorrect context specified'); return false; } if (!is_bool($doanything)) { throw new coding_exception('Capability parameter "doanything" is wierd ("' . $doanything . '"). This has to be fixed in code.'); } // make sure there is a real user specified if ($user === null) { $userid = isset($USER->id) ? $USER->id : 0; } else { $userid = is_object($user) ? $user->id : $user; } // capability must exist if (!($capinfo = get_capability_info($capability))) { debugging('Capability "' . $capability . '" was not found! This should be fixed in code.'); return false; } // make sure the guest account and not-logged-in users never get any risky caps no matter what the actual settings are. if ($capinfo->captype === 'write' or (int) $capinfo->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS)) { if (isguestuser($userid) or $userid == 0) { return false; } } if (is_null($context->path) or $context->depth == 0) { //this should not happen $contexts = array(SYSCONTEXTID, $context->id); $context->path = '/' . SYSCONTEXTID . '/' . $context->id; debugging('Context id ' . $context->id . ' does not have valid path, please use build_context_path()', DEBUG_DEVELOPER); } else { $contexts = explode('/', $context->path); array_shift($contexts); } if (CLI_SCRIPT && !isset($USER->access)) { // In cron, some modules setup a 'fake' $USER, // ensure we load the appropriate accessdata. if (isset($ACCESSLIB_PRIVATE->accessdatabyuser[$userid])) { $ACCESSLIB_PRIVATE->dirtycontexts = null; //load fresh dirty contexts } else { load_user_accessdata($userid); $ACCESSLIB_PRIVATE->dirtycontexts = array(); } $USER->access = $ACCESSLIB_PRIVATE->accessdatabyuser[$userid]; } else { if (isset($USER->id) && $USER->id == $userid && !isset($USER->access)) { // caps not loaded yet - better to load them to keep BC with 1.8 // not-logged-in user or $USER object set up manually first time here load_all_capabilities(); $ACCESSLIB_PRIVATE->accessdatabyuser = array(); // reset the cache for other users too, the dirty contexts are empty now $ACCESSLIB_PRIVATE->roledefinitions = array(); } } // Load dirty contexts list if needed if (!isset($ACCESSLIB_PRIVATE->dirtycontexts)) { if (isset($USER->access['time'])) { $ACCESSLIB_PRIVATE->dirtycontexts = get_dirty_contexts($USER->access['time']); } else { $ACCESSLIB_PRIVATE->dirtycontexts = array(); } } // Careful check for staleness... if (count($ACCESSLIB_PRIVATE->dirtycontexts) !== 0 and is_contextpath_dirty($contexts, $ACCESSLIB_PRIVATE->dirtycontexts)) { // reload all capabilities - preserving loginas, roleswitches, etc // and then cleanup any marks of dirtyness... at least from our short // term memory! :-) $ACCESSLIB_PRIVATE->accessdatabyuser = array(); $ACCESSLIB_PRIVATE->roledefinitions = array(); if (CLI_SCRIPT) { load_user_accessdata($userid); $USER->access = $ACCESSLIB_PRIVATE->accessdatabyuser[$userid]; $ACCESSLIB_PRIVATE->dirtycontexts = array(); } else { reload_all_capabilities(); } } // Find out if user is admin - it is not possible to override the doanything in any way // and it is not possible to switch to admin role either. if ($doanything) { if (is_siteadmin($userid)) { if ($userid != $USER->id) { return true; } // make sure switchrole is not used in this context if (empty($USER->access['rsw'])) { return true; } $parts = explode('/', trim($context->path, '/')); $path = ''; $switched = false; foreach ($parts as $part) { $path .= '/' . $part; if (!empty($USER->access['rsw'][$path])) { $switched = true; break; } } if (!$switched) { return true; } //ok, admin switched role in this context, let's use normal access control rules } } // divulge how many times we are called //// error_log("has_capability: id:{$context->id} path:{$context->path} userid:$userid cap:$capability"); if (isset($USER->id) && $USER->id == $userid) { // we must accept strings and integers in $userid // // For the logged in user, we have $USER->access // which will have all RAs and caps preloaded for // course and above contexts. // // Contexts below courses && contexts that do not // hang from courses are loaded into $USER->access // on demand, and listed in $USER->access[loaded] // if ($context->contextlevel <= CONTEXT_COURSE) { // Course and above are always preloaded return has_capability_in_accessdata($capability, $context, $USER->access); } // Load accessdata for below-the-course contexts if (!path_inaccessdata($context->path, $USER->access)) { // error_log("loading access for context {$context->path} for $capability at {$context->contextlevel} {$context->id}"); // $bt = debug_backtrace(); // error_log("bt {$bt[0]['file']} {$bt[0]['line']}"); load_subcontext($USER->id, $context, $USER->access); } return has_capability_in_accessdata($capability, $context, $USER->access); } if (!isset($ACCESSLIB_PRIVATE->accessdatabyuser[$userid])) { load_user_accessdata($userid); } if ($context->contextlevel <= CONTEXT_COURSE) { // Course and above are always preloaded return has_capability_in_accessdata($capability, $context, $ACCESSLIB_PRIVATE->accessdatabyuser[$userid]); } // Load accessdata for below-the-course contexts as needed if (!path_inaccessdata($context->path, $ACCESSLIB_PRIVATE->accessdatabyuser[$userid])) { // error_log("loading access for context {$context->path} for $capability at {$context->contextlevel} {$context->id}"); // $bt = debug_backtrace(); // error_log("bt {$bt[0]['file']} {$bt[0]['line']}"); load_subcontext($userid, $context, $ACCESSLIB_PRIVATE->accessdatabyuser[$userid]); } return has_capability_in_accessdata($capability, $context, $ACCESSLIB_PRIVATE->accessdatabyuser[$userid]); }
/** * Builds and returns the rows that will make up the right part of the grader report * @param boolean $displayaverages whether to display average rows in the table * @return array Array of html_table_row objects */ public function get_right_rows($displayaverages) { global $CFG, $USER, $OUTPUT, $DB, $PAGE; $rows = array(); $this->rowcount = 0; $numrows = count($this->gtree->get_levels()); $numusers = count($this->users); $gradetabindex = 1; $columnstounset = array(); $strgrade = $this->get_lang_string('grade'); $strfeedback = $this->get_lang_string("feedback"); $arrows = $this->get_sort_arrows(); $jsarguments = array('cfg' => array('ajaxenabled' => false), 'items' => array(), 'users' => array(), 'feedback' => array(), 'grades' => array()); $jsscales = array(); // Get preferences once. $showactivityicons = $this->get_pref('showactivityicons'); $quickgrading = $this->get_pref('quickgrading'); $showquickfeedback = $this->get_pref('showquickfeedback'); $enableajax = $this->get_pref('enableajax'); $showanalysisicon = $this->get_pref('showanalysisicon'); // Get strings which are re-used inside the loop. $strftimedatetimeshort = get_string('strftimedatetimeshort'); $strexcludedgrades = get_string('excluded', 'grades'); $strerror = get_string('error'); foreach ($this->gtree->get_levels() as $key => $row) { $headingrow = new html_table_row(); $headingrow->attributes['class'] = 'heading_name_row'; foreach ($row as $columnkey => $element) { $sortlink = clone $this->baseurl; if (isset($element['object']->id)) { $sortlink->param('sortitemid', $element['object']->id); } $eid = $element['eid']; $object = $element['object']; $type = $element['type']; $categorystate = @$element['categorystate']; if (!empty($element['colspan'])) { $colspan = $element['colspan']; } else { $colspan = 1; } if (!empty($element['depth'])) { $catlevel = 'catlevel' . $element['depth']; } else { $catlevel = ''; } // Element is a filler if ($type == 'filler' or $type == 'fillerfirst' or $type == 'fillerlast') { $fillercell = new html_table_cell(); $fillercell->attributes['class'] = $type . ' ' . $catlevel; $fillercell->colspan = $colspan; $fillercell->text = ' '; // This is a filler cell; don't use a <th>, it'll confuse screen readers. $fillercell->header = false; $headingrow->cells[] = $fillercell; } else { if ($type == 'category') { // Make sure the grade category has a grade total or at least has child grade items. if (grade_tree::can_output_item($element)) { // Element is a category. $categorycell = new html_table_cell(); $categorycell->attributes['class'] = 'category ' . $catlevel; $categorycell->colspan = $colspan; $categorycell->text = $this->get_course_header($element); $categorycell->header = true; $categorycell->scope = 'col'; // Print icons. if ($USER->gradeediting[$this->courseid]) { $categorycell->text .= $this->get_icons($element); } $headingrow->cells[] = $categorycell; } } else { // Element is a grade_item if ($element['object']->id == $this->sortitemid) { if ($this->sortorder == 'ASC') { $arrow = $this->get_sort_arrow('up', $sortlink); } else { $arrow = $this->get_sort_arrow('down', $sortlink); } } else { $arrow = $this->get_sort_arrow('move', $sortlink); } $headerlink = $this->gtree->get_element_header($element, true, $showactivityicons, false, false, true); $itemcell = new html_table_cell(); $itemcell->attributes['class'] = $type . ' ' . $catlevel . ' highlightable' . ' i' . $element['object']->id; $itemcell->attributes['data-itemid'] = $element['object']->id; if ($element['object']->is_hidden()) { $itemcell->attributes['class'] .= ' dimmed_text'; } $singleview = ''; // FIXME: MDL-52678 This is extremely hacky we should have an API for inserting grade column links. if (get_capability_info('gradereport/singleview:view')) { if (has_all_capabilities(array('gradereport/singleview:view', 'moodle/grade:viewall', 'moodle/grade:edit'), $this->context)) { $url = new moodle_url('/grade/report/singleview/index.php', array('id' => $this->course->id, 'item' => 'grade', 'itemid' => $element['object']->id)); $singleview = $OUTPUT->action_icon($url, new pix_icon('t/editstring', get_string('singleview', 'grades', $element['object']->get_name()))); } } $itemcell->colspan = $colspan; $itemcell->text = shorten_text($headerlink) . $arrow . $singleview; $itemcell->header = true; $itemcell->scope = 'col'; $headingrow->cells[] = $itemcell; } } } $rows[] = $headingrow; } $rows = $this->get_right_icons_row($rows); // Preload scale objects for items with a scaleid and initialize tab indices $scaleslist = array(); $tabindices = array(); foreach ($this->gtree->get_items() as $itemid => $item) { $scale = null; if (!empty($item->scaleid)) { $scaleslist[] = $item->scaleid; $jsarguments['items'][$itemid] = array('id' => $itemid, 'name' => $item->get_name(true), 'type' => 'scale', 'scale' => $item->scaleid, 'decimals' => $item->get_decimals()); } else { $jsarguments['items'][$itemid] = array('id' => $itemid, 'name' => $item->get_name(true), 'type' => 'value', 'scale' => false, 'decimals' => $item->get_decimals()); } $tabindices[$item->id]['grade'] = $gradetabindex; $tabindices[$item->id]['feedback'] = $gradetabindex + $numusers; $gradetabindex += $numusers * 2; } $scalesarray = array(); if (!empty($scaleslist)) { $scalesarray = $DB->get_records_list('scale', 'id', $scaleslist); } $jsscales = $scalesarray; // Get all the grade items if the user can not view hidden grade items. // It is possible that the user is simply viewing the 'Course total' by switching to the 'Aggregates only' view // and that this user does not have the ability to view hidden items. In this case we still need to pass all the // grade items (in case one has been hidden) as the course total shown needs to be adjusted for this particular // user. if (!$this->canviewhidden) { $allgradeitems = grade_item::fetch_all(array('courseid' => $this->courseid)); } foreach ($this->users as $userid => $user) { if ($this->canviewhidden) { $altered = array(); $unknown = array(); } else { $usergrades = $this->allgrades[$userid]; $hidingaffected = grade_grade::get_hiding_affected($usergrades, $allgradeitems); $altered = $hidingaffected['altered']; $unknown = $hidingaffected['unknown']; unset($hidingaffected); } $itemrow = new html_table_row(); $itemrow->id = 'user_' . $userid; $fullname = fullname($user); $jsarguments['users'][$userid] = $fullname; foreach ($this->gtree->items as $itemid => $unused) { $item =& $this->gtree->items[$itemid]; $grade = $this->grades[$userid][$item->id]; $itemcell = new html_table_cell(); $itemcell->id = 'u' . $userid . 'i' . $itemid; $itemcell->attributes['data-itemid'] = $itemid; // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); if (in_array($itemid, $unknown)) { $gradeval = null; } else { if (array_key_exists($itemid, $altered)) { $gradeval = $altered[$itemid]; } else { $gradeval = $grade->finalgrade; } } if (!empty($grade->finalgrade)) { $gradevalforjs = null; if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $gradevalforjs = (int) $gradeval; } else { $gradevalforjs = format_float($gradeval, $decimalpoints); } $jsarguments['grades'][] = array('user' => $userid, 'item' => $itemid, 'grade' => $gradevalforjs); } // MDL-11274 // Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden' if (!$this->canviewhidden and $grade->is_hidden()) { if (!empty($CFG->grade_hiddenasdate) and $grade->get_datesubmitted() and !$item->is_category_item() and !$item->is_course_item()) { // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records $itemcell->text = "<span class='datesubmitted'>" . userdate($grade->get_datesubmitted(), $strftimedatetimeshort) . "</span>"; } else { $itemcell->text = '-'; } $itemrow->cells[] = $itemcell; continue; } // emulate grade element $eid = $this->gtree->get_grade_eid($grade); $element = array('eid' => $eid, 'object' => $grade, 'type' => 'grade'); $itemcell->attributes['class'] .= ' grade i' . $itemid; if ($item->is_category_item()) { $itemcell->attributes['class'] .= ' cat'; } if ($item->is_course_item()) { $itemcell->attributes['class'] .= ' course'; } if ($grade->is_overridden()) { $itemcell->attributes['class'] .= ' overridden'; $itemcell->attributes['aria-label'] = get_string('overriddengrade', 'gradereport_grader'); } if (!empty($grade->feedback)) { $feedback = wordwrap(trim(format_string($grade->feedback, $grade->feedbackformat)), 34, '<br>'); $itemcell->attributes['data-feedback'] = $feedback; $jsarguments['feedback'][] = array('user' => $userid, 'item' => $itemid, 'content' => $feedback); } if ($grade->is_excluded()) { // Adding white spaces before and after to prevent a screenreader from // thinking that the words are attached to the next/previous <span> or text. $itemcell->text .= " <span class='excludedfloater'>" . $strexcludedgrades . "</span> "; } // Do not show any icons if no grade (no record in DB to match) if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) { $itemcell->text .= $this->get_icons($element); } $hidden = ''; if ($grade->is_hidden()) { $hidden = ' dimmed_text '; } $gradepass = '******'; if ($grade->is_passed($item)) { $gradepass = '******'; } else { if (is_null($grade->is_passed($item))) { $gradepass = ''; } } // if in editing mode, we need to print either a text box // or a drop down (for scales) // grades in item of type grade category or course are not directly editable if ($item->needsupdate) { $itemcell->text .= "<span class='gradingerror{$hidden}'>" . $strerror . "</span>"; } else { if ($USER->gradeediting[$this->courseid]) { if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $itemcell->attributes['class'] .= ' grade_type_scale'; } else { if ($item->gradetype == GRADE_TYPE_VALUE) { $itemcell->attributes['class'] .= ' grade_type_value'; } else { if ($item->gradetype == GRADE_TYPE_TEXT) { $itemcell->attributes['class'] .= ' grade_type_text'; } } } if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $scale = $scalesarray[$item->scaleid]; $gradeval = (int) $gradeval; // scales use only integers $scales = explode(",", $scale->scale); // reindex because scale is off 1 // MDL-12104 some previous scales might have taken up part of the array // so this needs to be reset $scaleopt = array(); $i = 0; foreach ($scales as $scaleoption) { $i++; $scaleopt[$i] = $scaleoption; } if ($quickgrading and $grade->is_editable()) { $oldval = empty($gradeval) ? -1 : $gradeval; if (empty($item->outcomeid)) { $nogradestr = $this->get_lang_string('nograde'); } else { $nogradestr = $this->get_lang_string('nooutcome', 'grades'); } $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id' => 'grade_' . $userid . '_' . $item->id); $gradelabel = $fullname . ' ' . $item->itemname; $itemcell->text .= html_writer::label(get_string('useractivitygrade', 'gradereport_grader', $gradelabel), $attributes['id'], false, array('class' => 'accesshide')); $itemcell->text .= html_writer::select($scaleopt, 'grade[' . $userid . '][' . $item->id . ']', $gradeval, array(-1 => $nogradestr), $attributes); } else { if (!empty($scale)) { $scales = explode(",", $scale->scale); // invalid grade if gradeval < 1 if ($gradeval < 1) { $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>-</span>"; } else { $gradeval = $grade->grade_item->bounded_grade($gradeval); //just in case somebody changes scale $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>{$scales[$gradeval - 1]}</span>"; } } } } else { if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type if ($quickgrading and $grade->is_editable()) { $value = format_float($gradeval, $decimalpoints); $gradelabel = $fullname . ' ' . $item->itemname; $itemcell->text .= '<label class="accesshide" for="grade_' . $userid . '_' . $item->id . '">' . get_string('useractivitygrade', 'gradereport_grader', $gradelabel) . '</label>'; $itemcell->text .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade'] . '" type="text" class="text" title="' . $strgrade . '" name="grade[' . $userid . '][' . $item->id . ']" id="grade_' . $userid . '_' . $item->id . '" value="' . $value . '" />'; } else { $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>" . format_float($gradeval, $decimalpoints) . "</span>"; } } } // If quickfeedback is on, print an input element if ($showquickfeedback and $grade->is_editable()) { $feedbacklabel = $fullname . ' ' . $item->itemname; $itemcell->text .= '<label class="accesshide" for="feedback_' . $userid . '_' . $item->id . '">' . get_string('useractivityfeedback', 'gradereport_grader', $feedbacklabel) . '</label>'; $itemcell->text .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'] . '" id="feedback_' . $userid . '_' . $item->id . '" size="6" title="' . $strfeedback . '" type="text" name="feedback[' . $userid . '][' . $item->id . ']" value="' . s($grade->feedback) . '" />'; } } else { // Not editing $gradedisplaytype = $item->get_displaytype(); if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $itemcell->attributes['class'] .= ' grade_type_scale'; } else { if ($item->gradetype == GRADE_TYPE_VALUE) { $itemcell->attributes['class'] .= ' grade_type_value'; } else { if ($item->gradetype == GRADE_TYPE_TEXT) { $itemcell->attributes['class'] .= ' grade_type_text'; } } } // Only allow edting if the grade is editable (not locked, not in a unoverridable category, etc). if ($enableajax && $grade->is_editable()) { // If a grade item is type text, and we don't have show quick feedback on, it can't be edited. if ($item->gradetype != GRADE_TYPE_TEXT || $showquickfeedback) { $itemcell->attributes['class'] .= ' clickable'; } } if ($item->needsupdate) { $itemcell->text .= "<span class='gradingerror{$hidden}{$gradepass}'>" . $error . "</span>"; } else { // The max and min for an aggregation may be different to the grade_item. if (!is_null($gradeval)) { $item->grademax = $grade->get_grade_max(); $item->grademin = $grade->get_grade_min(); } $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>" . grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null) . "</span>"; if ($showanalysisicon) { $itemcell->text .= $this->gtree->get_grade_analysis_icon($grade); } } } } // Enable keyboard navigation if the grade is editable (not locked, not in a unoverridable category, etc). if ($enableajax && $grade->is_editable()) { // If a grade item is type text, and we don't have show quick feedback on, it can't be edited. if ($item->gradetype != GRADE_TYPE_TEXT || $showquickfeedback) { $itemcell->attributes['class'] .= ' gbnavigable'; } } if (!empty($this->gradeserror[$item->id][$userid])) { $itemcell->text .= $this->gradeserror[$item->id][$userid]; } $itemrow->cells[] = $itemcell; } $rows[] = $itemrow; } if ($enableajax) { $jsarguments['cfg']['ajaxenabled'] = true; $jsarguments['cfg']['scales'] = array(); foreach ($jsscales as $scale) { // Trim the scale values, as they may have a space that is ommitted from values later. $jsarguments['cfg']['scales'][$scale->id] = array_map('trim', explode(',', $scale->scale)); } $jsarguments['cfg']['feedbacktrunclength'] = $this->feedback_trunc_length; // Student grades and feedback are already at $jsarguments['feedback'] and $jsarguments['grades'] } $jsarguments['cfg']['isediting'] = (bool) $USER->gradeediting[$this->courseid]; $jsarguments['cfg']['courseid'] = $this->courseid; $jsarguments['cfg']['studentsperpage'] = $this->get_students_per_page(); $jsarguments['cfg']['showquickfeedback'] = (bool) $showquickfeedback; $module = array('name' => 'gradereport_grader', 'fullpath' => '/grade/report/grader/module.js', 'requires' => array('base', 'dom', 'event', 'event-mouseenter', 'event-key', 'io-queue', 'json-parse', 'overlay')); $PAGE->requires->js_init_call('M.gradereport_grader.init_report', $jsarguments, false, $module); $PAGE->requires->strings_for_js(array('addfeedback', 'feedback', 'grade'), 'grades'); $PAGE->requires->strings_for_js(array('ajaxchoosescale', 'ajaxclicktoclose', 'ajaxerror', 'ajaxfailedupdate', 'ajaxfieldchanged'), 'gradereport_grader'); if (!$enableajax && $USER->gradeediting[$this->courseid]) { $PAGE->requires->yui_module('moodle-core-formchangechecker', 'M.core_formchangechecker.init', array(array('formid' => 'gradereport_grader'))); $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle'); } $rows = $this->get_right_range_row($rows); if ($displayaverages) { $rows = $this->get_right_avg_row($rows, true); $rows = $this->get_right_avg_row($rows); } return $rows; }
/** * This file keeps track of upgrades to * the forum module * * Sometimes, changes between versions involve * alterations to database structures and other * major things that may break installations. * * The upgrade function in this file will attempt * to perform all the necessary actions to upgrade * your older installation to the current version. * * If there's something it cannot do itself, it * will tell you what you need to do. * * The commands in here will all be database-neutral, * using the methods of database_manager class * * Please do not forget to use upgrade_set_timeout() * before any action that may take longer time to finish. * * @package mod_forum * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ function xmldb_forum_upgrade($oldversion) { global $CFG, $DB, $OUTPUT; $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. // Moodle v2.2.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.3.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.4.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013020500) { // Define field displaywordcount to be added to forum. $table = new xmldb_table('forum'); $field = new xmldb_field('displaywordcount', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'completionposts'); // Conditionally launch add field displaywordcount. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013020500, 'forum'); } // Forcefully assign mod/forum:allowforcesubscribe to frontpage role, as we missed that when // capability was introduced. if ($oldversion < 2013021200) { // If capability mod/forum:allowforcesubscribe is defined then set it for frontpage role. if (get_capability_info('mod/forum:allowforcesubscribe')) { assign_legacy_capabilities('mod/forum:allowforcesubscribe', array('frontpage' => CAP_ALLOW)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013021200, 'forum'); } // Moodle v2.5.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013071000) { // Define table forum_digests to be created. $table = new xmldb_table('forum_digests'); // Adding fields to table forum_digests. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('forum', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('maildigest', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '-1'); // Adding keys to table forum_digests. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); $table->add_key('forum', XMLDB_KEY_FOREIGN, array('forum'), 'forum', array('id')); $table->add_key('forumdigest', XMLDB_KEY_UNIQUE, array('forum', 'userid', 'maildigest')); // Conditionally launch create table for forum_digests. if (!$dbman->table_exists($table)) { $dbman->create_table($table); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013071000, 'forum'); } // Moodle v2.6.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014040400) { // Define index userid-postid (not unique) to be dropped form forum_read. $table = new xmldb_table('forum_read'); $index = new xmldb_index('userid-postid', XMLDB_INDEX_NOTUNIQUE, array('userid', 'postid')); // Conditionally launch drop index userid-postid. if ($dbman->index_exists($table, $index)) { $dbman->drop_index($table, $index); } // Define index postid-userid (not unique) to be added to forum_read. $index = new xmldb_index('postid-userid', XMLDB_INDEX_NOTUNIQUE, array('postid', 'userid')); // Conditionally launch add index postid-userid. if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014040400, 'forum'); } // Moodle v2.7.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014051201) { // Incorrect values that need to be replaced. $replacements = array(11 => 20, 12 => 50, 13 => 100); // Run the replacements. foreach ($replacements as $old => $new) { $DB->set_field('forum', 'maxattachments', $new, array('maxattachments' => $old)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014051201, 'forum'); } if ($oldversion < 2014081500) { // Define index course (not unique) to be added to forum_discussions. $table = new xmldb_table('forum_discussions'); $index = new xmldb_index('course', XMLDB_INDEX_NOTUNIQUE, array('course')); // Conditionally launch add index course. if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014081500, 'forum'); } if ($oldversion < 2014081900) { // Define table forum_discussion_subs to be created. $table = new xmldb_table('forum_discussion_subs'); // Adding fields to table forum_discussion_subs. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('forum', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('discussion', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('preference', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1'); // Adding keys to table forum_discussion_subs. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('forum', XMLDB_KEY_FOREIGN, array('forum'), 'forum', array('id')); $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); $table->add_key('discussion', XMLDB_KEY_FOREIGN, array('discussion'), 'forum_discussions', array('id')); $table->add_key('user_discussions', XMLDB_KEY_UNIQUE, array('userid', 'discussion')); // Conditionally launch create table for forum_discussion_subs. if (!$dbman->table_exists($table)) { $dbman->create_table($table); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014081900, 'forum'); } if ($oldversion < 2014103000) { // Find records with multiple userid/postid combinations and find the lowest ID. // Later we will remove all those which don't match this ID. $sql = "\n SELECT MIN(id) as lowid, userid, postid\n FROM {forum_read}\n GROUP BY userid, postid\n HAVING COUNT(id) > 1"; if ($duplicatedrows = $DB->get_recordset_sql($sql)) { foreach ($duplicatedrows as $row) { $DB->delete_records_select('forum_read', 'userid = ? AND postid = ? AND id <> ?', array($row->userid, $row->postid, $row->lowid)); } } $duplicatedrows->close(); // Forum savepoint reached. upgrade_mod_savepoint(true, 2014103000, 'forum'); } if ($oldversion < 2014110300) { // Changing precision of field preference on table forum_discussion_subs to (10). $table = new xmldb_table('forum_discussion_subs'); $field = new xmldb_field('preference', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '1', 'discussion'); // Launch change of precision for field preference. $dbman->change_field_precision($table, $field); // Forum savepoint reached. upgrade_mod_savepoint(true, 2014110300, 'forum'); } // Moodle v2.8.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.9.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2015102900) { // Groupid = 0 is never valid. $DB->set_field('forum_discussions', 'groupid', -1, array('groupid' => 0)); // Forum savepoint reached. upgrade_mod_savepoint(true, 2015102900, 'forum'); } // Moodle v3.0.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2015120800) { // Add support for pinned discussions. $table = new xmldb_table('forum_discussions'); $field = new xmldb_field('pinned', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'timeend'); if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2015120800, 'forum'); } return true; }
/** * This file keeps track of upgrades to * the forum module * * Sometimes, changes between versions involve * alterations to database structures and other * major things that may break installations. * * The upgrade function in this file will attempt * to perform all the necessary actions to upgrade * your older installation to the current version. * * If there's something it cannot do itself, it * will tell you what you need to do. * * The commands in here will all be database-neutral, * using the methods of database_manager class * * Please do not forget to use upgrade_set_timeout() * before any action that may take longer time to finish. * * @package mod_hsuforum * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @copyright Copyright (c) 2012 Moodlerooms Inc. (http://www.moodlerooms.com) * @author Mark Nielsen */ function xmldb_hsuforum_upgrade($oldversion) { global $CFG, $DB, $OUTPUT; $dbman = $DB->get_manager(); // loads ddl manager and xmldb classes //===== 1.9.0 upgrade line ======// if ($oldversion < 2011112801) { /// HSUFORUM UPGRADES // Rename field hsuforum on table hsuforum_discussions to forum $table = new xmldb_table('hsuforum_discussions'); $field = new xmldb_field('hsuforum', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'course'); // Launch rename field hsuforum $dbman->rename_field($table, $field, 'forum'); // Rename field hsuforum on table hsuforum_subscriptions to forum $table = new xmldb_table('hsuforum_subscriptions'); $field = new xmldb_field('hsuforum', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'userid'); // Launch rename field hsuforum $dbman->rename_field($table, $field, 'forum'); // Rename field hsuforumid on table hsuforum_read to forumid $table = new xmldb_table('hsuforum_read'); $field = new xmldb_field('hsuforumid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'userid'); // Launch rename field hsuforumid $dbman->rename_field($table, $field, 'forumid'); // hsuforum_discussion_subscripts was too long of a name // Define table hsuforum_discussion_subscripts to be renamed to hsuforum_subscriptions_disc $table = new xmldb_table('hsuforum_discussion_subscripts'); // Launch rename table for hsuforum_discussion_subscripts $dbman->rename_table($table, 'hsuforum_subscriptions_disc'); /// HSUFORUM UPGRADES END //MDL-13866 - send forum ratins to gradebook again require_once $CFG->dirroot . '/mod/hsuforum/lib.php'; hsuforum_upgrade_grades(); upgrade_mod_savepoint(true, 2011112801, 'hsuforum'); } if ($oldversion < 2011112802) { /// Define field completiondiscussions to be added to forum $table = new xmldb_table('hsuforum'); $field = new xmldb_field('completiondiscussions'); $field->set_attributes(XMLDB_TYPE_INTEGER, '9', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'blockperiod'); /// Launch add field completiondiscussions if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } $field = new xmldb_field('completionreplies'); $field->set_attributes(XMLDB_TYPE_INTEGER, '9', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'completiondiscussions'); /// Launch add field completionreplies if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } /// Define field completionposts to be added to forum $field = new xmldb_field('completionposts'); $field->set_attributes(XMLDB_TYPE_INTEGER, '9', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'completionreplies'); /// Launch add field completionposts if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } upgrade_mod_savepoint(true, 2011112802, 'hsuforum'); } if ($oldversion < 2011112803) { ///////////////////////////////////// /// new file storage upgrade code /// ///////////////////////////////////// $fs = get_file_storage(); $empty = $DB->sql_empty(); // silly oracle empty string handling workaround $sqlfrom = "FROM {hsuforum_posts} p\n JOIN {hsuforum_discussions} d ON d.id = p.discussion\n JOIN {hsuforum} f ON f.id = d.forum\n JOIN {modules} m ON m.name = 'hsuforum'\n JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = f.id)\n WHERE p.attachment <> '{$empty}' AND p.attachment <> '1'"; $count = $DB->count_records_sql("SELECT COUNT('x') {$sqlfrom}"); $rs = $DB->get_recordset_sql("SELECT p.id, p.attachment, p.userid, d.forum, f.course, cm.id AS cmid {$sqlfrom} ORDER BY f.course, f.id, d.id"); if ($rs->valid()) { $pbar = new progress_bar('migrateforumfiles', 500, true); $i = 0; foreach ($rs as $post) { $i++; upgrade_set_timeout(60); // set up timeout, may also abort execution $pbar->update($i, $count, "Migrating forum posts - {$i}/{$count}."); $attachmentmigrated = false; $basepath = "{$CFG->dataroot}/{$post->course}/{$CFG->moddata}/hsuforum/{$post->forum}/{$post->id}"; $files = get_directory_list($basepath); foreach ($files as $file) { $filepath = "{$basepath}/{$file}"; if (!is_readable($filepath)) { //file missing?? echo $OUTPUT->notification("File not readable, skipping: " . $filepath); $post->attachment = ''; $DB->update_record('hsuforum_posts', $post); continue; } $context = context_module::instance($post->cmid); $filearea = 'attachment'; $filename = clean_param(pathinfo($filepath, PATHINFO_BASENAME), PARAM_FILE); if ($filename === '') { echo $OUTPUT->notification("Unsupported post filename, skipping: " . $filepath); $post->attachment = ''; $DB->update_record('hsuforum_posts', $post); continue; } if (!$fs->file_exists($context->id, 'mod_hsuforum', $filearea, $post->id, '/', $filename)) { $file_record = array('contextid' => $context->id, 'component' => 'mod_hsuforum', 'filearea' => $filearea, 'itemid' => $post->id, 'filepath' => '/', 'filename' => $filename, 'userid' => $post->userid); if ($fs->create_file_from_pathname($file_record, $filepath)) { $attachmentmigrated = true; unlink($filepath); } } } if ($attachmentmigrated) { $post->attachment = '1'; $DB->update_record('hsuforum_posts', $post); } // remove dirs if empty @rmdir("{$CFG->dataroot}/{$post->course}/{$CFG->moddata}/hsuforum/{$post->forum}/{$post->id}"); @rmdir("{$CFG->dataroot}/{$post->course}/{$CFG->moddata}/hsuforum/{$post->forum}"); @rmdir("{$CFG->dataroot}/{$post->course}/{$CFG->moddata}/hsuforum"); } } $rs->close(); upgrade_mod_savepoint(true, 2011112803, 'hsuforum'); } if ($oldversion < 2011112804) { /// Define field maxattachments to be added to forum $table = new xmldb_table('hsuforum'); $field = new xmldb_field('maxattachments', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1', 'maxbytes'); /// Conditionally launch add field maxattachments if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } /// HSUFORUM specific upgrades to maxattach and multiattach $field = new xmldb_field('maxattach', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '5'); if ($dbman->field_exists($table, $field)) { $DB->execute("\n UPDATE {hsuforum}\n SET maxattachments = maxattach\n "); $dbman->drop_field($table, $field); } $field = new xmldb_field('multiattach', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1'); if ($dbman->field_exists($table, $field)) { // This disabled attachments, so clear out maxattachments $DB->execute("\n UPDATE {hsuforum}\n SET maxattachments = 0\n WHERE multiattach = 0\n "); $dbman->drop_field($table, $field); } /// forum savepoint reached upgrade_mod_savepoint(true, 2011112804, 'hsuforum'); } if ($oldversion < 2011112805) { /// Rename field format on table hsuforum_posts to messageformat $table = new xmldb_table('hsuforum_posts'); $field = new xmldb_field('format', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'message'); /// Launch rename field format $dbman->rename_field($table, $field, 'messageformat'); /// forum savepoint reached upgrade_mod_savepoint(true, 2011112805, 'hsuforum'); } if ($oldversion < 2011112806) { /// Define field messagetrust to be added to hsuforum_posts $table = new xmldb_table('hsuforum_posts'); $field = new xmldb_field('messagetrust', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'messageformat'); /// Launch add field messagetrust $dbman->add_field($table, $field); /// forum savepoint reached upgrade_mod_savepoint(true, 2011112806, 'hsuforum'); } if ($oldversion < 2011112807) { $trustmark = '#####TRUSTTEXT#####'; $rs = $DB->get_recordset_sql("SELECT * FROM {hsuforum_posts} WHERE message LIKE ?", array($trustmark . '%')); foreach ($rs as $post) { if (strpos($post->message, $trustmark) !== 0) { // probably lowercase in some DBs? continue; } $post->message = str_replace($trustmark, '', $post->message); $post->messagetrust = 1; $DB->update_record('hsuforum_posts', $post); } $rs->close(); /// forum savepoint reached upgrade_mod_savepoint(true, 2011112807, 'hsuforum'); } if ($oldversion < 2011112808) { /// Define field introformat to be added to forum $table = new xmldb_table('hsuforum'); $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'intro'); /// Launch add field introformat if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // conditionally migrate to html format in intro if ($CFG->texteditors !== 'textarea') { $rs = $DB->get_recordset('hsuforum', array('introformat' => FORMAT_MOODLE), '', 'id,intro,introformat'); foreach ($rs as $f) { $f->intro = text_to_html($f->intro, false, false, true); $f->introformat = FORMAT_HTML; $DB->update_record('hsuforum', $f); upgrade_set_timeout(); } $rs->close(); } /// forum savepoint reached upgrade_mod_savepoint(true, 2011112808, 'hsuforum'); } /// Dropping all enums/check contraints from core. MDL-18577 if ($oldversion < 2011112809) { /// Changing list of values (enum) of field type on table forum to none $table = new xmldb_table('hsuforum'); $field = new xmldb_field('type', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, 'general', 'course'); /// Launch change of list of values for field type $dbman->drop_enum_from_field($table, $field); /// forum savepoint reached upgrade_mod_savepoint(true, 2011112809, 'hsuforum'); } if ($oldversion < 2011112810) { /// Clean existing wrong rates. MDL-18227 $DB->delete_records('hsuforum_ratings', array('post' => 0)); /// forum savepoint reached upgrade_mod_savepoint(true, 2011112810, 'hsuforum'); } if ($oldversion < 2011112811) { //migrate forumratings to the central rating table $table = new xmldb_table('hsuforum_ratings'); if ($dbman->table_exists($table)) { //forum ratings only have a single time column so use it for both time created and modified $sql = "INSERT INTO {rating} (contextid, component, ratingarea, scaleid, itemid, rating, userid, timecreated, timemodified)\n\n SELECT cxt.id, 'mod_hsuforum', 'post', f.scale, r.post AS itemid, r.rating, r.userid, r.time AS timecreated, r.time AS timemodified\n FROM {hsuforum_ratings} r\n JOIN {hsuforum_posts} p ON p.id=r.post\n JOIN {hsuforum_discussions} d ON d.id=p.discussion\n JOIN {hsuforum} f ON f.id=d.forum\n JOIN {course_modules} cm ON cm.instance=f.id\n JOIN {context} cxt ON cxt.instanceid=cm.id\n JOIN {modules} m ON m.id=cm.module\n WHERE m.name = :modname AND cxt.contextlevel = :contextlevel"; $params['modname'] = 'hsuforum'; $params['contextlevel'] = CONTEXT_MODULE; $DB->execute($sql, $params); //now drop hsuforum_ratings $dbman->drop_table($table); } upgrade_mod_savepoint(true, 2011112811, 'hsuforum'); } if ($oldversion < 2011112812) { // Remove the forum digests message provider MDL-23145 $DB->delete_records('message_providers', array('name' => 'digests', 'component' => 'mod_hsuforum')); // forum savepoint reached upgrade_mod_savepoint(true, 2011112812, 'hsuforum'); } if ($oldversion < 2011112813) { // rename files from borked upgrade in 2.0dev $fs = get_file_storage(); $rs = $DB->get_recordset('files', array('component' => 'mod_form')); foreach ($rs as $oldrecord) { $file = $fs->get_file_instance($oldrecord); $newrecord = array('component' => 'mod_hsuforum'); if (!$fs->file_exists($oldrecord->contextid, 'mod_hsuforum', $oldrecord->filearea, $oldrecord->itemid, $oldrecord->filepath, $oldrecord->filename)) { $fs->create_file_from_storedfile($newrecord, $file); } $file->delete(); } $rs->close(); upgrade_mod_savepoint(true, 2011112813, 'hsuforum'); } if ($oldversion < 2011112814) { // rating.component and rating.ratingarea have now been added as mandatory fields. // Presently you can only rate forum posts so component = 'mod_hsuforum' and ratingarea = 'post' // for all ratings with a forum context. // We want to update all ratings that belong to a forum context and don't already have a // component set. // This could take a while reset upgrade timeout to 5 min upgrade_set_timeout(60 * 20); $sql = "UPDATE {rating}\n SET component = 'mod_hsuforum', ratingarea = 'post'\n WHERE contextid IN (\n SELECT ctx.id\n FROM {context} ctx\n JOIN {course_modules} cm ON cm.id = ctx.instanceid\n JOIN {modules} m ON m.id = cm.module\n WHERE ctx.contextlevel = 70 AND\n m.name = 'hsuforum'\n ) AND component = 'unknown'"; $DB->execute($sql); upgrade_mod_savepoint(true, 2011112814, 'hsuforum'); } // Moodle v2.1.0 release upgrade line // Put any upgrade step following this // Moodle v2.2.0 release upgrade line // Put any upgrade step following this if ($oldversion < 2011112907) { /// Conditionally add field privatereply to be added to hsuforum $table = new xmldb_table('hsuforum_posts'); $field = new xmldb_field('privatereply'); $field->set_attributes(XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'flags'); if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Define index privatereply (not unique) to be added to hsuforum_posts $table = new xmldb_table('hsuforum_posts'); $index = new xmldb_index('privatereply', XMLDB_INDEX_NOTUNIQUE, array('privatereply')); // Conditionally launch add index privatereply if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Rename field hsuforumid on table hsuforum_track_prefs to forumid $table = new xmldb_table('hsuforum_track_prefs'); $field = new xmldb_field('hsuforumid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'userid'); // Conditionally launch rename field hsuforumid (if it exists) if ($dbman->field_exists($table, $field)) { $dbman->rename_field($table, $field, 'forumid'); } // hsuforum savepoint reached upgrade_mod_savepoint(true, 2011112907, 'hsuforum'); } // Moodle v2.2.0 release upgrade line // Put any upgrade step following this // Moodle v2.3.0 release upgrade line // Put any upgrade step following this // Moodle v2.4.0 release upgrade line // Put any upgrade step following this // Forcefully assign mod/hsuforum:allowforcesubscribe to frontpage role, as we missed that when // capability was introduced. if ($oldversion < 2012112901) { // If capability mod/hsuforum:allowforcesubscribe is defined then set it for frontpage role. if (get_capability_info('mod/hsuforum:allowforcesubscribe')) { assign_legacy_capabilities('mod/hsuforum:allowforcesubscribe', array('frontpage' => CAP_ALLOW)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2012112901, 'hsuforum'); } if ($oldversion < 2012112902) { // Forum and hsuforum were reading from the same $CFG values, create new ones for hsuforum. $digestmailtime = 17; // Default in settings.php if (!empty($CFG->digestmailtime)) { $digestmailtime = $CFG->digestmailtime; } set_config('hsuforum_digestmailtime', $digestmailtime); $digestmailtimelast = 0; if (!empty($CFG->digestmailtimelast)) { $digestmailtimelast = $CFG->digestmailtimelast; } set_config('hsuforum_digestmailtimelast', $digestmailtimelast); // Forum savepoint reached. upgrade_mod_savepoint(true, 2012112902, 'hsuforum'); } if ($oldversion < 2013020500) { // Define field displaywordcount to be added to forum. $table = new xmldb_table('hsuforum'); $field = new xmldb_field('displaywordcount', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'completionposts'); // Conditionally launch add field displaywordcount. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013020500, 'hsuforum'); } // Moodle v2.5.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014021900) { // Define table hsuforum_digests to be created. $table = new xmldb_table('hsuforum_digests'); // Adding fields to table hsuforum_digests. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('forum', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('maildigest', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '-1'); // Adding keys to table hsuforum_digests. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); $table->add_key('forum', XMLDB_KEY_FOREIGN, array('forum'), 'forum', array('id')); $table->add_key('forumdigest', XMLDB_KEY_UNIQUE, array('forum', 'userid', 'maildigest')); // Conditionally launch create table for hsuforum_digests. if (!$dbman->table_exists($table)) { $dbman->create_table($table); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014021900, 'hsuforum'); } // Moodle v2.6.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014040400) { // Define index userid-postid (not unique) to be dropped form hsuforum_read. $table = new xmldb_table('hsuforum_read'); $index = new xmldb_index('userid-postid', XMLDB_INDEX_NOTUNIQUE, array('userid', 'postid')); // Conditionally launch drop index userid-postid. if ($dbman->index_exists($table, $index)) { $dbman->drop_index($table, $index); } // Define index postid-userid (not unique) to be added to hsuforum_read. $index = new xmldb_index('postid-userid', XMLDB_INDEX_NOTUNIQUE, array('postid', 'userid')); // Conditionally launch add index postid-userid. if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014040400, 'hsuforum'); } // Moodle v2.7.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014051201) { // Incorrect values that need to be replaced. $replacements = array(11 => 20, 12 => 50, 13 => 100); // Run the replacements. foreach ($replacements as $old => $new) { $DB->set_field('hsuforum', 'maxattachments', $new, array('maxattachments' => $old)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014051201, 'hsuforum'); } if ($oldversion < 2014051203) { // Find records with multiple userid/postid combinations and find the lowest ID. // Later we will remove all those which don't match this ID. $sql = "\n SELECT MIN(id) as lowid, userid, postid\n FROM {hsuforum_read}\n GROUP BY userid, postid\n HAVING COUNT(id) > 1"; if ($duplicatedrows = $DB->get_recordset_sql($sql)) { foreach ($duplicatedrows as $row) { $DB->delete_records_select('hsuforum_read', 'userid = ? AND postid = ? AND id <> ?', array($row->userid, $row->postid, $row->lowid)); } } $duplicatedrows->close(); // Forum savepoint reached. upgrade_mod_savepoint(true, 2014051203, 'hsuforum'); } if ($oldversion < 2014092400) { // Define fields to be added to hsuforum table. $table = new xmldb_table('hsuforum'); $fields = array(); $fields[] = new xmldb_field('showsubstantive', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'displaywordcount'); $fields[] = new xmldb_field('showbookmark', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'showsubstantive'); // Go through each field and add if it doesn't already exist. foreach ($fields as $field) { // Conditionally launch add field. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } } // Hsuforum savepoint reached. upgrade_mod_savepoint(true, 2014092400, 'hsuforum'); } if ($oldversion < 2014093000) { // Define fields to be added to hsuforum table. $table = new xmldb_table('hsuforum'); $field = new xmldb_field('allowprivatereplies', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'showbookmark'); // Conditionally launch add field. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Hsuforum savepoint reached. upgrade_mod_savepoint(true, 2014093000, 'hsuforum'); } if ($oldversion < 2014093001) { // Set default settings for existing forums. $DB->execute("\n UPDATE {hsuforum}\n SET allowprivatereplies = 1,\n showsubstantive = 1,\n showbookmark = 1\n\n "); // Hsuforum savepoint reached. upgrade_mod_savepoint(true, 2014093001, 'hsuforum'); } // Convert global configs to plugin configs if ($oldversion < 2014100600) { $configs = array('allowforcedreadtracking', 'cleanreadtime', 'digestmailtime', 'digestmailtimelast', 'disablebookmark', 'disablesubstantive', 'displaymode', 'enablerssfeeds', 'enabletimedposts', 'lastreadclean', 'longpost', 'manydiscussions', 'maxattachments', 'maxbytes', 'oldpostdays', 'replytouser', 'shortpost', 'showbookmark', 'showsubstantive', 'trackingtype', 'trackreadposts', 'usermarksread'); // Migrate legacy configs to plugin configs. foreach ($configs as $config) { $oldvar = 'hsuforum_' . $config; if (isset($CFG->{$oldvar})) { // Set new config variable up based on legacy config. set_config($config, $CFG->{$oldvar}, 'hsuforum'); // Delete legacy config. unset_config($oldvar); } } // Hsuforum savepoint reached. upgrade_mod_savepoint(true, 2014100600, 'hsuforum'); } if ($oldversion < 2014121700) { // Define fields to be added to hsuforum table. $table = new xmldb_table('hsuforum'); $field = new xmldb_field('showrecent', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'displaywordcount'); // Conditionally launch add field. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Hsuforum savepoint reached. upgrade_mod_savepoint(true, 2014121700, 'hsuforum'); } return true; }
/** * This file keeps track of upgrades to * the forum module * * Sometimes, changes between versions involve * alterations to database structures and other * major things that may break installations. * * The upgrade function in this file will attempt * to perform all the necessary actions to upgrade * your older installation to the current version. * * If there's something it cannot do itself, it * will tell you what you need to do. * * The commands in here will all be database-neutral, * using the methods of database_manager class * * Please do not forget to use upgrade_set_timeout() * before any action that may take longer time to finish. * * @package mod_forum * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ function xmldb_forum_upgrade($oldversion) { global $CFG, $DB, $OUTPUT; $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. // Moodle v2.2.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.3.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.4.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013020500) { // Define field displaywordcount to be added to forum. $table = new xmldb_table('forum'); $field = new xmldb_field('displaywordcount', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'completionposts'); // Conditionally launch add field displaywordcount. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013020500, 'forum'); } // Forcefully assign mod/forum:allowforcesubscribe to frontpage role, as we missed that when // capability was introduced. if ($oldversion < 2013021200) { // If capability mod/forum:allowforcesubscribe is defined then set it for frontpage role. if (get_capability_info('mod/forum:allowforcesubscribe')) { assign_legacy_capabilities('mod/forum:allowforcesubscribe', array('frontpage' => CAP_ALLOW)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013021200, 'forum'); } // Moodle v2.5.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2013071000) { // Define table forum_digests to be created. $table = new xmldb_table('forum_digests'); // Adding fields to table forum_digests. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('forum', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null); $table->add_field('maildigest', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '-1'); // Adding keys to table forum_digests. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); $table->add_key('forum', XMLDB_KEY_FOREIGN, array('forum'), 'forum', array('id')); $table->add_key('forumdigest', XMLDB_KEY_UNIQUE, array('forum', 'userid', 'maildigest')); // Conditionally launch create table for forum_digests. if (!$dbman->table_exists($table)) { $dbman->create_table($table); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2013071000, 'forum'); } // Moodle v2.6.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014040400) { // Define index userid-postid (not unique) to be dropped form forum_read. $table = new xmldb_table('forum_read'); $index = new xmldb_index('userid-postid', XMLDB_INDEX_NOTUNIQUE, array('userid', 'postid')); // Conditionally launch drop index userid-postid. if ($dbman->index_exists($table, $index)) { $dbman->drop_index($table, $index); } // Define index postid-userid (not unique) to be added to forum_read. $index = new xmldb_index('postid-userid', XMLDB_INDEX_NOTUNIQUE, array('postid', 'userid')); // Conditionally launch add index postid-userid. if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014040400, 'forum'); } // Moodle v2.7.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014051201) { // Incorrect values that need to be replaced. $replacements = array(11 => 20, 12 => 50, 13 => 100); // Run the replacements. foreach ($replacements as $old => $new) { $DB->set_field('forum', 'maxattachments', $new, array('maxattachments' => $old)); } // Forum savepoint reached. upgrade_mod_savepoint(true, 2014051201, 'forum'); } return true; }
/** * Is the user allowed to add this type of module to this course? * @param object $course the course settings. Only $course->id is used. * @param string $modname the module name. E.g. 'forum' or 'quiz'. * @return bool whether the current user is allowed to add this type of module to this course. */ function course_allowed_module($course, $modname) { global $DB; if (is_numeric($modname)) { throw new coding_exception('Function course_allowed_module no longer supports numeric module ids. Please update your code to pass the module name.'); } $capability = 'mod/' . $modname . ':addinstance'; if (!get_capability_info($capability)) { // Debug warning that the capability does not exist, but no more than once per page. static $warned = array(); $archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER); if (!isset($warned[$modname]) && $archetype !== MOD_ARCHETYPE_SYSTEM) { debugging('The module ' . $modname . ' does not define the standard capability ' . $capability, DEBUG_DEVELOPER); $warned[$modname] = 1; } // If the capability does not exist, the module can always be added. return true; } $coursecontext = context_course::instance($course->id); return has_capability($capability, $coursecontext); }
/** * Allows/denies a capability at the specified context * * @throws Exception * @param array $data * @return void */ protected function process_permission_override($data) { // Will throw an exception if it does not exist. $context = $this->get_context($data['contextlevel'], $data['reference']); switch ($data['permission']) { case get_string('allow', 'role'): $permission = CAP_ALLOW; break; case get_string('prevent', 'role'): $permission = CAP_PREVENT; break; case get_string('prohibit', 'role'): $permission = CAP_PROHIBIT; break; default: throw new Exception('The \'' . $data['permission'] . '\' permission does not exist'); break; } if (is_null(get_capability_info($data['capability']))) { throw new Exception('The \'' . $data['capability'] . '\' capability does not exist'); } role_change_permission($data['roleid'], $context, $data['capability'], $permission); }
/** * Function used to return a list of users where the given user has a particular capability. * * This is used e.g. to find all the users where someone is able to manage their learning plans, * it also would be useful for mentees etc. * * @param string $capability - The capability string we are filtering for. If '' is passed, * an always matching filter is returned. * @param int $userid - The user id we are using for the access checks. Defaults to current user. * @param int $type - The type of named params to return (passed to $DB->get_in_or_equal). * @param string $prefix - The type prefix for the db table (passed to $DB->get_in_or_equal). * @return list($sql, $params) Same as $DB->get_in_or_equal(). * @todo MDL-52243 Move this function to lib/accesslib.php */ public static function filter_users_with_capability_on_user_context_sql($capability, $userid = 0, $type = SQL_PARAMS_QM, $prefix = 'param') { global $USER, $DB; $allresultsfilter = array('> 0', array()); $noresultsfilter = array('= -1', array()); if (empty($capability)) { return $allresultsfilter; } if (!($capinfo = get_capability_info($capability))) { throw new coding_exception('Capability does not exist: ' . $capability); } if (empty($userid)) { $userid = $USER->id; } // Make sure the guest account and not-logged-in users never get any risky caps no matter what the actual settings are. if ($capinfo->captype === 'write' or $capinfo->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS)) { if (isguestuser($userid) or $userid == 0) { return $noresultsfilter; } } if (is_siteadmin($userid)) { // No filtering for site admins. return $allresultsfilter; } // Check capability on system level. $syscontext = context_system::instance(); $hassystem = has_capability($capability, $syscontext, $userid); $access = get_user_access_sitewide($userid); // Build up a list of level 2 contexts (candidates to be user context). $filtercontexts = array(); foreach ($access['ra'] as $path => $role) { $parts = explode('/', $path); if (count($parts) == 3) { $filtercontexts[$parts[2]] = $parts[2]; } else { if (count($parts) > 3) { // We know this is not a user context because there is another path with more than 2 levels. unset($filtercontexts[$parts[2]]); } } } // Add all contexts in which a role may be overidden. foreach ($access['rdef'] as $pathandroleid => $def) { $matches = array(); if (!isset($def[$capability])) { // The capability is not mentioned, we can ignore. continue; } list($contextpath, $roleid) = explode(':', $pathandroleid, 2); $parts = explode('/', $contextpath); if (count($parts) != 3) { // Only get potential user contexts, they only ever have 2 slashes /parentId/Id. continue; } $filtercontexts[$parts[2]] = $parts[2]; } // No interesting contexts - return all or no results. if (empty($filtercontexts)) { if ($hassystem) { return $allresultsfilter; } else { return $noresultsfilter; } } // Fetch all interesting contexts for further examination. list($insql, $params) = $DB->get_in_or_equal($filtercontexts, SQL_PARAMS_NAMED); $params['level'] = CONTEXT_USER; $fields = context_helper::get_preload_record_columns_sql('ctx'); $interestingcontexts = $DB->get_recordset_sql('SELECT ' . $fields . ' FROM {context} ctx WHERE ctx.contextlevel = :level AND ctx.id ' . $insql . ' ORDER BY ctx.id', $params); if ($hassystem) { // If allowed at system, search for exceptions prohibiting the capability at user context. $excludeusers = array(); foreach ($interestingcontexts as $contextrecord) { $candidateuserid = $contextrecord->ctxinstance; context_helper::preload_from_record($contextrecord); $usercontext = context_user::instance($candidateuserid); // Has capability should use the data already preloaded. if (!has_capability($capability, $usercontext, $userid)) { $excludeusers[$candidateuserid] = $candidateuserid; } } // Construct SQL excluding users with this role assigned for this user. if (empty($excludeusers)) { $interestingcontexts->close(); return $allresultsfilter; } list($sql, $params) = $DB->get_in_or_equal($excludeusers, $type, $prefix, false); } else { // If not allowed at system, search for exceptions allowing the capability at user context. $allowusers = array(); foreach ($interestingcontexts as $contextrecord) { $candidateuserid = $contextrecord->ctxinstance; context_helper::preload_from_record($contextrecord); $usercontext = context_user::instance($candidateuserid); // Has capability should use the data already preloaded. if (has_capability($capability, $usercontext, $userid)) { $allowusers[$candidateuserid] = $candidateuserid; } } // Construct SQL excluding users with this role assigned for this user. if (empty($allowusers)) { $interestingcontexts->close(); return $noresultsfilter; } list($sql, $params) = $DB->get_in_or_equal($allowusers, $type, $prefix); } $interestingcontexts->close(); // Return the goods!. return array($sql, $params); }
/** * Check whether a user has a particular capability in a given context. * * For example: * $context = get_context_instance(CONTEXT_MODULE, $cm->id); * has_capability('mod/forum:replypost',$context) * * By default checks the capabilities of the current user, but you can pass a * different userid. By default will return true for admin users, but you can override that with the fourth argument. * * Guest and not-logged-in users can never get any dangerous capability - that is any write capability * or capabilities with XSS, config or data loss risks. * * @param string $capability the name of the capability to check. For example mod/forum:view * @param context $context the context to check the capability in. You normally get this with {@link get_context_instance}. * @param integer|object $user A user id or object. By default (null) checks the permissions of the current user. * @param boolean $doanything If false, ignores effect of admin role assignment * @return boolean true if the user has this capability. Otherwise false. */ function has_capability($capability, context $context, $user = null, $doanything = true) { global $USER, $CFG, $SCRIPT, $ACCESSLIB_PRIVATE; if (during_initial_install()) { if ($SCRIPT === "/{$CFG->admin}/index.php" or $SCRIPT === "/{$CFG->admin}/cli/install.php" or $SCRIPT === "/{$CFG->admin}/cli/install_database.php") { // we are in an installer - roles can not work yet return true; } else { return false; } } if (strpos($capability, 'moodle/legacy:') === 0) { throw new coding_exception('Legacy capabilities can not be used any more!'); } if (!is_bool($doanything)) { throw new coding_exception('Capability parameter "doanything" is wierd, only true or false is allowed. This has to be fixed in code.'); } // capability must exist if (!($capinfo = get_capability_info($capability))) { debugging('Capability "' . $capability . '" was not found! This has to be fixed in code.'); return false; } if (!isset($USER->id)) { // should never happen $USER->id = 0; } // make sure there is a real user specified if ($user === null) { $userid = $USER->id; } else { $userid = is_object($user) ? $user->id : $user; } // make sure forcelogin cuts off not-logged-in users if enabled if (!empty($CFG->forcelogin) and $userid == 0) { return false; } // make sure the guest account and not-logged-in users never get any risky caps no matter what the actual settings are. if ($capinfo->captype === 'write' or $capinfo->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS)) { if (isguestuser($userid) or $userid == 0) { return false; } } // somehow make sure the user is not deleted and actually exists if ($userid != 0) { if ($userid == $USER->id and isset($USER->deleted)) { // this prevents one query per page, it is a bit of cheating, // but hopefully session is terminated properly once user is deleted if ($USER->deleted) { return false; } } else { if (!context_user::instance($userid, IGNORE_MISSING)) { // no user context == invalid userid return false; } } } // context path/depth must be valid if (empty($context->path) or $context->depth == 0) { // this should not happen often, each upgrade tries to rebuild the context paths debugging('Context id ' . $context->id . ' does not have valid path, please use build_context_path()'); if (is_siteadmin($userid)) { return true; } else { return false; } } // Find out if user is admin - it is not possible to override the doanything in any way // and it is not possible to switch to admin role either. if ($doanything) { if (is_siteadmin($userid)) { if ($userid != $USER->id) { return true; } // make sure switchrole is not used in this context if (empty($USER->access['rsw'])) { return true; } $parts = explode('/', trim($context->path, '/')); $path = ''; $switched = false; foreach ($parts as $part) { $path .= '/' . $part; if (!empty($USER->access['rsw'][$path])) { $switched = true; break; } } if (!$switched) { return true; } //ok, admin switched role in this context, let's use normal access control rules } } // Careful check for staleness... $context->reload_if_dirty(); if ($USER->id == $userid) { if (!isset($USER->access)) { load_all_capabilities(); } $access =& $USER->access; } else { // make sure user accessdata is really loaded get_user_accessdata($userid, true); $access =& $ACCESSLIB_PRIVATE->accessdatabyuser[$userid]; } // Load accessdata for below-the-course context if necessary, // all contexts at and above all courses are already loaded if ($context->contextlevel != CONTEXT_COURSE and $coursecontext = $context->get_course_context(false)) { load_course_context($userid, $coursecontext, $access); } return has_capability_in_accessdata($capability, $context, $access); }
* * This tool lets the adminstrator edit the definition for all roles for one * particular capability. So, for example, suppose you want to make sure that * only certain roles have the mod/quiz:preview capability, then this is the * tool for you. You can do that on one page, without having to click through * the pages that show each different role definition. * * @package tool_editrolesbycap * @copyright 2012 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once dirname(__FILE__) . '/../../../config.php'; require_once dirname(__FILE__) . '/locallib.php'; require_once $CFG->libdir . '/adminlib.php'; $cap = optional_param('cap', '', PARAM_CAPABILITY); $capability = get_capability_info($cap); require_login(); $context = context_system::instance(); require_capability('moodle/role:manage', $context); $showadvanced = get_user_preferences('definerole_showadvanced', false); if (optional_param('toggleadvanced', false, PARAM_BOOL)) { $showadvanced = !$showadvanced; set_user_preference('definerole_showadvanced', $showadvanced); } $params = array(); if ($capability) { $capability->name = $cap; $params['cap'] = $capability->name; } admin_externalpage_setup('tooleditrolesbycap', '', $params); $form = new tool_editrolesbycap_capability_form(new moodle_url('/admin/tool/editrolesbycap/index.php'), $params);