~ubuntu-branches/ubuntu/utopic/moodle/utopic

« back to all changes in this revision

Viewing changes to admin/roles/lib.php

  • Committer: Package Import Robot
  • Author(s): Thijs Kinkhorst
  • Date: 2014-05-12 16:10:38 UTC
  • mfrom: (36.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20140512161038-puyqf65k4e0s8ytz
Tags: 2.6.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
<?php
2
 
 
3
2
// This file is part of Moodle - http://moodle.org/
4
3
//
5
4
// Moodle is free software: you can redistribute it and/or modify
18
17
/**
19
18
 * Library code used by the roles administration interfaces.
20
19
 *
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
26
 
 *
27
 
 * @package    core
28
 
 * @subpackage role
 
20
 * @package    core_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
31
23
 */
32
24
 
33
 
require_once($CFG->libdir.'/adminlib.php');
34
 
require_once($CFG->dirroot.'/user/selector/lib.php');
35
 
 
36
 
// Classes for producing tables with one row per capability ====================
37
 
 
38
 
/**
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.
43
 
 *
44
 
 * An ajaxy search UI shown at the top, if JavaScript is on.
45
 
 */
46
 
abstract class capability_table_base {
47
 
    /** The context this table relates to. */
48
 
    protected $context;
49
 
 
50
 
    /** The capabilities to display. Initialised as fetch_context_capabilities($context). */
51
 
    protected $capabilities = array();
52
 
 
53
 
    /** Added as an id="" attribute to the table on output. */
54
 
    protected $id;
55
 
 
56
 
    /** Added to the class="" attribute on output. */
57
 
    protected $classes = array('rolecap');
58
 
 
59
 
    /** Default number of capabilities in the table for the search UI to be shown. */
60
 
    const NUM_CAPS_FOR_SEARCH = 12;
61
 
 
62
 
    /**
63
 
     * Constructor
64
 
     * @param object $context the context this table relates to.
65
 
     * @param string $id what to put in the id="" attribute.
66
 
     */
67
 
    public function __construct($context, $id) {
68
 
        $this->context = $context;
69
 
        $this->capabilities = fetch_context_capabilities($context);
70
 
        $this->id = $id;
71
 
    }
72
 
 
73
 
    /**
74
 
     * Use this to add class="" attributes to the table. You get the rolecap by
75
 
     * default.
76
 
     * @param array $classnames of class names.
77
 
     */
78
 
    public function add_classes($classnames) {
79
 
        $this->classes = array_unique(array_merge($this->classes, $classnames));
80
 
    }
81
 
 
82
 
    /**
83
 
     * Display the table.
84
 
     */
85
 
    public function display() {
86
 
        if (count($this->capabilities) > capability_table_base::NUM_CAPS_FOR_SEARCH) {
87
 
            global $PAGE;
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));
90
 
        }
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";
95
 
 
96
 
    /// Loop over capabilities.
97
 
        $contextlevel = 0;
98
 
        $component = '';
99
 
        foreach ($this->capabilities as $capability) {
100
 
            if ($this->skip_row($capability)) {
101
 
                continue;
102
 
            }
103
 
 
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);
107
 
            }
108
 
            $contextlevel = $capability->contextlevel;
109
 
            $component = $capability->component;
110
 
 
111
 
        /// Start the row.
112
 
            echo '<tr class="' . implode(' ', array_unique(array_merge(array('rolecap'),
113
 
                    $this->get_row_classes($capability)))) . '">';
114
 
 
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>';
118
 
 
119
 
        /// Add the cells specific to this table.
120
 
            $this->add_row_cells($capability);
121
 
 
122
 
        /// End the row.
123
 
            echo "</tr>\n";
124
 
        }
125
 
 
126
 
    /// End of the table.
127
 
        echo "</tbody>\n</table>\n";
128
 
    }
129
 
 
130
 
    /**
131
 
     * Used to output a heading rows when the context level or component changes.
132
 
     * @param object $capability gives the new component and contextlevel.
133
 
     */
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>';
138
 
 
139
 
    }
140
 
 
141
 
    /** For subclasses to override, output header cells, after the initial capability one. */
142
 
    protected abstract function add_header_cells();
143
 
 
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();
146
 
 
147
 
    /**
148
 
     * For subclasses to override. Allows certain capabilties
149
 
     * to be left out of the table.
150
 
     *
151
 
     * @param object $capability the capability this row relates to.
152
 
     * @return boolean. If true, this row is omitted from the table.
153
 
     */
154
 
    protected function skip_row($capability) {
155
 
        return false;
156
 
    }
157
 
 
158
 
    /**
159
 
     * For subclasses to override. A change to reaturn class names that are added
160
 
     * to the class="" attribute on the &lt;tr> for this capability.
161
 
     *
162
 
     * @param object $capability the capability this row relates to.
163
 
     * @return array of class name strings.
164
 
     */
165
 
    protected function get_row_classes($capability) {
166
 
        return array();
167
 
    }
168
 
 
169
 
    /**
170
 
     * For subclasses to override. Output the data cells for this capability. The
171
 
     * capability name cell will already have been output.
172
 
     *
173
 
     * You can rely on get_row_classes always being called before add_row_cells.
174
 
     *
175
 
     * @param object $capability the capability this row relates to.
176
 
     */
177
 
    protected abstract function add_row_cells($capability);
178
 
}
179
 
 
180
 
/**
181
 
 * Subclass of capability_table_base for use on the Check permissions page.
182
 
 *
183
 
 * We have one additional column, Allowed, which contains yes/no.
184
 
 */
185
 
class check_capability_table extends capability_table_base {
186
 
    protected $user;
187
 
    protected $fullname;
188
 
    protected $contextname;
189
 
    protected $stryes;
190
 
    protected $strno;
191
 
    private $hascap;
192
 
 
193
 
    /**
194
 
     * Constructor
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.
198
 
     */
199
 
    public function __construct($context, $user, $contextname) {
200
 
        global $CFG;
201
 
        parent::__construct($context, 'explaincaps');
202
 
        $this->user = $user;
203
 
        $this->fullname = fullname($user);
204
 
        $this->contextname = $contextname;
205
 
        $this->stryes = get_string('yes');
206
 
        $this->strno = get_string('no');
207
 
    }
208
 
 
209
 
    protected function add_header_cells() {
210
 
        echo '<th>' . get_string('allowed', 'role') . '</th>';
211
 
    }
212
 
 
213
 
    protected function num_extra_columns() {
214
 
        return 1;
215
 
    }
216
 
 
217
 
    protected function get_row_classes($capability) {
218
 
        $this->hascap = has_capability($capability->name, $this->context, $this->user->id);
219
 
        if ($this->hascap) {
220
 
            return array('yes');
221
 
        } else {
222
 
            return array('no');
223
 
        }
224
 
    }
225
 
 
226
 
    protected function add_row_cells($capability) {
227
 
        global $OUTPUT;
228
 
        if ($this->hascap) {
229
 
            $result = $this->stryes;
230
 
        } else {
231
 
            $result = $this->strno;
232
 
        }
233
 
        $a = new stdClass;
234
 
        $a->fullname = $this->fullname;
235
 
        $a->capability = $capability->name;
236
 
        $a->context = $this->contextname;
237
 
        echo '<td>' . $result . '</td>';
238
 
    }
239
 
}
240
 
 
241
 
 
242
 
/**
243
 
 * Subclass of capability_table_base for use on the Permissions page.
244
 
 */
245
 
class permissions_table extends capability_table_base {
246
 
    protected $contextname;
247
 
    protected $allowoverrides;
248
 
    protected $allowsafeoverrides;
249
 
    protected $overridableroles;
250
 
    protected $roles;
251
 
    protected $icons = array();
252
 
 
253
 
    /**
254
 
     * Constructor
255
 
     * @param object $context the context this table relates to.
256
 
     * @param string $contextname print_context_name($context) - to save recomputing.
257
 
     */
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;
264
 
 
265
 
        $roles = get_all_roles($context);
266
 
        $this->roles = role_fix_names(array_reverse($roles, true), $context, ROLENAME_ALIAS, true);
267
 
 
268
 
    }
269
 
 
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>';
274
 
    }
275
 
 
276
 
    protected function num_extra_columns() {
277
 
        return 3;
278
 
    }
279
 
 
280
 
    protected function add_row_cells($capability) {
281
 
        global $OUTPUT, $PAGE;
282
 
 
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;
289
 
 
290
 
 
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]);
298
 
        }
299
 
        foreach ($forbidden as $id=>$unused) {
300
 
            unset($allowable[$id]);
301
 
            unset($forbitable[$id]);
302
 
        }
303
 
 
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')));
310
 
                }
311
 
            }
312
 
        }
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')));
320
 
                }
321
 
            }
322
 
        }
323
 
        $forbiddenroles = implode(', ', $forbiddenroles);
324
 
 
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>';
328
 
        }
329
 
 
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>';
333
 
        }
334
 
 
335
 
        $risks = $this->get_risks($capability);
336
 
 
337
 
        echo '<td>' . $risks . '</td>';
338
 
        echo '<td>' . $neededroles . '</td>';
339
 
        echo '<td>' . $forbiddenroles . '</td>';
340
 
    }
341
 
 
342
 
    protected function get_risks($capability) {
343
 
        global $OUTPUT;
344
 
 
345
 
        $allrisks = get_all_risks();
346
 
        $risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'role'))));
347
 
 
348
 
        $return = '';
349
 
 
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));
355
 
                }
356
 
                $return .= $this->icons[$type];
357
 
            }
358
 
        }
359
 
 
360
 
        return $return;
361
 
    }
362
 
}
363
 
 
364
 
 
365
 
/**
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.
370
 
 */
371
 
abstract class capability_table_with_risks extends capability_table_base {
372
 
    protected $allrisks;
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;
381
 
    protected $changed;
382
 
    protected $roleid;
383
 
 
384
 
    public function __construct($context, $id, $roleid) {
385
 
        parent::__construct($context, $id);
386
 
 
387
 
        $this->allrisks = get_all_risks();
388
 
        $this->risksurl = get_docs_url(s(get_string('risks', 'role')));
389
 
 
390
 
        $this->allpermissions = array(
391
 
            CAP_INHERIT => 'inherit',
392
 
            CAP_ALLOW => 'allow',
393
 
            CAP_PREVENT => 'prevent' ,
394
 
            CAP_PROHIBIT => 'prohibit',
395
 
        );
396
 
 
397
 
        $this->strperms = array();
398
 
        foreach ($this->allpermissions as $permname) {
399
 
            $this->strperms[$permname] =  get_string($permname, 'role');
400
 
        }
401
 
 
402
 
        $this->roleid = $roleid;
403
 
        $this->load_current_permissions();
404
 
 
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;
409
 
            }
410
 
            $this->capabilities[$capid]->locked = false;
411
 
        }
412
 
    }
413
 
 
414
 
    protected function load_current_permissions() {
415
 
        global $DB;
416
 
 
417
 
    /// Load the overrides/definition in this context.
418
 
        if ($this->roleid) {
419
 
            $this->permissions = $DB->get_records_menu('role_capabilities', array('roleid' => $this->roleid,
420
 
                    'contextid' => $this->context->id), '', 'capability,permission');
421
 
        } else {
422
 
            $this->permissions = array();
423
 
        }
424
 
    }
425
 
 
426
 
    protected abstract function load_parent_permissions();
427
 
 
428
 
    /**
429
 
     * Update $this->permissions based on submitted data, while making a list of
430
 
     * changed capabilities in $this->changed.
431
 
     */
432
 
    public function read_submitted_permissions() {
433
 
        $this->changed = array();
434
 
 
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
438
 
                continue;
439
 
            }
440
 
 
441
 
            $permission = optional_param($cap->name, null, PARAM_PERMISSION);
442
 
            if (is_null($permission)) {
443
 
            /// A permission was not specified in submitted data.
444
 
                continue;
445
 
            }
446
 
 
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;
452
 
            }
453
 
        }
454
 
    }
455
 
 
456
 
    /**
457
 
     * Save the new values of any permissions that have been changed.
458
 
     */
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);
464
 
        }
465
 
 
466
 
    /// Force accessinfo refresh for users visiting this context.
467
 
        mark_context_dirty($this->context->path);
468
 
    }
469
 
 
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;
475
 
            }
476
 
        }
477
 
        parent::display();
478
 
    }
479
 
 
480
 
    protected function add_header_cells() {
481
 
        global $OUTPUT;
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>';
485
 
    }
486
 
 
487
 
    protected function num_extra_columns() {
488
 
        return count($this->displaypermissions) + count($this->allrisks);
489
 
    }
490
 
 
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;
496
 
            }
497
 
        }
498
 
        return $rowclasses;
499
 
    }
500
 
 
501
 
    protected abstract function add_permission_cells($capability);
502
 
 
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);
510
 
            }
511
 
            echo '</td>';
512
 
        }
513
 
    }
514
 
 
515
 
    /**
516
 
     * Print a risk icon, as a link to the Risks page on Moodle Docs.
517
 
     *
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'.
520
 
     */
521
 
    function get_risk_icon($type) {
522
 
        global $OUTPUT;
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')));
528
 
        }
529
 
        return $this->riskicons[$type];
530
 
    }
531
 
}
532
 
 
533
 
/**
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.)
537
 
 */
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. */
540
 
    protected $role;
541
 
    /** Used to store errors found when validating the data. */
542
 
    protected $errors;
543
 
    protected $contextlevels;
544
 
    protected $allcontextlevels;
545
 
    protected $disabled = '';
546
 
 
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');
552
 
 
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')
560
 
        );
561
 
    }
562
 
 
563
 
    protected function load_current_permissions() {
564
 
        global $DB;
565
 
        if ($this->roleid) {
566
 
            if (!$this->role = $DB->get_record('role', array('id' => $this->roleid))) {
567
 
                throw new moodle_exception('invalidroleid');
568
 
            }
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);
573
 
            } else {
574
 
                $this->contextlevels = array();
575
 
            }
576
 
        } else {
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();
583
 
        }
584
 
        parent::load_current_permissions();
585
 
    }
586
 
 
587
 
    public function read_submitted_permissions() {
588
 
        global $DB;
589
 
        $this->errors = array();
590
 
 
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');
600
 
            }
601
 
        }
602
 
        if ($DB->record_exists_select('role', 'shortname = ? and id <> ?', array($this->role->shortname, $this->roleid))) {
603
 
            $this->errors['shortname'] = get_string('errorexistsroleshortname', 'role');
604
 
        }
605
 
 
606
 
        // Role name.
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');
614
 
            }
615
 
        }
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');
618
 
        }
619
 
 
620
 
        // Description.
621
 
        $description = optional_param('description', null, PARAM_RAW);
622
 
        if (!is_null($description)) {
623
 
            $this->role->description = $description;
624
 
        }
625
 
 
626
 
        // Legacy type.
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;
632
 
            } else {
633
 
                $this->role->archetype = '';
634
 
            }
635
 
        }
636
 
 
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)) {
641
 
                if ($assignable) {
642
 
                    $this->contextlevels[$cl] = $cl;
643
 
                } else {
644
 
                    unset($this->contextlevels[$cl]);
645
 
                }
646
 
            }
647
 
        }
648
 
 
649
 
        // Now read the permissions for each capability.
650
 
        parent::read_submitted_permissions();
651
 
    }
652
 
 
653
 
    public function is_submission_valid() {
654
 
        return empty($this->errors);
655
 
    }
656
 
 
657
 
    /**
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.
660
 
     */
661
 
    public function make_copy() {
662
 
        $this->roleid = 0;
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';
666
 
    }
667
 
 
668
 
    public function get_role_name() {
669
 
        return $this->role->name;
670
 
    }
671
 
 
672
 
    public function get_role_id() {
673
 
        return $this->role->id;
674
 
    }
675
 
 
676
 
    public function get_archetype() {
677
 
        return $this->role->archetype;
678
 
    }
679
 
 
680
 
    protected function load_parent_permissions() {
681
 
        $this->parentpermissions = get_default_capabilities($this->role->archetype);
682
 
    }
683
 
 
684
 
    public function save_changes() {
685
 
        global $DB;
686
 
 
687
 
        if (!$this->roleid) {
688
 
            // Creating role
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.
691
 
        } else {
692
 
            // Updating role
693
 
            $DB->update_record('role', $this->role);
694
 
        }
695
 
 
696
 
        // Assignable contexts.
697
 
        set_role_contextlevels($this->role->id, $this->contextlevels);
698
 
 
699
 
        // Permissions.
700
 
        parent::save_changes();
701
 
    }
702
 
 
703
 
    protected function get_name_field($id) {
704
 
        return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->name) . '" />';
705
 
    }
706
 
 
707
 
    protected function get_shortname_field($id) {
708
 
        return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->shortname) . '" />';
709
 
    }
710
 
 
711
 
    protected function get_description_field($id) {
712
 
        return print_textarea(true, 10, 50, 50, 10, 'description', $this->role->description, 0, true);
713
 
    }
714
 
 
715
 
    protected function get_archetype_field($id) {
716
 
        $options = array();
717
 
        $options[''] = get_string('none');
718
 
        foreach(get_role_archetypes() as $type) {
719
 
            $options[$type] = get_string('archetype'.$type, 'role');
720
 
        }
721
 
        return html_writer::select($options, 'archetype', $this->role->archetype, false);
722
 
    }
723
 
 
724
 
    protected function get_assignable_levels_control() {
725
 
        $output = '';
726
 
        foreach ($this->allcontextlevels as $cl => $clname) {
727
 
            $extraarguments = $this->disabled;
728
 
            if (in_array($cl, $this->contextlevels)) {
729
 
                $extraarguments .= 'checked="checked" ';
730
 
            }
731
 
            if (!$this->disabled) {
732
 
                $output .= '<input type="hidden" name="contextlevel' . $cl . '" value="0" />';
733
 
            }
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";
737
 
        }
738
 
        return $output;
739
 
    }
740
 
 
741
 
    /**
742
 
     * Returns an array of roles of the allowed type.
743
 
     *
744
 
     * @param string $type Must be one of: assign, switch, or override.
745
 
     * @return array
746
 
     */
747
 
    protected function get_allow_roles_list($type) {
748
 
        global $DB;
749
 
 
750
 
        if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
751
 
            debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
752
 
            return array();
753
 
        }
754
 
 
755
 
        if (empty($this->roleid)) {
756
 
            return array();
757
 
        }
758
 
 
759
 
        $sql = "SELECT r.*
760
 
                  FROM {role} r
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));
765
 
    }
766
 
 
767
 
    /**
768
 
     * Returns an array of roles with the allowed type.
769
 
     *
770
 
     * @param string $type Must be one of: assign, switch, or override.
771
 
     * @return array Am array of role names with the allowed type
772
 
     */
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);
777
 
        } else {
778
 
            return get_string('none');
779
 
        }
780
 
    }
781
 
 
782
 
    /**
783
 
     * Returns information about the risks associated with a role.
784
 
     *
785
 
     * @return string
786
 
     */
787
 
    protected function get_role_risks_info() {
788
 
        return '';
789
 
    }
790
 
 
791
 
    protected function print_field($name, $caption, $field) {
792
 
        global $OUTPUT;
793
 
        // Attempt to generate HTML like formslib.
794
 
        echo '<div class="fitem">';
795
 
        echo '<div class="fitemtitle">';
796
 
        if ($name) {
797
 
            echo '<label for="' . $name . '">';
798
 
        }
799
 
        echo $caption;
800
 
        if ($name) {
801
 
            echo "</label>\n";
802
 
        }
803
 
        echo '</div>';
804
 
        if (isset($this->errors[$name])) {
805
 
            $extraclass = ' error';
806
 
        } else {
807
 
            $extraclass = '';
808
 
        }
809
 
        echo '<div class="felement' . $extraclass . '">';
810
 
        if (isset($this->errors[$name])) {
811
 
            echo $OUTPUT->error_text($this->errors[$name]);
812
 
        }
813
 
        echo $field;
814
 
        echo '</div>';
815
 
        echo '</div>';
816
 
    }
817
 
 
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') . '" />';
822
 
        echo '</div>';
823
 
    }
824
 
 
825
 
    public function display() {
826
 
        global $OUTPUT;
827
 
        // Extra fields at the top of the page.
828
 
        echo '<div class="topfields clearfix">';
829
 
        $this->print_field('shortname', get_string('roleshortname', 'role').'&nbsp;'.$OUTPUT->help_icon('roleshortname', 'role'), $this->get_shortname_field('shortname'));
830
 
        $this->print_field('name', get_string('customrolename', 'role').'&nbsp;'.$OUTPUT->help_icon('customrolename', 'role'), $this->get_name_field('name'));
831
 
        $this->print_field('edit-description', get_string('customroledescription', 'role').'&nbsp;'.$OUTPUT->help_icon('customroledescription', 'role'), $this->get_description_field('description'));
832
 
        $this->print_field('menuarchetype', get_string('archetype', 'role').'&nbsp;'.$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);
839
 
        }
840
 
        echo "</div>";
841
 
 
842
 
        $this->print_show_hide_advanced_button();
843
 
 
844
 
        // Now the permissions table.
845
 
        parent::display();
846
 
    }
847
 
 
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];
852
 
            $extraclass = '';
853
 
            if ($perm == $this->parentpermissions[$capability->name]) {
854
 
                $extraclass = ' capdefault';
855
 
            }
856
 
            $checked = '';
857
 
            if ($this->permissions[$capability->name] == $perm) {
858
 
                $checked = 'checked="checked" ';
859
 
            }
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>';
865
 
        }
866
 
    }
867
 
}
868
 
 
869
 
class define_role_table_basic extends define_role_table_advanced {
870
 
    protected $stradvmessage;
871
 
    protected $strallow;
872
 
 
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]];
878
 
    }
879
 
 
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') . '" />';
883
 
        echo '</div>';
884
 
    }
885
 
 
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) {
892
 
            $checked = '';
893
 
            if ($perm == CAP_ALLOW) {
894
 
                $checked = 'checked="checked" ';
895
 
            }
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>';
899
 
        } else {
900
 
            echo '<input type="hidden" name="' . $capability->name . '" value="' . $perm . '" />';
901
 
            echo $this->strperms[$permname] . '<span class="note">' . $this->stradvmessage . '</span>';
902
 
        }
903
 
        echo '</td>';
904
 
    }
905
 
}
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" ';
911
 
    }
912
 
 
913
 
    public function save_changes() {
914
 
        throw new moodle_exception('invalidaccess');
915
 
    }
916
 
 
917
 
    protected function get_name_field($id) {
918
 
        return role_get_name($this->role);
919
 
    }
920
 
 
921
 
    protected function get_shortname_field($id) {
922
 
        return $this->role->shortname;
923
 
    }
924
 
 
925
 
    protected function get_description_field($id) {
926
 
        return role_get_description($this->role);
927
 
    }
928
 
 
929
 
    protected function get_archetype_field($id) {
930
 
        if (empty($this->role->archetype)) {
931
 
            return get_string('none');
932
 
        } else {
933
 
            return get_string('archetype'.$this->role->archetype, 'role');
934
 
        }
935
 
    }
936
 
 
937
 
    protected function print_show_hide_advanced_button() {
938
 
        // Do nothing.
939
 
    }
940
 
 
941
 
    /**
942
 
     * Returns HTML risk icons.
943
 
     *
944
 
     * @return string
945
 
     */
946
 
    protected function get_role_risks_info() {
947
 
        global $OUTPUT;
948
 
 
949
 
        if (empty($this->roleid)) {
950
 
            return '';
951
 
        }
952
 
 
953
 
        $risks = array();
954
 
        $allrisks = get_all_risks();
955
 
        foreach ($this->capabilities as $capability) {
956
 
            $perm = $this->permissions[$capability->name];
957
 
            if ($perm != CAP_ALLOW) {
958
 
                continue;
959
 
            }
960
 
            foreach ($allrisks as $type=>$risk) {
961
 
                if ($risk & (int)$capability->riskbitmask) {
962
 
                    $risks[$type] = $risk;
963
 
                }
964
 
            }
965
 
        }
966
 
 
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));
971
 
        }
972
 
 
973
 
        return implode(' ', $risks);
974
 
    }
975
 
 
976
 
    /**
977
 
     * Returns true if the row should be skipped.
978
 
     *
979
 
     * @param string $capability
980
 
     * @return bool
981
 
     */
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.
987
 
            return true;
988
 
        }
989
 
        parent::skip_row($capability);
990
 
    }
991
 
 
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]);
998
 
        } else {
999
 
            $default = "&#xa0;";
1000
 
        }
1001
 
        echo '<td class="' . $permname . '">' . $this->strperms[$permname] . '<span class="note">' .
1002
 
                $default . '</span></td>';
1003
 
 
1004
 
    }
1005
 
}
1006
 
 
1007
 
class override_permissions_table_advanced extends capability_table_with_risks {
1008
 
    protected $strnotset;
1009
 
    protected $haslockedcapabilities = false;
1010
 
 
1011
 
    /**
1012
 
     * Constructor
1013
 
     *
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.
1017
 
     *
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.
1022
 
     */
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');
1027
 
 
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;
1034
 
                }
1035
 
            }
1036
 
        }
1037
 
    }
1038
 
 
1039
 
    protected function load_parent_permissions() {
1040
 
        global $DB;
1041
 
 
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);
1045
 
    }
1046
 
 
1047
 
    public function has_locked_capabilities() {
1048
 
        return $this->haslockedcapabilities;
1049
 
    }
1050
 
 
1051
 
    protected function add_permission_cells($capability) {
1052
 
        $disabled = '';
1053
 
        if ($capability->locked || $this->parentpermissions[$capability->name] == CAP_PROHIBIT) {
1054
 
            $disabled = ' disabled="disabled"';
1055
 
        }
1056
 
 
1057
 
    /// One cell for each possible permission.
1058
 
        foreach ($this->displaypermissions as $perm => $permname) {
1059
 
            $strperm = $this->strperms[$permname];
1060
 
            $extraclass = '';
1061
 
            if ($perm != CAP_INHERIT && $perm == $this->parentpermissions[$capability->name]) {
1062
 
                $extraclass = ' capcurrent';
1063
 
            }
1064
 
            $checked = '';
1065
 
            if ($this->permissions[$capability->name] == $perm) {
1066
 
                $checked = 'checked="checked" ';
1067
 
            }
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;
1075
 
                } else {
1076
 
                    $inherited = $this->strperms[$this->allpermissions[$inherited]];
1077
 
                }
1078
 
                $strperm .= ' (' . $inherited . ')';
1079
 
            }
1080
 
            echo '<span class="note">' . $strperm . '</span>';
1081
 
            echo '</label></td>';
1082
 
        }
1083
 
    }
1084
 
}
1085
 
 
1086
 
// User selectors for managing role assignments ================================
1087
 
 
1088
 
/**
1089
 
 * Base class to avoid duplicating code.
1090
 
 */
1091
 
abstract class role_assign_user_selector_base extends user_selector_base {
1092
 
    protected $roleid;
1093
 
    protected $context;
1094
 
 
1095
 
    /**
1096
 
     * @param string $name control name
1097
 
     * @param array $options should have two elements with keys groupid and courseid.
1098
 
     */
1099
 
    public function __construct($name, $options) {
1100
 
        global $CFG;
1101
 
        if (isset($options['context'])) {
1102
 
            $this->context = $options['context'];
1103
 
        } else {
1104
 
            $this->context = context::instance_by_id($options['contextid']);
1105
 
        }
1106
 
        $options['accesscontext'] = $this->context;
1107
 
        parent::__construct($name, $options);
1108
 
        $this->roleid = $options['roleid'];
1109
 
        require_once($CFG->dirroot . '/group/lib.php');
1110
 
    }
1111
 
 
1112
 
    protected function get_options() {
1113
 
        global $CFG;
1114
 
        $options = parent::get_options();
1115
 
        $options['file'] = $CFG->admin . '/roles/lib.php';
1116
 
        $options['roleid'] = $this->roleid;
1117
 
        $options['contextid'] = $this->context->id;
1118
 
        return $options;
1119
 
    }
1120
 
}
1121
 
 
1122
 
/**
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).
1126
 
 *
1127
 
 * This returns only enrolled users in this context.
1128
 
 */
1129
 
class potential_assignees_below_course extends role_assign_user_selector_base {
1130
 
    public function find_users($search) {
1131
 
        global $DB;
1132
 
 
1133
 
        list($enrolsql, $eparams) = get_enrolled_sql($this->context);
1134
 
 
1135
 
        // Now we have to go to the database.
1136
 
        list($wherecondition, $params) = $this->search_sql($search, 'u');
1137
 
        $params = array_merge($params, $eparams);
1138
 
 
1139
 
        if ($wherecondition) {
1140
 
            $wherecondition = ' AND ' . $wherecondition;
1141
 
        }
1142
 
 
1143
 
        $fields      = 'SELECT ' . $this->required_fields_sql('u');
1144
 
        $countfields = 'SELECT COUNT(u.id)';
1145
 
 
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)
1149
 
                        $wherecondition
1150
 
                        AND ra.id IS NULL";
1151
 
        $params['contextid'] = $this->context->id;
1152
 
        $params['roleid'] = $this->roleid;
1153
 
 
1154
 
        list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext);
1155
 
        $order = ' ORDER BY ' . $sort;
1156
 
 
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);
1162
 
            }
1163
 
        }
1164
 
 
1165
 
        // If not, show them.
1166
 
        $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
1167
 
 
1168
 
        if (empty($availableusers)) {
1169
 
            return array();
1170
 
        }
1171
 
 
1172
 
        if ($search) {
1173
 
            $groupname = get_string('potusersmatching', 'role', $search);
1174
 
        } else {
1175
 
            $groupname = get_string('potusers', 'role');
1176
 
        }
1177
 
 
1178
 
        return array($groupname => $availableusers);
1179
 
    }
1180
 
}
1181
 
 
1182
 
/**
1183
 
 * User selector subclass for the selection of users in the check permissions page.
1184
 
 *
1185
 
 * @copyright 2012 Petr Skoda {@link http://skodak.org}
1186
 
 */
1187
 
class role_check_users_selector extends user_selector_base {
1188
 
    /** @var bool limit listing of users to enrolled only */
1189
 
    var $onlyenrolled;
1190
 
 
1191
 
    /**
1192
 
     * Constructor.
1193
 
     *
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());
1197
 
     */
1198
 
    public function __construct($name, $options) {
1199
 
        if (!isset($options['multiselect'])) {
1200
 
            $options['multiselect'] = false;
1201
 
        }
1202
 
        parent::__construct($name, $options);
1203
 
 
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;
1208
 
        } else {
1209
 
            $this->onlyenrolled = false;
1210
 
        }
1211
 
    }
1212
 
 
1213
 
    public function find_users($search) {
1214
 
        global $DB;
1215
 
 
1216
 
        list($wherecondition, $params) = $this->search_sql($search, 'u');
1217
 
 
1218
 
        $fields      = 'SELECT ' . $this->required_fields_sql('u');
1219
 
        $countfields = 'SELECT COUNT(1)';
1220
 
 
1221
 
        $coursecontext = $this->accesscontext->get_course_context(false);
1222
 
 
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;
1229
 
 
1230
 
            if ($this->onlyenrolled) {
1231
 
                $sql2 = null;
1232
 
            } else {
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
1237
 
                               AND ue.id IS NULL";
1238
 
                $params['courseid2'] = $coursecontext->instanceid;
1239
 
            }
1240
 
 
1241
 
        } else {
1242
 
            if ($this->onlyenrolled) {
1243
 
                // Bad luck, current user may not view only enrolled users.
1244
 
                return array();
1245
 
            }
1246
 
            $sql1 = null;
1247
 
            $sql2 = " FROM {user} u
1248
 
                     WHERE $wherecondition";
1249
 
        }
1250
 
 
1251
 
        $params['contextid'] = $this->accesscontext->id;
1252
 
 
1253
 
        list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext);
1254
 
        $order = ' ORDER BY ' . $sort;
1255
 
 
1256
 
        $result = array();
1257
 
 
1258
 
        if ($search) {
1259
 
            $groupname1 = get_string('enrolledusersmatching', 'enrol', $search);
1260
 
            $groupname2 = get_string('potusersmatching', 'role', $search);
1261
 
        } else {
1262
 
            $groupname1 = get_string('enrolledusers', 'enrol');
1263
 
            $groupname2 = get_string('potusers', 'role');
1264
 
        }
1265
 
 
1266
 
        if ($sql1) {
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();
1272
 
 
1273
 
            } else {
1274
 
                $enrolledusers = $DB->get_records_sql($fields . $sql1 . $order, array_merge($params, $sortparams));
1275
 
                if ($enrolledusers) {
1276
 
                    $result[$groupname1] = $enrolledusers;
1277
 
                }
1278
 
            }
1279
 
            if ($sql2) {
1280
 
                $result[''] = array();
1281
 
            }
1282
 
        }
1283
 
        if ($sql2) {
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();
1289
 
            } else {
1290
 
                $otherusers = $DB->get_records_sql($fields . $sql2 . $order, array_merge($params, $sortparams));
1291
 
                if ($otherusers) {
1292
 
                    $result[$groupname2] = $otherusers;
1293
 
                }
1294
 
            }
1295
 
        }
1296
 
 
1297
 
        return $result;
1298
 
    }
1299
 
 
1300
 
    protected function get_options() {
1301
 
        global $CFG;
1302
 
        $options = parent::get_options();
1303
 
        $options['file'] = $CFG->admin . '/roles/lib.php';
1304
 
        return $options;
1305
 
    }
1306
 
}
1307
 
 
1308
 
/**
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.
1312
 
 */
1313
 
class potential_assignees_course_and_above extends role_assign_user_selector_base {
1314
 
    public function find_users($search) {
1315
 
        global $DB;
1316
 
 
1317
 
        list($wherecondition, $params) = $this->search_sql($search, '');
1318
 
 
1319
 
        $fields      = 'SELECT ' . $this->required_fields_sql('');
1320
 
        $countfields = 'SELECT COUNT(1)';
1321
 
 
1322
 
        $sql = " FROM {user}
1323
 
                WHERE $wherecondition
1324
 
                      AND id NOT IN (
1325
 
                         SELECT r.userid
1326
 
                           FROM {role_assignments} r
1327
 
                          WHERE r.contextid = :contextid
1328
 
                                AND r.roleid = :roleid)";
1329
 
 
1330
 
        list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext);
1331
 
        $order = ' ORDER BY ' . $sort;
1332
 
 
1333
 
        $params['contextid'] = $this->context->id;
1334
 
        $params['roleid'] = $this->roleid;
1335
 
 
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);
1340
 
            }
1341
 
        }
1342
 
 
1343
 
        $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
1344
 
 
1345
 
        if (empty($availableusers)) {
1346
 
            return array();
1347
 
        }
1348
 
 
1349
 
        if ($search) {
1350
 
            $groupname = get_string('potusersmatching', 'role', $search);
1351
 
        } else {
1352
 
            $groupname = get_string('potusers', 'role');
1353
 
        }
1354
 
 
1355
 
        return array($groupname => $availableusers);
1356
 
    }
1357
 
}
1358
 
 
1359
 
/**
1360
 
 * User selector subclass for the list of users who already have the role in
1361
 
 * question on the assign roles page.
1362
 
 */
1363
 
class existing_role_holders extends role_assign_user_selector_base {
1364
 
 
1365
 
    public function __construct($name, $options) {
1366
 
        parent::__construct($name, $options);
1367
 
    }
1368
 
 
1369
 
    public function find_users($search) {
1370
 
        global $DB;
1371
 
 
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;
1376
 
 
1377
 
        list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext);
1378
 
        $params = array_merge($params, $sortparams);
1379
 
 
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
1384
 
                WHERE
1385
 
                    $wherecondition AND
1386
 
                    ctx.id $ctxcondition AND
1387
 
                    ra.roleid = :roleid
1388
 
                ORDER BY ctx.depth DESC, ra.component, $sort";
1389
 
        $contextusers = $DB->get_records_sql($sql, $params);
1390
 
 
1391
 
        // No users at all.
1392
 
        if (empty($contextusers)) {
1393
 
            return array();
1394
 
        }
1395
 
 
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;
1401
 
        $dummyuser->id = 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])) {
1410
 
                continue;
1411
 
            }
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));
1417
 
                } else {
1418
 
                    $groupname = $this->parent_con_group_name($search, $currentcontextid);
1419
 
                }
1420
 
                $results[$groupname] = $currentgroup;
1421
 
                // Get ready for the next group.
1422
 
                $currentcontextid = $user->contextid;
1423
 
                $currentgroup = array();
1424
 
            }
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;
1429
 
            }
1430
 
            if ($user->component !== '') {
1431
 
                // bad luck, you can tweak only manual role assignments
1432
 
                $user->disabled = true;
1433
 
            }
1434
 
            unset($user->component);
1435
 
            $currentgroup[$user->id] = $user;
1436
 
        }
1437
 
 
1438
 
        return $results;
1439
 
    }
1440
 
 
1441
 
    protected function this_con_group_name($search, $numusers) {
1442
 
        if ($this->context->contextlevel == CONTEXT_SYSTEM) {
1443
 
            // Special case in the System context.
1444
 
            if ($search) {
1445
 
                return get_string('extusersmatching', 'role', $search);
1446
 
            } else {
1447
 
                return get_string('extusers', 'role');
1448
 
            }
1449
 
        }
1450
 
        $contexttype = get_contextlevel_name($this->context->contextlevel);
1451
 
        if ($search) {
1452
 
            $a = new stdClass;
1453
 
            $a->search = $search;
1454
 
            $a->contexttype = $contexttype;
1455
 
            if ($numusers) {
1456
 
                return get_string('usersinthisxmatching', 'role', $a);
1457
 
            } else {
1458
 
                return get_string('noneinthisxmatching', 'role', $a);
1459
 
            }
1460
 
        } else {
1461
 
            if ($numusers) {
1462
 
                return get_string('usersinthisx', 'role', $contexttype);
1463
 
            } else {
1464
 
                return get_string('noneinthisx', 'role', $contexttype);
1465
 
            }
1466
 
        }
1467
 
    }
1468
 
 
1469
 
    protected function parent_con_group_name($search, $contextid) {
1470
 
        $context = context::instance_by_id($contextid);
1471
 
        $contextname = print_context_name($context, true, true);
1472
 
        if ($search) {
1473
 
            $a = new stdClass;
1474
 
            $a->contextname = $contextname;
1475
 
            $a->search = $search;
1476
 
            return get_string('usersfrommatching', 'role', $a);
1477
 
        } else {
1478
 
            return get_string('usersfrom', 'role', $contextname);
1479
 
        }
1480
 
    }
1481
 
}
1482
 
 
1483
 
