### Eclipse Workspace Patch 1.0 #P moodle20t Index: user/tabs.php =================================================================== RCS file: /cvsroot/moodle/moodle/user/tabs.php,v retrieving revision 1.86 diff -u -r1.86 tabs.php --- user/tabs.php 28 Feb 2010 15:47:47 -0000 1.86 +++ user/tabs.php 5 Mar 2010 08:29:09 -0000 @@ -218,11 +218,11 @@ if (!empty($showroles) and !empty($user)) { // this variable controls whether this roles is showed, or not, so only user/view page should set this flag $usercontext = get_context_instance(CONTEXT_USER, $user->id); if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', - 'moodle/role:override', 'moodle/role:manage'), $usercontext)) { + 'moodle/role:override', 'moodle/role:manage', 'moodle/role:review'), $usercontext)) { $toprow[] = new tabobject('roles', $CFG->wwwroot.'/'.$CFG->admin.'/roles/usersroles.php?userid='.$user->id.'&courseid='.$course->id ,get_string('roles')); - if (in_array($currenttab, array('usersroles', 'assign', 'override', 'check'))) { + if (in_array($currenttab, array('usersroles', 'assign', 'permissions', 'check'))) { $inactive = array('roles'); $activetwo = array('roles'); @@ -233,12 +233,12 @@ $secondrow[] = new tabobject('assign', $CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$usercontext->id.'&userid='.$user->id.'&courseid='.$course->id ,get_string('assignrolesrelativetothisuser', 'role'), '', true); } - if (!empty($overridableroles) || $currenttab=='override') { - $secondrow[] = new tabobject('override', $CFG->wwwroot.'/'.$CFG->admin.'/roles/override.php?contextid='.$usercontext->id.'&userid='.$user->id.'&courseid='.$course->id - ,get_string('overridepermissions', 'role'), '', true); + if (!empty($overridableroles) || $currenttab=='permissions' || has_capability('moodle/role:review', $usercontext)) { + $secondrow[] = new tabobject('permissions', $CFG->wwwroot.'/'.$CFG->admin.'/roles/permissions.php?contextid='.$usercontext->id.'&userid='.$user->id.'&courseid='.$course->id + ,get_string('permissions', 'role'), '', true); } if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', - 'moodle/role:override', 'moodle/role:assign'), $usercontext)) { + 'moodle/role:override', 'moodle/role:assign', 'moodle/role:review'), $usercontext)) { $secondrow[] = new tabobject('check', $CFG->wwwroot.'/'.$CFG->admin.'/roles/check.php?contextid='.$usercontext->id.'&userid='.$user->id.'&courseid='.$course->id, get_string('checkpermissions', 'role')); Index: admin/roles/managetabs.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/managetabs.php,v retrieving revision 1.10 diff -u -r1.10 managetabs.php --- admin/roles/managetabs.php 1 Nov 2009 10:38:54 -0000 1.10 +++ admin/roles/managetabs.php 5 Mar 2010 08:28:55 -0000 @@ -1,45 +1,39 @@ . /** * Defines the tab bar used on the manage/allow assign/allow overrides pages. * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ - if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); // It must be included from a Moodle page - } +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); // It must be included from a Moodle page +} - $toprow = array(); - $toprow[] = new tabobject('manage', $CFG->wwwroot.'/'.$CFG->admin.'/roles/manage.php', get_string('manageroles', 'role')); - $toprow[] = new tabobject('assign', $CFG->wwwroot.'/'.$CFG->admin.'/roles/allow.php?mode=assign', get_string('allowassign', 'role')); - $toprow[] = new tabobject('override', $CFG->wwwroot.'/'.$CFG->admin.'/roles/allow.php?mode=override', get_string('allowoverride', 'role')); - $toprow[] = new tabobject('switch', $CFG->wwwroot.'/'.$CFG->admin.'/roles/allow.php?mode=switch', get_string('allowswitch', 'role')); - $tabs = array($toprow); +$toprow = array(); +$toprow[] = new tabobject('manage', new moodle_url('/admin/roles/manage.php'), get_string('manageroles', 'role')); +$toprow[] = new tabobject('assign', new moodle_url('/admin/roles/allow.php', array('mode'=>'assign')), get_string('allowassign', 'role')); +$toprow[] = new tabobject('override', new moodle_url('/admin/roles/allow.php', array('mode'=>'override')), get_string('allowoverride', 'role')); +$toprow[] = new tabobject('switch', new moodle_url('/admin/roles/allow.php', array('mode'=>'switch')), get_string('allowswitch', 'role')); +$tabs = array($toprow); - print_tabs($tabs, $currenttab); +print_tabs($tabs, $currenttab); Index: admin/roles/define.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/define.php,v retrieving revision 1.14 diff -u -r1.14 define.php --- admin/roles/define.php 3 Jan 2010 15:46:15 -0000 1.14 +++ admin/roles/define.php 5 Mar 2010 08:28:54 -0000 @@ -1,27 +1,19 @@ . /** * Lets the user edit role definitions. @@ -32,9 +24,11 @@ * edit - edit the definition of a role * view - view the definition of a role * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); Index: admin/roles/lib.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/lib.php,v retrieving revision 1.41 diff -u -r1.41 lib.php --- admin/roles/lib.php 11 Feb 2010 16:27:55 -0000 1.41 +++ admin/roles/lib.php 5 Mar 2010 08:28:55 -0000 @@ -1,34 +1,34 @@ . /** * Library code used by the roles administration interfaces. * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * Responds to actions: + * add - add a new role + * duplicate - like add, only initialise the new role by using an existing one. + * edit - edit the definition of a role + * view - view the definition of a role + * + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->dirroot.'/user/selector/lib.php'); @@ -83,6 +83,10 @@ * Display the table. */ public function display() { + if (count($this->capabilities) > capability_table_base::NUM_CAPS_FOR_SEARCH) { + global $PAGE; + $PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, get_string('filter'), get_string('clear'))); + } echo '' . "\n\n"; echo ''; $this->add_header_cells(); @@ -119,11 +123,7 @@ } /// End of the table. - echo "\n
' . get_string('capability','role') . '
\n"; - if (count($this->capabilities) > capability_table_base::NUM_CAPS_FOR_SEARCH) { - global $PAGE; - $PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, get_string('filter'), get_string('clear'))); - } + echo "\n\n"; } /** @@ -179,17 +179,14 @@ /** * Subclass of capability_table_base for use on the Check permissions page. * - * We have two additional columns, Allowed, which contains yes/no, and Explanation, - * which contains a pop-up link to explainhascapability.php. + * We have one additional column, Allowed, which contains yes/no. */ -class explain_capability_table extends capability_table_base { +class check_capability_table extends capability_table_base { protected $user; protected $fullname; - protected $baseurl; protected $contextname; protected $stryes; protected $strno; - protected $strexplanation; private $hascap; /** @@ -204,21 +201,16 @@ $this->user = $user; $this->fullname = fullname($user); $this->contextname = $contextname; - $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . - '/roles/explain.php?user=' . $user->id . - '&contextid=' . $context->id . '&capability='; $this->stryes = get_string('yes'); $this->strno = get_string('no'); - $this->strexplanation = get_string('explanation'); } protected function add_header_cells() { echo '' . get_string('allowed', 'role') . ''; - echo '' . $this->strexplanation . ''; } protected function num_extra_columns() { - return 2; + return 1; } protected function skip_row($capability) { @@ -238,27 +230,150 @@ global $OUTPUT; if ($this->hascap) { $result = $this->stryes; - $tooltip = 'whydoesuserhavecap'; } else { $result = $this->strno; - $tooltip = 'whydoesusernothavecap'; } $a = new stdClass; $a->fullname = $this->fullname; $a->capability = $capability->name; $a->context = $this->contextname; echo '' . $result . ''; - echo ''; + } +} - $url = $this->baseurl . $capability->name; - echo $OUTPUT->action_link($url, $this->strexplanation, - new popup_action('click', $url, 'hascapabilityexplanation', array('height' => 600, 'width' => 600)), - array('title'=>get_string($tooltip, 'role', $a))); - echo ''; +/** + * Subclass of capability_table_base for use on the Permissions page. + */ +class permissions_table extends capability_table_base { + protected $contextname; + protected $allowoverrides; + protected $allowsafeoverrides; + protected $overridableroles; + protected $roles; + protected $icons = array(); + + /** + * Constructor + * @param object $context the context this table relates to. + * @param string $contextname print_context_name($context) - to save recomputing. + */ + public function __construct($context, $contextname, $allowoverrides, $allowsafeoverrides, $overridableroles) { + global $DB; + + parent::__construct($context, 'permissions'); + $this->contextname = $contextname; + $this->allowoverrides = $allowoverrides; + $this->allowsafeoverrides = $allowsafeoverrides; + $this->overridableroles = $overridableroles; + + $roles = $DB->get_records('role', null, 'sortorder DESC'); + foreach ($roles as $roleid=>$role) { + $roles[$roleid] = $role->name; + } + $this->roles = role_fix_names($roles, $context); + + } + + protected function add_header_cells() { + echo '' . get_string('risks', 'role') . ''; + echo '' . get_string('neededroles', 'role') . ''; + echo '' . get_string('prohibitedroles', 'role') . ''; + } + + protected function num_extra_columns() { + return 3; + } + + protected function skip_row($capability) { + return $capability->name != 'moodle/site:doanything' && is_legacy($capability->name); + } + + protected function add_row_cells($capability) { + global $OUTPUT, $PAGE; + + $context = $this->context; + $contextid = $this->context->id; + $allowoverrides = $this->allowoverrides; + $allowsafeoverrides = $this->allowsafeoverrides; + $overridableroles = $this->overridableroles; + $roles = $this->roles; + + + list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name); + $neededroles = array(); + $forbiddenroles = array(); + $allowable = $overridableroles; + $forbitable = $overridableroles; + foreach ($neededroles as $id=>$unused) { + unset($allowable[$id]); + } + foreach ($forbidden as $id=>$unused) { + unset($allowable[$id]); + unset($forbitable[$id]); + } + + foreach ($roles as $id=>$name) { + if (isset($needed[$id])) { + $neededroles[$id] = $roles[$id]; + if (isset($overridableroles[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) { + $preventurl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'roleid'=>$id, 'capability'=>$capability->name, 'prevent'=>1)); + $neededroles[$id] .= $OUTPUT->action_icon($preventurl, new pix_icon('t/delete', get_string('prevent', 'role'))); + } + } + } + $neededroles = implode(', ', $neededroles); + foreach ($roles as $id=>$name) { + if (isset($forbidden[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) { + $forbiddenroles[$id] = $roles[$id]; + if (isset($overridableroles[$id]) and prohibit_is_removable($id, $context, $capability->name)) { + $unprohibiturl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'roleid'=>$id, 'capability'=>$capability->name, 'unprohibit'=>1)); + $forbiddenroles[$id] .= $OUTPUT->action_icon($unprohibiturl, new pix_icon('t/delete', get_string('delete'))); + } + } + } + $forbiddenroles = implode(', ', $forbiddenroles); + + if ($allowable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) { + $allowurl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'capability'=>$capability->name, 'allow'=>1)); + $neededroles .= '
'.$OUTPUT->action_icon($allowurl, new pix_icon('t/add', get_string('allow', 'role'))).'
'; + } + + if ($forbitable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) { + $prohibiturl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'capability'=>$capability->name, 'prohibit'=>1)); + $forbiddenroles .= '
'.$OUTPUT->action_icon($prohibiturl, new pix_icon('t/add', get_string('prohibit', 'role'))).'
'; + } + + $risks = $this->get_risks($capability); + + echo '' . $risks . ''; + echo '' . $neededroles . ''; + echo '' . $forbiddenroles . ''; + } + + protected function get_risks($capability) { + global $OUTPUT; + + $allrisks = get_all_risks(); + $risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'role')))); + + $return = ''; + + foreach ($allrisks as $type=>$risk) { + if ($risk & (int)$capability->riskbitmask) { + if (!isset($this->icons[$type])) { + $pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin')); + $this->icons[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl)); + } + $return .= $this->icons[$type]; + } + } + + return $return; } } + /** * This subclass is the bases for both the define roles and override roles * pages. As well as adding the risks columns, this also provides generic @@ -900,32 +1015,6 @@ } } -class override_permissions_table_basic extends override_permissions_table_advanced { - protected $stradvmessage; - - public function __construct($context, $roleid, $safeoverridesonly) { - parent::__construct($context, $roleid, $safeoverridesonly); - unset($this->displaypermissions[CAP_PROHIBIT]); - $this->stradvmessage = get_string('useshowadvancedtochange', 'role'); - } - - protected function skip_row($capability) { - return is_legacy($capability->name) || $capability->locked; - } - - protected function add_permission_cells($capability) { - if ($this->permissions[$capability->name] == CAP_PROHIBIT) { - $permname = $this->allpermissions[CAP_PROHIBIT]; - echo ''; - echo ''; - echo $this->strperms[$permname] . '' . $this->stradvmessage . ''; - echo ''; - } else { - parent::add_permission_cells($capability); - } - } -} - // User selectors for managing role assignments ================================ /** Index: admin/roles/allow.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/allow.php,v retrieving revision 1.6 diff -u -r1.6 allow.php --- admin/roles/allow.php 1 Nov 2009 10:38:54 -0000 1.6 +++ admin/roles/allow.php 5 Mar 2010 08:28:53 -0000 @@ -1,83 +1,74 @@ . /** - * this page defines what roles can do things with other roles. For example - * which roles can assign which other roles, or which roles can switch to - * which other roles. + * Allow overriding of roles by other roles * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ - - require_once(dirname(__FILE__) . '/../../config.php'); - require_once($CFG->libdir . '/adminlib.php'); - require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); - - $mode = required_param('mode', PARAM_ACTION); - $classformode = array( - 'assign' => 'role_allow_assign_page', - 'override' => 'role_allow_override_page', - 'switch' => 'role_allow_switch_page' - ); - if (!isset($classformode[$mode])) { - print_error('invalidmode', '', '', $mode); - } - - $baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/roles/allow.php?mode=' . $mode; - admin_externalpage_setup('defineroles', '', array(), $baseurl); - require_login(); - - $syscontext = get_context_instance(CONTEXT_SYSTEM); - require_capability('moodle/role:manage', $syscontext); - - $controller = new $classformode[$mode](); - - if (optional_param('submit', false, PARAM_BOOL) && data_submitted() && confirm_sesskey()) { - $controller->process_submission(); - mark_context_dirty($syscontext->path); - add_to_log(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl), '', '', $USER->id); - redirect($baseurl); - } - - $controller->load_current_settings(); - -/// Display the editing form. - admin_externalpage_print_header(); - - $currenttab = $mode; - require_once('managetabs.php'); - - $table = $controller->get_table(); - - echo $OUTPUT->box($controller->get_intro_text()); - - echo '
'; - echo ''; - echo $OUTPUT->table($table); - echo '
'; - echo '
'; + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(dirname(__FILE__) . '/../../config.php'); +require_once($CFG->libdir . '/adminlib.php'); +require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); + +$mode = required_param('mode', PARAM_ACTION); +$classformode = array( + 'assign' => 'role_allow_assign_page', + 'override' => 'role_allow_override_page', + 'switch' => 'role_allow_switch_page' +); +if (!isset($classformode[$mode])) { + print_error('invalidmode', '', '', $mode); +} + +$baseurl = new moodle_url('/admin/roles/allow.php', array('mode'=>$mode)); +admin_externalpage_setup('defineroles', '', array(), $baseurl); + +$syscontext = get_context_instance(CONTEXT_SYSTEM); +require_capability('moodle/role:manage', $syscontext); + +$controller = new $classformode[$mode](); + +if (optional_param('submit', false, PARAM_BOOL) && data_submitted() && confirm_sesskey()) { + $controller->process_submission(); + mark_context_dirty($syscontext->path); + add_to_log(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl), '', '', $USER->id); + redirect($baseurl); +} + +$controller->load_current_settings(); + +// Display the editing form. +echo $OUTPUT->header(); + +$currenttab = $mode; +require('managetabs.php'); + +$table = $controller->get_table(); + +echo $OUTPUT->box($controller->get_intro_text()); + +echo '
'; +echo ''; +echo $OUTPUT->table($table); +echo '
'; +echo '
'; - echo $OUTPUT->footer(); +echo $OUTPUT->footer(); Index: admin/roles/usersroles.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/usersroles.php,v retrieving revision 1.15 diff -u -r1.15 usersroles.php --- admin/roles/usersroles.php 1 Feb 2010 03:26:16 -0000 1.15 +++ admin/roles/usersroles.php 5 Mar 2010 08:28:55 -0000 @@ -1,37 +1,30 @@ . /** * User roles report list all the users who have been assigned a particular * role in all contexts. * + * @package moodlecore + * @subpackage role * @copyright © 2007 The Open University and others * @author t.j.hunt@open.ac.uk and others - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once(dirname(__FILE__) . '/../../config.php'); @@ -138,7 +131,8 @@ $showroles = 1; $currenttab = 'usersroles'; -include_once($CFG->dirroot.'/user/tabs.php'); +include($CFG->dirroot.'/user/tabs.php'); + echo $OUTPUT->heading($title, 3); echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthnormal'); Index: admin/roles/module.js =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/module.js,v retrieving revision 1.1 diff -u -r1.1 module.js --- admin/roles/module.js 24 Jan 2010 19:37:46 -0000 1.1 +++ admin/roles/module.js 5 Mar 2010 08:28:55 -0000 @@ -5,113 +5,111 @@ M.core_role = {}; -M.core_role.CapTableFilter = function(Y, tableid, strsearch, strclear) { - this.delayhandle = -1, - this.searchdelay = 100, // milliseconds - - this.Y = Y - // Find the form controls. - this.table = document.getElementById(tableid); - - // Create a div to hold the search UI. - this.div = document.createElement('div'); - this.div.className = 'capabilitysearchui'; - this.div.style.width = this.table.offsetWidth + 'px'; - - // Create the capability search input. - this.input = document.createElement('input'); - this.input.type = 'text'; - this.input.id = tableid + 'capabilitysearch'; - - // Create a label for the search input. - this.label = document.createElement('label'); - this.label.htmlFor = this.input.id; - this.label.appendChild(document.createTextNode(strsearch + ' ')); - - // Create a clear button to clear the input. - this.button = document.createElement('input'); - this.button.value = strclear; - this.button.type = 'button'; - this.button.disabled = true; - - // Tie it all together - this.div.appendChild(this.label); - this.div.appendChild(this.input); - this.div.appendChild(this.button); - this.table.parentNode.insertBefore(this.div, this.table); - Y.on('keyup', this.change, this.input, this); - Y.on('click', this.clear, this.button, this); - - // Horrible hack! - var hidden = document.createElement('input'); - hidden.type = 'hidden'; - hidden.disabled = true; - this.div.appendChild(hidden); - hidden = document.createElement('input'); - hidden.type = 'hidden'; - hidden.disabled = true; - this.div.appendChild(hidden); -}; - -M.core_role.CapTableFilter.prototype.clear = function () { - this.input.value = ''; - if (this.delayhandle != -1) { - clearTimeout(this.delayhandle); - this.delayhandle = -1; - } - this.filter(); -}; +M.core_role.init_cap_table_filter = function(Y, tableid, strsearch, strclear) { + var CapTableFilter = function(tableid, strsearch, strclear) { + this.delayhandle = -1, + this.searchdelay = 100, // milliseconds + + // Find the form controls. + this.table = document.getElementById(tableid); + + // Create a div to hold the search UI. + this.div = document.createElement('div'); + this.div.className = 'capabilitysearchui'; + this.div.style.width = this.table.offsetWidth + 'px'; + + // Create the capability search input. + this.input = document.createElement('input'); + this.input.type = 'text'; + this.input.id = tableid + 'capabilitysearch'; + + // Create a label for the search input. + this.label = document.createElement('label'); + this.label.htmlFor = this.input.id; + this.label.appendChild(document.createTextNode(strsearch + ' ')); + + // Create a clear button to clear the input. + this.button = document.createElement('input'); + this.button.value = strclear; + this.button.type = 'button'; + this.button.disabled = true; + + // Tie it all together + this.div.appendChild(this.label); + this.div.appendChild(this.input); + this.div.appendChild(this.button); + this.table.parentNode.insertBefore(this.div, this.table); + Y.on('keyup', this.change, this.input, this); + Y.on('click', this.clear, this.button, this); + + // Horrible hack! + var hidden = document.createElement('input'); + hidden.type = 'hidden'; + hidden.disabled = true; + this.div.appendChild(hidden); + hidden = document.createElement('input'); + hidden.type = 'hidden'; + hidden.disabled = true; + this.div.appendChild(hidden); + }; + + CapTableFilter.prototype.clear = function () { + this.input.value = ''; + if (this.delayhandle != -1) { + clearTimeout(this.delayhandle); + this.delayhandle = -1; + } + this.filter(); + }; -M.core_role.CapTableFilter.prototype.change = function() { - var self = this; - var handle = setTimeout(function(){self.filter();}, this.searchdelay); - if (this.delayhandle != -1) { - clearTimeout(this.delayhandle); - } - this.delayhandle = handle; -}; + CapTableFilter.prototype.change = function() { + var self = this; + var handle = setTimeout(function(){self.filter();}, this.searchdelay); + if (this.delayhandle != -1) { + clearTimeout(this.delayhandle); + } + this.delayhandle = handle; + }; -M.core_role.CapTableFilter.prototype.set_visible = function(row, visible) { - if (visible) { - this.Y.one(row).removeClass('hiddenrow'); - } else { - this.Y.one(row).addClass('hiddenrow'); - } -}; + CapTableFilter.prototype.set_visible = function(row, visible) { + if (visible) { + Y.one(row).removeClass('hiddenrow'); + } else { + Y.one(row).addClass('hiddenrow'); + } + }; -M.core_role.CapTableFilter.prototype.filter = function() { - var filtertext = this.input.value.toLowerCase(); - this.button.disabled = (filtertext == ''); - var lastheading = null; - var capssincelastheading = 0; - - Y.all('#'+this.table.id+' tr').each(function(row, index, list) { - if (row.hasClass('rolecapheading')) { - if (lastheading) { - this.set_visible(lastheading, capssincelastheading > 0); + CapTableFilter.prototype.filter = function() { + var filtertext = this.input.value.toLowerCase(); + this.button.disabled = (filtertext == ''); + var lastheading = null; + var capssincelastheading = 0; + + Y.all('#'+this.table.id+' tr').each(function(row, index, list) { + if (row.hasClass('rolecapheading')) { + if (lastheading) { + this.set_visible(lastheading, capssincelastheading > 0); + } + lastheading = row; + capssincelastheading = 0; } - lastheading = row; - capssincelastheading = 0; - } - if (row.hasClass('rolecap')) { - var capname = row.one('.cap-name').get('text') + '|' + row.one('.cap-desc a').get('text').toLowerCase(); - if (capname.indexOf(filtertext) >= 0) { - this.set_visible(row, true); - capssincelastheading += 1; - } else { - this.set_visible(row, false); + if (row.hasClass('rolecap')) { + var capname = row.one('.cap-name').get('text') + '|' + row.one('.cap-desc a').get('text').toLowerCase(); + if (capname.indexOf(filtertext) >= 0) { + this.set_visible(row, true); + capssincelastheading += 1; + } else { + this.set_visible(row, false); + } } - } - }, this); - - if (lastheading) { - this.set_visible(lastheading, capssincelastheading > 0); - } -}; + }, this); + if (lastheading) { + this.set_visible(lastheading, capssincelastheading > 0); + } + }; -M.core_role.init_cap_table_filter = function(Y, tableid, strsearch, strclear) { - new M.core_role.CapTableFilter(Y, tableid, strsearch, strclear); + new CapTableFilter(tableid, strsearch, strclear); }; Index: admin/roles/tabs.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/tabs.php,v retrieving revision 1.58 diff -u -r1.58 tabs.php --- admin/roles/tabs.php 16 Jan 2010 15:40:04 -0000 1.58 +++ admin/roles/tabs.php 5 Mar 2010 08:28:55 -0000 @@ -1,35 +1,29 @@ . /** * Handles headers and tabs for the roles control at any level apart from SYSTEM level * We assume that $currenttab, $assignableroles and $overridableroles are defined * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ if (!defined('MOODLE_INTERNAL')) { die('Direct access to this script is forbidden.'); // It must be included from a Moodle page @@ -56,11 +50,9 @@ $PAGE->navbar->add($straction); $PAGE->set_title($title); $PAGE->set_heading($SITE->fullname); - echo $OUTPUT->header(); break; case CONTEXT_USER: - echo $OUTPUT->header(); break; case CONTEXT_COURSECAT: @@ -78,14 +70,12 @@ $PAGE->navbar->add(get_string("roles")); $PAGE->set_title($title); $PAGE->set_heading("$SITE->fullname: $strcourses"); - echo $OUTPUT->header(); break; case CONTEXT_COURSE: if ($context->instanceid != SITEID) { $course = $DB->get_record('course', array('id'=>$context->instanceid)); - require_login($course); if (empty($title)) { $title = get_string("editcoursesettings"); } @@ -93,7 +83,6 @@ $PAGE->navbar->add(get_string('roles'), $roleslink, navigation_node::TYPE_SETTING); $PAGE->set_title($title); $PAGE->set_heading($course->fullname); - echo $OUTPUT->header(); } break; @@ -105,8 +94,6 @@ print_error('invalidcourse'); } - require_login($course); - $PAGE->navigation->add(get_string('roles')); if (empty($title)) { @@ -114,45 +101,16 @@ } $PAGE->set_title($title); $PAGE->set_cacheable(false); - echo $OUTPUT->header(); break; case CONTEXT_BLOCK: if ($blockinstance = $DB->get_record('block_instances', array('id' => $context->instanceid))) { $blockname = print_context_name($context); - $parentcontext = get_context_instance_by_id($blockinstance->parentcontextid); - switch ($parentcontext->contextlevel) { - case CONTEXT_SYSTEM: - break; - - case CONTEXT_COURSECAT: - $PAGE->set_category_by_id($parentcontext->instanceid); - break; - - case CONTEXT_COURSE: - require_login($parentcontext->instanceid); - break; - - case CONTEXT_MODULE: - $cm = get_coursemodule_from_id('', $parentcontext->instanceid); - require_login($parentcontext->instanceid, false, $cm); - break; - - case CONTEXT_USER: - break; - - default: - throw new invalid_state_exception('Block context ' . $blockname . - ' has parent context with an improper contextlevel ' . $parentcontext->contextlevel); - - - } $PAGE->navbar->add($blockname); $PAGE->navbar->add($straction); $PAGE->set_title("$straction: $blockname"); $PAGE->set_heading($PAGE->course->fullname); - echo $OUTPUT->header(); } break; @@ -167,16 +125,12 @@ $toprow = array(); $inactive = array(); $activetwo = array(); +$secondrow = array(); +$permissionsrow = array(); if ($context->contextlevel != CONTEXT_SYSTEM) { // Print tabs for anything except SYSTEM context - if (!empty($returnurl)) { - $returnurlparam = '&returnurl=' . $returnurl; - } else { - $returnurlparam = ''; - } - if ($context->contextlevel == CONTEXT_MODULE) { // Only show update button if module $toprow[] = new tabobject('update', $CFG->wwwroot.'/course/mod.php?update='. $context->instanceid.'&return=true&sesskey='.sesskey(), get_string('settings')); @@ -184,29 +138,40 @@ if (!empty($assignableroles) || $currenttab=='assign') { $toprow[] = new tabobject('assign', - $CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id.$returnurlparam, + new moodle_url('/admin/roles/assign.php', array('contextid'=>$context->id)), get_string('localroles', 'role'), '', true); } - if (!empty($overridableroles)) { - $toprow[] = new tabobject('override', - $CFG->wwwroot.'/'.$CFG->admin.'/roles/override.php?contextid='.$context->id.$returnurlparam, - get_string('overridepermissions', 'role'), '', true); + if (has_capability('moodle/role:review', $context) or !empty($overridableroles)) { + $permissionsrow['permissions'] = new tabobject('permissions', + new moodle_url('/admin/roles/permissions.php', array('contextid'=>$context->id)), + get_string('permissions', 'role'), '', true); } if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:assign'), $context)) { - $toprow[] = new tabobject('check', - $CFG->wwwroot.'/'.$CFG->admin.'/roles/check.php?contextid='.$context->id.$returnurlparam, + $permissionsrow['check'] = new tabobject('check', + new moodle_url('/admin/roles/check.php', array('contextid'=>$context->id)), get_string('checkpermissions', 'role')); } + if ($permissionsrow) { + $firstpermissionrow = reset($permissionsrow); + $toprow[] = new tabobject('toppermissions', $firstpermissionrow->link, get_string('permissions', 'role'), '', true); + if (!empty($permissionsrow[$currenttab])) { + $secondrow = array_values($permissionsrow); + $inactive = array('toppermissions'); + $activetwo = array('toppermissions'); + } + } + if (!empty($availablefilters)) { $toprow[] = new tabobject('filters', - $CFG->wwwroot.'/filter/manage.php?contextid=' . $context->id, + new moodle_url('/filter/manage.php', array('contextid'=>$context->id)), get_string('filters', 'admin')); } } +unset($permissionsrow); /// Here other core tabs should go (always calling tabs.php files) /// All the logic to decide what to show must be self-contained in the tabs file @@ -215,26 +180,26 @@ /// Finally, we support adding some 'on-the-fly' tabs here /// All the logic to decide what to show must be self-cointained in the tabs file - if (!empty($CFG->extratabs)) { - if ($extratabs = explode(',', $CFG->extratabs)) { - asort($extratabs); - foreach($extratabs as $extratab) { - /// Each extra tab must be one $CFG->dirroot relative file - if (file_exists($CFG->dirroot . '/' . $extratab)) { - include_once($CFG->dirroot . '/' . $extratab); - } +if (!empty($CFG->extratabs)) { + if ($extratabs = explode(',', $CFG->extratabs)) { + asort($extratabs); + foreach($extratabs as $extratab) { + /// Each extra tab must be one $CFG->dirroot relative file + if (file_exists($CFG->dirroot . '/' . $extratab)) { + include($CFG->dirroot . '/' . $extratab); } } } +} - $inactive[] = $currenttab; +$inactive[] = $currenttab; - $tabs = array($toprow); +$tabs = array($toprow); /// If there are any secondrow defined, let's introduce it - if (isset($secondrow) && is_array($secondrow) && !empty($secondrow)) { - $tabs[] = $secondrow; - } +if (!empty($secondrow)) { + $tabs[] = $secondrow; +} - print_tabs($tabs, $currenttab, $inactive, $activetwo); +print_tabs($tabs, $currenttab, $inactive, $activetwo); Index: admin/roles/explain.php =================================================================== RCS file: admin/roles/explain.php diff -N admin/roles/explain.php --- admin/roles/explain.php 16 Jan 2010 15:40:04 -0000 1.12 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,280 +0,0 @@ -set_url('/admin/roles/explain.php', array('user'=>$userid, 'contextid'=>$contextid, 'capability'=>$capability)); - -// Get the context and its parents. -$context = get_context_instance_by_id($contextid); -if (!$context) { - print_error('unknowncontext'); -} -$contextids = get_parent_contexts($context); -array_unshift($contextids, $context->id); -$contexts = array(); -$number = count($contextids); -foreach ($contextids as $contextid) { - $contexts[$contextid] = get_context_instance_by_id($contextid); - $contexts[$contextid]->name = print_context_name($contexts[$contextid], true, true); - $contexts[$contextid]->number = $number--; -} - -// Validate the user id. -if ($userid) { - $user = $DB->get_record('user', array('id' => $userid)); - if (!$user) { - print_error('nosuchuser'); - } -} else { - $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID); - if (!empty($CFG->forcelogin) || - ($context->contextlevel >= CONTEXT_COURSE && !in_array($frontpagecontext->id, $contextids))) { - print_error('cannotgetherewithoutloggingin', 'role'); - } -} - -// Check access permissions. -require_login(); -if (!has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', - 'moodle/role:override', 'moodle/role:assign'), $context)) { - print_error('nopermissions', '', get_string('explainpermissions')); -} - -// This duplicates code in load_all_capabilities and has_capability. -$systempath = '/' . SYSCONTEXTID; -if ($userid == 0) { - if (!empty($CFG->notloggedinroleid)) { - $accessdata = get_role_access($CFG->notloggedinroleid); - $accessdata['ra'][$systempath] = array($CFG->notloggedinroleid); - } else { - $accessdata = array(); - $accessdata['ra'] = array(); - $accessdata['rdef'] = array(); - $accessdata['loaded'] = array(); - } -} else if (isguestuser($user)) { - $guestrole = get_guest_role(); - $accessdata = get_role_access($guestrole->id); - $accessdata['ra'][$systempath] = array($guestrole->id); -} else { - $accessdata = load_user_accessdata($userid); -} -if ($context->contextlevel > CONTEXT_COURSE && !path_inaccessdata($context->path, $accessdata)) { - load_subcontext($userid, $context, $accessdata); -} - -// Load the roles we need. -$roleids = array(); -foreach ($accessdata['ra'] as $roleassignments) { - $roleids = array_merge($roleassignments, $roleids); -} -$roles = $DB->get_records_list('role', 'id', $roleids); -$rolenames = array(); -foreach ($roles as $role) { - $rolenames[$role->id] = $role->name; -} -$rolenames = role_fix_names($rolenames, $context); - -// Pass over the data once, to find the cell that determines the result. -$userhascapability = has_capability($capability, $context, $userid, false); -$areprohibits = false; -$decisiveassigncon = 0; -$decisiveoverridecon = 0; -foreach ($contexts as $con) { - if (!empty($accessdata['ra'][$con->path])) { - // The array_unique here is to work around bug MDL-14817. Once that bug is - // fixed, it can be removed - $ras = array_unique($accessdata['ra'][$con->path]); - } else { - $ras = array(); - } - $con->firstoverride = 0; - foreach ($contexts as $ocon) { - $summedpermission = 0; - $gotsomething = false; - foreach ($ras as $roleid) { - if (isset($accessdata['rdef'][$ocon->path . ':' . $roleid][$capability])) { - $perm = $accessdata['rdef'][$ocon->path . ':' . $roleid][$capability]; - } else { - $perm = CAP_INHERIT; - } - if ($perm && !$gotsomething) { - $gotsomething = true; - $con->firstoverride = $ocon->id; - } - if ($perm == CAP_PROHIBIT) { - $areprohibits = true; - $decisiveassigncon = 0; - $decisiveoverridecon = 0; - break; - } - $summedpermission += $perm; - } - if (!$areprohibits && !$decisiveassigncon && $summedpermission) { - $decisiveassigncon = $con->id; - $decisiveoverridecon = $ocon->id; - break; - } else if ($gotsomething) { - break; - } - } -} -if (!$areprohibits && !$decisiveassigncon) { - $decisiveassigncon = SYSCONTEXTID; - $decisiveoverridecon = SYSCONTEXTID; -} - -// Make a fake role to simplify rendering the table below. -$rolenames[0] = get_string('none'); - -// Prepare some arrays of strings. -$cssclasses = array( - CAP_INHERIT => 'inherit', - CAP_ALLOW => 'allow', - CAP_PREVENT => 'prevent', - CAP_PROHIBIT => 'prohibit', - '' => '' -); -$strperm = array( - CAP_INHERIT => get_string('inherit', 'role'), - CAP_ALLOW => get_string('allow', 'role'), - CAP_PREVENT => get_string('prevent', 'role'), - CAP_PROHIBIT => get_string('prohibit', 'role'), - '' => '' -); - -// Start the output. -$PAGE->set_title(get_string('explainpermission', 'role')); -echo $OUTPUT->header(); -echo $OUTPUT->heading(get_string('explainpermission', 'role')); - -// Print a summary of what we are doing. -$a = new stdClass; -if ($userid) { - $a->fullname = fullname($user); -} else { - $a->fullname = get_string('nobody'); -} -$a->capability = $capability; -$a->context = reset($contexts)->name; -if ($userhascapability) { - echo '

' . get_string('whydoesuserhavecap', 'role', $a) . '

'; -} else { - echo '

' . get_string('whydoesusernothavecap', 'role', $a) . '

'; -} - -// Print the table header rows. -echo ''; -echo ''; -if (count($contexts) > 1) { - echo ''; -} -echo ''; -echo ''; -echo ''; -foreach (array_slice($contexts, 0, count($contexts) - 1) as $con) { - echo ''; -} -echo ''; - -// Now print the bulk of the table. -foreach ($contexts as $con) { - if (!empty($accessdata['ra'][$con->path])) { - // The array_unique here is to work around bug MDL-14817. Once that bug is - // fixed, it can be removed - $ras = array_unique($accessdata['ra'][$con->path]); - } else { - $ras = array(0); - } - $firstcell = ''; - $rowclass = ' class="newcontext"'; - foreach ($ras as $roleid) { - $extraclass = ''; - if (!$roleid) { - $extraclass = ' noroles'; - } - echo '' . $firstcell . ''; - $overridden = false; - foreach ($contexts as $ocon) { - if ($roleid == 0) { - $perm = ''; - } else { - if (isset($accessdata['rdef'][$ocon->path . ':' . $roleid][$capability])) { - $perm = $accessdata['rdef'][$ocon->path . ':' . $roleid][$capability]; - } else { - $perm = CAP_INHERIT; - } - } - if ($perm === CAP_INHERIT && $ocon->id == SYSCONTEXTID) { - $permission = get_string('notset', 'role'); - } else { - $permission = $strperm[$perm]; - } - $classes = $cssclasses[$perm]; - if (!$areprohibits && $decisiveassigncon == $con->id && $decisiveoverridecon == $ocon->id) { - $classes .= ' decisive'; - if ($userhascapability) { - $classes .= ' has'; - } else { - $classes .= ' hasnot'; - } - } - if ($overridden) { - $classes .= ' overridden'; - } - echo ''; - if ($con->firstoverride == $ocon->id) { - $overridden = true; - } - } - echo ''; - $firstcell = ''; - $rowclass = ''; - } -} -echo '
' . get_string('roleassignments', 'role') . '' . get_string('overridesbycontext', 'role') . '' . get_string('roledefinitions', 'role') . '
' . get_string('context', 'role') . - '' . get_string('role') . '' . $con->number . '
' . $con->number . '. ' . $con->name . '' . $rolenames[$roleid] . '' . $permission . '
'; - -// Finish the page. -echo get_string('explainpermissionsinfo', 'role'); -if ($userid && $capability != 'moodle/site:doanything' && !$userhascapability && - has_capability('moodle/site:doanything', $context, $userid)) { - echo '

' . get_string('explainpermissionsdoanything', 'role', $capability) . '

'; -} -echo $OUTPUT->close_window_button(); -echo $OUTPUT->footer(); Index: admin/roles/override.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/override.php,v retrieving revision 1.79 diff -u -r1.79 override.php --- admin/roles/override.php 9 Feb 2010 19:23:11 -0000 1.79 +++ admin/roles/override.php 5 Mar 2010 08:28:55 -0000 @@ -1,208 +1,161 @@ . /** * Lets you override role definitions in contexts. * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ - - require_once(dirname(__FILE__) . '/../../config.php'); - require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); - - $contextid = required_param('contextid', PARAM_INT); // context id - $roleid = optional_param('roleid', 0, PARAM_INT); // requested role id - $userid = optional_param('userid', 0, PARAM_INT); // needed for user tabs - $courseid = optional_param('courseid', 0, PARAM_INT); // needed for user tabs - $returnurl = optional_param('returnurl', null, PARAM_LOCALURL); - -/// Get the base URL for this and related pages into a convenient variable. - $urlparams = array('contextid' => $contextid); - if (!empty($userid)) { - $urlparams['userid'] = $userid; - } - if ($courseid && $courseid != SITEID) { - $urlparams['courseid'] = $courseid; - } - if ($returnurl) { - $urlparams['returnurl'] = $returnurl; - } - $PAGE->set_url('/admin/roles/override.php', $urlparams); - $baseurl = $PAGE->url->out(); + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); +require_once("$CFG->dirroot/$CFG->admin/roles/lib.php"); + +$contextid = required_param('contextid', PARAM_INT); // context id +$roleid = required_param('roleid', PARAM_INT); // requested role id + +// security first +list($context, $course, $cm) = get_context_info_array($contextid); +require_login($course, false, $cm); +$safeoverridesonly = !has_capability('moodle/role:override', $context); +if ($safeoverridesonly) { + require_capability('moodle/role:safeoverride', $context); +} + +$PAGE->set_url('/admin/roles/override.php', array('contextid' => $contextid, 'roleid' => $roleid)); +$PAGE->set_context($context); -/// Validate the contextid parameter. - if (!$context = $DB->get_record('context', array('id'=>$contextid))) { - print_error('wrongcontextid', 'error'); - } - $isfrontpage = $context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID; - $contextname = print_context_name($context); +$userid = 0; +$tabfile = null; - if ($context->contextlevel == CONTEXT_SYSTEM) { - print_error('cannotoverridebaserole', 'error'); - } +if ($course) { + $isfrontpage = ($context->contextlevel == CONTEXT_COURSE and $context->instanceid == SITEID); -/// Validate the courseid parameter. - if ($context->contextlevel == CONTEXT_COURSE) { - $courseid = $context->instanceid; - if (!$course = $DB->get_record('course', array('id'=>$courseid))) { - print_error('invalidcourse'); - } - } if ($courseid) { // we need this for user tabs in user context - if (!$course = $DB->get_record('course', array('id'=>$courseid))) { - print_error('invalidcourse'); - } +} else { + $isfrontpage = false; + if ($context->contextlevel == CONTEXT_USER) { + $courseid = optional_param('courseid', SITEID, PARAM_INT); // needed for user/tabs.php + $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST); + $PAGE->url->param('courseid', $courseid); + $userid = $context->instanceid; } else { - $course = clone($SITE); - $courseid = SITEID; + $course = $SITE; } +} -/// Check access permissions. - require_login($course); - $safeoverridesonly = !has_capability('moodle/role:override', $context); - if ($safeoverridesonly) { - require_capability('moodle/role:safeoverride', $context); - } +$courseid = $course->id; -/// Handle the cancel button. - if (optional_param('cancel', false, PARAM_BOOL)) { - redirect($baseurl); - } +$baseurl = $PAGE->url->out(); +$returnurl = new moodle_url('/admin/roles/permissions.php', array('contextid' => $context->id)); -/// Handle the toggle advanced mode button. - $showadvanced = get_user_preferences('overridepermissions_showadvanced', false); - if (optional_param('toggleadvanced', false, PARAM_BOOL)) { - $showadvanced = !$showadvanced; - set_user_preference('overridepermissions_showadvanced', $showadvanced); - } +$role = $DB->get_record('role', array('id'=>$roleid), '*', MUST_EXIST); -/// These are needed early because of tabs.php - $assignableroles = get_assignable_roles($context, ROLENAME_BOTH); - list($overridableroles, $overridecounts, $nameswithcounts) = get_overridable_roles($context, ROLENAME_BOTH, true); - -/// Make sure this user can override that role - if ($roleid && !isset($overridableroles[$roleid])) { - $a = new stdClass; - $a->roleid = $roleid; - $a->context = $contextname; - print_error('cannotoverriderolehere', '', get_context_url($context), $a); - } +// These are needed early because of tabs.php +$assignableroles = get_assignable_roles($context, ROLENAME_BOTH); +list($overridableroles, $overridecounts, $nameswithcounts) = get_overridable_roles($context, ROLENAME_BOTH, true); +// Work out an appropriate page title. +$contextname = print_context_name($context); +$straction = get_string('overrideroles', 'role'); // Used by tabs.php +$a = (object)array('context' => $contextname, 'role' => $overridableroles[$roleid]); +$title = get_string('overridepermissionsforrole', 'role', $a); -/// If we are actually overriding a role, create the table object, and save changes if appropriate. - if ($roleid) { - if ($showadvanced) { - $overridestable = new override_permissions_table_advanced($context, $roleid, $safeoverridesonly); - } else { - $overridestable = new override_permissions_table_basic($context, $roleid, $safeoverridesonly); - } - $overridestable->read_submitted_permissions(); +// Print the header and tabs +if ($context->contextlevel == CONTEXT_SYSTEM) { + print_error('cannotoverridebaserole', 'error'); - if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) { - $overridestable->save_changes(); - $rolename = $overridableroles[$roleid]; - add_to_log($course->id, 'role', 'override', 'admin/roles/override.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id); - redirect($baseurl); - } - } +} else if ($context->contextlevel == CONTEXT_USER) { + // NOTE: this is not linked from UI for now + $userid = $context->instanceid; + $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0), '*', MUST_EXIST); + $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); -/// Work out an appropriate page title. - if ($roleid) { - $a = new stdClass; - $a->role = $overridableroles[$roleid]; - $a->context = $contextname; - $title = get_string('overridepermissionsforrole', 'role', $a); + // course header + if ($isfrontpage) { + $PAGE->set_heading($course->fullname); } else { - if ($isfrontpage) { - $title = get_string('frontpageoverrides', 'admin'); - } else { - $title = get_string('overridepermissionsin', 'role', $contextname); + if (has_capability('moodle/course:viewparticipants', get_context_instance(CONTEXT_COURSE, $courseid))) { + $PAGE->navbar->add(get_string('participants'), new moodle_url('/user/index.php', array('id'=>$courseid))); } + $PAGE->set_heading($fullname); } + $PAGE->navbar->add($fullname, new moodle_url("$CFG->wwwroot/user/view.php", array('id'=>$userid,'course'=>$courseid))); + $PAGE->navbar->add($straction); - /// Print the header and tabs - $straction = get_string('overrideroles', 'role'); // Used by tabs.php - if ($context->contextlevel == CONTEXT_USER) { - $user = $DB->get_record('user', array('id'=>$userid)); - $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); - - $PAGE->set_title($title); - if ($courseid != SITEID) { - if (has_capability('moodle/course:viewparticipants', get_context_instance(CONTEXT_COURSE, $course->id))) { - $PAGE->navbar->add(get_string('participants'), new moodle_url('/user/index.php', array('id'=>$course->id))); - } - $PAGE->set_heading($fullname); - } else { - $PAGE->set_heading($course->fullname); - } - $PAGE->navbar->add($fullname, new moodle_url("$CFG->wwwroot/user/view.php", array('id'=>$userid,'course'=>$courseid))); - $PAGE->navbar->add($straction); - echo $OUTPUT->header(); - - $showroles = 1; - $currenttab = 'override'; - include_once($CFG->dirroot.'/user/tabs.php'); - } else if ($context->contextlevel==CONTEXT_COURSE and $context->instanceid == SITEID) { - require_once($CFG->libdir.'/adminlib.php'); - admin_externalpage_setup('frontpageroles', '', array('contextid' => $contextid, 'roleid' => $roleid), $CFG->wwwroot . '/' . $CFG->admin . '/roles/override.php'); - admin_externalpage_print_header(); - $currenttab = 'override'; - include_once('tabs.php'); - } else { - $currenttab = 'override'; - include_once('tabs.php'); - } - - echo $OUTPUT->heading_with_help($title, 'overrides'); + $showroles = 1; + $currenttab = 'permissions'; + $tabfile = $CFG->dirroot.'/user/tabs.php'; + +} else if ($isfrontpage) { + admin_externalpage_setup('frontpageroles', '', array(), $PAGE->url); + $currenttab = 'permissions'; + $tabfile = 'tabs.php'; + +} else { + $currenttab = 'permissions'; + $tabfile = 'tabs.php'; +} + + +// Handle the cancel button. +if (optional_param('cancel', false, PARAM_BOOL)) { + redirect($returnurl); +} + +// Make sure this user can override that role +if (empty($overridableroles[$roleid])) { + $a = new stdClass; + $a->roleid = $roleid; + $a->context = $contextname; + print_error('cannotoverriderolehere', '', get_context_url($context), $a); +} + +// If we are actually overriding a role, create the table object, and save changes if appropriate. +$overridestable = new override_permissions_table_advanced($context, $roleid, $safeoverridesonly); +$overridestable->read_submitted_permissions(); + +if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) { + $overridestable->save_changes(); + $rolename = $overridableroles[$roleid]; + add_to_log($course->id, 'role', 'override', 'admin/roles/override.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id); + redirect($returnurl); +} + +// Finally start page output +echo $OUTPUT->header(); +if ($tabfile) { + include($tabfile); +} +echo $OUTPUT->heading_with_help($title, 'overrides'); + +// Show UI for overriding roles. +if (!empty($capabilities)) { + echo $OUTPUT->box(get_string('nocapabilitiesincontext', 'role'), 'generalbox boxaligncenter'); + +} else { + // Print the capabilities overrideable in this context + echo $OUTPUT->box_start('generalbox capbox'); - if ($roleid) { - /// Show UI for overriding roles. - - if (!empty($capabilities)) { - echo $OUTPUT->box(get_string('nocapabilitiesincontext', 'role'), 'generalbox boxaligncenter'); - - } else { - // Print the capabilities overrideable in this context - echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter'); - - if ($showadvanced) { - $showadvancedlabel = get_string('hideadvanced', 'form'); - } else { - $showadvancedlabel = get_string('showadvanced', 'form'); - } - ?> -
+ ?> +
- -
- -
-
- - -
+ ' . get_string('highlightedcellsshowinherit', 'role') . '

'; @@ -218,50 +171,17 @@
+ box_end(); - box_end(); +} - } - - /// Print a form to swap roles, and a link back to the all roles list. - echo ''; - - } else if (empty($overridableroles)) { - /// Print a message that there are no roles that can me assigned here. - echo $OUTPUT->heading(get_string('notabletooverrideroleshere', 'role'), 3, 'mdl-align'); - - } else { - /// Show UI for choosing a role to assign. - - $table = new html_table(); - $table->tablealign = 'center'; - $table->width = '60%'; - $table->head = array(get_string('role'), get_string('description'), get_string('overrides', 'role')); - $table->wrap = array('nowrap', '', 'nowrap'); - $table->align = array('right', 'left', 'center'); - - foreach ($overridableroles as $roleid => $rolename) { - $countusers = 0; - $description = format_string($DB->get_field('role', 'description', array('id'=>$roleid))); - $table->data[] = array(''.$rolename.'', - $description, $overridecounts[$roleid]); - } - - echo $OUTPUT->table($table); - - if (!$isfrontpage && ($url = get_context_url($context))) { - echo ''; - } else if ($returnurl) { - echo ''; - } - } +// Print a form to swap roles, and a link back to the all roles list. +echo ''; - echo $OUTPUT->footer(); +echo $OUTPUT->footer(); Index: admin/roles/check.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/check.php,v retrieving revision 1.14 diff -u -r1.14 check.php --- admin/roles/check.php 16 Jan 2010 15:40:04 -0000 1.14 +++ admin/roles/check.php 5 Mar 2010 08:28:54 -0000 @@ -1,34 +1,28 @@ . /** * Shows the result of has_capability for every capability for a user in a context. * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); @@ -36,7 +30,6 @@ $contextid = required_param('contextid',PARAM_INT); $userid = optional_param('userid', 0, PARAM_INT); // needed for user tabs $courseid = optional_param('courseid', 0, PARAM_INT); // needed for user tabs - $returnurl = optional_param('returnurl', null, PARAM_LOCALURL); $urlparams = array('contextid' => $contextid); if (!empty($userid)) { @@ -45,9 +38,6 @@ if ($courseid && $courseid != SITEID) { $urlparams['courseid'] = $courseid; } - if ($returnurl) { - $urlparams['returnurl'] = $returnurl; - } $PAGE->set_url('/admin/roles/check.php', $urlparams); if (! $context = get_context_instance_by_id($contextid)) { @@ -120,21 +110,22 @@ $showroles = 1; $currenttab = 'check'; - include_once($CFG->dirroot.'/user/tabs.php'); + include($CFG->dirroot.'/user/tabs.php'); } else if ($context->contextlevel == CONTEXT_SYSTEM) { admin_externalpage_setup('checkpermissions', '', array('contextid' => $contextid)); - admin_externalpage_print_header(); + echo $OUTPUT->header(); } else if ($context->contextlevel == CONTEXT_COURSE and $context->instanceid == SITEID) { admin_externalpage_setup('frontpageroles', '', array('contextid' => $contextid), $CFG->wwwroot . '/' . $CFG->admin . '/roles/check.php'); - admin_externalpage_print_header(); + echo $OUTPUT->header(); $currenttab = 'check'; - include_once('tabs.php'); + include('tabs.php'); } else { + echo $OUTPUT->header(); $currenttab = 'check'; - include_once('tabs.php'); + include('tabs.php'); } /// Print heading. @@ -146,7 +137,7 @@ echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide'); echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3); - $table = new explain_capability_table($context, $reportuser, $contextname); + $table = new check_capability_table($context, $reportuser, $contextname); $table->display(); echo $OUTPUT->box_end(); @@ -178,12 +169,8 @@ echo $OUTPUT->box_end(); /// Appropriate back link. - if (!$isfrontpage && ($url = get_context_url($context))) { - echo ''; - } else if ($returnurl) { - echo ''; + if ($context->contextlevel > CONTEXT_USER) { + echo ''; } echo $OUTPUT->footer(); Index: admin/roles/manage.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/manage.php,v retrieving revision 1.83 diff -u -r1.83 manage.php --- admin/roles/manage.php 3 Jan 2010 20:47:14 -0000 1.83 +++ admin/roles/manage.php 5 Mar 2010 08:28:55 -0000 @@ -1,27 +1,19 @@ . /** * Lets the user define and edit roles. @@ -36,9 +28,11 @@ * For all but the first two of those, you also need a roleid parameter, and * possibly some other data. * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); @@ -194,7 +188,7 @@ } /// Print the page header and tabs. - admin_externalpage_print_header(); + echo $OUTPUT->header(); $currenttab = 'manage'; include_once('managetabs.php'); Index: admin/roles/assign.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/roles/assign.php,v retrieving revision 1.123 diff -u -r1.123 assign.php --- admin/roles/assign.php 27 Feb 2010 11:59:23 -0000 1.123 +++ admin/roles/assign.php 5 Mar 2010 08:28:54 -0000 @@ -1,34 +1,28 @@ . /** * Lets you assign roles to users in a particular context. * - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @package roles - *//** */ + * @package moodlecore + * @subpackage role + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); @@ -42,7 +36,6 @@ $hidden = optional_param('hidden', 0, PARAM_BOOL); // whether this assignment is hidden $extendperiod = optional_param('extendperiod', 0, PARAM_INT); $extendbase = optional_param('extendbase', 3, PARAM_INT); - $returnurl = optional_param('returnurl', null, PARAM_LOCALURL); $urlparams = array('contextid' => $contextid); if (!empty($userid)) { @@ -51,9 +44,6 @@ if ($courseid && $courseid != SITEID) { $urlparams['courseid'] = $courseid; } - if ($returnurl) { - $urlparams['returnurl'] = $returnurl; - } $PAGE->set_url('/admin/roles/assign.php', $urlparams); $baseurl = $PAGE->url->out(); @@ -65,26 +55,27 @@ $contextname = print_context_name($context); $inmeta = 0; + $cm = null; if ($context->contextlevel == CONTEXT_COURSE) { $courseid = $context->instanceid; - if ($course = $DB->get_record('course', array('id'=>$courseid))) { - $inmeta = $course->metacourse; - } else { - print_error('invalidcourse', 'error'); - } - } else if (!empty($courseid)){ // we need this for user tabs in user context - if (!$course = $DB->get_record('course', array('id'=>$courseid))) { - print_error('invalidcourse', 'error'); - } + } else if ($context->contextlevel == CONTEXT_MODULE) { + $cm = get_coursemodule_from_id('', $context->instanceid, 0, false, MUST_EXIST); + $courseid = $cm->course; + + } else if (!empty($courseid)) { // we need this for user tabs in user context + // pass it } else { $courseid = SITEID; $course = clone($SITE); } + $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST); + $inmeta = $course->metacourse; + /// Check login and permissions. - require_login($course); + require_login($course, false, $cm); require_capability('moodle/role:assign', $context); /// These are needed early because of tabs.php @@ -276,19 +267,21 @@ $showroles = 1; $currenttab = 'assign'; + echo $OUTPUT->header(); include($CFG->dirroot.'/user/tabs.php'); } else if ($context->contextlevel == CONTEXT_SYSTEM) { admin_externalpage_setup('assignroles', '', array('contextid' => $contextid, 'roleid' => $roleid)); - admin_externalpage_print_header(); + echo $OUTPUT->header(); } else if ($isfrontpage) { admin_externalpage_setup('frontpageroles', '', array('contextid' => $contextid, 'roleid' => $roleid)); - admin_externalpage_print_header(); + echo $OUTPUT->header(); $currenttab = 'assign'; include('tabs.php'); } else { + echo $OUTPUT->header(); $currenttab = 'assign'; include('tabs.php'); } @@ -440,12 +433,8 @@ echo $OUTPUT->table($table); - if (!$isfrontpage && ($url = get_context_url($context))) { - echo ''; - } else if ($returnurl) { - echo ''; + if ($context->contextlevel > CONTEXT_USER) { + echo ''; } } Index: lib/adminlib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/adminlib.php,v retrieving revision 1.435 diff -u -r1.435 adminlib.php --- lib/adminlib.php 27 Feb 2010 22:45:29 -0000 1.435 +++ lib/adminlib.php 5 Mar 2010 08:29:04 -0000 @@ -61,22 +61,14 @@ * require_once($CFG->libdir.'/adminlib.php'); * admin_externalpage_setup('foo'); * // functionality like processing form submissions goes here - * admin_externalpage_print_header(); + * $OUTPUT->header(); * // your HTML goes here - * print_footer(); + * $OUTPUT->footer(); * * * The admin_externalpage_setup() function call ensures the user is logged in, * and makes sure that they have the proper role permission to access the page. - * - * The admin_externalpage_print_header() function prints the header (it figures - * out what category and subcategories the page is classified under) and ensures - * that you're using the admin pagelib (which provides the admin tree block and - * the admin bookmarks block). - * - * The admin_externalpage_print_footer() function properly closes the tables - * opened up by the admin_externalpage_print_header() function and prints the - * standard Moodle footer. + * It also configures all $PAGE properties needed for navigation. * * ADMIN_CATEGORY OBJECTS * @@ -5264,6 +5256,7 @@ if (strpos($PAGE->pagetype, 'admin-') !== 0) { $PAGE->set_pagetype('admin-' . $PAGE->pagetype); } + $PAGE->set_pagelayout('admin'); if (empty($SITE->fullname) || empty($SITE->shortname)) { // During initial install. @@ -5303,35 +5296,6 @@ } /** - * Print header for admin page - * @deprecated since Moodle 20. Please use normal $OUTPUT->header() instead - * @param string $focus focus element - */ -function admin_externalpage_print_header($focus='') { - global $CFG, $PAGE, $SITE, $OUTPUT; - - //debugging('admin_externalpage_print_header is deprecated. Please $OUTPUT->header() instead.', DEBUG_DEVELOPER); - - if (!is_string($focus)) { - $focus = ''; // BC compatibility, there used to be adminroot parameter - } - - $PAGE->set_focuscontrol($focus); - - echo $OUTPUT->header(); -} - -/** - * @deprecated since Moodle 1.9. Please use normal $OUTPUT->footer() instead - */ -function admin_externalpage_print_footer() { -// TODO Still 103 referernces in core code. Don't do debugging output yet. - debugging('admin_externalpage_print_footer is deprecated. Please $OUTPUT->footer() instead.', DEBUG_DEVELOPER); - global $OUTPUT; - echo $OUTPUT->footer(); -} - -/** * Returns the reference to admin tree root * * @return object admin_roow object Index: lib/accesslib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/accesslib.php,v retrieving revision 1.626 diff -u -r1.626 accesslib.php --- lib/accesslib.php 23 Dec 2009 01:24:17 -0000 1.626 +++ lib/accesslib.php 5 Mar 2010 08:29:00 -0000 @@ -780,8 +780,7 @@ } /** - * - * Walk the accessdata array and return true/false + * Does the user have a capability to do something? * * Walk the accessdata array and return true/false. * Deals with prohibits, roleswitching, aggregating @@ -793,7 +792,7 @@ * Notes: * * Switch Roles exits early - * ----------------------- + * ------------------------ * cap checks within a switchrole need to exit early * in our bottom up processing so they don't "see" that * there are real RAs that can do all sorts of things. @@ -805,218 +804,112 @@ * course you'll have techer+defaultloggedinuser. * We try to mimic that in switchrole. * - * Local-most role definition and role-assignment wins - * --------------------------------------------------- - * So if the local context has said 'allow', it wins - * over a high-level context that says 'deny'. - * This is applied when walking rdefs, and RAs. - * Only at the same context the values are SUM()med. - * - * The exception is CAP_PROHIBIT. + * Permission evaluation + * --------------------- + * Originaly there was an extremely complicated way + * to determine the user access that dealt with + * "locality" or role assignemnts and role overrides. + * Now we simply evaluate access for each roel separately + * and then verify if user has at least one role with allow + * and at the same time no role with prohibit. + * + * Incorrectly set Guest role as Default user role + * ----------------------------------------------- + * Admins have to make sure that the "Default user role" does + * not have 'moodle/course:view' or 'moodle/legacy:guest'! * - * "Guest default role" exception + * Incorrectly set Frontpage role * ------------------------------ + * Admins have to make sure that the "Frontpage role" does + * not have 'moodle/legacy:guest'. * - * See MDL-7513 and $ignoreguest below for details. - * - * The rule is that - * - * IF we are being asked about moodle/legacy:guest - * OR moodle/course:view - * FOR a real, logged-in user - * AND we reached the top of the path in ra and rdef - * AND that role has moodle/legacy:guest === 1... - * THEN we act as if we hadn't seen it. - * - * Note that this function must be kept in synch with has_capability_in_accessdata. - * - * To Do: - * @todo Document how it works - * @todo Rewrite in ASM - * - * @global object * @param string $capability * @param object $context * @param array $accessdata * @param bool $doanything * @return bool */ -function has_capability_in_accessdata($capability, $context, $accessdata, $doanything) { - +function has_capability_in_accessdata($capability, $context, array $accessdata, $doanything) { global $CFG; - $path = $context->path; - - // build $contexts as a list of "paths" of the current - // contexts and parents with the order top-to-bottom - $contexts = array($path); - while (preg_match('!^(/.+)/\d+$!', $path, $matches)) { - $path = $matches[1]; - array_unshift($contexts, $path); + if (empty($context->id)) { + throw new coding_exception('Invalid context specified'); } - $ignoreguest = false; - if (isset($accessdata['dr']) - && ($capability == 'moodle/course:view' - || $capability == 'moodle/legacy:guest')) { - // At the base, ignore rdefs where moodle/legacy:guest - // is set - $ignoreguest = $accessdata['dr']; + // Build $paths as a list of current + all parent "paths" with order bottom-to-top + $contextids = explode('/', trim($context->path, '/')); + $paths = array($context->path); + while ($contextids) { + array_pop($contextids); + $paths[] = '/' . implode('/', $contextids); + } + unset($contextids); + + if ($doanything and strpos($capability, 'moodle/legacy:') === 0) { + // admins do not have any legacy capabilities + $doanything = false; } - // Coerce it to an int - $CAP_PROHIBIT = (int)CAP_PROHIBIT; - - $cc = count($contexts); - - $can = 0; - $capdepth = 0; + $roles = array(); + $switchedrole = false; - // - // role-switches loop - // - if (isset($accessdata['rsw'])) { - // check for isset() is fast - // empty() is slow... - if (empty($accessdata['rsw'])) { - unset($accessdata['rsw']); // keep things fast and unambiguous - break; - } + // Find out if role switched + if (!empty($accessdata['rsw'])) { // From the bottom up... - for ($n=$cc-1;$n>=0;$n--) { - $ctxp = $contexts[$n]; + foreach ($paths as $path) { if (isset($accessdata['rsw'][$ctxp])) { - // Found a switchrole assignment - // check for that role _plus_ the default user role - $ras = array($accessdata['rsw'][$ctxp],$CFG->defaultuserroleid); - for ($rn=0;$rn<2;$rn++) { - $roleid = (int)$ras[$rn]; - // Walk the path for capabilities - // from the bottom up... - for ($m=$cc-1;$m>=0;$m--) { - $capctxp = $contexts[$m]; - if (isset($accessdata['rdef']["{$capctxp}:$roleid"][$capability])) { - $perm = (int)$accessdata['rdef']["{$capctxp}:$roleid"][$capability]; - - // The most local permission (first to set) wins - // the only exception is CAP_PROHIBIT - if ($can === 0) { - $can = $perm; - } elseif ($perm === $CAP_PROHIBIT) { - $can = $perm; - break; - } - } - } - } - // As we are dealing with a switchrole, - // we return _here_, do _not_ walk up - // the hierarchy any further - if ($can < 1) { - if ($doanything) { - // didn't find it as an explicit cap, - // but maybe the user can doanything in this context... - return has_capability_in_accessdata('moodle/site:doanything', $context, $accessdata, false); - } else { - return false; - } - } else { - return true; - } - + // Found a switchrole assignment - check for that role _plus_ the default user role + $roles = array($accessdata['rsw'][$ctxp]=>null, $CFG->defaultuserroleid=>null); + $switchedrole = true; + break; } } } - // - // Main loop for normal RAs - // From the bottom up... - // - for ($n=$cc-1;$n>=0;$n--) { - $ctxp = $contexts[$n]; - if (isset($accessdata['ra'][$ctxp])) { - // Found role assignments on this leaf - $ras = $accessdata['ra'][$ctxp]; - - $rc = count($ras); - $ctxcan = 0; - $ctxcapdepth = 0; - for ($rn=0;$rn<$rc;$rn++) { - $roleid = (int)$ras[$rn]; - $rolecan = 0; - $rolecapdepth = 0; - // Walk the path for capabilities - // from the bottom up... - for ($m=$cc-1;$m>=0;$m--) { - $capctxp = $contexts[$m]; - // ignore some guest caps - // at base ra and rdef - if ($ignoreguest == $roleid - && $n === 0 - && $m === 0 - && isset($accessdata['rdef']["{$capctxp}:$roleid"]['moodle/legacy:guest']) - && $accessdata['rdef']["{$capctxp}:$roleid"]['moodle/legacy:guest'] > 0) { - continue; - } - if (isset($accessdata['rdef']["{$capctxp}:$roleid"][$capability])) { - $perm = (int)$accessdata['rdef']["{$capctxp}:$roleid"][$capability]; - // The most local permission (first to set) wins - // the only exception is CAP_PROHIBIT - if ($rolecan === 0) { - $rolecan = $perm; - $rolecapdepth = $m; - } elseif ($perm === $CAP_PROHIBIT) { - $rolecan = $perm; - $rolecapdepth = $m; - break; - } - } + if (!$switchedrole) { + // get all users roles in this context and above + foreach ($paths as $path) { + if (isset($accessdata['ra'][$path])) { + foreach ($accessdata['ra'][$path] as $roleid) { + $roles[$roleid] = null; } - // Rules for RAs at the same context... - // - prohibits always wins - // - permissions at the same ctxlevel & capdepth are added together - // - deeper capdepth wins - if ($ctxcan === $CAP_PROHIBIT || $rolecan === $CAP_PROHIBIT) { - $ctxcan = $CAP_PROHIBIT; - $ctxcapdepth = 0; - } elseif ($ctxcapdepth === $rolecapdepth) { - $ctxcan += $rolecan; - } elseif ($ctxcapdepth < $rolecapdepth) { - $ctxcan = $rolecan; - $ctxcapdepth = $rolecapdepth; - } else { // ctxcaptdepth is deeper - // rolecap ignored + } + } + + // 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 or $capability === 'moodle/site:doanything') { + $systempath = '/'.SYSCONTEXTID; + foreach ($roles as $roleid=>$ignored) { + if (isset($accessdata['rdef']["{$systempath}:$roleid"]['moodle/site:doanything']) and $accessdata['rdef']["{$systempath}:$roleid"]['moodle/site:doanything'] == CAP_ALLOW) { + return true; } } - // The most local RAs with a defined - // permission ($ctxcan) win, except - // for CAP_PROHIBIT - // NOTE: If we want the deepest RDEF to - // win regardless of the depth of the RA, - // change the elseif below to read - // ($can === 0 || $capdepth < $ctxcapdepth) { - if ($ctxcan === $CAP_PROHIBIT) { - $can = $ctxcan; - break; - } elseif ($can === 0) { // see note above - $can = $ctxcan; - $capdepth = $ctxcapdepth; + if ($capability === 'moodle/site:doanything') { + // do anything can not be overridden, prevented or prohibited + return false; } } } - if ($can < 1) { - if ($doanything) { - // didn't find it as an explicit cap, - // but maybe the user can doanything in this context... - return has_capability_in_accessdata('moodle/site:doanything', $context, $accessdata, false); - } else { - return false; + // Now find out what access is given to each role, going bottom-->up direction + foreach ($roles as $roleid => $ignored) { + foreach ($paths as $path) { + if (isset($accessdata['rdef']["{$path}:$roleid"][$capability])) { + $perm = (int)$accessdata['rdef']["{$path}:$roleid"][$capability]; + if ($perm === CAP_PROHIBIT or is_null($roles[$roleid])) { + $roles[$roleid] = $perm; + } + } } - } else { - return true; + } + // any CAP_PROHIBIT found means no permission for the user + if (array_search(CAP_PROHIBIT, $roles) !== false) { + return false; } + // at least one CAP_ALLOW means the user has a permission + return (array_search(CAP_ALLOW, $roles) !== false); } /** @@ -2604,12 +2497,12 @@ /** * Get a context instance as an object, from a given context id. * - * @global object - * @global object * @param mixed $id a context id or array of ids. + * @param int $strictness IGNORE_MISSING means compatible mode, false returned if record not found, debug message if more found; + * MUST_EXIST means throw exception if no record or multiple records found * @return mixed object, array of the context object, or false. */ -function get_context_instance_by_id($id) { +function get_context_instance_by_id($id, $strictness=IGNORE_MISSING) { global $DB, $ACCESSLIB_PRIVATE; if ($id == SYSCONTEXTID) { @@ -2620,7 +2513,7 @@ return $ACCESSLIB_PRIVATE->contextsbyid[$id]; } - if ($context = $DB->get_record('context', array('id'=>$id))) { + if ($context = $DB->get_record('context', array('id'=>$id), '*', $strictness)) { cache_context($context); return $context; } @@ -2642,6 +2535,40 @@ return $DB->get_record('role_capabilities', array('roleid'=>$roleid, 'capability'=>$capability, 'contextid'=>$contextid)); } +/** + * Returns context instance plus related course and cm instances + * @param int $contextid + * @return array of ($context, $course, $cm) + */ +function get_context_info_array($contextid) { + global $DB; + + $context = get_context_instance_by_id($contextid, MUST_EXIST); + $course = null; + $cm = null; + + if ($context->contextlevel == CONTEXT_COURSE) { + $course = $DB->get_record('course', array('id'=>$context->instanceid), '*', MUST_EXIST); + + } else if ($context->contextlevel == CONTEXT_MODULE) { + $cm = get_coursemodule_from_id('', $context->instanceid, 0, false, MUST_EXIST); + $course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST); + + } else if ($context->contextlevel == CONTEXT_BLOCK) { + $parentcontexts = get_parent_contexts($context, false); + $parent = reset($parentcontexts); + $parent = get_context_instance_by_id($parent); + + if ($parent->contextlevel == CONTEXT_COURSE) { + $course = $DB->get_record('course', array('id'=>$parent->instanceid), '*', MUST_EXIST); + } else if ($parent->contextlevel == CONTEXT_MODULE) { + $cm = get_coursemodule_from_id('', $parent->instanceid, 0, false, MUST_EXIST); + $course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST); + } + } + + return array($context, $course, $cm); +} ////////////////////////////////////// @@ -3507,52 +3434,44 @@ * CONTEXT_COURSE, this is the course page. For CONTEXT_USER it is the * user profile page. * - * First three parameters as for - * - * @global object - * @global object - * @global object * @param object $context the context. - * @return string a suitable URL, or blank. + * @return moodle_url */ function get_context_url($context) { - global $CFG, $COURSE, $DB; + global $COURSE, $DB; - $url = ''; switch ($context->contextlevel) { case CONTEXT_USER: - $url = $CFG->wwwroot . '/user/view.php?id=' . $context->instanceid; + $url = new moodle_url('/user/view.php', array('id'=>$context->instanceid)); if ($COURSE->id != SITEID) { - $url .= '&courseid=' . $COURSE->id; + $url->param('courseid', $COURSE->id); } - break; + return $url;; case CONTEXT_COURSECAT: // Coursecat -> coursecat or site - $url = $CFG->wwwroot . '/course/category.php?id=' . $context->instanceid; - break; + return new moodle_url('/course/category.php', array('id'=>$context->instanceid)); case CONTEXT_COURSE: // 1 to 1 to course cat - if ($context->instanceid == SITEID) { - $url = $CFG->wwwroot . '/'; - } else { - $url = $CFG->wwwroot . '/course/view.php?id=' . $context->instanceid; + if ($context->instanceid != SITEID) { + return new moodle_url('/course/view.php', array('id'=>$context->instanceid)); } break; case CONTEXT_MODULE: // 1 to 1 to course if ($modname = $DB->get_field_sql('SELECT md.name AS modname FROM {course_modules} cm ' . 'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?', array($context->instanceid))) { - $url = $CFG->wwwroot . '/mod/' . $modname . '/view.php?id=' . $context->instanceid; + return new moodle_url('/mod/' . $modname . '/view.php', array('id'=>$context->instanceid)); } break; - case CONTEXT_SYSTEM: case CONTEXT_BLOCK: - default: - $url = ''; + $parentcontexts = get_parent_contexts($context, false); + $parent = reset($parentcontexts); + $parent = get_context_instance_by_id($parent); + return get_context_url($parent); } - return $url; + return new moodle_url('/'); } /** @@ -4768,20 +4687,16 @@ * which can get rather large - and has a serious perf impact * on some DBs. * - * @global object - * @global object * @param object $context - * @param string $capability - string capability, or an array of capabilities, in which - * case users having any of those capabilities will be returned. - * For performance reasons, you are advised to put the capability - * that the user is most likely to have first. + * @param string|array $capability - capability name(s) * @param string $fields - fields to be pulled. The user table is aliased to 'u'. u.id MUST be included. * @param string $sort - the sort order. Default is lastaccess time. * @param mixed $limitfrom - number of records to skip (offset) * @param mixed $limitnum - number of records to fetch - * @param mixed $groups - single group or array of groups - only return + * @param string|array $groups - single group or array of groups - only return * users who are in one of these group(s). - * @param mixed $exceptions - list of users to exclude, comma separated or array + * @param string|array $exceptions - list of users to exclude, comma separated or array + * @param bool $doanything prohibit takes over admin roles here, in has_capability() it does not * @param bool $view - set to true when roles are pulled for display only * this is so that we can filter roles with no visible * assignment, for example, you might want to "hide" all @@ -4793,17 +4708,23 @@ * in $groups. * @return mixed */ -function get_users_by_capability($context, $capability, $fields='', $sort='', - $limitfrom='', $limitnum='', $groups='', $exceptions='', $doanything=true, - $view=false, $useviewallgroups=false) { +function get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='', $limitnum='', + $groups='', $exceptions='', $doanything=true, $view=false, $useviewallgroups=false) { global $CFG, $DB; - $ctxids = substr($context->path, 1); // kill leading slash + if (empty($context->id)) { + throw new coding_exception('Invalid context specified'); + } + + $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : null; + $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : null; + + $ctxids = trim($context->path, '/'); $ctxids = str_replace('/', ',', $ctxids); // Context is the frontpage - $isfrontpage = false; $iscoursepage = false; // coursepage other than fp + $isfrontpage = false; if ($context->contextlevel == CONTEXT_COURSE) { if ($context->instanceid == SITEID) { $isfrontpage = true; @@ -4811,153 +4732,115 @@ $iscoursepage = true; } } + $isfrontpage = ($isfrontpage || is_inside_frontpage($context)); - // What roles/rolecaps are interesting? - if (is_array($capability)) { - $caps = $capability; - } else { - $caps = array($capability); - } - if ($doanything === true) { + $caps = (array)$capability; + if ($doanything) { $caps[] = 'moodle/site:doanything'; - $doanything_join=''; - $doanything_cond=''; - - } else { - // This is an outer join against - // admin-ish roleids. Any row that succeeds - // in JOINing here ends up removed from - // the resultset. This means we remove - // rolecaps from roles that also have - // 'doanything' capabilities. - $doanything_join="LEFT OUTER JOIN ( - SELECT DISTINCT rc.roleid - FROM {role_capabilities} rc - WHERE rc.capability=:capany - AND rc.permission=".CAP_ALLOW." - AND rc.contextid IN ($ctxids) - ) dar - ON rc.roleid=dar.roleid"; - $doanything_cond="AND dar.roleid IS NULL"; - } - - // fetch all capability records - we'll walk several - // times over them, and should be a small set - - $negperm = false; // has any negative (<0) permission? - $roleids = array(); - - list($capstest, $params) = $DB->get_in_or_equal($caps, SQL_PARAMS_NAMED, 'cap0'); - $params['capany'] = 'moodle/site:doanything'; + } - $sql = "SELECT rc.id, rc.roleid, rc.permission, rc.capability, - ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel + // contruct list of context paths bottom-->top + $contextids = explode(',', $ctxids); + $paths = array($context->path); + $contextids2 = $contextids; + while ($contextids2) { + array_pop($contextids2); + $paths[] = '/' . implode('/', $contextids2); + } + unset($contextids2); + + + // we need to find out all roles that have these capabilities either in definition or in overrides + $defs = array(); + list($incontexts, $params) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'con000'); + list($incaps, $params2) = $DB->get_in_or_equal($caps, SQL_PARAMS_NAMED, 'cap000'); + $params = array_merge($params, $params2); + $sql = "SELECT rc.id, rc.roleid, rc.permission, rc.capability, ctx.path FROM {role_capabilities} rc JOIN {context} ctx on rc.contextid = ctx.id - $doanything_join - WHERE rc.capability $capstest AND ctx.id IN ($ctxids) - $doanything_cond - ORDER BY rc.roleid ASC, ctx.depth ASC"; + WHERE rc.contextid $incontexts AND rc.capability $incaps"; - if ($capdefs = $DB->get_records_sql($sql, $params)) { - foreach ($capdefs AS $rcid=>$rc) { - $roleids[] = (int)$rc->roleid; - if ($rc->permission < 0) { - $negperm = true; - } - } - } - - $roleids = array_unique($roleids); - - if (count($roleids)===0) { // noone here! - return array(); + $rcs = $DB->get_records_sql($sql, $params); + foreach ($rcs as $rc) { + $defs[$rc->capability][$rc->path][$rc->roleid] = $rc->permission; } - // is the default role interesting? does it have - // a relevant rolecap? (we use this a lot later) - if (isset($CFG->defaultuserroleid) and in_array((int)$CFG->defaultuserroleid, $roleids, true)) { - $defaultroleinteresting = true; - } else { - $defaultroleinteresting = false; - } - - // is the default role interesting? does it have - // a relevant rolecap? (we use this a lot later) - if (($isfrontpage or is_inside_frontpage($context)) and !empty($CFG->defaultfrontpageroleid) and in_array((int)$CFG->defaultfrontpageroleid, $roleids, true)) { - if (!empty($CFG->fullusersbycapabilityonfrontpage)) { - // new in 1.9.6 - full support for defaultfrontpagerole MDL-19039 - $frontpageroleinteresting = true; - } else { - // old style 1.9.0-1.9.5 - much faster + fewer negative override problems on frontpage - $frontpageroleinteresting = ($context->contextlevel == CONTEXT_COURSE); + // go through the permissions bottom-->top direction to evaluate the current permission, + // first one wins (prohibit is an exception that always wins) + $access = array(); + foreach ($caps as $cap) { + foreach ($paths as $path) { + if (empty($defs[$cap][$path])) { + continue; + } + foreach($defs[$cap][$path] as $roleid => $perm) { + if ($perm == CAP_PROHIBIT) { + $access[$cap][$roleid] = CAP_PROHIBIT; + continue; + } + if (!isset($access[$cap][$roleid])) { + $access[$cap][$roleid] = (int)$perm; + } + } } - } else { - $frontpageroleinteresting = false; } - // - // Prepare query clauses - // - $wherecond = array(); - - // Non-deleted users. We never return deleted users. - $wherecond['nondeleted'] = 'u.deleted = 0'; - - /// Groups - if ($groups) { - if (is_array($groups)) { - $grouptest = 'gm.groupid IN (' . implode(',', $groups) . ')'; - } else { - $grouptest = 'gm.groupid = ' . (int)$groups; + // make lists of roles that are needed and prohibited in this context + $needed = array(); // one of these is enough + $prohibited = array(); // must not have any of these + foreach ($caps as $cap) { + if (empty($access[$cap])) { + continue; } - $grouptest = 'ra.userid IN (SELECT userid FROM ' . - '{groups_members} gm WHERE ' . $grouptest . ')'; - - if ($useviewallgroups) { - $viewallgroupsusers = get_users_by_capability($context, - 'moodle/site:accessallgroups', 'u.id, u.id', '', '', '', '', $exceptions); - $wherecond['groups'] = '('. $grouptest . ' OR ra.userid IN (' . - implode(',', array_keys($viewallgroupsusers)) . '))'; - } else { - $wherecond['groups'] = '(' . $grouptest .')'; + foreach ($access[$cap] as $roleid => $perm) { + if ($perm == CAP_PROHIBIT) { + unset($needed[$cap][$roleid]); + $prohibited[$cap][$roleid] = true; + } else if ($perm == CAP_ALLOW and empty($prohibited[$cap][$roleid])) { + $needed[$cap][$roleid] = true; + } + } + if (empty($needed[$cap]) or !empty($prohibited[$cap][$defaultuserroleid])) { + // easy, nobody has the permission + unset($needed[$cap]); + unset($prohibited[$cap]); + } else if ($isfrontpage and !empty($prohibited[$cap][$defaultfrontpageroleid])) { + // everybody is disqualified on the frontapge + unset($needed[$cap]); + unset($prohibited[$cap]); } - } - - /// User exceptions - if (!empty($exceptions)) { - if (is_array($exceptions)) { - $exceptions = implode(',', $exceptions); + if (empty($prohibited[$cap])) { + unset($prohibited[$cap]); } - $wherecond['userexceptions'] = ' u.id NOT IN ('.$exceptions.')'; } - /// Set up hidden role-assignments sql - if ($view && !has_capability('moodle/role:viewhiddenassigns', $context)) { - $condhiddenra = 'AND ra.hidden = 0 '; - $sscondhiddenra = 'AND ssra.hidden = 0 '; - } else { - $condhiddenra = ''; - $sscondhiddenra = ''; + if (empty($needed)) { + // there can not be anybody if no roles match this request + return array(); } - // Collect WHERE conditions - $where = implode(' AND ', array_values($wherecond)); - if ($where != '') { - $where = 'WHERE ' . $where; + if (empty($prohibited)) { + // we can compact the needed roles + $n = array(); + foreach ($needed as $cap) { + foreach ($cap as $roleid=>$unused) { + $n[$roleid] = true; + } + } + $needed = array('any'=>$n); + unset($n); } - /// Set up default fields + /// ***** Set up default fields ****** if (empty($fields)) { if ($iscoursepage) { - $fields = 'u.*, ul.timeaccess as lastaccess'; + $fields = 'u.*, ul.timeaccess AS lastaccess'; } else { $fields = 'u.*'; } } else { - if (debugging('', DEBUG_DEVELOPER) && strpos($fields, 'u.*') === false && - strpos($fields, 'u.id') === false) { - debugging('u.id must be included in the list of fields passed to get_users_by_capability.', DEBUG_DEVELOPER); + if (debugging('', DEBUG_DEVELOPER) && strpos($fields, 'u.*') === false && strpos($fields, 'u.id') === false) { + debugging('u.id must be included in the list of fields passed to get_users_by_capability().', DEBUG_DEVELOPER); } } @@ -4969,377 +4852,140 @@ $sort = 'u.lastaccess'; } } - $sortby = $sort ? " ORDER BY $sort " : ''; + $sortby = "ORDER BY $sort"; + + // Prepare query clauses + $wherecond = array(); + $params = array(); + $joins = array(); // User lastaccess JOIN - if ((strpos($sort, 'ul.timeaccess') === FALSE) and (strpos($fields, 'ul.timeaccess') === FALSE)) { // user_lastaccess is not required MDL-13810 - $uljoin = ''; + if ((strpos($sort, 'ul.timeaccess') === false) and (strpos($fields, 'ul.timeaccess') === false)) { + // user_lastaccess is not required MDL-13810 } else { - $uljoin = "LEFT OUTER JOIN {user_lastaccess} ul - ON (ul.userid = u.id AND ul.courseid = {$context->instanceid})"; + if ($iscoursepage) { + $joins[] = "LEFT OUTER JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = {$context->instanceid})"; + } else { + throw new coding_exception('Invalid sort in get_users_by_capability(), ul.timeaccess allowed only for course contexts.'); + } } - // - // Simple cases - No negative permissions means we can take shortcuts - // - if (!$negperm) { + /// We never return deleted users or guest acount. + $wherecond[] = "u.deleted = 0 AND u.username <> 'guest'"; - // at the frontpage, and all site users have it - easy! - if ($frontpageroleinteresting) { - return $DB->get_records_sql("SELECT $fields - FROM {user} u - WHERE u.deleted = 0 - ORDER BY $sort", - $limitfrom, $limitnum); - } - - // all site users have it, anyway - // TODO: NOT ALWAYS! Check this case because this gets run for cases like this: - // 1) Default role has the permission for a module thing like mod/choice:choose - // 2) We are checking for an activity module context in a course - // 3) Thus all users are returned even though course:view is also required - if ($defaultroleinteresting) { - $sql = "SELECT $fields - FROM {user} u - $uljoin - $where - ORDER BY $sort"; - return $DB->get_records_sql($sql, null, $limitfrom, $limitnum); - } - - /// Simple SQL assuming no negative rolecaps. - /// We use a subselect to grab the role assignments - /// ensuring only one row per user -- even if they - /// have many "relevant" role assignments. - $select = " SELECT $fields"; - $from = " FROM {user} u - JOIN (SELECT DISTINCT ssra.userid - FROM {role_assignments} ssra - WHERE ssra.contextid IN ($ctxids) - AND ssra.roleid IN (".implode(',',$roleids) .") - $sscondhiddenra - ) ra ON ra.userid = u.id - $uljoin "; - return $DB->get_records_sql($select.$from.$where.$sortby, null, $limitfrom, $limitnum); - } - - // - // If there are any negative rolecaps, we need to - // work through a subselect that will bring several rows - // per user (one per RA). - // Since we cannot do the job in pure SQL (not without SQL stored - // procedures anyway), we end up tied to processing the data in PHP - // all the way down to pagination. - // - // In some cases, this will mean bringing across a ton of data -- - // when paginating, we have to walk the permisisons of all the rows - // in the _previous_ pages to get the pagination correct in the case - // of users that end up not having the permission - this removed. - // - - // Prepare the role permissions datastructure for fast lookups - $roleperms = array(); // each role cap and depth - foreach ($capdefs AS $rcid=>$rc) { - - $rid = (int)$rc->roleid; - $perm = (int)$rc->permission; - $rcdepth = (int)$rc->ctxdepth; - if (!isset($roleperms[$rc->capability][$rid])) { - $roleperms[$rc->capability][$rid] = (object)array('perm' => $perm, - 'rcdepth' => $rcdepth); + /// Groups + if ($groups) { + $groups = (array)$groups; + list($grouptest, $grpparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED, 'grp000'); + $grouptest = "u.id IN (SELECT userid FROM {groups_members} gm WHERE gm.groupid $grouptest)"; + $params = array_merge($params, $grpparams); + + if ($useviewallgroups) { + $viewallgroupsusers = get_users_by_capability($context, 'moodle/site:accessallgroups', 'u.id, u.id', '', '', '', '', $exceptions); + $wherecond[] = "($grouptest OR u.id IN (" . implode(',', array_keys($viewallgroupsusers)) . '))'; } else { - if ($roleperms[$rc->capability][$rid]->perm == CAP_PROHIBIT) { - continue; - } - // override - as we are going - // from general to local perms - // (as per the ORDER BY...depth ASC above) - // and local perms win... - $roleperms[$rc->capability][$rid] = (object)array('perm' => $perm, - 'rcdepth' => $rcdepth); + $wherecond[] = "($grouptest)"; } + } + /// User exceptions + if (!empty($exceptions)) { + $exceptions = (array)$exceptions; + list($exsql, $exparams) = $DB->get_in_or_equal($exceptions, SQL_PARAMS_NAMED, 'exc000', false); + $params = array_merge($params, $exparams); + $wherecond[] = "u.id $exsql"; } - if ($context->contextlevel == CONTEXT_SYSTEM - || $isfrontpage - || $defaultroleinteresting) { - - // Handle system / sitecourse / defaultrole-with-perhaps-neg-overrides - // with a SELECT FROM user LEFT OUTER JOIN against ra - - // This is expensive on the SQL and PHP sides - - // moves a ton of data across the wire. - $ss = "SELECT u.id as userid, ra.roleid, - ctx.depth - FROM {user} u - LEFT OUTER JOIN {role_assignments} ra - ON (ra.userid = u.id - AND ra.contextid IN ($ctxids) - AND ra.roleid IN (".implode(',',$roleids) .") - $condhiddenra) - LEFT OUTER JOIN {context} ctx - ON ra.contextid=ctx.id - WHERE u.deleted=0"; + /// Set up hidden role-assignments sql + if ($view and !has_capability('moodle/role:viewhiddenassigns', $context)) { + $condhiddenra = 'AND hidden = 0'; } else { - // "Normal complex case" - the rolecaps we are after will - // be defined in a role assignment somewhere. - $ss = "SELECT ra.userid as userid, ra.roleid, - ctx.depth - FROM {role_assignments} ra - JOIN {context} ctx - ON ra.contextid=ctx.id - WHERE ra.contextid IN ($ctxids) - $condhiddenra - AND ra.roleid IN (".implode(',',$roleids) .")"; - } - - $select = "SELECT $fields ,ra.roleid, ra.depth "; - $from = "FROM ($ss) ra - JOIN {user} u - ON ra.userid=u.id - $uljoin "; - - // Each user's entries MUST come clustered together - // and RAs ordered in depth DESC - the role/cap resolution - // code depends on this. - $sort .= ' , ra.userid ASC, ra.depth DESC'; - $sortby .= ' , ra.userid ASC, ra.depth DESC '; - - if (!$rs = $DB->get_recordset_sql($select.$from.$where.$sortby)) { - return array(); + $condhiddenra = ''; } - // - // Process the user accounts+RAs, folding repeats together... - // - // The processing for this recordset is tricky - to fold - // the role/perms of users with multiple role-assignments - // correctly while still processing one-row-at-a-time - // we need to add a few additional 'private' fields to - // the results array - so we can treat the rows as a - // state machine to track the cap/perms and at what RA-depth - // and RC-depth they were defined. - // - // So what we do here is: - // - loop over rows, checking pagination limits - // - when we find a new user, if we are in the page add it to the - // $results, and start building $ras array with its role-assignments - // - when we are dealing with the next user, or are at the end of the userlist - // (last rec or last in page), trigger the check-permission idiom - // - the check permission idiom will - // - add the default enrolment if needed - // - call has_any_capability_from_rarc(), which based on RAs and RCs will return a bool - // (should be fairly tight code ;-) ) - // - if the user has permission, all is good, just $c++ (counter) - // - ...else, decrease the counter - so pagination is kept straight, - // and (if we are in the page) remove from the results - // - $results = array(); - - // pagination controls - $c = 0; - $limitfrom = (int)$limitfrom; - $limitnum = (int)$limitnum; - - // - // Track our last user id so we know when we are dealing - // with a new user... - // - $lastuserid = 0; - // - // In this loop, we - // $ras: role assignments, multidimensional array - // treat as a stack - going from local to general - // $ras = (( roleid=> x, $depth=>y) , ( roleid=> x, $depth=>y)) - // - foreach($rs as $user) { - - //error_log(" Record: " . print_r($user,1)); - - // - // Pagination controls - // Note that we might end up removing a user - // that ends up _not_ having the rights, - // therefore rolling back $c - // - if ($lastuserid != $user->id) { - - // Did the last user end up with a positive permission? - if ($lastuserid !=0) { - if ($frontpageroleinteresting) { - // add frontpage role if interesting - $ras[] = array('roleid' => $CFG->defaultfrontpageroleid, - 'depth' => $context->depth); - } - if ($defaultroleinteresting) { - // add the role at the end of $ras - $ras[] = array( 'roleid' => $CFG->defaultuserroleid, - 'depth' => 1 ); + // now add the needed and prohibited roles conditions as joins + if (!empty($needed['any'])) { + // simple case - there are no prohibits involved + if (!empty($needed['any'][$defaultuserroleid]) or ($isfrontpage and !empty($needed['any'][$defaultfrontpageroleid]))) { + // everybody + } else { + $joins[] = "JOIN (SELECT DISTINCT userid + FROM {role_assignments} + WHERE contextid IN ($ctxids) + AND roleid IN (".implode(',', array_keys($needed['any'])) .") + $condhiddenra + ) ra ON ra.userid = u.id"; + } + } else { + $unions = array(); + $everybody = false; + foreach ($needed as $cap=>$unused) { + if (empty($prohibited[$cap])) { + if (!empty($needed[$cap][$defaultuserroleid]) or ($isfrontpage and !empty($needed[$cap][$defaultfrontpageroleid]))) { + $everybody = true; + break; + } else { + $unions[] = "SELECT userid + FROM {role_assignments} + WHERE contextid IN ($ctxids) + AND roleid IN (".implode(',', array_keys($needed[$cap])) .") + $condhiddenra"; } - if (has_any_capability_from_rarc($ras, $roleperms, $caps)) { - $c++; + } else { + if (!empty($needed[$cap][$defaultuserroleid]) or ($isfrontpage and !empty($needed[$cap][$defaultfrontpageroleid]))) { + // everybody except the prohibitted - hiding does not matter + $unions[] = "SELECT id AS userid + FROM {user} + WHERE id NOT IN (SELECT userid + FROM {role_assignments} + WHERE contextid IN ($ctxids) + AND roleid IN (".implode(',', array_keys($prohibited[$cap])) ."))"; + } else { - // remove the user from the result set, - // only if we are 'in the page' - if ($limitfrom === 0 || $c >= $limitfrom) { - unset($results[$lastuserid]); + if ($condhiddenra) { + $unions[] = "SELECT userid + FROM {role_assignments} + WHERE contextid IN ($ctxids) + AND roleid IN (".implode(',', array_keys($needed[$cap])) .") $condhiddenra + AND userid NOT IN (SELECT userid + FROM {role_assignments} + WHERE contextid IN ($ctxids) + AND roleid IN (".implode(',', array_keys($prohibited[$cap])) ."))"; + } else { + $unions[] = "SELECT userid + FROM {role_assignments} + WHERE contextid IN ($ctxids) + AND roleid IN (".implode(',', array_keys($needed[$cap])) .") + AND roleid NOT IN (".implode(',', array_keys($prohibited[$cap])) .")"; } } } - - // Did we hit pagination limit? - if ($limitnum !==0 && $c >= ($limitfrom+$limitnum)) { // we are done! - break; - } - - // New user setup, and $ras reset - $lastuserid = $user->id; - $ras = array(); - if (!empty($user->roleid)) { - $ras[] = array( 'roleid' => (int)$user->roleid, - 'depth' => (int)$user->depth ); - } - - // if we are 'in the page', also add the rec - // to the results... - if ($limitfrom === 0 || $c >= $limitfrom) { - $results[$user->id] = $user; // trivial - } - } else { - // Additional RA for $lastuserid - $ras[] = array( 'roleid'=>(int)$user->roleid, - 'depth'=>(int)$user->depth ); } - - } // end while(fetch) - $rs->close(); - - // Prune last entry if necessary - if ($lastuserid !=0) { - if ($frontpageroleinteresting) { - // add frontpage role if interesting - $ras[] = array('roleid' => $CFG->defaultfrontpageroleid, - 'depth' => $context->depth); - } - if ($defaultroleinteresting) { - // add the role at the end of $ras - $ras[] = array( 'roleid' => $CFG->defaultuserroleid, - 'depth' => 1 ); - } - if (!has_any_capability_from_rarc($ras, $roleperms, $caps)) { - // remove the user from the result set, - // only if we are 'in the page' - if ($limitfrom === 0 || $c >= $limitfrom) { - if (isset($results[$lastuserid])) { - unset($results[$lastuserid]); - } + if (!$everybody) { + if (count($unions) > 1) { + $unions = implode(' UNION ', $unions); + } else { + $unions = reset($unions); } + $joins[] = "JOIN (SELECT DISTINCT userid FROM ( $unions ) us) ra ON ra.userid = u.id"; } } - return $results; -} + // Collect WHERE conditions and needed joins + $where = implode(' AND ', $wherecond); + if ($where !== '') { + $where = 'WHERE ' . $where; + } + $joins = implode("\n", $joins); -/** - * Check if any of a list of capabilities is granted - * - * Fast (fast!) utility function to resolve if any of a list of capabilities is - * granted, based on Role Assignments and Role Capabilities. - * - * Used (at least) by get_users_by_capability(). - * - * If PHP had fast built-in memoize functions, we could - * add a $contextid parameter and memoize the return values. - * - * Note that this function must be kept in synch with has_capability_in_accessdata. - * - * @param array $ras role assignments - * @param array $roleperms role permissions - * @param string $capabilities array of capability names - * @return bool - */ -function has_any_capability_from_rarc($ras, $roleperms, $caps) { - // Mini-state machine, using $hascap - // $hascap[ 'moodle/foo:bar' ]->perm = CAP_SOMETHING (numeric constant) - // $hascap[ 'moodle/foo:bar' ]->radepth = depth of the role assignment that set it - // $hascap[ 'moodle/foo:bar' ]->rcdepth = depth of the rolecap that set it - // -- when resolving conflicts, we need to look into radepth first, if unresolved - - $hascap = array(); - - // - // Compute which permission/roleassignment/rolecap - // wins for each capability we are walking - // - foreach ($ras as $ra) { - foreach ($caps as $cap) { - if (!isset($roleperms[$cap][$ra['roleid']])) { - // nothing set for this cap - skip - continue; - } - // We explicitly clone here as we - // add more properties to it - // that must stay separate from the - // original roleperm data structure - $rp = clone($roleperms[$cap][$ra['roleid']]); - $rp->radepth = $ra['depth']; - - // Trivial case, we are the first to set - if (!isset($hascap[$cap])) { - $hascap[$cap] = $rp; - } - - // - // Resolve who prevails, in order of precendence - // - Prohibits always wins - // - Locality of RA - // - Locality of RC - // - //// Prohibits... - if ($rp->perm === CAP_PROHIBIT) { - $hascap[$cap] = $rp; - continue; - } - if ($hascap[$cap]->perm === CAP_PROHIBIT) { - continue; - } + /// Ok, let's get the users! + $sql = "SELECT $fields + FROM {user} u + $joins + $where + ORDER BY $sort"; - // Locality of RA - the look is ordered by depth DESC - // so from local to general - - // Higher RA loses to local RA... unless perm===0 - /// Thanks to the order of the records, $rp->radepth <= $hascap[$cap]->radepth - if ($rp->radepth > $hascap[$cap]->radepth) { - error_log('Should not happen @ ' . __FUNCTION__.':'.__LINE__); - } - if ($rp->radepth < $hascap[$cap]->radepth) { - if ($hascap[$cap]->perm!==0) { - // Wider RA loses to local RAs... - continue; - } else { - // "Higher RA resolves conflict" case, - // local RAs had cancelled eachother - $hascap[$cap] = $rp; - continue; - } - } - // Same ralevel - locality of RC wins - if ($rp->rcdepth > $hascap[$cap]->rcdepth) { - $hascap[$cap] = $rp; - continue; - } - if ($rp->rcdepth > $hascap[$cap]->rcdepth) { - continue; - } - // We match depth - add them - $hascap[$cap]->perm += $rp->perm; - } - } - foreach ($caps as $capability) { - if (isset($hascap[$capability]) && $hascap[$capability]->perm > 0) { - return true; - } - } - return false; + return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); } /** @@ -6318,3 +5964,169 @@ $DB->insert_record('role_capabilities', $cap); } } + + +/** + * Returns two lists, this can be used to find out if user has capability. + * Having any neede role and no forbidden role in this context means + * user has this capability in this context, + * + * @param object $context + * @param string $capability + * @return array($neededroles, $forbiddenroles) + */ +function get_roles_with_cap_in_context($context, $capability) { + global $DB; + + $ctxids = trim($context->path, '/'); // kill leading slash + $ctxids = str_replace('/', ',', $ctxids); + + $sql = "SELECT rc.id, rc.roleid, rc.permission, ctx.depth + FROM {role_capabilities} rc + JOIN {context} ctx ON ctx.id = rc.contextid + WHERE rc.capability = :cap AND ctx.id IN ($ctxids) + ORDER BY rc.roleid ASC, ctx.depth DESC"; + $params = array('cap'=>$capability); + + if (!$capdefs = $DB->get_records_sql($sql, $params)) { + // no cap definitions --> no capability + return array(array(), array()); + } + + $forbidden = array(); + $needed = array(); + foreach($capdefs as $def) { + if (isset($forbidden[$def->roleid])) { + continue; + } + if ($def->permission == CAP_PROHIBIT) { + $forbidden[$def->roleid] = $def->roleid; + unset($needed[$def->roleid]); + continue; + } + if (!isset($needed[$def->roleid])) { + if ($def->permission == CAP_ALLOW) { + $needed[$def->roleid] = true; + } else if ($def->permission == CAP_PREVENT) { + $needed[$def->roleid] = false; + } + } + } + unset($capdefs); + + // remove all those roles not allowing + foreach($needed as $key=>$value) { + if (!$value) { + unset($needed[$key]); + } else { + $needed[$key] = $key; + } + } + + return array($needed, $forbidden); +} + +/** + * This function verifies the prohibit comes from this context + * and there are no more prohibits in parent contexts. + * @param object $context + * @param string $capability name + * @return bool + */ +function prohibit_is_removable($roleid, $context, $capability) { + global $DB; + + $ctxids = trim($context->path, '/'); // kill leading slash + $ctxids = str_replace('/', ',', $ctxids); + + $params = array('roleid'=>$roleid, 'cap'=>$capability, 'prohibit'=>CAP_PROHIBIT); + + $sql = "SELECT ctx.id + FROM {role_capabilities} rc + JOIN {context} ctx ON ctx.id = rc.contextid + WHERE rc.roleid = :roleid AND rc.permission = :prohibit AND rc.capability = :cap AND ctx.id IN ($ctxids) + ORDER BY ctx.depth DESC"; + + if (!$prohibits = $DB->get_records_sql($sql, $params)) { + // no prohibits == nothing to remove + return true; + } + + if (count($prohibits) > 1) { + // more prohibints can not be removed + return false; + } + + return !empty($prohibits[$context->id]); +} + +/** + * More user friendly role permission changing, + * it should produce as few overrides as possible. + * @param int $roleid + * @param object $context + * @param string $capname capability name + * @param int $permission + * @return void + */ +function role_change_permission($roleid, $context, $capname, $permission) { + global $DB; + + if ($capname === 'moodle/site:doanything' or is_legacy($capname)) { + return; + } + + if ($permission == CAP_INHERIT) { + unassign_capability($capname, $roleid, $context->id); + mark_context_dirty($context->path); + return; + } + + $ctxids = trim($context->path, '/'); // kill leading slash + $ctxids = str_replace('/', ',', $ctxids); + + $params = array('roleid'=>$roleid, 'cap'=>$capname); + + $sql = "SELECT ctx.id, rc.permission, ctx.depth + FROM {role_capabilities} rc + JOIN {context} ctx ON ctx.id = rc.contextid + WHERE rc.roleid = :roleid AND rc.capability = :cap AND ctx.id IN ($ctxids) + ORDER BY ctx.depth DESC"; + + if ($existing = $DB->get_records_sql($sql, $params)) { + foreach($existing as $e) { + if ($e->permission == CAP_PROHIBIT) { + // prohibit can not be overridden, no point in changing anything + return; + } + } + $lowest = array_shift($existing); + if ($lowest->permission == $permission) { + // permission already set in this context or parent - nothing to do + return; + } + if ($existing) { + $parent = array_shift($existing); + if ($parent->permission == $permission) { + // permission already set in parent context or parent - just unset in this context + // we do this because we want as few overrides as possible for performance reasons + unassign_capability($capname, $roleid, $context->id); + mark_context_dirty($context->path); + return; + } + } + + } else { + if ($permission == CAP_PREVENT) { + // nothing means role does not have permission + return; + } + } + + // assign the needed capability + assign_capability($capname, $permission, $roleid, $context->id, true); + + // force cap reloading + mark_context_dirty($context->path); +} + Index: lib/deprecatedlib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/deprecatedlib.php,v retrieving revision 1.213 diff -u -r1.213 deprecatedlib.php --- lib/deprecatedlib.php 17 Feb 2010 16:59:42 -0000 1.213 +++ lib/deprecatedlib.php 5 Mar 2010 08:29:07 -0000 @@ -3010,8 +3010,8 @@ global $OUTPUT; - $buttoncontinue = new simple_button(new moodle_url($linkyes, $optionsyes), get_string('yes'), $methodyes); - $buttoncancel = new simple_button(new moodle_url($linkno, $optionsno), get_string('no'), $methodno); + $buttoncontinue = new single_button(new moodle_url($linkyes, $optionsyes), get_string('yes'), $methodyes); + $buttoncancel = new single_button(new moodle_url($linkno, $optionsno), get_string('no'), $methodno); echo $OUTPUT->confirm($message, $buttoncontinue, $buttoncancel); } @@ -3666,6 +3666,36 @@ return ''; } + +/** + * Print header for admin page + * @deprecated since Moodle 20. Please use normal $OUTPUT->header() instead + * @param string $focus focus element + */ +function admin_externalpage_print_header($focus='') { + global $CFG, $PAGE, $SITE, $OUTPUT; + + //debugging('admin_externalpage_print_header is deprecated. Please $OUTPUT->header() instead.', DEBUG_DEVELOPER); + + if (!is_string($focus)) { + $focus = ''; // BC compatibility, there used to be adminroot parameter + } + + $PAGE->set_focuscontrol($focus); + + echo $OUTPUT->header(); +} + +/** + * @deprecated since Moodle 1.9. Please use normal $OUTPUT->footer() instead + */ +function admin_externalpage_print_footer() { +// TODO Still 103 referernces in core code. Don't do debugging output yet. + debugging('admin_externalpage_print_footer is deprecated. Please $OUTPUT->footer() instead.', DEBUG_DEVELOPER); + global $OUTPUT; + echo $OUTPUT->footer(); +} + /// CALENDAR MANAGEMENT //////////////////////////////////////////////////////////////// Index: theme/standardold/style/styles_color.css =================================================================== RCS file: /cvsroot/moodle/moodle/theme/standardold/style/styles_color.css,v retrieving revision 1.1 diff -u -r1.1 styles_color.css --- theme/standardold/style/styles_color.css 12 Jan 2010 17:26:50 -0000 1.1 +++ theme/standardold/style/styles_color.css 5 Mar 2010 08:29:07 -0000 @@ -947,51 +947,173 @@ color:#ff0000; } -#admin-roles-override .capcurrent { - background-color:#FFFFFF; - border: 1px solid #cecece; +form.mform .required label { + color:#a00; } -table.explainpermissions .decisive.has, -#explaincaps .rolecap.yes { - background-color: #ddffdd; +form.mform .fdescription.required { + color:#a00; } -table.explainpermissions .decisive.hasnot, -table.explainpermissions .prohibit, -#explaincaps .rolecap.no { - background-color: #ffdddd; +form.mform .required .fgroup span label { + color:#000; } -table.explainpermissions .prohibit, -table.explainpermissions .decisive { - font-weight: bold; + +/**** role related CSS ****/ + +.capbox { + width: 80%; + margin-left:auto; + margin-right:auto; } -table.explainpermissions .overridden { - text-decoration: line-through; + +table.rolecap { + width: 100%; } -#admin-roles-define .capdefault { - background-color:#dddddd; - border: 1px solid #cecece; + +table.rolecap th { + border: none; } -#admin-roles-manage .rolecap, -#admin-roles-override .rolecap { - border:none; - border-bottom:1px solid; - border-bottom-color: #cecece; +table.rolecap th { + text-align: left; + font-weight: normal; +} + +table.rolecap thead th { + background-color: #dddddd; + font-weight: bold; +} + +table.rolecap tr { + border-bottom: 1px solid #cecece; } .rolecap .cap-name, .rolecap .note { + font-size: 0.75em; + display: block; + padding: 0 0.5em; +} + +.rolecap .cap-name { color: #888; } -form.mform .required label { - color:#a00; +table.rolecap .hiddenrow { + display: none; } -form.mform .fdescription.required { - color:#a00; + +table.rolecap .inherit, +table.rolecap .allow, +table.rolecap .prevent, +table.rolecap .prohibit { + text-align:center; } -form.mform .required .fgroup span label { - color:#000; + +table.rolecap label { + display: block; + width: 100%; + min-height: 2.5em; +} + +table#explaincaps { + width: 60%; + margin-left:auto; + margin-right:auto; +} +table#explaincaps .rolecap.no { + background-color: #ffdddd; +} + +table#explaincaps .rolecap.yes { + background-color: #ddffdd; +} + +#admin-roles-define .backlink, +#admin-roles-permissions .backlink, +#admin-roles-assign .backlink, +#admin-roles-check .backlink, +#admin-roles-override .backlink { + text-align: right; + margin-top: 2em; +} + +#admin-roles-override .capcurrent { + background-color:#FFFFFF; + border: 1px solid #cecece; +} + +#admin-roles-permissions .advancedoverride { + text-align: right; +} + +#admin-roles-define .capdefault { + background-color:#dddddd; + border: 1px solid #cecece; +} + +#admin-roles-define .topfields { + margin: 1em 0 2em; +} + +.roleassigntable { + width: 80%; +} +.roleassigntable td { + vertical-align: top; + padding: 0.2em 0.3em +} +.roleassigntable p { + text-align: left; + margin: 0.2em 0; +} +.roleassigntable #existingcell, +.roleassigntable #potentialcell { + width: 42%; +} +.roleassigntable #existingcell label, +.roleassigntable #potentialcell label { + font-weight: bold; +} +.roleassigntable #buttonscell { + width: 16%; +} +.roleassigntable #buttonscell #add, +.roleassigntable #buttonscell #remove { + width: 100%; + margin: 0.3em 0; + padding: 0.5em 0; +} +.roleassigntable #buttonscell p { + margin: 0.3em 0; +} +.roleassigntable #buttonscell #assignoptions { + font-size: 0.75em; +} +.roleassigntable #buttonscell #assignoptions .collapsibleregioncaption { + font-weight: bold; +} +.roleassigntable #buttonscell #addcontrols { + margin-top: 3em; + height: 13em; +} +.roleassigntable #removeselect_wrapper, +.roleassigntable #addselect_wrapper { + width: 100%; +} +.roleassigntable #removeselect_wrapper label, +.roleassigntable #addselect_wrapper label { + font-weight: normal; +} + +#admin-roles-override .overridenotice, +#admin-roles-define .definenotice { + margin: 1em 10% 2em; + text-align: left; } +.capabilitysearchui { + text-align: left; + margin-left: auto; + margin-right: auto; +} Index: theme/standardold/style/styles_layout.css =================================================================== RCS file: /cvsroot/moodle/moodle/theme/standardold/style/styles_layout.css,v retrieving revision 1.8 diff -u -r1.8 styles_layout.css --- theme/standardold/style/styles_layout.css 24 Feb 2010 08:12:18 -0000 1.8 +++ theme/standardold/style/styles_layout.css 5 Mar 2010 08:29:09 -0000 @@ -113,6 +113,22 @@ text-align: center; } +.buttons { + text-align:center +} + +.buttons div, +.buttons form { + display:inline; +} + +.singlebutton { + text-align:center; + padding: 5px; + margin: 0px; +} + + form { margin-bottom:0; } @@ -249,21 +265,6 @@ margin-right:auto; } -#notice .buttons { - text-align:center -} - -#notice .buttons div, -#notice .buttons form { - display:inline; -} - -#notice .singlebutton { - text-align:center; - padding: 5px; - margin: 0px; -} - .errorbox { border-width:1px; border-style:solid; @@ -505,16 +506,6 @@ font-weight: normal; } -#group-groupings .buttons { - margin: 20px; - text-align:center; -} - -#group-groupings .buttons .singlebutton { - display: inline; - padding: 5px; -} - #group-usersummary { width: 14em; } @@ -1065,10 +1056,6 @@ text-align: center; } -#admin-maintenance .buttons { - text-align:center; -} - #admin-report-unittest-index .exception pre { padding: 8px; } @@ -1136,177 +1123,6 @@ #admin-qtypes #qtypes img.spacer { width: 16px; } -#filter-manage .buttons, -#admin-roles-allow .buttons, -#admin-roles-manage .buttons, -#admin-roles-define .buttons, -#admin-roles-override .buttons { - margin: 20px; - text-align:center; -} -#admin-roles-manage .buttons .singlebutton, -#admin-roles-define .buttons .singlebutton, -#admin-roles-override .buttons .singlebutton { - display: inline; - padding: 5px; -} -#admin-roles-define .topfields { - margin: 1em 0 2em; -} -.roleassigntable { - width: 100%; -} -.roleassigntable td { - vertical-align: top; - padding: 0.2em 0.3em -} -.roleassigntable p { - text-align: left; - margin: 0.2em 0; -} -.roleassigntable #existingcell, -.roleassigntable #potentialcell { - width: 42%; -} -.roleassigntable #existingcell label, -.roleassigntable #potentialcell label { - font-weight: bold; -} -.roleassigntable #buttonscell { - width: 16%; -} -.roleassigntable #buttonscell #add, -.roleassigntable #buttonscell #remove { - width: 100%; - margin: 0.3em 0; - padding: 0.5em 0; -} -.roleassigntable #buttonscell p { - margin: 0.3em 0; -} -.roleassigntable #buttonscell #assignoptions { - font-size: 0.75em; -} -.roleassigntable #buttonscell #assignoptions .collapsibleregioncaption { - font-weight: bold; -} -.roleassigntable #buttonscell #addcontrols { - margin-top: 3em; - height: 13em; -} -.roleassigntable #removeselect_wrapper, -.roleassigntable #addselect_wrapper { - width: 100%; -} -.roleassigntable #removeselect_wrapper label, -.roleassigntable #addselect_wrapper label { - font-weight: normal; -} -#admin-roles-define .mform { - width: 100%; -} -#filter-manage .backlink, -#admin-roles-manage .backlink, -#admin-roles-define .backlink, -#admin-roles-explain .backlink, -#admin-roles-assign .backlink, -#admin-roles-override .backlink { - text-align: right; - width: 90%; - margin: 2em auto 1em; -} - -#admin-roles-explain #chooseuser h3 { - margin-top: 0; -} -#admin-roles-explain #chooseusersubmit { - margin: 1em 0 0; - text-align: center; -} -#admin-roles-usersroles .contextname { - margin: 0.5em 0 0; -} -#admin-roles-usersroles p { - margin: 0; -} -table.rolecap { - margin-left: auto; - margin-right: auto; -} -.capabilitysearchui { - text-align: left; - margin-left: auto; - margin-right: auto; -} -table.rolecap .hiddenrow { - display: none; -} - -tr.rolecap th { - text-align: left; - font-weight: normal; -} -table.rolecap .inherit, -table.rolecap .allow, -table.rolecap .prevent, -table.rolecap .prohibit { - text-align:center; -} -table.rolecap label { - display: block; - width: 100%; - min-height: 2.5em; -} -.rolecap .cap-name, -.rolecap .note { - display: block; - padding: 0 0.5em; -} - -#admin-roles-override .cell.c1, -#admin-roles-assign .cell.c3, -#admin-roles-assign .cell.c1 { - padding-top: 0.75em; -} - -#admin-roles-override .overridenotice, -#admin-roles-define .definenotice { - margin: 1em 10% 2em; - text-align: left; -} - -table.explainpermissions { - border: 1px solid black; -} -table.explainpermissions .cell { - border-bottom: none; -} -table.explainpermissions th.header, -table.explainpermissions th.cell, -table.explainpermissions td.cell { - border-left: 1px solid black; - border-right: 1px solid black; - vertical-align: middle; -} -table.explainpermissions .newcontext .cell, -table.explainpermissions .row2 th.header { - border-top: 1px solid black; -} -table.explainpermissions .cell.inherit, -table.explainpermissions .cell.noroles { - color: gray; -} -table.explainpermissions th.assignment { - text-align: left; - padding-left: 0.5em; -} -table.explainpermissions .cell.prohibit { - font-weight: bold; -} -table.explainpermissions .cell { - padding: 0.2em 0.5em; - text-align: center; -} #admin-lang .generalbox { text-align:center; margin:auto; @@ -2555,17 +2371,6 @@ padding: 10px; } -body#admin-course-index .buttons .singlebutton, -body#admin-course-category .buttons .singlebutton { - display: inline; -} - -body#admin-course-index .buttons, -body#admin-course-category .buttons { - text-align: center; - margin-bottom: 15px; -} - body#admin-course-index .editcourse { margin-left:auto; margin-right:auto; @@ -2793,28 +2598,8 @@ /* scales edit */ -.grade-edit-scale .buttons { - margin: 20px; - text-align:center; -} - -.grade-edit-scale .buttons .singlebutton { - display: inline; - padding: 5px; -} - /* outcomes edit */ -.grade-edit-outcome .buttons { - margin: 20px; - text-align:center; -} - -.grade-edit-outcome .buttons .singlebutton { - display: inline; - padding: 5px; -} - div.allcoursegrades { width: 100%; text-align: right; @@ -2835,20 +2620,10 @@ padding-bottom:15px; } -.grade-edit-tree .buttons { - margin: 20px; - text-align:center; -} - .grade-edit-tree .idnumber { margin-left: 15px; } -.grade-edit-tree .buttons .singlebutton { - display: inline; - padding: 5px; -} - .grade-edit-tree .movetarget { position: relative; width: 80px; @@ -3928,16 +3703,6 @@ text-align: center; } -#user-view .buttons, -#user-index .buttons { - text-align: center; -} - -#user-view .buttons form, -#user-view .buttons form div { - display:inline; -} - body#user-index #longtimenosee, body#user-index #showall { text-align: center; Index: theme/standardold/style/styles_fonts.css =================================================================== RCS file: /cvsroot/moodle/moodle/theme/standardold/style/styles_fonts.css,v retrieving revision 1.1 diff -u -r1.1 styles_fonts.css --- theme/standardold/style/styles_fonts.css 12 Jan 2010 17:26:50 -0000 1.1 +++ theme/standardold/style/styles_fonts.css 5 Mar 2010 08:29:08 -0000 @@ -261,11 +261,6 @@ font-size: 0.8em; } -.rolecap .cap-name, -.rolecap .note { - font-size: 0.75em; -} - #adminsettings .form-shortname { font-size: 0.75em; } @@ -274,12 +269,6 @@ font-size: 0.8em; } -#admin-roles-override .cell.c1, -#admin-roles-assign .cell.c3, -#admin-roles-assign .cell.c1 { - font-size: 0.7em; -} - #admin-lang .translator .strkey { font-size: 0.75em; } Index: lang/en_utf8/role.php =================================================================== RCS file: /cvsroot/moodle/moodle/lang/en_utf8/role.php,v retrieving revision 1.100 diff -u -r1.100 role.php --- lang/en_utf8/role.php 19 Feb 2010 19:27:12 -0000 1.100 +++ lang/en_utf8/role.php 5 Mar 2010 08:28:56 -0000 @@ -282,6 +282,19 @@ $string['xroleassignments'] = '$a\'s role assignments'; $string['xuserswiththerole'] = 'Users with the role \"$a->role\"'; +// pending new strings for new permission UI +$string['advancedoverride'] = 'Advanced role override'; +$string['confirmroleunprohibit'] = 'Do you really want to remove $a->role from the list of prohibited roles for capability $a->cap in context $a->context?'; +$string['confirmroleprevent'] = 'Do you really want to remove $a->role from the list of allowed roles for capability $a->cap in context $a->context?'; +$string['neededroles'] = 'Roles with permission'; +$string['permissionsincontext'] = 'Permissions in $a'; +$string['prohibitedroles'] = 'Prohibited'; +$string['roleallowheader'] = 'Allow role:'; +$string['roleallowinfo'] = 'Select a role to be added to the list of allowed roles in context $a->context, capability $a->cap:'; +$string['roleprohibitheader'] = 'Prohibit role'; +$string['roleprohibitinfo'] = 'Select a role to be added to the list of prohibited roles in context $a->context, capability $a->cap:'; +$string['roleselect'] = 'Select role'; + //OBSOLETED in 1.9! $string['course:viewcoursegrades'] = 'View course grades'; $string['user:viewusergrades'] = 'View user grades'; Index: version.php =================================================================== RCS file: /cvsroot/moodle/moodle/version.php,v retrieving revision 1.1462 diff -u -r1.1462 version.php --- version.php 5 Mar 2010 00:41:58 -0000 1.1462 +++ version.php 5 Mar 2010 08:28:53 -0000 @@ -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 = 2010021900; // YYYYMMDD = date of the last version bump + $version = 2010021901; // YYYYMMDD = date of the last version bump // XX = daily increments $release = '2.0 dev (Build: 20100305)'; // Human-friendly version name Index: config-dist.php =================================================================== RCS file: /cvsroot/moodle/moodle/config-dist.php,v retrieving revision 1.128 diff -u -r1.128 config-dist.php --- config-dist.php 5 Jan 2010 22:18:03 -0000 1.128 +++ config-dist.php 5 Mar 2010 08:28:53 -0000 @@ -237,12 +237,6 @@ // logs in. The site front page will always show the same (logged-out) view. // $CFG->disablemycourses = true; // -// Enable this option if you need fully working default frontpage role, -// please note it might cause serious memory and performance issues, -// also there should not be any negative capabilities in default -// frontpage role (MDL-19039). -// $CFG->fullusersbycapabilityonfrontpage = true; -// // If this setting is set to true, then Moodle will track the IP of the // current user to make sure it hasn't changed during a session. This // will prevent the possibility of sessions being hijacked via XSS, but it Index: lib/db/access.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/db/access.php,v retrieving revision 1.119 diff -u -r1.119 access.php --- lib/db/access.php 19 Feb 2010 19:11:06 -0000 1.119 +++ lib/db/access.php 5 Mar 2010 08:29:07 -0000 @@ -440,6 +440,19 @@ ) ), + 'moodle/role:review' => array( + + 'riskbitmask' => RISK_PERSONAL, + + 'captype' => 'read', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + 'moodle/role:override' => array( 'riskbitmask' => RISK_SPAM | RISK_PERSONAL | RISK_XSS, Index: admin/roles/permissions_forms.php =================================================================== RCS file: admin/roles/permissions_forms.php diff -N admin/roles/permissions_forms.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ admin/roles/permissions_forms.php 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,101 @@ +. + +/** + * This script serves draft files of current user + * + * @package moodlecore + * @subpackage role + * @copyright 2009 Petr Skoda (skodak) info@skodak.org + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +require_once("$CFG->libdir/formslib.php"); + + +class role_allow_form extends moodleform { + + // Define the form + function definition() { + global $CFG; + + $mform = $this->_form; + list($context, $capability, $overridableroles) = $this->_customdata; + + list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name); + foreach($needed as $id=>$unused) { + unset($overridableroles[$id]); + } + foreach($forbidden as $id=>$unused) { + unset($overridableroles[$id]); + } + + $mform->addElement('header', 'allowheader', get_string('roleallowheader', 'role')); + + $mform->addElement('select', 'roleid', get_string('roleselect', 'role'), $overridableroles); + + $mform->addElement('hidden','capability'); + $mform->setType('capability', PARAM_CAPABILITY); + $mform->setDefault('capability', $capability->name); + + $mform->addElement('hidden','contextid'); + $mform->setType('contextid', PARAM_INT); + $mform->setDefault('contextid', $context->id); + + $mform->addElement('hidden','allow'); + $mform->setType('allow', PARAM_INT); + $mform->setDefault('allow', 1); + + $this->add_action_buttons(true, get_string('allow', 'role')); + } +} + + +class role_prohibit_form extends moodleform { + + // Define the form + function definition() { + global $CFG; + + $mform = $this->_form; + list($context, $capability, $overridableroles) = $this->_customdata; + + list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name); + foreach($forbidden as $id=>$unused) { + unset($overridableroles[$id]); + } + + $mform->addElement('header', 'ptohibitheader', get_string('roleprohibitheader', 'role')); + + $mform->addElement('select', 'roleid', get_string('roleselect', 'role'), $overridableroles); + + $mform->addElement('hidden','capability'); + $mform->setType('capability', PARAM_CAPABILITY); + $mform->setDefault('capability', $capability->name); + + $mform->addElement('hidden','contextid'); + $mform->setType('contextid', PARAM_INT); + $mform->setDefault('contextid', $context->id); + + $mform->addElement('hidden','prohibit'); + $mform->setType('prohibit', PARAM_INT); + $mform->setDefault('prohibit', 1); + + $this->add_action_buttons(true, get_string('prohibit', 'role')); + } +} Index: pix/t/add.gif =================================================================== RCS file: pix/t/add.gif diff -N pix/t/add.gif --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ pix/t/add.gif 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,1 @@ +GIF89a lll!,  S` 5a; \ No newline at end of file Index: admin/roles/permissions.php =================================================================== RCS file: admin/roles/permissions.php diff -N admin/roles/permissions.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ admin/roles/permissions.php 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,252 @@ +. + +/** + * This script serves draft files of current user + * + * @package moodlecore + * @subpackage role + * @copyright 2009 Petr Skoda (skodak) info@skodak.org + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../config.php'); +require_once("$CFG->dirroot/$CFG->admin/roles/lib.php"); +require_once("permissions_forms.php"); + +$contextid = required_param('contextid',PARAM_INT); + +$roleid = optional_param('roleid', 0, PARAM_INT); +$capability = optional_param('capability', false, PARAM_CAPABILITY); +$confirm = optional_param('confirm', 0, PARAM_BOOL); +$prevent = optional_param('prevent', 0, PARAM_BOOL); +$allow = optional_param('allow', 0, PARAM_BOOL); +$unprohibit = optional_param('unprohibit', 0, PARAM_BOOL); +$prohibit = optional_param('prohibit', 0, PARAM_BOOL); + +// security first +list($context, $course, $cm) = get_context_info_array($contextid); +require_login($course, false, $cm); +require_capability('moodle/role:review', $context); + +$PAGE->set_url('/admin/roles/permissions.php', array('contextid' => $contextid)); +$PAGE->set_context($context); + +$userid = 0; +$tabfile = null; + +if ($course) { + $isfrontpage = ($context->contextlevel == CONTEXT_COURSE and $context->instanceid == SITEID); + +} else { + $isfrontpage = false; + if ($context->contextlevel == CONTEXT_USER) { + $courseid = optional_param('courseid', SITEID, PARAM_INT); // needed for user/tabs.php + $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST); + $PAGE->url->param('courseid', $courseid); + $userid = $context->instanceid; + } else { + $course = $SITE; + } +} + +$courseid = $course->id; + + +// These are needed early because of tabs.php +$assignableroles = get_assignable_roles($context, ROLENAME_BOTH); +list($overridableroles, $overridecounts, $nameswithcounts) = get_overridable_roles($context, ROLENAME_BOTH, true); + +if ($capability) { + $capability = $DB->get_record('capabilities', array('name'=>$capability), '*', MUST_EXIST); +} + +$allowoverrides = has_capability('moodle/role:override', $context); +$allowsafeoverrides = has_capability('moodle/role:safeoverride', $context); + +$contextname = print_context_name($context); +$title = get_string('permissionsincontext', 'role', $contextname); +$straction = get_string('permissions', 'role'); // Used by tabs.php +$PAGE->set_title($title); + +// Print the header and tabs +if ($context->contextlevel == CONTEXT_SYSTEM) { + print_error('cannotoverridebaserole', 'error'); + +} else if ($context->contextlevel == CONTEXT_USER) { + // NOTE: this is not linked from UI for now + $userid = $context->instanceid; + $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0), '*', MUST_EXIST); + $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); + + // course header + if ($isfrontpage) { + $PAGE->set_heading($course->fullname); + } else { + if (has_capability('moodle/course:viewparticipants', get_context_instance(CONTEXT_COURSE, $courseid))) { + $PAGE->navbar->add(get_string('participants'), new moodle_url('/user/index.php', array('id'=>$courseid))); + } + $PAGE->set_heading($fullname); + } + $PAGE->navbar->add($fullname, new moodle_url("$CFG->wwwroot/user/view.php", array('id'=>$userid,'course'=>$courseid))); + $PAGE->navbar->add($straction); + + $showroles = 1; + $currenttab = 'permissions'; + $tabfile = $CFG->dirroot.'/user/tabs.php'; + +} else if ($isfrontpage) { + admin_externalpage_setup('frontpageroles', '', array(), $PAGE->url); + $currenttab = 'permissions'; + $tabfile = 'tabs.php'; + +} else { + $currenttab = 'permissions'; + $tabfile = 'tabs.php'; +} + +// handle confirmations and actions +if ($prevent and isset($overridableroles[$roleid]) and $capability) { + if ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability))) { + if ($confirm and data_submitted() and confirm_sesskey()) { + role_change_permission($roleid, $context, $capability->name, CAP_PREVENT); + redirect($PAGE->url); + + } else { + $a = (object)array('cap'=>get_capability_docs_link($capability)." ($capability->name)", 'role'=>$overridableroles[$roleid], 'context'=>$contextname); + $message = get_string('confirmroleprevent', 'role', $a); + $continueurl = new moodle_url($PAGE->url, array('contextid'=>$context->id, 'roleid'=>$roleid, 'capability'=>$capability->name, 'prevent'=>1, 'sesskey'=>sesskey(), 'confirm'=>1)); + + echo $OUTPUT->header(); + if ($tabfile) { + include($tabfile); + } + echo $OUTPUT->heading($title); + echo $OUTPUT->confirm($message, $continueurl, $PAGE->url); + echo $OUTPUT->footer(); + die; + } + } +} + +if ($unprohibit and isset($overridableroles[$roleid]) and $capability) { + if ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability))) { + if ($confirm and data_submitted() and confirm_sesskey()) { + role_change_permission($roleid, $context, $capability->name, CAP_INHERIT); + redirect($PAGE->url); + + } else { + $a = (object)array('cap'=>get_capability_docs_link($capability)." ($capability->name)", 'role'=>$overridableroles[$roleid], 'context'=>$contextname); + $message = get_string('confirmroleunprohibit', 'role', $a); + $continueurl = new moodle_url($PAGE->url, array('contextid'=>$context->id, 'roleid'=>$roleid, 'capability'=>$capability->name, 'unprohibit'=>1, 'sesskey'=>sesskey(), 'confirm'=>1)); + + echo $OUTPUT->header(); + if ($tabfile) { + include($tabfile); + } + echo $OUTPUT->heading($title); + echo $OUTPUT->confirm($message, $continueurl, $PAGE->url); + echo $OUTPUT->footer(); + die; + } + } +} + +if ($allow and $capability) { + if ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability))) { + $mform = new role_allow_form(null, array($context, $capability, $overridableroles)); + if ($mform->is_cancelled()) { + redirect($PAGE->url); + + } else if ($data = $mform->get_data() and !empty($data->roleid)) { + $roleid = $data->roleid; + if (isset($overridableroles[$roleid])) { + role_change_permission($roleid, $context, $capability->name, CAP_ALLOW); + } + redirect($PAGE->url); + + } else { + $a = (object)array('cap'=>get_capability_docs_link($capability)." ($capability->name)", 'context'=>$contextname); + $message = get_string('roleallowinfo', 'role', $a); + + echo $OUTPUT->header(); + if ($tabfile) { + include($tabfile); + } + echo $OUTPUT->heading($title); + echo $OUTPUT->box($message); + $mform->display(); + echo $OUTPUT->footer(); + die; + } + } +} + +if ($prohibit and $capability) { + if ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability))) { + $mform = new role_prohibit_form(null, array($context, $capability, $overridableroles)); + if ($mform->is_cancelled()) { + redirect($PAGE->url); + + } else if ($data = $mform->get_data() and !empty($data->roleid)) { + $roleid = $data->roleid; + if (isset($overridableroles[$roleid])) { + role_change_permission($roleid, $context, $capability->name, CAP_PROHIBIT); + } + redirect($PAGE->url); + + } else { + $a = (object)array('cap'=>get_capability_docs_link($capability)." ($capability->name)", 'context'=>$contextname); + $message = get_string('roleprohibitinfo', 'role', $a); + + echo $OUTPUT->header(); + if ($tabfile) { + include($tabfile); + } + echo $OUTPUT->box($message); + $mform->display(); + echo $OUTPUT->footer(); + die; + } + } +} + +echo $OUTPUT->header(); +if ($tabfile) { + include($tabfile); +} +echo $OUTPUT->heading($title); + +$table = new permissions_table($context, $contextname, $allowoverrides, $allowsafeoverrides, $overridableroles); +echo $OUTPUT->box_start('generalbox capbox'); +// print link to advanced override page +if ($overridableroles) { + $overrideurl = new moodle_url('/admin/roles/override.php', array('contextid' => $context->id)); + $select = new single_select($overrideurl, 'roleid', $nameswithcounts); + $select->label = get_string('advancedoverride', 'role'); + echo '
'.$OUTPUT->render($select).'
'; +} +$table->display(); +echo $OUTPUT->box_end(); + + +if ($context->contextlevel > CONTEXT_USER) { + echo ''; +} + +echo $OUTPUT->footer($course); +