3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * Library code used by the roles administration interfaces.
21 * Responds to actions:
22 * add - add a new role
23 * duplicate - like add, only initialise the new role by using an existing one.
24 * edit - edit the definition of a role
25 * view - view the definition of a role
29 * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 require_once($CFG->libdir
.'/adminlib.php');
34 require_once($CFG->dirroot
.'/user/selector/lib.php');
36 // Classes for producing tables with one row per capability ====================
39 * This class represents a table with one row for each of a list of capabilities
40 * where the first cell in the row contains the capability name, and there is
41 * arbitrary stuff in the rest of the row. This class is used by
42 * admin/roles/manage.php, override.php and check.php.
44 * An ajaxy search UI shown at the top, if JavaScript is on.
46 abstract class capability_table_base
{
47 /** The context this table relates to. */
50 /** The capabilities to display. Initialised as fetch_context_capabilities($context). */
51 protected $capabilities = array();
53 /** Added as an id="" attribute to the table on output. */
56 /** Added to the class="" attribute on output. */
57 protected $classes = array('rolecap');
59 /** Default number of capabilities in the table for the search UI to be shown. */
60 const NUM_CAPS_FOR_SEARCH
= 12;
64 * @param object $context the context this table relates to.
65 * @param string $id what to put in the id="" attribute.
67 public function __construct($context, $id) {
68 $this->context
= $context;
69 $this->capabilities
= fetch_context_capabilities($context);
74 * Use this to add class="" attributes to the table. You get the rolecap by
76 * @param array $classnames of class names.
78 public function add_classes($classnames) {
79 $this->classes
= array_unique(array_merge($this->classes
, $classnames));
85 public function display() {
86 if (count($this->capabilities
) > capability_table_base
::NUM_CAPS_FOR_SEARCH
) {
88 $PAGE->requires
->strings_for_js(array('filter','clear'),'moodle');
89 $PAGE->requires
->js_init_call('M.core_role.init_cap_table_filter', array($this->id
, $this->context
->id
));
91 echo '<table class="' . implode(' ', $this->classes
) . '" id="' . $this->id
. '">' . "\n<thead>\n";
92 echo '<tr><th class="name" align="left" scope="col">' . get_string('capability','role') . '</th>';
93 $this->add_header_cells();
94 echo "</tr>\n</thead>\n<tbody>\n";
96 /// Loop over capabilities.
99 foreach ($this->capabilities
as $capability) {
100 if ($this->skip_row($capability)) {
104 /// Prints a breaker if component or name or context level has changed
105 if (component_level_changed($capability, $component, $contextlevel)) {
106 $this->print_heading_row($capability);
108 $contextlevel = $capability->contextlevel
;
109 $component = $capability->component
;
112 echo '<tr class="' . implode(' ', array_unique(array_merge(array('rolecap'),
113 $this->get_row_classes($capability)))) . '">';
115 /// Table cell for the capability name.
116 echo '<th scope="row" class="name"><span class="cap-desc">' . get_capability_docs_link($capability) .
117 '<span class="cap-name">' . $capability->name
. '</span></span></th>';
119 /// Add the cells specific to this table.
120 $this->add_row_cells($capability);
126 /// End of the table.
127 echo "</tbody>\n</table>\n";
131 * Used to output a heading rows when the context level or component changes.
132 * @param object $capability gives the new component and contextlevel.
134 protected function print_heading_row($capability) {
135 echo '<tr class="rolecapheading header"><td colspan="' . (1 +
$this->num_extra_columns()) . '" class="header"><strong>' .
136 get_component_string($capability->component
, $capability->contextlevel
) .
137 '</strong></td></tr>';
141 /** For subclasses to override, output header cells, after the initial capability one. */
142 protected abstract function add_header_cells();
144 /** For subclasses to override, return the number of cells that add_header_cells/add_row_cells output. */
145 protected abstract function num_extra_columns();
148 * For subclasses to override. Allows certain capabilties
149 * to be left out of the table.
151 * @param object $capability the capability this row relates to.
152 * @return boolean. If true, this row is omitted from the table.
154 protected function skip_row($capability) {
159 * For subclasses to override. A change to reaturn class names that are added
160 * to the class="" attribute on the <tr> for this capability.
162 * @param object $capability the capability this row relates to.
163 * @return array of class name strings.
165 protected function get_row_classes($capability) {
170 * For subclasses to override. Output the data cells for this capability. The
171 * capability name cell will already have been output.
173 * You can rely on get_row_classes always being called before add_row_cells.
175 * @param object $capability the capability this row relates to.
177 protected abstract function add_row_cells($capability);
181 * Subclass of capability_table_base for use on the Check permissions page.
183 * We have one additional column, Allowed, which contains yes/no.
185 class check_capability_table
extends capability_table_base
{
188 protected $contextname;
195 * @param object $context the context this table relates to.
196 * @param object $user the user we are generating the results for.
197 * @param string $contextname print_context_name($context) - to save recomputing.
199 public function __construct($context, $user, $contextname) {
201 parent
::__construct($context, 'explaincaps');
203 $this->fullname
= fullname($user);
204 $this->contextname
= $contextname;
205 $this->stryes
= get_string('yes');
206 $this->strno
= get_string('no');
209 protected function add_header_cells() {
210 echo '<th>' . get_string('allowed', 'role') . '</th>';
213 protected function num_extra_columns() {
217 protected function get_row_classes($capability) {
218 $this->hascap
= has_capability($capability->name
, $this->context
, $this->user
->id
);
226 protected function add_row_cells($capability) {
229 $result = $this->stryes
;
231 $result = $this->strno
;
234 $a->fullname
= $this->fullname
;
235 $a->capability
= $capability->name
;
236 $a->context
= $this->contextname
;
237 echo '<td>' . $result . '</td>';
243 * Subclass of capability_table_base for use on the Permissions page.
245 class permissions_table
extends capability_table_base
{
246 protected $contextname;
247 protected $allowoverrides;
248 protected $allowsafeoverrides;
249 protected $overridableroles;
251 protected $icons = array();
255 * @param object $context the context this table relates to.
256 * @param string $contextname print_context_name($context) - to save recomputing.
258 public function __construct($context, $contextname, $allowoverrides, $allowsafeoverrides, $overridableroles) {
259 parent
::__construct($context, 'permissions');
260 $this->contextname
= $contextname;
261 $this->allowoverrides
= $allowoverrides;
262 $this->allowsafeoverrides
= $allowsafeoverrides;
263 $this->overridableroles
= $overridableroles;
265 $roles = get_all_roles($context);
266 $this->roles
= role_fix_names(array_reverse($roles, true), $context, ROLENAME_ALIAS
, true);
270 protected function add_header_cells() {
271 echo '<th>' . get_string('risks', 'role') . '</th>';
272 echo '<th>' . get_string('neededroles', 'role') . '</th>';
273 echo '<th>' . get_string('prohibitedroles', 'role') . '</th>';
276 protected function num_extra_columns() {
280 protected function add_row_cells($capability) {
281 global $OUTPUT, $PAGE;
283 $context = $this->context
;
284 $contextid = $this->context
->id
;
285 $allowoverrides = $this->allowoverrides
;
286 $allowsafeoverrides = $this->allowsafeoverrides
;
287 $overridableroles = $this->overridableroles
;
288 $roles = $this->roles
;
291 list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name
);
292 $neededroles = array();
293 $forbiddenroles = array();
294 $allowable = $overridableroles;
295 $forbitable = $overridableroles;
296 foreach ($neededroles as $id=>$unused) {
297 unset($allowable[$id]);
299 foreach ($forbidden as $id=>$unused) {
300 unset($allowable[$id]);
301 unset($forbitable[$id]);
304 foreach ($roles as $id=>$name) {
305 if (isset($needed[$id])) {
306 $neededroles[$id] = $roles[$id];
307 if (isset($overridableroles[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
308 $preventurl = new moodle_url($PAGE->url
, array('contextid'=>$contextid, 'roleid'=>$id, 'capability'=>$capability->name
, 'prevent'=>1));
309 $neededroles[$id] .= $OUTPUT->action_icon($preventurl, new pix_icon('t/delete', get_string('prevent', 'role')));
313 $neededroles = implode(', ', $neededroles);
314 foreach ($roles as $id=>$name) {
315 if (isset($forbidden[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
316 $forbiddenroles[$id] = $roles[$id];
317 if (isset($overridableroles[$id]) and prohibit_is_removable($id, $context, $capability->name
)) {
318 $unprohibiturl = new moodle_url($PAGE->url
, array('contextid'=>$contextid, 'roleid'=>$id, 'capability'=>$capability->name
, 'unprohibit'=>1));
319 $forbiddenroles[$id] .= $OUTPUT->action_icon($unprohibiturl, new pix_icon('t/delete', get_string('delete')));
323 $forbiddenroles = implode(', ', $forbiddenroles);
325 if ($allowable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
326 $allowurl = new moodle_url($PAGE->url
, array('contextid'=>$contextid, 'capability'=>$capability->name
, 'allow'=>1));
327 $neededroles .= '<div class="allowmore">'.$OUTPUT->action_icon($allowurl, new pix_icon('t/add', get_string('allow', 'role'))).'</div>';
330 if ($forbitable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
331 $prohibiturl = new moodle_url($PAGE->url
, array('contextid'=>$contextid, 'capability'=>$capability->name
, 'prohibit'=>1));
332 $forbiddenroles .= '<div class="prohibitmore">'.$OUTPUT->action_icon($prohibiturl, new pix_icon('t/add', get_string('prohibit', 'role'))).'</div>';
335 $risks = $this->get_risks($capability);
337 echo '<td>' . $risks . '</td>';
338 echo '<td>' . $neededroles . '</td>';
339 echo '<td>' . $forbiddenroles . '</td>';
342 protected function get_risks($capability) {
345 $allrisks = get_all_risks();
346 $risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'role'))));
350 foreach ($allrisks as $type=>$risk) {
351 if ($risk & (int)$capability->riskbitmask
) {
352 if (!isset($this->icons
[$type])) {
353 $pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
354 $this->icons
[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl));
356 $return .= $this->icons
[$type];
366 * This subclass is the bases for both the define roles and override roles
367 * pages. As well as adding the risks columns, this also provides generic
368 * facilities for showing a certain number of permissions columns, and
369 * recording the current and submitted permissions for each capability.
371 abstract class capability_table_with_risks
extends capability_table_base
{
373 protected $allpermissions; // We don't need perms ourselves, but all our subclasses do.
374 protected $strperms; // Language string cache.
375 protected $risksurl; // URL in moodledocs about risks.
376 protected $riskicons = array(); // Cache to avoid regenerating the HTML for each risk icon.
377 /** The capabilities to highlight as default/inherited. */
378 protected $parentpermissions;
379 protected $displaypermissions;
380 protected $permissions;
384 public function __construct($context, $id, $roleid) {
385 parent
::__construct($context, $id);
387 $this->allrisks
= get_all_risks();
388 $this->risksurl
= get_docs_url(s(get_string('risks', 'role')));
390 $this->allpermissions
= array(
391 CAP_INHERIT
=> 'inherit',
392 CAP_ALLOW
=> 'allow',
393 CAP_PREVENT
=> 'prevent' ,
394 CAP_PROHIBIT
=> 'prohibit',
397 $this->strperms
= array();
398 foreach ($this->allpermissions
as $permname) {
399 $this->strperms
[$permname] = get_string($permname, 'role');
402 $this->roleid
= $roleid;
403 $this->load_current_permissions();
405 /// Fill in any blank permissions with an explicit CAP_INHERIT, and init a locked field.
406 foreach ($this->capabilities
as $capid => $cap) {
407 if (!isset($this->permissions
[$cap->name
])) {
408 $this->permissions
[$cap->name
] = CAP_INHERIT
;
410 $this->capabilities
[$capid]->locked
= false;
414 protected function load_current_permissions() {
417 /// Load the overrides/definition in this context.
419 $this->permissions
= $DB->get_records_menu('role_capabilities', array('roleid' => $this->roleid
,
420 'contextid' => $this->context
->id
), '', 'capability,permission');
422 $this->permissions
= array();
426 protected abstract function load_parent_permissions();
429 * Update $this->permissions based on submitted data, while making a list of
430 * changed capabilities in $this->changed.
432 public function read_submitted_permissions() {
433 $this->changed
= array();
435 foreach ($this->capabilities
as $cap) {
436 if ($cap->locked ||
$this->skip_row($cap)) {
437 /// The user is not allowed to change the permission for this capability
441 $permission = optional_param($cap->name
, null, PARAM_PERMISSION
);
442 if (is_null($permission)) {
443 /// A permission was not specified in submitted data.
447 /// If the permission has changed, update $this->permissions and
448 /// Record the fact there is data to save.
449 if ($this->permissions
[$cap->name
] != $permission) {
450 $this->permissions
[$cap->name
] = $permission;
451 $this->changed
[] = $cap->name
;
457 * Save the new values of any permissions that have been changed.
459 public function save_changes() {
460 /// Set the permissions.
461 foreach ($this->changed
as $changedcap) {
462 assign_capability($changedcap, $this->permissions
[$changedcap],
463 $this->roleid
, $this->context
->id
, true);
466 /// Force accessinfo refresh for users visiting this context.
467 mark_context_dirty($this->context
->path
);
470 public function display() {
471 $this->load_parent_permissions();
472 foreach ($this->capabilities
as $cap) {
473 if (!isset($this->parentpermissions
[$cap->name
])) {
474 $this->parentpermissions
[$cap->name
] = CAP_INHERIT
;
480 protected function add_header_cells() {
482 echo '<th colspan="' . count($this->displaypermissions
) . '" scope="col">' .
483 get_string('permission', 'role') . ' ' . $OUTPUT->help_icon('permission', 'role') . '</th>';
484 echo '<th class="risk" colspan="' . count($this->allrisks
) . '" scope="col">' . get_string('risks','role') . '</th>';
487 protected function num_extra_columns() {
488 return count($this->displaypermissions
) +
count($this->allrisks
);
491 protected function get_row_classes($capability) {
492 $rowclasses = array();
493 foreach ($this->allrisks
as $riskname => $risk) {
494 if ($risk & (int)$capability->riskbitmask
) {
495 $rowclasses[] = $riskname;
501 protected abstract function add_permission_cells($capability);
503 protected function add_row_cells($capability) {
504 $this->add_permission_cells($capability);
505 /// One cell for each possible risk.
506 foreach ($this->allrisks
as $riskname => $risk) {
507 echo '<td class="risk ' . str_replace('risk', '', $riskname) . '">';
508 if ($risk & (int)$capability->riskbitmask
) {
509 echo $this->get_risk_icon($riskname);
516 * Print a risk icon, as a link to the Risks page on Moodle Docs.
518 * @param string $type the type of risk, will be one of the keys from the
519 * get_all_risks array. Must start with 'risk'.
521 function get_risk_icon($type) {
523 if (!isset($this->riskicons
[$type])) {
524 $iconurl = $OUTPUT->pix_url('i/' . str_replace('risk', 'risk_', $type));
525 $text = '<img src="' . $iconurl . '" alt="' . get_string($type . 'short', 'admin') . '" />';
526 $action = new popup_action('click', $this->risksurl
, 'docspopup');
527 $this->riskicons
[$type] = $OUTPUT->action_link($this->risksurl
, $text, $action, array('title'=>get_string($type, 'admin')));
529 return $this->riskicons
[$type];
534 * As well as tracking the permissions information about the role we are creating
535 * or editing, we also track the other information about the role. (This class is
536 * starting to be more and more like a formslib form in some respects.)
538 class define_role_table_advanced
extends capability_table_with_risks
{
539 /** Used to store other information (besides permissions) about the role we are creating/editing. */
541 /** Used to store errors found when validating the data. */
543 protected $contextlevels;
544 protected $allcontextlevels;
545 protected $disabled = '';
547 public function __construct($context, $roleid) {
548 $this->roleid
= $roleid;
549 parent
::__construct($context, 'defineroletable', $roleid);
550 $this->displaypermissions
= $this->allpermissions
;
551 $this->strperms
[$this->allpermissions
[CAP_INHERIT
]] = get_string('notset', 'role');
553 $this->allcontextlevels
= array(
554 CONTEXT_SYSTEM
=> get_string('coresystem'),
555 CONTEXT_USER
=> get_string('user'),
556 CONTEXT_COURSECAT
=> get_string('category'),
557 CONTEXT_COURSE
=> get_string('course'),
558 CONTEXT_MODULE
=> get_string('activitymodule'),
559 CONTEXT_BLOCK
=> get_string('block')
563 protected function load_current_permissions() {
566 if (!$this->role
= $DB->get_record('role', array('id' => $this->roleid
))) {
567 throw new moodle_exception('invalidroleid');
569 $contextlevels = get_role_contextlevels($this->roleid
);
570 // Put the contextlevels in the array keys, as well as the values.
571 if (!empty($contextlevels)) {
572 $this->contextlevels
= array_combine($contextlevels, $contextlevels);
574 $this->contextlevels
= array();
577 $this->role
= new stdClass
;
578 $this->role
->name
= '';
579 $this->role
->shortname
= '';
580 $this->role
->description
= '';
581 $this->role
->archetype
= '';
582 $this->contextlevels
= array();
584 parent
::load_current_permissions();
587 public function read_submitted_permissions() {
589 $this->errors
= array();
591 // Role short name. We clean this in a special way. We want to end up
592 // with only lowercase safe ASCII characters.
593 $shortname = optional_param('shortname', null, PARAM_RAW
);
594 if (!is_null($shortname)) {
595 $this->role
->shortname
= $shortname;
596 $this->role
->shortname
= textlib
::specialtoascii($this->role
->shortname
);
597 $this->role
->shortname
= textlib
::strtolower(clean_param($this->role
->shortname
, PARAM_ALPHANUMEXT
));
598 if (empty($this->role
->shortname
)) {
599 $this->errors
['shortname'] = get_string('errorbadroleshortname', 'role');
602 if ($DB->record_exists_select('role', 'shortname = ? and id <> ?', array($this->role
->shortname
, $this->roleid
))) {
603 $this->errors
['shortname'] = get_string('errorexistsroleshortname', 'role');
607 $name = optional_param('name', null, PARAM_TEXT
);
608 if (!is_null($name)) {
609 $this->role
->name
= $name;
610 // Hack: short names of standard roles are equal to archetypes, empty name means localised via lang packs.
611 $archetypes = get_role_archetypes();
612 if (!isset($archetypes[$shortname]) and html_is_blank($this->role
->name
)) {
613 $this->errors
['name'] = get_string('errorbadrolename', 'role');
616 if ($this->role
->name
!== '' and $DB->record_exists_select('role', 'name = ? and id <> ?', array($this->role
->name
, $this->roleid
))) {
617 $this->errors
['name'] = get_string('errorexistsrolename', 'role');
621 $description = optional_param('description', null, PARAM_RAW
);
622 if (!is_null($description)) {
623 $this->role
->description
= $description;
627 $archetype = optional_param('archetype', null, PARAM_RAW
);
628 if (isset($archetype)) {
629 $archetypes = get_role_archetypes();
630 if (isset($archetypes[$archetype])){
631 $this->role
->archetype
= $archetype;
633 $this->role
->archetype
= '';
637 // Assignable context levels.
638 foreach ($this->allcontextlevels
as $cl => $notused) {
639 $assignable = optional_param('contextlevel' . $cl, null, PARAM_BOOL
);
640 if (!is_null($assignable)) {
642 $this->contextlevels
[$cl] = $cl;
644 unset($this->contextlevels
[$cl]);
649 // Now read the permissions for each capability.
650 parent
::read_submitted_permissions();
653 public function is_submission_valid() {
654 return empty($this->errors
);
658 * Call this after the table has been initialised, so to indicate that
659 * when save is called, we want to make a duplicate role.
661 public function make_copy() {
663 unset($this->role
->id
);
664 $this->role
->name
= role_get_name($this->role
, null, ROLENAME_ORIGINAL
) . ' ' . get_string('copyasnoun');
665 $this->role
->shortname
.= 'copy';
668 public function get_role_name() {
669 return $this->role
->name
;
672 public function get_role_id() {
673 return $this->role
->id
;
676 public function get_archetype() {
677 return $this->role
->archetype
;
680 protected function load_parent_permissions() {
681 $this->parentpermissions
= get_default_capabilities($this->role
->archetype
);
684 public function save_changes() {
687 if (!$this->roleid
) {
689 $this->role
->id
= create_role($this->role
->name
, $this->role
->shortname
, $this->role
->description
, $this->role
->archetype
);
690 $this->roleid
= $this->role
->id
; // Needed to make the parent::save_changes(); call work.
693 $DB->update_record('role', $this->role
);
696 // Assignable contexts.
697 set_role_contextlevels($this->role
->id
, $this->contextlevels
);
700 parent
::save_changes();
703 protected function get_name_field($id) {
704 return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role
->name
) . '" />';
707 protected function get_shortname_field($id) {
708 return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role
->shortname
) . '" />';
711 protected function get_description_field($id) {
712 return print_textarea(true, 10, 50, 50, 10, 'description', $this->role
->description
, 0, true);
715 protected function get_archetype_field($id) {
717 $options[''] = get_string('none');
718 foreach(get_role_archetypes() as $type) {
719 $options[$type] = get_string('archetype'.$type, 'role');
721 return html_writer
::select($options, 'archetype', $this->role
->archetype
, false);
724 protected function get_assignable_levels_control() {
726 foreach ($this->allcontextlevels
as $cl => $clname) {
727 $extraarguments = $this->disabled
;
728 if (in_array($cl, $this->contextlevels
)) {
729 $extraarguments .= 'checked="checked" ';
731 if (!$this->disabled
) {
732 $output .= '<input type="hidden" name="contextlevel' . $cl . '" value="0" />';
734 $output .= '<input type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
735 '" value="1" ' . $extraarguments . '/> ';
736 $output .= '<label for="cl' . $cl . '">' . $clname . "</label><br />\n";
742 * Returns an array of roles of the allowed type.
744 * @param string $type Must be one of: assign, switch, or override.
747 protected function get_allow_roles_list($type) {
750 if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
751 debugging('Invalid role allowed type specified', DEBUG_DEVELOPER
);
755 if (empty($this->roleid
)) {
761 JOIN {role_allow_{$type}} a ON a.allow{$type} = r.id
762 WHERE a.roleid = :roleid
763 ORDER BY r.sortorder ASC";
764 return $DB->get_records_sql($sql, array('roleid'=>$this->roleid
));
768 * Returns an array of roles with the allowed type.
770 * @param string $type Must be one of: assign, switch, or override.
771 * @return array Am array of role names with the allowed type
773 protected function get_allow_role_control($type) {
774 if ($roles = $this->get_allow_roles_list($type)) {
775 $roles = role_fix_names($roles, null, ROLENAME_ORIGINAL
, true);
776 return implode(', ', $roles);
778 return get_string('none');
783 * Returns information about the risks associated with a role.
787 protected function get_role_risks_info() {
791 protected function print_field($name, $caption, $field) {
793 // Attempt to generate HTML like formslib.
794 echo '<div class="fitem">';
795 echo '<div class="fitemtitle">';
797 echo '<label for="' . $name . '">';
804 if (isset($this->errors
[$name])) {
805 $extraclass = ' error';
809 echo '<div class="felement' . $extraclass . '">';
810 if (isset($this->errors
[$name])) {
811 echo $OUTPUT->error_text($this->errors
[$name]);
818 protected function print_show_hide_advanced_button() {
819 echo '<p class="definenotice">' . get_string('highlightedcellsshowdefault', 'role') . ' </p>';
820 echo '<div class="advancedbutton">';
821 echo '<input type="submit" name="toggleadvanced" value="' . get_string('hideadvanced', 'form') . '" />';
825 public function display() {
827 // Extra fields at the top of the page.
828 echo '<div class="topfields clearfix">';
829 $this->print_field('shortname', get_string('roleshortname', 'role').' '.$OUTPUT->help_icon('roleshortname', 'role'), $this->get_shortname_field('shortname'));
830 $this->print_field('name', get_string('customrolename', 'role').' '.$OUTPUT->help_icon('customrolename', 'role'), $this->get_name_field('name'));
831 $this->print_field('edit-description', get_string('customroledescription', 'role').' '.$OUTPUT->help_icon('customroledescription', 'role'), $this->get_description_field('description'));
832 $this->print_field('menuarchetype', get_string('archetype', 'role').' '.$OUTPUT->help_icon('archetype', 'role'), $this->get_archetype_field('archetype'));
833 $this->print_field('', get_string('maybeassignedin', 'role'), $this->get_assignable_levels_control());
834 $this->print_field('', get_string('allowassign', 'role'), $this->get_allow_role_control('assign'));
835 $this->print_field('', get_string('allowoverride', 'role'), $this->get_allow_role_control('override'));
836 $this->print_field('', get_string('allowswitch', 'role'), $this->get_allow_role_control('switch'));
837 if ($risks = $this->get_role_risks_info()) {
838 $this->print_field('', get_string('rolerisks', 'role'), $risks);
842 $this->print_show_hide_advanced_button();
844 // Now the permissions table.
848 protected function add_permission_cells($capability) {
849 /// One cell for each possible permission.
850 foreach ($this->displaypermissions
as $perm => $permname) {
851 $strperm = $this->strperms
[$permname];
853 if ($perm == $this->parentpermissions
[$capability->name
]) {
854 $extraclass = ' capdefault';
857 if ($this->permissions
[$capability->name
] == $perm) {
858 $checked = 'checked="checked" ';
860 echo '<td class="' . $permname . $extraclass . '">';
861 echo '<label><input type="radio" name="' . $capability->name
.
862 '" value="' . $perm . '" ' . $checked . '/> ';
863 echo '<span class="note">' . $strperm . '</span>';
864 echo '</label></td>';
869 class define_role_table_basic
extends define_role_table_advanced
{
870 protected $stradvmessage;
873 public function __construct($context, $roleid) {
874 parent
::__construct($context, $roleid);
875 $this->displaypermissions
= array(CAP_ALLOW
=> $this->allpermissions
[CAP_ALLOW
]);
876 $this->stradvmessage
= get_string('useshowadvancedtochange', 'role');
877 $this->strallow
= $this->strperms
[$this->allpermissions
[CAP_ALLOW
]];
880 protected function print_show_hide_advanced_button() {
881 echo '<div class="advancedbutton">';
882 echo '<input type="submit" name="toggleadvanced" value="' . get_string('showadvanced', 'form') . '" />';
886 protected function add_permission_cells($capability) {
887 $perm = $this->permissions
[$capability->name
];
888 $permname = $this->allpermissions
[$perm];
889 $defaultperm = $this->allpermissions
[$this->parentpermissions
[$capability->name
]];
890 echo '<td class="' . $permname . '">';
891 if ($perm == CAP_ALLOW ||
$perm == CAP_INHERIT
) {
893 if ($perm == CAP_ALLOW
) {
894 $checked = 'checked="checked" ';
896 echo '<input type="hidden" name="' . $capability->name
. '" value="' . CAP_INHERIT
. '" />';
897 echo '<label><input type="checkbox" name="' . $capability->name
.
898 '" value="' . CAP_ALLOW
. '" ' . $checked . '/> ' . $this->strallow
. '</label>';
900 echo '<input type="hidden" name="' . $capability->name
. '" value="' . $perm . '" />';
901 echo $this->strperms
[$permname] . '<span class="note">' . $this->stradvmessage
. '</span>';
906 class view_role_definition_table
extends define_role_table_advanced
{
907 public function __construct($context, $roleid) {
908 parent
::__construct($context, $roleid);
909 $this->displaypermissions
= array(CAP_ALLOW
=> $this->allpermissions
[CAP_ALLOW
]);
910 $this->disabled
= 'disabled="disabled" ';
913 public function save_changes() {
914 throw new moodle_exception('invalidaccess');
917 protected function get_name_field($id) {
918 return role_get_name($this->role
);
921 protected function get_shortname_field($id) {
922 return $this->role
->shortname
;
925 protected function get_description_field($id) {
926 return role_get_description($this->role
);
929 protected function get_archetype_field($id) {
930 if (empty($this->role
->archetype
)) {
931 return get_string('none');
933 return get_string('archetype'.$this->role
->archetype
, 'role');
937 protected function print_show_hide_advanced_button() {
942 * Returns HTML risk icons.
946 protected function get_role_risks_info() {
949 if (empty($this->roleid
)) {
954 $allrisks = get_all_risks();
955 foreach ($this->capabilities
as $capability) {
956 $perm = $this->permissions
[$capability->name
];
957 if ($perm != CAP_ALLOW
) {
960 foreach ($allrisks as $type=>$risk) {
961 if ($risk & (int)$capability->riskbitmask
) {
962 $risks[$type] = $risk;
967 $risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'role'))));
968 foreach ($risks as $type=>$risk) {
969 $pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
970 $risks[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl));
973 return implode(' ', $risks);
977 * Returns true if the row should be skipped.
979 * @param string $capability
982 protected function skip_row($capability) {
983 $perm = $this->permissions
[$capability->name
];
984 if ($perm == CAP_INHERIT
) {
985 // Do not print empty rows in role overview, admins need to know quickly what is allowed and prohibited,
986 // if they want to see the list of all capabilities they can go to edit role page.
989 parent
::skip_row($capability);
992 protected function add_permission_cells($capability) {
993 $perm = $this->permissions
[$capability->name
];
994 $permname = $this->allpermissions
[$perm];
995 $defaultperm = $this->allpermissions
[$this->parentpermissions
[$capability->name
]];
996 if ($permname != $defaultperm) {
997 $default = get_string('defaultx', 'role', $this->strperms
[$defaultperm]);
1001 echo '<td class="' . $permname . '">' . $this->strperms
[$permname] . '<span class="note">' .
1002 $default . '</span></td>';
1007 class override_permissions_table_advanced
extends capability_table_with_risks
{
1008 protected $strnotset;
1009 protected $haslockedcapabilities = false;
1014 * This method loads loads all the information about the current state of
1015 * the overrides, then updates that based on any submitted data. It also
1016 * works out which capabilities should be locked for this user.
1018 * @param object $context the context this table relates to.
1019 * @param integer $roleid the role being overridden.
1020 * @param boolean $safeoverridesonly If true, the user is only allowed to override
1021 * capabilities with no risks.
1023 public function __construct($context, $roleid, $safeoverridesonly) {
1024 parent
::__construct($context, 'overriderolestable', $roleid);
1025 $this->displaypermissions
= $this->allpermissions
;
1026 $this->strnotset
= get_string('notset', 'role');
1028 /// Determine which capabilities should be locked.
1029 if ($safeoverridesonly) {
1030 foreach ($this->capabilities
as $capid => $cap) {
1031 if (!is_safe_capability($cap)) {
1032 $this->capabilities
[$capid]->locked
= true;
1033 $this->haslockedcapabilities
= true;
1039 protected function load_parent_permissions() {
1042 /// Get the capabilities from the parent context, so that can be shown in the interface.
1043 $parentcontext = context
::instance_by_id(get_parent_contextid($this->context
));
1044 $this->parentpermissions
= role_context_capabilities($this->roleid
, $parentcontext);
1047 public function has_locked_capabilities() {
1048 return $this->haslockedcapabilities
;
1051 protected function add_permission_cells($capability) {
1053 if ($capability->locked ||
$this->parentpermissions
[$capability->name
] == CAP_PROHIBIT
) {
1054 $disabled = ' disabled="disabled"';
1057 /// One cell for each possible permission.
1058 foreach ($this->displaypermissions
as $perm => $permname) {
1059 $strperm = $this->strperms
[$permname];
1061 if ($perm != CAP_INHERIT
&& $perm == $this->parentpermissions
[$capability->name
]) {
1062 $extraclass = ' capcurrent';
1065 if ($this->permissions
[$capability->name
] == $perm) {
1066 $checked = 'checked="checked" ';
1068 echo '<td class="' . $permname . $extraclass . '">';
1069 echo '<label><input type="radio" name="' . $capability->name
.
1070 '" value="' . $perm . '" ' . $checked . $disabled . '/> ';
1071 if ($perm == CAP_INHERIT
) {
1072 $inherited = $this->parentpermissions
[$capability->name
];
1073 if ($inherited == CAP_INHERIT
) {
1074 $inherited = $this->strnotset
;
1076 $inherited = $this->strperms
[$this->allpermissions
[$inherited]];
1078 $strperm .= ' (' . $inherited . ')';
1080 echo '<span class="note">' . $strperm . '</span>';
1081 echo '</label></td>';
1086 // User selectors for managing role assignments ================================
1089 * Base class to avoid duplicating code.
1091 abstract class role_assign_user_selector_base
extends user_selector_base
{
1096 * @param string $name control name
1097 * @param array $options should have two elements with keys groupid and courseid.
1099 public function __construct($name, $options) {
1101 if (isset($options['context'])) {
1102 $this->context
= $options['context'];
1104 $this->context
= context
::instance_by_id($options['contextid']);
1106 $options['accesscontext'] = $this->context
;
1107 parent
::__construct($name, $options);
1108 $this->roleid
= $options['roleid'];
1109 require_once($CFG->dirroot
. '/group/lib.php');
1112 protected function get_options() {
1114 $options = parent
::get_options();
1115 $options['file'] = $CFG->admin
. '/roles/lib.php';
1116 $options['roleid'] = $this->roleid
;
1117 $options['contextid'] = $this->context
->id
;
1123 * User selector subclass for the list of potential users on the assign roles page,
1124 * when we are assigning in a context below the course level. (CONTEXT_MODULE and
1125 * some CONTEXT_BLOCK).
1127 * This returns only enrolled users in this context.
1129 class potential_assignees_below_course
extends role_assign_user_selector_base
{
1130 public function find_users($search) {
1133 list($enrolsql, $eparams) = get_enrolled_sql($this->context
);
1135 // Now we have to go to the database.
1136 list($wherecondition, $params) = $this->search_sql($search, 'u');
1137 $params = array_merge($params, $eparams);
1139 if ($wherecondition) {
1140 $wherecondition = ' AND ' . $wherecondition;
1143 $fields = 'SELECT ' . $this->required_fields_sql('u');
1144 $countfields = 'SELECT COUNT(u.id)';
1146 $sql = " FROM {user} u
1147 LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
1148 WHERE u.id IN ($enrolsql)
1151 $params['contextid'] = $this->context
->id
;
1152 $params['roleid'] = $this->roleid
;
1154 list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext
);
1155 $order = ' ORDER BY ' . $sort;
1157 // Check to see if there are too many to show sensibly.
1158 if (!$this->is_validating()) {
1159 $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
1160 if ($potentialmemberscount > $this->maxusersperpage
) {
1161 return $this->too_many_results($search, $potentialmemberscount);
1165 // If not, show them.
1166 $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
1168 if (empty($availableusers)) {
1173 $groupname = get_string('potusersmatching', 'role', $search);
1175 $groupname = get_string('potusers', 'role');
1178 return array($groupname => $availableusers);
1183 * User selector subclass for the selection of users in the check permissions page.
1185 * @copyright 2012 Petr Skoda {@link http://skodak.org}
1187 class role_check_users_selector
extends user_selector_base
{
1188 /** @var bool limit listing of users to enrolled only */
1194 * @param string $name the control name/id for use in the HTML.
1195 * @param array $options other options needed to construct this selector.
1196 * You must be able to clone a userselector by doing new get_class($us)($us->get_name(), $us->get_options());
1198 public function __construct($name, $options) {
1199 if (!isset($options['multiselect'])) {
1200 $options['multiselect'] = false;
1202 parent
::__construct($name, $options);
1204 $coursecontext = $this->accesscontext
->get_course_context(false);
1205 if ($coursecontext and $coursecontext->id
!= SITEID
and !has_capability('moodle/role:manage', $coursecontext)) {
1206 // Prevent normal teachers from looking up all users.
1207 $this->onlyenrolled
= true;
1209 $this->onlyenrolled
= false;
1213 public function find_users($search) {
1216 list($wherecondition, $params) = $this->search_sql($search, 'u');
1218 $fields = 'SELECT ' . $this->required_fields_sql('u');
1219 $countfields = 'SELECT COUNT(1)';
1221 $coursecontext = $this->accesscontext
->get_course_context(false);
1223 if ($coursecontext and $coursecontext != SITEID
) {
1224 $sql1 = " FROM {user} u
1225 JOIN {user_enrolments} ue ON (ue.userid = u.id)
1226 JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid1)
1227 WHERE $wherecondition";
1228 $params['courseid1'] = $coursecontext->instanceid
;
1230 if ($this->onlyenrolled
) {
1233 $sql2 = " FROM {user} u
1234 LEFT JOIN ({user_enrolments} ue
1235 JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid2)) ON (ue.userid = u.id)
1236 WHERE $wherecondition
1238 $params['courseid2'] = $coursecontext->instanceid
;
1242 if ($this->onlyenrolled
) {
1243 // Bad luck, current user may not view only enrolled users.
1247 $sql2 = " FROM {user} u
1248 WHERE $wherecondition";
1251 $params['contextid'] = $this->accesscontext
->id
;
1253 list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext
);
1254 $order = ' ORDER BY ' . $sort;
1259 $groupname1 = get_string('enrolledusersmatching', 'enrol', $search);
1260 $groupname2 = get_string('potusersmatching', 'role', $search);
1262 $groupname1 = get_string('enrolledusers', 'enrol');
1263 $groupname2 = get_string('potusers', 'role');
1267 $enrolleduserscount = $DB->count_records_sql($countfields . $sql1, $params);
1268 if (!$this->is_validating() and $enrolleduserscount > $this->maxusersperpage
) {
1269 $result[$groupname1] = array();
1270 $toomany = $this->too_many_results($search, $enrolleduserscount);
1271 $result[implode(' - ', array_keys($toomany))] = array();
1274 $enrolledusers = $DB->get_records_sql($fields . $sql1 . $order, array_merge($params, $sortparams));
1275 if ($enrolledusers) {
1276 $result[$groupname1] = $enrolledusers;
1280 $result[''] = array();
1284 $otheruserscount = $DB->count_records_sql($countfields . $sql2, $params);
1285 if (!$this->is_validating() and $otheruserscount > $this->maxusersperpage
) {
1286 $result[$groupname2] = array();
1287 $toomany = $this->too_many_results($search, $otheruserscount);
1288 $result[implode(' - ', array_keys($toomany))] = array();
1290 $otherusers = $DB->get_records_sql($fields . $sql2 . $order, array_merge($params, $sortparams));
1292 $result[$groupname2] = $otherusers;
1300 protected function get_options() {
1302 $options = parent
::get_options();
1303 $options['file'] = $CFG->admin
. '/roles/lib.php';
1309 * User selector subclass for the list of potential users on the assign roles page,
1310 * when we are assigning in a context at or above the course level. In this case we
1311 * show all the users in the system who do not already have the role.
1313 class potential_assignees_course_and_above
extends role_assign_user_selector_base
{
1314 public function find_users($search) {
1317 list($wherecondition, $params) = $this->search_sql($search, '');
1319 $fields = 'SELECT ' . $this->required_fields_sql('');
1320 $countfields = 'SELECT COUNT(1)';
1322 $sql = " FROM {user}
1323 WHERE $wherecondition
1326 FROM {role_assignments} r
1327 WHERE r.contextid = :contextid
1328 AND r.roleid = :roleid)";
1330 list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext
);
1331 $order = ' ORDER BY ' . $sort;
1333 $params['contextid'] = $this->context
->id
;
1334 $params['roleid'] = $this->roleid
;
1336 if (!$this->is_validating()) {
1337 $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
1338 if ($potentialmemberscount > $this->maxusersperpage
) {
1339 return $this->too_many_results($search, $potentialmemberscount);
1343 $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
1345 if (empty($availableusers)) {
1350 $groupname = get_string('potusersmatching', 'role', $search);
1352 $groupname = get_string('potusers', 'role');
1355 return array($groupname => $availableusers);
1360 * User selector subclass for the list of users who already have the role in
1361 * question on the assign roles page.
1363 class existing_role_holders
extends role_assign_user_selector_base
{
1365 public function __construct($name, $options) {
1366 parent
::__construct($name, $options);
1369 public function find_users($search) {
1372 list($wherecondition, $params) = $this->search_sql($search, 'u');
1373 list($ctxcondition, $ctxparams) = $DB->get_in_or_equal(get_parent_contexts($this->context
, true), SQL_PARAMS_NAMED
, 'ctx');
1374 $params = array_merge($params, $ctxparams);
1375 $params['roleid'] = $this->roleid
;
1377 list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext
);
1378 $params = array_merge($params, $sortparams);
1380 $sql = "SELECT ra.id as raid," . $this->required_fields_sql('u') . ",ra.contextid,ra.component
1381 FROM {role_assignments} ra
1382 JOIN {user} u ON u.id = ra.userid
1383 JOIN {context} ctx ON ra.contextid = ctx.id
1386 ctx.id $ctxcondition AND
1388 ORDER BY ctx.depth DESC, ra.component, $sort";
1389 $contextusers = $DB->get_records_sql($sql, $params);
1392 if (empty($contextusers)) {
1396 // We have users. Out put them in groups by context depth.
1397 // To help the loop below, tack a dummy user on the end of the results
1398 // array, to trigger output of the last group.
1399 $dummyuser = new stdClass
;
1400 $dummyuser->contextid
= 0;
1402 $dummyuser->component
= '';
1403 $contextusers[] = $dummyuser;
1404 $results = array(); // The results array we are building up.
1405 $doneusers = array(); // Ensures we only list each user at most once.
1406 $currentcontextid = $this->context
->id
;
1407 $currentgroup = array();
1408 foreach ($contextusers as $user) {
1409 if (isset($doneusers[$user->id
])) {
1412 $doneusers[$user->id
] = 1;
1413 if ($user->contextid
!= $currentcontextid) {
1414 // We have got to the end of the previous group. Add it to the results array.
1415 if ($currentcontextid == $this->context
->id
) {
1416 $groupname = $this->this_con_group_name($search, count($currentgroup));
1418 $groupname = $this->parent_con_group_name($search, $currentcontextid);
1420 $results[$groupname] = $currentgroup;
1421 // Get ready for the next group.
1422 $currentcontextid = $user->contextid
;
1423 $currentgroup = array();
1425 // Add this user to the group we are building up.
1426 unset($user->contextid
);
1427 if ($currentcontextid != $this->context
->id
) {
1428 $user->disabled
= true;
1430 if ($user->component
!== '') {
1431 // bad luck, you can tweak only manual role assignments
1432 $user->disabled
= true;
1434 unset($user->component
);
1435 $currentgroup[$user->id
] = $user;
1441 protected function this_con_group_name($search, $numusers) {
1442 if ($this->context
->contextlevel
== CONTEXT_SYSTEM
) {
1443 // Special case in the System context.
1445 return get_string('extusersmatching', 'role', $search);
1447 return get_string('extusers', 'role');
1450 $contexttype = get_contextlevel_name($this->context
->contextlevel
);
1453 $a->search
= $search;
1454 $a->contexttype
= $contexttype;
1456 return get_string('usersinthisxmatching', 'role', $a);
1458 return get_string('noneinthisxmatching', 'role', $a);
1462 return get_string('usersinthisx', 'role', $contexttype);
1464 return get_string('noneinthisx', 'role', $contexttype);
1469 protected function parent_con_group_name($search, $contextid) {
1470 $context = context
::instance_by_id($contextid);
1471 $contextname = print_context_name($context, true, true);
1474 $a->contextname
= $contextname;
1475 $a->search
= $search;
1476 return get_string('usersfrommatching', 'role', $a);
1478 return get_string('usersfrom', 'role', $contextname);
1484 * Base class for managing the data in the grid of checkboxes on the role allow
1485 * allow/overrides/switch editing pages (allow.php).
1487 abstract class role_allow_role_page
{
1488 protected $tablename;
1489 protected $targetcolname;
1491 protected $allowed = null;
1494 * @param string $tablename the table where our data is stored.
1495 * @param string $targetcolname the name of the target role id column.
1497 public function __construct($tablename, $targetcolname) {
1498 $this->tablename
= $tablename;
1499 $this->targetcolname
= $targetcolname;
1500 $this->load_required_roles();
1504 * Load information about all the roles we will need information about.
1506 protected function load_required_roles() {
1508 $this->roles
= role_fix_names(get_all_roles(), context_system
::instance(), ROLENAME_ORIGINAL
);
1512 * Update the data with the new settings submitted by the user.
1514 public function process_submission() {
1516 /// Delete all records, then add back the ones that should be allowed.
1517 $DB->delete_records($this->tablename
);
1518 foreach ($this->roles
as $fromroleid => $notused) {
1519 foreach ($this->roles
as $targetroleid => $alsonotused) {
1520 if (optional_param('s_' . $fromroleid . '_' . $targetroleid, false, PARAM_BOOL
)) {
1521 $this->set_allow($fromroleid, $targetroleid);
1528 * Set one allow in the database.
1529 * @param integer $fromroleid
1530 * @param integer $targetroleid
1532 protected abstract function set_allow($fromroleid, $targetroleid);
1535 * Load the current allows from the database.
1537 public function load_current_settings() {
1539 /// Load the current settings
1540 $this->allowed
= array();
1541 foreach ($this->roles
as $role) {
1542 // Make an array $role->id => false. This is probably too clever for its own good.
1543 $this->allowed
[$role->id
] = array_combine(array_keys($this->roles
), array_fill(0, count($this->roles
), false));
1545 $rs = $DB->get_recordset($this->tablename
);
1546 foreach ($rs as $allow) {
1547 $this->allowed
[$allow->roleid
][$allow->{$this->targetcolname
}] = true;
1553 * @param integer $targetroleid a role id.
1554 * @return boolean whether the user should be allowed to select this role as a
1557 protected function is_allowed_target($targetroleid) {
1562 * @return object a $table structure that can be passed to print_table, containing
1563 * one cell for each checkbox.
1565 public function get_table() {
1566 $table = new html_table();
1567 $table->tablealign
= 'center';
1568 $table->cellpadding
= 5;
1569 $table->cellspacing
= 0;
1570 $table->width
= '90%';
1571 $table->align
= array('left');
1572 $table->rotateheaders
= true;
1573 $table->head
= array(' ');
1574 $table->colclasses
= array('');
1576 /// Add role name headers.
1577 foreach ($this->roles
as $targetrole) {
1578 $table->head
[] = $targetrole->localname
;
1579 $table->align
[] = 'left';
1580 if ($this->is_allowed_target($targetrole->id
)) {
1581 $table->colclasses
[] = '';
1583 $table->colclasses
[] = 'dimmed_text';
1587 /// Now the rest of the table.
1588 foreach ($this->roles
as $fromrole) {
1589 $row = array($fromrole->localname
);
1590 foreach ($this->roles
as $targetrole) {
1593 if ($this->allowed
[$fromrole->id
][$targetrole->id
]) {
1594 $checked = 'checked="checked" ';
1596 if (!$this->is_allowed_target($targetrole->id
)) {
1597 $disabled = 'disabled="disabled" ';
1599 $name = 's_' . $fromrole->id
. '_' . $targetrole->id
;
1600 $tooltip = $this->get_cell_tooltip($fromrole, $targetrole);
1601 $row[] = '<input type="checkbox" name="' . $name . '" id="' . $name .
1602 '" title="' . $tooltip . '" value="1" ' . $checked . $disabled . '/>' .
1603 '<label for="' . $name . '" class="accesshide">' . $tooltip . '</label>';
1605 $table->data
[] = $row;
1612 * Snippet of text displayed above the table, telling the admin what to do.
1613 * @return unknown_type
1615 public abstract function get_intro_text();
1619 * Subclass of role_allow_role_page for the Allow assigns tab.
1621 class role_allow_assign_page
extends role_allow_role_page
{
1622 public function __construct() {
1623 parent
::__construct('role_allow_assign', 'allowassign');
1626 protected function set_allow($fromroleid, $targetroleid) {
1627 allow_assign($fromroleid, $targetroleid);
1630 protected function get_cell_tooltip($fromrole, $targetrole) {
1632 $a->fromrole
= $fromrole->localname
;
1633 $a->targetrole
= $targetrole->localname
;
1634 return get_string('allowroletoassign', 'role', $a);
1637 public function get_intro_text() {
1638 return get_string('configallowassign', 'admin');
1643 * Subclass of role_allow_role_page for the Allow overrides tab.
1645 class role_allow_override_page
extends role_allow_role_page
{
1646 public function __construct() {
1647 parent
::__construct('role_allow_override', 'allowoverride');
1650 protected function set_allow($fromroleid, $targetroleid) {
1651 allow_override($fromroleid, $targetroleid);
1654 protected function get_cell_tooltip($fromrole, $targetrole) {
1656 $a->fromrole
= $fromrole->localname
;
1657 $a->targetrole
= $targetrole->localname
;
1658 return get_string('allowroletooverride', 'role', $a);
1661 public function get_intro_text() {
1662 return get_string('configallowoverride2', 'admin');
1667 * Subclass of role_allow_role_page for the Allow switches tab.
1669 class role_allow_switch_page
extends role_allow_role_page
{
1670 protected $allowedtargetroles;
1672 public function __construct() {
1673 parent
::__construct('role_allow_switch', 'allowswitch');
1676 protected function load_required_roles() {
1678 parent
::load_required_roles();
1679 $this->allowedtargetroles
= $DB->get_records_menu('role', NULL, 'id');
1682 protected function set_allow($fromroleid, $targetroleid) {
1683 allow_switch($fromroleid, $targetroleid);
1686 protected function is_allowed_target($targetroleid) {
1687 return isset($this->allowedtargetroles
[$targetroleid]);
1690 protected function get_cell_tooltip($fromrole, $targetrole) {
1692 $a->fromrole
= $fromrole->localname
;
1693 $a->targetrole
= $targetrole->localname
;
1694 return get_string('allowroletoswitch', 'role', $a);
1697 public function get_intro_text() {
1698 return get_string('configallowswitch', 'admin');
1703 * Get the potential assignees selector for a given context.
1705 * If this context is a course context, or inside a course context (module or
1706 * some blocks) then return a potential_assignees_below_course object. Otherwise
1707 * return a potential_assignees_course_and_above.
1709 * @param stdClass $context a context.
1710 * @param string $name passed to user selector constructor.
1711 * @param array $options to user selector constructor.
1712 * @return user_selector_base an appropriate user selector.
1714 function roles_get_potential_user_selector($context, $name, $options) {
1715 $blockinsidecourse = false;
1716 if ($context->contextlevel
== CONTEXT_BLOCK
) {
1717 $parentcontext = context
::instance_by_id(get_parent_contextid($context));
1718 $blockinsidecourse = in_array($parentcontext->contextlevel
, array(CONTEXT_MODULE
, CONTEXT_COURSE
));
1721 if (($context->contextlevel
== CONTEXT_MODULE ||
$blockinsidecourse) &&
1722 !is_inside_frontpage($context)) {
1723 $potentialuserselector = new potential_assignees_below_course('addselect', $options);
1725 $potentialuserselector = new potential_assignees_course_and_above('addselect', $options);
1727 return $potentialuserselector;
1730 class admins_potential_selector
extends user_selector_base
{
1732 * @param string $name control name
1733 * @param array $options should have two elements with keys groupid and courseid.
1735 public function __construct($name = null, $options = array()) {
1737 if (is_null($name)) {
1738 $name = 'addselect';
1740 $options['multiselect'] = false;
1741 $options['exclude'] = explode(',', $CFG->siteadmins
);
1742 parent
::__construct($name, $options);
1745 public function find_users($search) {
1747 list($wherecondition, $params) = $this->search_sql($search, '');
1749 $fields = 'SELECT ' . $this->required_fields_sql('');
1750 $countfields = 'SELECT COUNT(1)';
1752 $sql = " FROM {user}
1753 WHERE $wherecondition AND mnethostid = :localmnet";
1755 $params['localmnet'] = $CFG->mnet_localhost_id
; // it could be dangerous to make remote users admins and also this could lead to other problems
1757 list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext
);
1758 $order = ' ORDER BY ' . $sort;
1760 // Check to see if there are too many to show sensibly.
1761 if (!$this->is_validating()) {
1762 $potentialcount = $DB->count_records_sql($countfields . $sql, $params);
1763 if ($potentialcount > $this->maxusersperpage
) {
1764 return $this->too_many_results($search, $potentialcount);
1768 $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
1770 if (empty($availableusers)) {
1775 $groupname = get_string('potusersmatching', 'role', $search);
1777 $groupname = get_string('potusers', 'role');
1780 return array($groupname => $availableusers);
1783 protected function get_options() {
1785 $options = parent
::get_options();
1786 $options['file'] = $CFG->admin
. '/roles/lib.php';
1791 class admins_existing_selector
extends user_selector_base
{
1793 * @param string $name control name
1794 * @param array $options should have two elements with keys groupid and courseid.
1796 public function __construct($name = null, $options = array()) {
1797 if (is_null($name)) {
1798 $name = 'removeselect';
1800 $options['multiselect'] = false;
1801 parent
::__construct($name, $options);
1804 public function find_users($search) {
1806 list($wherecondition, $params) = $this->search_sql($search, '');
1808 $fields = 'SELECT ' . $this->required_fields_sql('');
1809 $countfields = 'SELECT COUNT(1)';
1811 if ($wherecondition) {
1812 $wherecondition = "$wherecondition AND id IN ($CFG->siteadmins)";
1814 $wherecondition = "id IN ($CFG->siteadmins)";
1816 $sql = " FROM {user}
1817 WHERE $wherecondition";
1819 list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext
);
1820 $params = array_merge($params, $sortparams);
1821 $order = ' ORDER BY ' . $sort;
1823 $availableusers = $DB->get_records_sql($fields . $sql . $order, $params);
1825 if (empty($availableusers)) {
1829 $mainadmin = array();
1830 $mainadminuser = get_admin();
1831 if ($mainadminuser && isset($availableusers[$mainadminuser->id
])) {
1832 $mainadmin = array($mainadminuser->id
=> $availableusers[$mainadminuser->id
]);
1833 unset($availableusers[$mainadminuser->id
]);
1838 $result[get_string('mainadmin', 'role')] = $mainadmin;
1841 if ($availableusers) {
1843 $groupname = get_string('extusersmatching', 'role', $search);
1845 $groupname = get_string('extusers', 'role');
1847 $result[$groupname] = $availableusers;
1853 protected function get_options() {
1855 $options = parent
::get_options();
1856 $options['file'] = $CFG->admin
. '/roles/lib.php';