/**
1484
 
 * Base class for managing the data in the grid of checkboxes on the role allow
1485
 
 * allow/overrides/switch editing pages (allow.php).
1486
 
 */
1487
 
abstract class role_allow_role_page {
1488
 
    protected $tablename;
1489
 
    protected $targetcolname;
1490
 
    protected $roles;
1491
 
    protected $allowed = null;
1492
 
 
1493
 
    /**
1494
 
     * @param string $tablename the table where our data is stored.
1495
 
     * @param string $targetcolname the name of the target role id column.
1496
 
     */
1497
 
    public function __construct($tablename, $targetcolname) {
1498
 
        $this->tablename = $tablename;
1499
 
        $this->targetcolname = $targetcolname;
1500
 
        $this->load_required_roles();
1501
 
    }
1502
 
 
1503
 
    /**
1504
 
     * Load information about all the roles we will need information about.
1505
 
     */
1506
 
    protected function load_required_roles() {
1507
 
    /// Get all roles
1508
 
        $this->roles = role_fix_names(get_all_roles(), context_system::instance(), ROLENAME_ORIGINAL);
1509
 
    }
1510
 
 
1511
 
    /**
1512
 
     * Update the data with the new settings submitted by the user.
1513
 
     */
1514
 
    public function process_submission() {
1515
 
        global $DB;
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);
1522
 
                }
1523
 
            }
1524
 
        }
1525
 
    }
1526
 
 
1527
 
    /**
1528
 
     * Set one allow in the database.
1529
 
     * @param integer $fromroleid
1530
 
     * @param integer $targetroleid
1531
 
     */
1532
 
    protected abstract function set_allow($fromroleid, $targetroleid);
1533
 
 
1534
 
    /**
1535
 
     * Load the current allows from the database.
1536
 
     */
1537
 
    public function load_current_settings() {
1538
 
        global $DB;
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));
1544
 
        }
1545
 
        $rs = $DB->get_recordset($this->tablename);
1546
 
        foreach ($rs as $allow) {
1547
 
            $this->allowed[$allow->roleid][$allow->{$this->targetcolname}] = true;
1548
 
        }
1549
 
        $rs->close();
1550
 
    }
1551
 
 
1552
 
    /**
1553
 
     * @param integer $targetroleid a role id.
1554
 
     * @return boolean whether the user should be allowed to select this role as a
1555
 
     * target role.
1556
 
     */
1557
 
    protected function is_allowed_target($targetroleid) {
1558
 
        return true;
1559
 
    }
1560
 
 
1561
 
    /**
1562
 
     * @return object a $table structure that can be passed to print_table, containing
1563
 
     * one cell for each checkbox.
1564
 
     */
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('&#xa0;');
1574
 
        $table->colclasses = array('');
1575
 
 
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[] = '';
1582
 
            } else {
1583
 
                $table->colclasses[] = 'dimmed_text';
1584
 
            }
1585
 
        }
1586
 
 
1587
 
    /// Now the rest of the table.
1588
 
        foreach ($this->roles as $fromrole) {
1589
 
            $row = array($fromrole->localname);
1590
 
            foreach ($this->roles as $targetrole) {
1591
 
                $checked = '';
1592
 
                $disabled = '';
1593
 
                if ($this->allowed[$fromrole->id][$targetrole->id]) {
1594
 
                    $checked = 'checked="checked" ';
1595
 
                }
1596
 
                if (!$this->is_allowed_target($targetrole->id)) {
1597
 
                    $disabled = 'disabled="disabled" ';
1598
 
                }
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>';
1604
 
            }
1605
 
            $table->data[] = $row;
1606
 
        }
1607
 
 
1608
 
        return $table;
1609
 
    }
1610
 
 
1611
 
    /**
1612
 
     * Snippet of text displayed above the table, telling the admin what to do.
1613
 
     * @return unknown_type
1614
 
     */
1615
 
    public abstract function get_intro_text();
1616
 
}
1617
 
 
1618
 
/**
1619
 
 * Subclass of role_allow_role_page for the Allow assigns tab.
1620
 
 */
1621
 
class role_allow_assign_page extends role_allow_role_page {
1622
 
    public function __construct() {
1623
 
        parent::__construct('role_allow_assign', 'allowassign');
1624
 
    }
1625
 
 
1626
 
    protected function set_allow($fromroleid, $targetroleid) {
1627
 
        allow_assign($fromroleid, $targetroleid);
1628
 
    }
1629
 
 
1630
 
    protected function get_cell_tooltip($fromrole, $targetrole) {
1631
 
        $a = new stdClass;
1632
 
        $a->fromrole = $fromrole->localname;
1633
 
        $a->targetrole = $targetrole->localname;
1634
 
        return get_string('allowroletoassign', 'role', $a);
1635
 
    }
1636
 
 
1637
 
    public function get_intro_text() {
1638
 
        return get_string('configallowassign', 'admin');
1639
 
    }
1640
 
}
1641
 
 
1642
 
/**
1643
 
 * Subclass of role_allow_role_page for the Allow overrides tab.
1644
 
 */
1645
 
class role_allow_override_page extends role_allow_role_page {
1646
 
    public function __construct() {
1647
 
        parent::__construct('role_allow_override', 'allowoverride');
1648
 
    }
1649
 
 
1650
 
    protected function set_allow($fromroleid, $targetroleid) {
1651
 
        allow_override($fromroleid, $targetroleid);
1652
 
    }
1653
 
 
1654
 
    protected function get_cell_tooltip($fromrole, $targetrole) {
1655
 
        $a = new stdClass;
1656
 
        $a->fromrole = $fromrole->localname;
1657
 
        $a->targetrole = $targetrole->localname;
1658
 
        return get_string('allowroletooverride', 'role', $a);
1659
 
    }
1660
 
 
1661
 
    public function get_intro_text() {
1662
 
        return get_string('configallowoverride2', 'admin');
1663
 
    }
1664
 
}
1665
 
 
1666
 
/**
1667
 
 * Subclass of role_allow_role_page for the Allow switches tab.
1668
 
 */
1669
 
class role_allow_switch_page extends role_allow_role_page {
1670
 
    protected $allowedtargetroles;
1671
 
 
1672
 
    public function __construct() {
1673
 
        parent::__construct('role_allow_switch', 'allowswitch');
1674
 
    }
1675
 
 
1676
 
    protected function load_required_roles() {
1677
 
        global $DB;
1678
 
        parent::load_required_roles();
1679
 
        $this->allowedtargetroles = $DB->get_records_menu('role', NULL, 'id');
1680
 
    }
1681
 
 
1682
 
