From: tjhunt Date: Thu, 13 Nov 2008 04:07:01 +0000 (+0000) Subject: roles interface: Code reorganisation and adding boilerplate comments. X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=1e8e46879c50deba57cf03bb2397f9169ac24f62;p=moodle.git roles interface: Code reorganisation and adding boilerplate comments. I have collected code that used to be in lib/adminlib.php, lib/accesslib.php and user/selector/lib.php into a new admin/roles/lib.php file. And I added standard GPL and Moodle comments to all the files in admin/roles. --- diff --git a/admin/roles/allowassign.php b/admin/roles/allowassign.php index 076962026e..3e9cfe6e78 100755 --- a/admin/roles/allowassign.php +++ b/admin/roles/allowassign.php @@ -1,4 +1,28 @@ -libdir.'/adminlib.php'); diff --git a/admin/roles/allowoverride.php b/admin/roles/allowoverride.php index 2bc768f28c..04041da2da 100755 --- a/admin/roles/allowoverride.php +++ b/admin/roles/allowoverride.php @@ -1,10 +1,38 @@ -libdir.'/adminlib.php'); diff --git a/admin/roles/assign.php b/admin/roles/assign.php index 3deb0d8428..16ccaa8aa8 100755 --- a/admin/roles/assign.php +++ b/admin/roles/assign.php @@ -1,9 +1,37 @@ -libdir.'/adminlib.php'); - require_once($CFG->dirroot.'/user/selector/lib.php'); + require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); require_js(array('yui_yahoo', 'yui_dom', 'yui_event')); require_js($CFG->admin . '/roles/roles.js'); diff --git a/admin/roles/explain.php b/admin/roles/explain.php index c21d47f211..5c51491be8 100755 --- a/admin/roles/explain.php +++ b/admin/roles/explain.php @@ -1,9 +1,37 @@ -libdir.'/adminlib.php'); - require_once($CFG->dirroot.'/user/selector/lib.php'); + require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); $contextid = required_param('contextid',PARAM_INT); $contextuserid = optional_param('userid', 0, PARAM_INT); // needed for user tabs @@ -109,74 +137,10 @@ /// If a user has been chosen, show all the permissions for this user. $user = $userselector->get_selected_user(); if (!is_null($user)) { - - /// Class for rendering the table. - class explain_cabability_table extends cabability_table_base { - protected $user; - protected $fullname; - protected $baseurl; - protected $contextname; - protected $stryes; - protected $strno; - protected $strexplanation; - private $hascap; - public function __construct($context, $user, $contextname) { - global $CFG; - parent::__construct($context, 'explaincaps'); - $this->user = $user; - $this->fullname = fullname($user); - $this->contextname = $contextname; - $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . - '/roles/explainhascapabiltiy.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; - } - protected function skip_row($capability) { - return $capability->name != 'moodle/site:doanything' && is_legacy($capability->name); - } - protected function get_row_classes($capability) { - $this->hascap = has_capability($capability->name, $this->context, $this->user->id); - if ($this->hascap) { - return array('yes'); - } else { - return array('no'); - } - } - protected function add_row_cells($capability) { - 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 ''; - link_to_popup_window($this->baseurl . $capability->name, 'hascapabilityexplanation', - $this->strexplanation, 600, 600, get_string($tooltip, 'role', $a)); - echo ''; - } - } - - require_js(array('yui_yahoo', 'yui_dom', 'yui_event')); - require_js($CFG->admin . '/roles/roles.js'); print_box_start('generalbox boxaligncenter boxwidthwide'); print_heading(get_string('permissionsforuser', 'role', fullname($user)), '', 3); - $table = new explain_cabability_table($context, $user, $contextname); + $table = new explain_capability_table($context, $user, $contextname); $table->display(); print_box_end(); diff --git a/admin/roles/explainhascapabiltiy.php b/admin/roles/explainhascapabiltiy.php index 6c7320f070..9be9674ad8 100644 --- a/admin/roles/explainhascapabiltiy.php +++ b/admin/roles/explainhascapabiltiy.php @@ -1,4 +1,35 @@ -libdir.'/adminlib.php'); +require_once($CFG->dirroot.'/user/selector/lib.php'); + +/** + * Print a risk icon, as a link to the Risks page on Moodle Docs. + * + * @param string $type the type of risk, will be one of the keys from the + * get_all_risks array. Must start with 'risk'. + */ +function print_risk_icon($type) { + global $CFG; + static $risksurl = null; + if (is_null($risksurl)) { + $risksurl = get_docs_url(s(get_string('risks', 'role'))); + } + $iconurl = $CFG->pixpath . '/i/' . str_replace('risk', 'risk_', $type) . '.gif'; + echo ' ' .
+            get_string($type . 'short', 'admin') . ''; +} + +// Classes for producing tables with one row per capability ==================== + +/** + * This class represents a table with one row for each of a list of capabilities + * where the first cell in the row contains the capability name, and there is + * arbitrary stuff in the rest of the row. This class is used by + * admin/roles/manage.php, override.php and explain.php. + * + * An ajaxy search UI shown at the top, if JavaScript is on. + */ +abstract class capability_table_base { + /** The context this table relates to. */ + protected $context; + + /** The capabilities to display. Initialised as fetch_context_capabilities($context). */ + protected $capabilities = array(); + + /** Added as an id="" attribute to the table on output. */ + protected $id; + + /** Added to the class="" attribute on output. */ + protected $classes = array('rolecap'); + + /** Default number of capabilities in the table for the search UI to be shown. */ + const NUM_CAPS_FOR_SEARCH = 12; + + /** + * Constructor + * @param object $context the context this table relates to. + * @param string $id what to put in the id="" attribute. + */ + public function __construct($context, $id) { + $this->context = $context; + $this->capabilities = fetch_context_capabilities($context); + $this->id = $id; + } + + /** + * Use this to add class="" attributes to the table. You get the rolecap by + * default. + * @param array $classnames of class names. + */ + public function add_classes($classnames) { + $this->classes = array_unique(array_merge($this->classes, $classnames)); + } + + /** + * Display the table. + */ + public function display() { + echo '' . "\n\n"; + echo ''; + $this->add_header_cells(); + echo "\n\n\n"; + + /// Loop over capabilities. + $contextlevel = 0; + $component = ''; + foreach ($this->capabilities as $capability) { + if ($this->skip_row($capability)) { + continue; + } + + /// Prints a breaker if component or name or context level has changed + if (component_level_changed($capability, $component, $contextlevel)) { + $this->print_heading_row($capability); + } + $contextlevel = $capability->contextlevel; + $component = $capability->component; + + /// Start the row. + echo ''; + + /// Table cell for the capability name. + echo ''; + + /// Add the cells specific to this table. + $this->add_row_cells($capability); + + /// End the row. + echo "\n"; + } + + /// End of the table. + echo "\n
' . get_string('capability','role') . '
' . get_capability_docs_link($capability) . + '' . $capability->name . '
\n"; + if (count($this->capabilities) > capability_table_base::NUM_CAPS_FOR_SEARCH) { + global $CFG; + require_js(array('yui_yahoo', 'yui_dom', 'yui_event')); + require_js($CFG->admin . '/roles/roles.js'); + print_js_call('cap_table_filter.init', + array($this->id, get_string('search'), get_string('clear'))); + } + } + + /** + * Used to output a heading rows when the context level or component changes. + * @param object $capability gives the new component and contextlevel. + */ + protected function print_heading_row($capability) { + echo '' . + get_component_string($capability->component, $capability->contextlevel) . + ''; + + } + + /** For subclasses to override, output header cells, after the initial capability one. */ + protected abstract function add_header_cells(); + + /** For subclasses to override, return the number of cells that add_header_cells/add_row_cells output. */ + protected abstract function num_extra_columns(); + + /** + * For subclasses to override. Allows certain capabilties (e.g. legacy capabilities) + * to be left out of the table. + * + * @param object $capability the capability this row relates to. + * @return boolean. If true, this row is omitted from the table. + */ + protected function skip_row($capability) { + return false; + } + + /** + * For subclasses to override. A change to reaturn class names that are added + * to the class="" attribute on the <tr> for this capability. + * + * @param object $capability the capability this row relates to. + * @return array of class name strings. + */ + protected function get_row_classes($capability) { + return array(); + } + + /** + * For subclasses to override. Output the data cells for this capability. The + * capability name cell will already have been output. + * + * You can rely on get_row_classes always being called before add_row_cells. + * + * @param object $capability the capability this row relates to. + */ + protected abstract function add_row_cells($capability); +} + +/** + * 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. + */ +class explain_capability_table extends capability_table_base { + protected $user; + protected $fullname; + protected $baseurl; + protected $contextname; + protected $stryes; + protected $strno; + protected $strexplanation; + private $hascap; + + /** + * Constructor + * @param object $context the context this table relates to. + * @param object $user the user we are generating the results for. + * @param string $contextname print_context_name($context) - to save recomputing. + */ + public function __construct($context, $user, $contextname) { + global $CFG; + parent::__construct($context, 'explaincaps'); + $this->user = $user; + $this->fullname = fullname($user); + $this->contextname = $contextname; + $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . + '/roles/explainhascapabiltiy.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; + } + + protected function skip_row($capability) { + return $capability->name != 'moodle/site:doanything' && is_legacy($capability->name); + } + + protected function get_row_classes($capability) { + $this->hascap = has_capability($capability->name, $this->context, $this->user->id); + if ($this->hascap) { + return array('yes'); + } else { + return array('no'); + } + } + + protected function add_row_cells($capability) { + 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 ''; + link_to_popup_window($this->baseurl . $capability->name, 'hascapabilityexplanation', + $this->strexplanation, 600, 600, get_string($tooltip, 'role', $a)); + echo ''; + } +} + +// User selectors for managing role assignments ================================ + +/** + * Base class to avoid duplicating code. + */ +abstract class role_assign_user_selector_base extends user_selector_base { + const MAX_USERS_PER_PAGE = 100; + + protected $roleid; + protected $context; + + /** + * @param string $name control name + * @param array $options should have two elements with keys groupid and courseid. + */ + public function __construct($name, $options) { + global $CFG; + parent::__construct($name, $options); + $this->roleid = $options['roleid']; + if (isset($options['context'])) { + $this->context = $options['context']; + } else { + $this->context = get_context_instance_by_id($options['contextid']); + } + require_once($CFG->dirroot . '/group/lib.php'); + } + + protected function get_options() { + $options = parent::get_options(); + $options['roleid'] = $this->roleid; + $options['contextid'] = $this->context->id; + return $options; + } +} + +/** + * User selector subclass for the list of potential users on the assign roles page, + * when we are assigning in a context below the course level. (CONTEXT_MODULE and + * CONTEXT_BLOCK). + * + * In this case we replicate part of get_users_by_capability() get the users + * with moodle/course:view (or moodle/site:doanything). We can't use + * get_users_by_capability() becuase + * 1) get_users_by_capability() does not deal with searching by name + * 2) exceptions array can be potentially large for large courses + */ +class potential_assignees_below_course extends role_assign_user_selector_base { + public function find_users($search) { + global $DB; + + // Get roles with some assignement to the 'moodle/course:view' capability. + $possibleroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $this->context); + if (empty($possibleroles)) { + // If there aren't any, we are done. + return array(); + } + + // Now exclude the admin roles, and check the actual permission on + // 'moodle/course:view' to make sure it is allow. + $doanythingroles = get_roles_with_capability('moodle/site:doanything', + CAP_ALLOW, get_context_instance(CONTEXT_SYSTEM)); + $validroleids = array(); + + foreach ($possibleroles as $possiblerole) { + if (isset($doanythingroles[$possiblerole->id])) { + continue; + } + + if ($caps = role_context_capabilities($possiblerole->id, $this->context, 'moodle/course:view')) { // resolved list + if (isset($caps['moodle/course:view']) && $caps['moodle/course:view'] > 0) { // resolved capability > 0 + $validroleids[] = $possiblerole->id; + } + } + } + + // If there are no valid roles, we are done. + if (!$validroleids) { + return array(); + } + + // Now we have to go to the database. + list($wherecondition, $params) = $this->search_sql($search, 'u'); + if ($wherecondition) { + $wherecondition = ' AND ' . $wherecondition; + } + $roleids = '('.implode(',', $validroleids).')'; + + $fields = 'SELECT ' . $this->required_fields_sql('u'); + $countfields = 'SELECT COUNT(1)'; + + $sql = " FROM {user} u + JOIN {role_assignments} ra ON ra.userid = u.id + JOIN {role} r ON r.id = ra.roleid + WHERE ra.contextid " . get_related_contexts_string($this->context)." + $wherecondition + AND ra.roleid IN $roleids + AND u.id NOT IN ( + SELECT u.id + FROM {role_assignments} r, {user} u + WHERE r.contextid = ? + AND u.id = r.userid + AND r.roleid = ?)"; + $order = ' ORDER BY lastname ASC, firstname ASC'; + + $params[] = $this->context->id; + $params[] = $this->roleid; + + // Check to see if there are too many to show sensibly. + if (!$this->is_validating()) { + $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); + if ($potentialmemberscount > role_assign_user_selector_base::MAX_USERS_PER_PAGE) { + return $this->too_many_results($search, $potentialmemberscount); + } + } + + // If not, show them. + $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + + if (empty($availableusers)) { + return array(); + } + + if ($search) { + $groupname = get_string('potusersmatching', 'role', $search); + } else { + $groupname = get_string('potusers', 'role'); + } + + return array($groupname => $availableusers); + } +} + +/** + * User selector subclass for the list of potential users on the assign roles page, + * when we are assigning in a context at or above the course level. In this case we + * show all the users in the system who do not already have the role. + */ +class potential_assignees_course_and_above extends role_assign_user_selector_base { + public function find_users($search) { + global $DB; + + list($wherecondition, $params) = $this->search_sql($search, ''); + + $fields = 'SELECT ' . $this->required_fields_sql(''); + $countfields = 'SELECT COUNT(1)'; + + $sql = " FROM {user} + WHERE $wherecondition + AND id NOT IN ( + SELECT u.id + FROM {role_assignments} r, {user} u + WHERE r.contextid = ? + AND u.id = r.userid + AND r.roleid = ?)"; + $order = ' ORDER BY lastname ASC, firstname ASC'; + + $params[] = $this->context->id; + $params[] = $this->roleid; + + if (!$this->is_validating()) { + $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); + if ($potentialmemberscount > role_assign_user_selector_base::MAX_USERS_PER_PAGE) { + return $this->too_many_results($search, $potentialmemberscount); + } + } + + $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + + if (empty($availableusers)) { + return array(); + } + + if ($search) { + $groupname = get_string('potusersmatching', 'role', $search); + } else { + $groupname = get_string('potusers', 'role'); + } + + return array($groupname => $availableusers); + } +} + +/** + * User selector subclass for the list of users who already have the role in + * question on the assign roles page. + */ +class existing_role_holders extends role_assign_user_selector_base { + protected $strhidden; + + public function __construct($name, $options) { + parent::__construct($name, $options); + $this->strhidden = get_string('hiddenassign'); + } + + public function find_users($search) { + list($wherecondition, $params) = $this->search_sql($search, 'u'); + $contextusers = get_role_users($this->roleid, $this->context, false, + $this->required_fields_sql('u') . ', ra.hidden', 'u.lastname, u.firstname', + true, '', '', '', $wherecondition, $params); + + if (empty($contextusers)) { + return array(); + } + + if ($search) { + $groupname = get_string('extusersmatching', 'role', $search); + } else { + $groupname = get_string('extusers', 'role'); + } + + return array($groupname => $contextusers); + } + + // Override to add (hidden) to hidden role assignments. + public function output_user($user) { + $output = parent::output_user($user); + if ($user->hidden) { + $output .= ' (' . $this->strhidden . ')'; + } + return $output; + } +} + +/** + * A special subclass to use when unassigning admins at site level. Disables + * the option for admins to unassign themselves. + */ +class existing_role_holders_site_admin extends existing_role_holders { + public function find_users($search) { + global $USER; + $groupedusers = parent::find_users($search); + foreach ($groupedusers as $group) { + foreach ($group as &$user) { + if ($user->id == $USER->id) { + $user->disabled = true; + } + } + } + return $groupedusers; + } +} + +?> \ No newline at end of file diff --git a/admin/roles/manage.php b/admin/roles/manage.php index b3f007e374..48bed9abaf 100755 --- a/admin/roles/manage.php +++ b/admin/roles/manage.php @@ -1,6 +1,37 @@ -dirroot . '/' . $CFG->admin . '/roles/lib.php'); require_once($CFG->libdir.'/adminlib.php'); diff --git a/admin/roles/managetabs.php b/admin/roles/managetabs.php index 170f315c54..efe8de986f 100755 --- a/admin/roles/managetabs.php +++ b/admin/roles/managetabs.php @@ -1,8 +1,37 @@ -dirroot . '/' . $CFG->admin . '/roles/lib.php'); $contextid = required_param('contextid', PARAM_INT); // context id $roleid = optional_param('roleid', 0, PARAM_INT); // requested role id diff --git a/admin/roles/tabs.php b/admin/roles/tabs.php index 0819694fd3..2087ac13a8 100755 --- a/admin/roles/tabs.php +++ b/admin/roles/tabs.php @@ -1,10 +1,38 @@ -dirroot.'/lib/blocklib.php'; @@ -3438,24 +3440,6 @@ function get_context_url($context) { return $url; } -/** - * Print a risk icon, as a link to the Risks page on Moodle Docs. - * - * @param string $type the type of risk, will be one of the keys from the - * get_all_risks array. Must start with 'risk'. - */ -function print_risk_icon($type) { - global $CFG; - static $risksurl = null; - if (is_null($risksurl)) { - $risksurl = get_docs_url(s(get_string('risks', 'role'))); - } - $iconurl = $CFG->pixpath . '/i/' . str_replace('risk', 'risk_', $type) . '.gif'; - echo ' ' .
-            get_string($type . 'short', 'admin') . ''; -} - /** * @return array all the known types of risk. The array keys can be used, for example * as CSS class names, or in calls to print_risk_icon. The values are the diff --git a/lib/adminlib.php b/lib/adminlib.php index df8c8ab59e..9326535e9c 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -6115,134 +6115,3 @@ class admin_setting_managerepository extends admin_setting { return highlight($query, $output); } } - -/** - * This class represents a table with one row for each of a list of capabilities - * where the first cell in the row contains the capability name, and there is - * arbitrary stuff in the rest of the row. This class is used by - * admin/roles/manage.php, override.php and explain.php. There is also some - * ajaxy search UI shown at the top, if JavaScript is on. - */ -abstract class cabability_table_base { - protected $context; - protected $capabilities = array(); - protected $id; - protected $classes = array('rolecap'); - const NUM_CAPS_FOR_SEARCH = 12; - - /** - * Constructor - * @param object $context the context this table relates to. - * @param string $id what to put in the id="" attribute. - */ - public function __construct($context, $id) { - $this->context = $context; - $this->capabilities = fetch_context_capabilities($context); - $this->id = $id; - } - - /** - * Use this to add class="" attributes to the table. You get the rolecap by - * default. - * @param array $classnames of class names. - */ - public function add_classes($classnames) { - $this->classes = array_unique(array_merge($this->classes, $classnames)); - } - - /** - * Display the table. - */ - public function display() { - echo '' . "\n\n"; - echo ''; - $this->add_header_cells(); - echo "\n\n\n"; - - /// Loop over capabilities. - $contextlevel = 0; - $component = ''; - foreach ($this->capabilities as $capability) { - if ($this->skip_row($capability)) { - continue; - } - - /// Prints a breaker if component or name or context level has changed - if (component_level_changed($capability, $component, $contextlevel)) { - $this->print_heading_row($capability); - } - $contextlevel = $capability->contextlevel; - $component = $capability->component; - - /// Start the row. - echo ''; - - /// Table cell for the capability name. - echo ''; - - /// Add the cells specific to this table. - $this->add_row_cells($capability); - - /// End the row. - echo "\n"; - } - - /// End of the table. - echo "\n
' . get_string('capability','role') . '
' . get_capability_docs_link($capability) . - '' . $capability->name . '
\n"; - if (count($this->capabilities) > cabability_table_base::NUM_CAPS_FOR_SEARCH) { - print_js_call('cap_table_filter.init', - array($this->id, get_string('search'), get_string('clear'))); - } - } - - /** - * Used to output a heading rows when the context level or component changes. - * @param object $capability gives the new component and contextlevel. - */ - protected function print_heading_row($capability) { - echo '' . - get_component_string($capability->component, $capability->contextlevel) . - ''; - - } - - /** For subclasses to override, output header cells, after the initial capability one. */ - protected abstract function add_header_cells(); - - /** For subclasses to override, return the number of cells that add_header_cells/add_row_cells output. */ - protected abstract function num_extra_columns(); - - /** - * For subclasses to override. Allows certain capabilties (e.g. legacy capabilities) - * to be left out of the table. - * - * @param object $capability the capability this row relates to. - * @return boolean. If true, this row is omitted from the table. - */ - protected function skip_row($capability) { - return false; - } - - /** - * For subclasses to override. A change to reaturn class names that are added - * to the class="" attribute on the <tr> for this capability. - * - * @param object $capability the capability this row relates to. - * @return array of class name strings. - */ - protected function get_row_classes($capability) { - return array(); - } - - /** - * For subclasses to override. Output the data cells for this capability. The - * capability name cell will already have been output. - * - * You can rely on get_row_classes always being called before add_row_cells. - * - * @param object $capability the capability this row relates to. - */ - protected abstract function add_row_cells($capability); -} \ No newline at end of file diff --git a/user/selector/lib.php b/user/selector/lib.php index 89b8cf473f..50e931874c 100644 --- a/user/selector/lib.php +++ b/user/selector/lib.php @@ -299,8 +299,8 @@ abstract class user_selector_base { * should not do this when validating. * * If you are writing a new user_selector subclass, I strongly recommend you - * look at some of the subclasses later in this file. They should help you - * see exactly what you have to do. + * look at some of the subclasses later in this file and in admin/roles/lib.php. + * They should help you see exactly what you have to do. * * @param string $search the search string. * @return array An array of arrays of users. The array keys of the outer @@ -634,248 +634,6 @@ abstract class user_selector_base { } } -// User selectors for managing role assignments ================================ - -/** - * Base class to avoid duplicating code. - */ -abstract class role_assign_user_selector_base extends user_selector_base { - const MAX_USERS_PER_PAGE = 100; - - protected $roleid; - protected $context; - - /** - * @param string $name control name - * @param array $options should have two elements with keys groupid and courseid. - */ - public function __construct($name, $options) { - global $CFG; - parent::__construct($name, $options); - $this->roleid = $options['roleid']; - if (isset($options['context'])) { - $this->context = $options['context']; - } else { - $this->context = get_context_instance_by_id($options['contextid']); - } - require_once($CFG->dirroot . '/group/lib.php'); - } - - protected function get_options() { - $options = parent::get_options(); - $options['roleid'] = $this->roleid; - $options['contextid'] = $this->context->id; - return $options; - } -} - -/** - * User selector subclass for the list of potential users on the assign roles page, - * when we are assigning in a context below the course level. (CONTEXT_MODULE and - * CONTEXT_BLOCK). - * - * In this case we replicate part of get_users_by_capability() get the users - * with moodle/course:view (or moodle/site:doanything). We can't use - * get_users_by_capability() becuase - * 1) get_users_by_capability() does not deal with searching by name - * 2) exceptions array can be potentially large for large courses - */ -class potential_assignees_below_course extends role_assign_user_selector_base { - public function find_users($search) { - global $DB; - - // Get roles with some assignement to the 'moodle/course:view' capability. - $possibleroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $this->context); - if (empty($possibleroles)) { - // If there aren't any, we are done. - return array(); - } - - // Now exclude the admin roles, and check the actual permission on - // 'moodle/course:view' to make sure it is allow. - $doanythingroles = get_roles_with_capability('moodle/site:doanything', - CAP_ALLOW, get_context_instance(CONTEXT_SYSTEM)); - $validroleids = array(); - - foreach ($possibleroles as $possiblerole) { - if (isset($doanythingroles[$possiblerole->id])) { - continue; - } - - if ($caps = role_context_capabilities($possiblerole->id, $this->context, 'moodle/course:view')) { // resolved list - if (isset($caps['moodle/course:view']) && $caps['moodle/course:view'] > 0) { // resolved capability > 0 - $validroleids[] = $possiblerole->id; - } - } - } - - // If there are no valid roles, we are done. - if (!$validroleids) { - return array(); - } - - // Now we have to go to the database. - list($wherecondition, $params) = $this->search_sql($search, 'u'); - if ($wherecondition) { - $wherecondition = ' AND ' . $wherecondition; - } - $roleids = '('.implode(',', $validroleids).')'; - - $fields = 'SELECT ' . $this->required_fields_sql('u'); - $countfields = 'SELECT COUNT(1)'; - - $sql = " FROM {user} u - JOIN {role_assignments} ra ON ra.userid = u.id - JOIN {role} r ON r.id = ra.roleid - WHERE ra.contextid " . get_related_contexts_string($this->context)." - $wherecondition - AND ra.roleid IN $roleids - AND u.id NOT IN ( - SELECT u.id - FROM {role_assignments} r, {user} u - WHERE r.contextid = ? - AND u.id = r.userid - AND r.roleid = ?)"; - $order = ' ORDER BY lastname ASC, firstname ASC'; - - $params[] = $this->context->id; - $params[] = $this->roleid; - - // Check to see if there are too many to show sensibly. - if (!$this->is_validating()) { - $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); - if ($potentialmemberscount > role_assign_user_selector_base::MAX_USERS_PER_PAGE) { - return $this->too_many_results($search, $potentialmemberscount); - } - } - - // If not, show them. - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); - - if (empty($availableusers)) { - return array(); - } - - if ($search) { - $groupname = get_string('potusersmatching', 'role', $search); - } else { - $groupname = get_string('potusers', 'role'); - } - - return array($groupname => $availableusers); - } -} - -/** - * User selector subclass for the list of potential users on the assign roles page, - * when we are assigning in a context at or above the course level. In this case we - * show all the users in the system who do not already have the role. - */ -class potential_assignees_course_and_above extends role_assign_user_selector_base { - public function find_users($search) { - global $DB; - - list($wherecondition, $params) = $this->search_sql($search, ''); - - $fields = 'SELECT ' . $this->required_fields_sql(''); - $countfields = 'SELECT COUNT(1)'; - - $sql = " FROM {user} - WHERE $wherecondition - AND id NOT IN ( - SELECT u.id - FROM {role_assignments} r, {user} u - WHERE r.contextid = ? - AND u.id = r.userid - AND r.roleid = ?)"; - $order = ' ORDER BY lastname ASC, firstname ASC'; - - $params[] = $this->context->id; - $params[] = $this->roleid; - - if (!$this->is_validating()) { - $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); - if ($potentialmemberscount > role_assign_user_selector_base::MAX_USERS_PER_PAGE) { - return $this->too_many_results($search, $potentialmemberscount); - } - } - - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); - - if (empty($availableusers)) { - return array(); - } - - if ($search) { - $groupname = get_string('potusersmatching', 'role', $search); - } else { - $groupname = get_string('potusers', 'role'); - } - - return array($groupname => $availableusers); - } -} - -/** - * User selector subclass for the list of users who already have the role in - * question on the assign roles page. - */ -class existing_role_holders extends role_assign_user_selector_base { - protected $strhidden; - - public function __construct($name, $options) { - parent::__construct($name, $options); - $this->strhidden = get_string('hiddenassign'); - } - - public function find_users($search) { - list($wherecondition, $params) = $this->search_sql($search, 'u'); - $contextusers = get_role_users($this->roleid, $this->context, false, - $this->required_fields_sql('u') . ', ra.hidden', 'u.lastname, u.firstname', - true, '', '', '', $wherecondition, $params); - - if (empty($contextusers)) { - return array(); - } - - if ($search) { - $groupname = get_string('extusersmatching', 'role', $search); - } else { - $groupname = get_string('extusers', 'role'); - } - - return array($groupname => $contextusers); - } - - // Override to add (hidden) to hidden role assignments. - public function output_user($user) { - $output = parent::output_user($user); - if ($user->hidden) { - $output .= ' (' . $this->strhidden . ')'; - } - return $output; - } -} - -/** - * A special subclass to use when unassigning admins at site level. Disables - * the option for admins to unassign themselves. - */ -class existing_role_holders_site_admin extends existing_role_holders { - public function find_users($search) { - global $USER; - $groupedusers = parent::find_users($search); - foreach ($groupedusers as $group) { - foreach ($group as &$user) { - if ($user->id == $USER->id) { - $user->disabled = true; - } - } - } - return $groupedusers; - } -} - // User selectors for managing group memebers ================================== /** diff --git a/user/selector/search.php b/user/selector/search.php index 00912a34c3..b7f198a85a 100644 --- a/user/selector/search.php +++ b/user/selector/search.php @@ -28,7 +28,7 @@ * * @license http://www.gnu.org/copyleft/gpl.html GNU Public License * @package userselector - */ + *//** */ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->dirroot . '/user/selector/lib.php');