Commit 3a0c6cca authored by skodak's avatar skodak
Browse files

MDL-8521 new feature - safe overrides, see tracker for details; merged from MOODLE_19_STABLE

parent 488aa8f8
......@@ -74,7 +74,7 @@
$table->data[] = array_merge(array(format_string($role->name)), $beta);
}
print_simple_box(get_string('configallowoverride', 'admin'), 'center');
print_simple_box(get_string('configallowoverride2', 'admin'), 'center');
echo '<form action="allowoverride.php" method="post">';
print_table($table);
......
......@@ -66,7 +66,6 @@
$overridableroles = get_overridable_roles($context, 'name', ROLENAME_BOTH);
$assignableroles = get_assignable_roles($context, 'name', ROLENAME_BOTH);
/// Get some language strings
$strpotentialusers = get_string('potentialusers', 'role');
......@@ -108,7 +107,7 @@
/// Make sure this user can assign that role
if ($roleid) {
if (!user_can_assign($context, $roleid)) {
if (!isset($assignableroles[$roleid])) {
error ('you can not override this role in this context');
}
}
......
......@@ -3,6 +3,7 @@
$strallow = get_string('allow','role');
$strprevent = get_string('prevent','role');
$strprohibit = get_string('prohibit','role');
$strsafewarning = get_string('safeoverridenotice', 'role');
?>
<form id="overrideform" action="override.php" method="post">
......@@ -67,7 +68,7 @@
$isprohibit = 0;
}
$isdisabled = $isprohibit;
$isdisabled = $isprohibit || $capability->locked;
$riskinfo = '<td class="risk managetrust">';
$rowclasses = '';
......@@ -138,10 +139,17 @@
<?php echo $riskinfo; ?>
</tr>
<?php } ?>
<?php } ?>
</table>
<div class="submit buttons">
<input type="submit" value="<?php print_string('savechanges') ?>" />
<input type="submit" name="cancel" value="<?php print_string('cancel') ?>" />
</div>
<?php
if ($safeoverridenotice) {
echo '<div class="sefeoverridenotice">'.$strsafewarning.'</div>';
}
?>
</form>
......@@ -20,7 +20,9 @@
print_error('cannotoverridebaserole', 'error');
}
if (!has_capability('moodle/role:override', $context)) {
$canoverride = has_capability('moodle/role:override', $context);
if (!$canoverride and !has_capability('moodle/role:safeoverride', $context)) {
print_error('nopermissions', 'error', '', 'change overrides in this context!');
}
......@@ -61,7 +63,7 @@
/// Make sure this user can override that role
if ($roleid) {
if (!user_can_override($context, $roleid)) {
if (!isset($overridableroles[$roleid])) {
error ('you can not override this role in this context');
}
}
......@@ -72,7 +74,30 @@
}
/// get all cababilities
$capabilities = fetch_context_capabilities($context);
$safeoverridenotice = false;
if ($roleid) {
if ($capabilities = fetch_context_capabilities($context)) {
// find out if we need to lock some capabilities
foreach ($capabilities as $capname=>$capability) {
$capabilities[$capname]->locked = false;
if ($canoverride) {
//ok no locking at all
continue;
}
//only limited safe overrides - spam only allowed
if ((RISK_DATALOSS & (int)$capability->riskbitmask)
or (RISK_MANAGETRUST & (int)$capability->riskbitmask)
or (RISK_CONFIG & (int)$capability->riskbitmask)
or (RISK_XSS & (int)$capability->riskbitmask)
or (RISK_PERSONAL & (int)$capability->riskbitmask)) {
$capabilities[$capname]->locked = true;
$safeoverridenotice = true;
}
}
}
} else {
$capabilities = null;
}
/// Process incoming role override
if ($data = data_submitted() and $roleid and confirm_sesskey()) {
......@@ -82,6 +107,10 @@
'', 'capability, permission, id');
foreach ($capabilities as $cap) {
if ($cap->locked) {
//user not allowed to change this cap
continue;
}
if (!isset($data->{$cap->name})) {
//cap not specified in form
......@@ -179,7 +208,7 @@
if (!empty($capabilities)) {
// Print the capabilities overrideable in this context
print_simple_box_start('center');
include_once('override.html');
include('override.html');
print_simple_box_end();
} else {
......
......@@ -63,10 +63,14 @@ class block_admin extends block_list {
/// Assign roles to the course
if ($course->id !== SITEID and has_capability('moodle/role:assign', $context)) {
$this->content->items[]='<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id.'">'.get_string('assignroles', 'role').'</a>';
$this->content->icons[]='<img src="'.$CFG->pixpath.'/i/roles.gif" class="icon" alt="" />';
if ($course->id != SITEID) {
if (has_capability('moodle/role:assign', $context)) {
$this->content->items[]='<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id.'">'.get_string('assignroles', 'role').'</a>';
$this->content->icons[]='<img src="'.$CFG->pixpath.'/i/roles.gif" class="icon" alt="" />';
} else if (get_overridable_roles($context, 'name', ROLENAME_ORIGINAL)) {
$this->content->items[]='<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/override.php?contextid='.$context->id.'">'.get_string('overridepermissions', 'role').'</a>';
$this->content->icons[]='<img src="'.$CFG->pixpath.'/i/roles.gif" class="icon" alt="" />';
}
}
/// View course grades (or just your own grades, same link)
......
......@@ -60,6 +60,7 @@ $string['configallowcoursethemes'] = 'If you enable this, then courses will be a
$string['configallowemailaddresses'] = 'If you want to restrict all new email addresses to particular domains, then list them here separated by spaces. All other domains will be rejected. To allow subdomains add the domain with a preceding \'.\'. eg <strong>ourcollege.edu.au .gov.au</strong>';
$string['configallowobjectembed'] = 'As a default security measure, normal users are not allowed to embed multimedia (like Flash) within texts using explicit EMBED and OBJECT tags in their HTML (although it can still be done safely using the mediaplugins filter). If you wish to allow these tags then enable this option.';
$string['configallowoverride'] = 'You can allow people with the roles on the left side to override some of the column roles';
$string['configallowoverride2'] = 'Select which role(s) can be overridden by each role in the left column.<br />Note that these settings only apply to users who have either the capability moodle/role:override or the capability moodle/role:safeoverride allowed.';
$string['configallowunenroll'] = 'If this is set \'Yes\', then students are allowed to unenrol themselves from courses whenever they like. Otherwise they are not allowed, and this process will be solely controlled by the teachers and administrators.';
$string['configallowuserblockhiding'] = 'Do you want to allow users to hide/show side blocks throughout this site? This feature uses Javascript and cookies to remember the state of each collapsible block, and only affects the user\'s own view.';
$string['configallowusermailcharset'] = 'Enabling this, every user in the site will be able to specify his own charset for email.';
......
......@@ -124,6 +124,7 @@ $string['risks'] = 'Risks';
$string['role:assign'] = 'Assign roles to users';
$string['role:manage'] = 'Create and manage roles';
$string['role:override'] = 'Override permissions for others';
$string['role:safeoverride'] = 'Override safe permissions for others';
$string['role:switchroles'] = 'Switch to other roles';
$string['role:unassignself'] = 'Unassign own roles';
$string['role:viewhiddenassigns'] = 'View hidden role assignments';
......@@ -131,6 +132,7 @@ $string['roleassignments'] = 'Role assignments';
$string['roles'] = 'Roles';
$string['roletoassign'] = 'Role to assign';
$string['roletooverride'] = 'Role to override';
$string['safeoverridenotice'] = 'Note: Capabilities with higher risks are locked because you are only allowed to override safe capabilities.';
$string['selectrole'] = 'Select a role';
$string['showallroles'] = 'Show all roles';
$string['site:accessallgroups'] = 'Access all groups';
......
......@@ -149,6 +149,7 @@ define('RISK_CONFIG', 0x0002);
define('RISK_XSS', 0x0004);
define('RISK_PERSONAL', 0x0008);
define('RISK_SPAM', 0x0010);
define('RISK_DATALOSS', 0x0020);
// rolename displays
define('ROLENAME_ORIGINAL', 0);// the name as defined in the role definition
......@@ -1756,7 +1757,7 @@ function moodle_install_roles() {
allow_assign($editteacherrole, $studentrole);
allow_assign($editteacherrole, $guestrole);
/// Set up default permissions for overrides
/// Set up default allow override matrix
allow_override($adminrole, $adminrole);
allow_override($adminrole, $coursecreatorrole);
allow_override($adminrole, $noneditteacherrole);
......@@ -1764,6 +1765,11 @@ function moodle_install_roles() {
allow_override($adminrole, $studentrole);
allow_override($adminrole, $guestrole);
allow_override($adminrole, $userrole);
allow_override($editteacherrole, $noneditteacherrole);
allow_override($editteacherrole, $studentrole);
allow_override($editteacherrole, $guestrole);
}
/**
......@@ -3815,6 +3821,9 @@ function get_user_roles_in_context($userid, $context, $view=true){
* @return boolean
*/
function user_can_override($context, $targetroleid) {
// TODO: not needed anymore, remove in 2.0
global $DB;
// first check if user has override capability
// if not return false;
......@@ -3954,45 +3963,33 @@ function allow_assign($sroleid, $troleid) {
* Gets a list of roles that this user can assign in this context
* @param object $context
* @param string $field
* @param int $rolenamedisplay
* @return array
*/
function get_assignable_roles($context, $field='name', $rolenamedisplay=ROLENAME_ALIAS) {
global $DB;
// this users RAs
$ras = get_user_roles($context);
$roleids = array();
foreach ($ras as $ra) {
$roleids[] = $ra->roleid;
}
unset($ra);
global $USER, $DB;
if (count($roleids)===0) {
if (!has_capability('moodle/role:assign', $context)) {
return array();
}
list($roleids, $params) = $DB->get_in_or_equal($roleids, SQL_PARAMS_QM);
// The subselect scopes the DISTINCT down to
// the role ids - a DISTINCT over the whole of
// the role table is much more expensive on some DBs
$sql = "SELECT r.id, r.$field
FROM {role} r
JOIN ( SELECT DISTINCT allowassign as allowedrole
FROM {role_allow_assign} raa
WHERE raa.roleid $roleids ) ar
ON r.id=ar.allowedrole
ORDER BY sortorder ASC";
if (!$rs = $DB->get_recordset_sql($sql, $params)) {
}
$parents = get_parent_contexts($context);
$parents[] = $context->id;
$contexts = implode(',' , $parents);
if (!$roles = $DB->get_records_sql("SELECT DISTINCT r.*
FROM {role} r,
{role_assignments} ra,
{role_allow_assign} raa
WHERE ra.userid = :userid AND ra.contextid IN ($contexts)
AND raa.roleid = ra.roleid AND r.id = raa.allowassign
ORDER BY r.sortorder ASC", array('userid'=>$USER->id))) {
return array();
}
$roles = array();
foreach ($rs as $r) {
$roles[$r->id] = $r->{$field};
foreach ($roles as $role) {
$roles[$role->id] = $role->$field;
}
$rs->close();
return role_fix_names($roles, $context, $rolenamedisplay);
}
......@@ -4000,53 +3997,37 @@ function get_assignable_roles($context, $field='name', $rolenamedisplay=ROLENAME
/**
* Gets a list of roles that this user can assign in this context, for the switchrole menu
*
* This is a quick-fix for MDL-13459 until MDL-8312 is sorted out...
* @param object $context
* @param string $field
* @param int $rolenamedisplay
* @return array
*/
function get_assignable_roles_for_switchrole($context, $field='name', $rolenamedisplay=ROLENAME_ALIAS) {
global $DB;
// this users RAs
$ras = get_user_roles($context);
$roleids = array();
foreach ($ras as $ra) {
$roleids[] = $ra->roleid;
}
unset($ra);
global $USER, $DB;
if (count($roleids)===0) {
if (!has_capability('moodle/role:assign', $context)) {
return array();
}
list($roleids, $params) = $DB->get_in_or_equal($roleids, SQL_PARAMS_QM);
// The subselect scopes the DISTINCT down to
// the role ids - a DISTINCT over the whole of
// the role table is much more expensive on some DBs
$sql = "SELECT r.id, r.$field
FROM {role} r
JOIN ( SELECT DISTINCT allowassign as allowedrole
FROM {role_allow_assign} raa
WHERE raa.roleid $roleids ) ar
ON r.id=ar.allowedrole
JOIN {role_capabilities} rc
ON (r.id = rc.roleid AND rc.capability = ?
AND rc.capability != ?)
ORDER BY sortorder ASC";
$params[] = 'moodle/course:view';
$params[] = 'moodle/site:doanything';
if (!$rs = $DB->get_recordset_sql($sql, $params)) {
}
$parents = get_parent_contexts($context);
$parents[] = $context->id;
$contexts = implode(',' , $parents);
if (!$roles = $DB->get_records_sql("SELECT DISTINCT r.*
FROM {role} r,
{role_assignments} ra,
{role_allow_assign} raa,
{role_capabilities} rc
WHERE ra.userid = :userid AND ra.contextid IN ($contexts)
AND raa.roleid = ra.roleid AND r.id = raa.allowassign
AND r.id = rc.roleid AND rc.capability = :viewcap AND rc.capability <> :anythingcap
ORDER BY r.sortorder ASC", array('userid'=>$USER->id, 'viewcap'=>'moodle/course:view', 'anythingcap'=>'moodle/site:doanything'))) {
return array();
}
$roles = array();
foreach ($rs as $r) {
$roles[$r->id] = $r->{$field};
foreach ($roles as $role) {
$roles[$role->id] = $role->$field;
}
$rs->close();
return role_fix_names($roles, $context, $rolenamedisplay);
}
......@@ -4054,21 +4035,36 @@ function get_assignable_roles_for_switchrole($context, $field='name', $rolenamed
/**
* Gets a list of roles that this user can override in this context
* @param object $context
* @param string $field
* @param int $rolenamedisplay
* @return array
*/
function get_overridable_roles($context, $field='name', $rolenamedisplay=ROLENAME_ALIAS) {
global $USER, $DB;
$options = array();
if (!has_capability('moodle/role:override', $context) and !has_capability('moodle/role:safeoverride', $context)) {
return array();
}
$parents = get_parent_contexts($context);
$parents[] = $context->id;
$contexts = implode(',' , $parents);
if (!$roles = $DB->get_records_sql("SELECT DISTINCT r.*
FROM {role} r,
{role_assignments} ra,
{role_allow_override} rao
WHERE ra.userid = :userid AND ra.contextid IN ($contexts)
AND rao.roleid = ra.roleid AND r.id = rao.allowoverride
ORDER BY r.sortorder ASC", array('userid'=>$USER->id))) {
return array();
}
if ($roles = get_all_roles()) {
foreach ($roles as $role) {
if (user_can_override($context, $role->id)) {
$options[$role->id] = $role->$field;
}
}
foreach ($roles as $role) {
$roles[$role->id] = $role->$field;
}
return role_fix_names($options, $context, $rolenamedisplay);
return role_fix_names($roles, $context, $rolenamedisplay);
}
/**
......@@ -4917,7 +4913,7 @@ function get_roles_on_exact_context($context) {
* The caller *must* check
* - that this op is allowed
* - that the requested role can be assigned in this ctx
* (hint, use get_assignable_roles())
* (hint, use get_assignable_roles_for_switchrole())
* - that the requested role is NOT $CFG->defaultuserroleid
*
* To "unswitch" pass 0 as the roleid.
......
......@@ -123,7 +123,7 @@ $moodle_capabilities = array(
'moodle/site:sendmessage' => array(
'riskbitmask' => RISK_PERSONAL,
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
......@@ -286,7 +286,7 @@ $moodle_capabilities = array(
'moodle/user:delete' => array(
'riskbitmask' => RISK_PERSONAL,
'riskbitmask' => RISK_PERSONAL, RISK_DATALOSS,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
......@@ -345,6 +345,8 @@ $moodle_capabilities = array(
'moodle/role:assign' => array(
'riskbitmask' => RISK_SPAM | RISK_PERSONAL | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
......@@ -364,6 +366,17 @@ $moodle_capabilities = array(
)
),
'moodle/role:safeoverride' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
'editingteacher' => CAP_ALLOW
)
),
'moodle/role:manage' => array(
'riskbitmask' => RISK_SPAM | RISK_PERSONAL | RISK_XSS,
......@@ -401,7 +414,7 @@ $moodle_capabilities = array(
'moodle/role:switchroles' => array(
'riskbitmask' => RISK_XSS,
'riskbitmask' => RISK_XSS | RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_SYSTEM,
......@@ -424,6 +437,8 @@ $moodle_capabilities = array(
'moodle/category:delete' => array(
'riskbitmask' => RISK_DATALOSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSECAT,
'legacy' => array(
......@@ -465,6 +480,8 @@ $moodle_capabilities = array(
'moodle/course:delete' => array(
'riskbitmask' => RISK_DATALOSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
......@@ -569,6 +586,8 @@ $moodle_capabilities = array(
'moodle/course:managemetacourse' => array(
'riskbitmask' => RISK_XSS | RISK_PERSONAL,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
......@@ -653,6 +672,8 @@ $moodle_capabilities = array(
'moodle/course:reset' => array(
'riskbitmask' => RISK_DATALOSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
......@@ -740,7 +761,7 @@ $moodle_capabilities = array(
'moodle/user:editprofile' => array(
'riskbitmask' => RISK_SPAM,
'riskbitmask' => RISK_SPAM | RISK_PERSONAL,
'captype' => 'write',
'contextlevel' => CONTEXT_USER,
......@@ -751,6 +772,8 @@ $moodle_capabilities = array(
'moodle/user:editownprofile' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
......@@ -1010,7 +1033,7 @@ $moodle_capabilities = array(
),
'moodle/grade:import' => array(
'riskbitmask' => RISK_PERSONAL,
'riskbitmask' => RISK_PERSONAL | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
......@@ -1033,7 +1056,7 @@ $moodle_capabilities = array(
),
'moodle/grade:manage' => array(
'riskbitmask' => RISK_PERSONAL,
'riskbitmask' => RISK_PERSONAL | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
......@@ -1120,6 +1143,8 @@ $moodle_capabilities = array(
),
'moodle/notes:manage' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
......@@ -1130,6 +1155,8 @@ $moodle_capabilities = array(
),
'moodle/tag:manage' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
......@@ -1140,6 +1167,8 @@ $moodle_capabilities = array(
),
'moodle/tag:create' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
......@@ -1149,6 +1178,8 @@ $moodle_capabilities = array(
),
'moodle/tag:edit' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'legacy' => array(
......
......@@ -56,6 +56,7 @@ $mod_assignment_capabilities = array(
),
'mod/assignment:grade' => array(
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
......
......@@ -241,6 +241,8 @@ $mod_forum_capabilities = array(
'mod/forum:managesubscriptions' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'legacy' => array(
......
......@@ -991,6 +991,10 @@ body#admin-modules table.generaltable td.c0
padding-top: 0.75em;
}
#admin-roles-override .sefeoverridenotice {
text-align:center;
}
#admin-lang .generalbox {
text-align:center;
margin:auto;
......
......@@ -6,7 +6,7 @@
// This is compared against the values stored in the database to determine
// whether upgrades should be performed (see lib/db/*.php)
$version = 2008070701; // YYYYMMDD = date of the last version bump
$version = 2008072300; // YYYYMMDD = date of the last version bump
// XX = daily increments
$release = '2.0 dev (Build: 20080723)'; // Human-friendly version name
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment