19
18
* 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
21
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
30
22
* @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');
25
defined('MOODLE_INTERNAL') || die();
1703
28
* Get the potential assignees selector for a given context.
1705
30
* 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.
31
* some blocks) then return a core_role_potential_assignees_below_course object. Otherwise
32
* return a core_role_potential_assignees_course_and_above.
1709
* @param stdClass $context a context.
34
* @param context $context a context.
1710
35
* @param string $name passed to user selector constructor.
1711
36
* @param array $options to user selector constructor.
1712
37
* @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);
39
function core_role_get_potential_user_selector(context $context, $name, $options) {
40
$blockinsidecourse = false;
41
if ($context->contextlevel == CONTEXT_BLOCK) {
42
$parentcontext = $context->get_parent_context();
43
$blockinsidecourse = in_array($parentcontext->contextlevel, array(CONTEXT_MODULE, CONTEXT_COURSE));
46
if (($context->contextlevel == CONTEXT_MODULE || $blockinsidecourse) &&
47
!is_inside_frontpage($context)) {
48
$potentialuserselector = new core_role_potential_assignees_below_course('addselect', $options);
50
$potentialuserselector = new core_role_potential_assignees_course_and_above('addselect', $options);
1727
53
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';