    protected function set_allow($fromroleid, $targetroleid) {
1683
 
        allow_switch($fromroleid, $targetroleid);
1684
 
    }
1685
 
 
1686
 
    protected function is_allowed_target($targetroleid) {
1687
 
        return isset($this->allowedtargetroles[$targetroleid]);
1688
 
    }
1689
 
 
1690
 
    protected function get_cell_tooltip($fromrole, $targetrole) {
1691
 
        $a = new stdClass;
1692
 
        $a->fromrole = $fromrole->localname;
1693
 
        $a->targetrole = $targetrole->localname;
1694
 
        return get_string('allowroletoswitch', 'role', $a);
1695
 
    }
1696
 
 
1697
 
    public function get_intro_text() {
1698
 
        return get_string('configallowswitch', 'admin');
1699
 
    }
1700
 
}
 
25
defined('MOODLE_INTERNAL') || die();
1701
26
 
1702
27
/**
1703
28
 * Get the potential assignees selector for a given context.
1704
29
 *
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.
1708
33
 *
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.
1713
38
 */
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));
1719
 
        }
1720
 
 
1721
 
        if (($context->contextlevel == CONTEXT_MODULE || $blockinsidecourse) &&
1722
 
                !is_inside_frontpage($context)) {
1723
 
            $potentialuserselector = new potential_assignees_below_course('addselect', $options);
1724
 
        } else {
1725
 
            $potentialuserselector = new potential_assignees_course_and_above('addselect', $options);
1726
 
        }
 
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));
 
44
    }
 
45
 
 
46
    if (($context->contextlevel == CONTEXT_MODULE || $blockinsidecourse) &&
 
47
            !is_inside_frontpage($context)) {
 
48
        $potentialuserselector = new core_role_potential_assignees_below_course('addselect', $options);
 
49
    } else {
 
50
        $potentialuserselector = new core_role_potential_assignees_course_and_above('addselect', $options);
 
51
    }
 
52
 
1727
53
    return $potentialuserselector;
1728
54
}
1729
 
 
1730
 
class admins_potential_selector extends user_selector_base {
1731
 
    /**
1732
 
     * @param string $name control name
1733
 
     * @param array $options should have two elements with keys groupid and courseid.
1734
 
     */
1735
 
    public function __construct($name = null, $options = array()) {
1736
 
        global $CFG;
1737
 
        if (is_null($name)) {
1738
 
            $name = 'addselect';
1739
 
        }
1740
 
        $options['multiselect'] = false;
1741
 
        $options['exclude'] = explode(',', $CFG->siteadmins);
1742
 
        parent::__construct($name, $options);
1743
 
    }
1744
 
 
1745
 
    public function find_users($search) {
1746
 
        global $CFG, $DB;
1747
 
        list($wherecondition, $params) = $this->search_sql($search, '');
1748
 
 
1749
 
        $fields      = 'SELECT ' . $this->required_fields_sql('');
1750
 
        $countfields = 'SELECT COUNT(1)';
1751
 
 
1752
 
        $sql = " FROM {user}
1753
 
                WHERE $wherecondition AND mnethostid = :localmnet";
1754
 
 
1755
 
        $params['localmnet'] = $CFG->mnet_localhost_id; // it could be dangerous to make remote users admins and also this could lead to other problems
1756
 
 
1757
 
        list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext);
1758
 
        $order = ' ORDER BY ' . $sort;
1759
 
 
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);
1765
 
            }
1766
 
        }
1767
 
 
1768
 
        $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
1769
 
 
1770
 
        if (empty($availableusers)) {
1771
 
            return array();
1772
 
        }
1773
 
 
1774
 
        if ($search) {
1775
 
            $groupname = get_string('potusersmatching', 'role', $search);
1776
 
        } else {
1777
 
            $groupname = get_string('potusers', 'role');
1778
 
        }
1779
 
 
1780
 
        return array($groupname => $availableusers);
1781
 
    }
1782
 
 
1783
 
    protected function get_options() {
1784
 
        global $CFG;
1785
 
        $options = parent::get_options();
1786
 
        $options['file'] = $CFG->admin . '/roles/lib.php';
1787
 
        return $options;
1788
 
    }
1789
 
}
1790
 
 
1791
 
class admins_existing_selector extends user_selector_base {
1792
 
    /**
1793
 
     * @param string $name control name
1794
 
     * @param array $options should have two elements with keys groupid and courseid.
1795
 
     */
1796
 
    public function __construct($name = null, $options = array()) {
1797
 
        if (is_null($name)) {
1798
 
            $name = 'removeselect';
1799
 
        }
1800
 
        $options['multiselect'] = false;
1801
 
        parent::__construct($name, $options);
1802
 
    }
1803
 
 
1804
 
    public function find_users($search) {
1805
 
        global $DB, $CFG;
1806
 
        list($wherecondition, $params) = $this->search_sql($search, '');
1807
 
 
1808
 
        $fields      = 'SELECT ' . $this->required_fields_sql('');
1809
 
        $countfields = 'SELECT COUNT(1)';
1810
 
 
1811
 
        if ($wherecondition) {
1812
 
            $wherecondition = "$wherecondition AND id IN ($CFG->siteadmins)";
1813
 
        } else {
1814
 
            $wherecondition = "id IN ($CFG->siteadmins)";
1815
 
        }
1816
 
        $sql = " FROM {user}
1817
 
                WHERE $wherecondition";
1818
 
 
1819
 
        list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext);
1820
 
        $params = array_merge($params, $sortparams);
1821
 
        $order = ' ORDER BY ' . $sort;
1822
 
 
1823
 
        $availableusers = $DB->get_records_sql($fields . $sql . $order, $params);
1824
 
 
1825
 
        if (empty($availableusers)) {
1826
 
            return array();
1827
 
        }
1828
 
 
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]);
1834
 
        }
1835
 
 
1836
 
        $result = array();
1837
 
        if ($mainadmin) {
1838
 
            $result[get_string('mainadmin', 'role')] = $mainadmin;
1839
 
        }
1840
 
 
1841
 
        if ($availableusers) {
1842
 
            if ($search) {
1843
 
                $groupname = get_string('extusersmatching', 'role', $search);
1844
 
            } else {
1845
 
                $groupname = get_string('extusers', 'role');
1846
 
            }
1847
 
            $result[$groupname] = $availableusers;
1848
 
        }
1849
 
 
1850
 
        return $result;
1851
 
    }
1852
 
 
1853
 
    protected function get_options() {
1854
 
        global $CFG;
1855
 
        $options = parent::get_options();
1856
 
        $options['file'] = $CFG->admin . '/roles/lib.php';
1857
 
        return $options;
1858
 
    }
1859
 
}