first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,113 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Existing admin user selector.
*
* @package core_role
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/user/selector/lib.php');
class core_role_admins_existing_selector extends user_selector_base {
/**
* Create instance.
*
* @param string $name control name
* @param array $options should have two elements with keys groupid and courseid.
*/
public function __construct($name = null, $options = array()) {
if (is_null($name)) {
$name = 'removeselect';
}
$options['includecustomfields'] = true;
parent::__construct($name, $options);
}
public function find_users($search) {
global $DB, $CFG;
[$wherecondition, $params] = $this->search_sql($search, 'u');
$params = array_merge($params, $this->userfieldsparams);
$fields = 'SELECT u.id, ' . $this->userfieldsselects;
if ($wherecondition) {
$wherecondition = "$wherecondition AND u.id IN ($CFG->siteadmins)";
} else {
$wherecondition = "u.id IN ($CFG->siteadmins)";
}
$sql = " FROM {user} u
$this->userfieldsjoin
WHERE $wherecondition";
[$sort, $sortparams] = users_order_by_sql('u', $search, $this->accesscontext, $this->userfieldsmappings);
$params = array_merge($params, $sortparams);
// Sort first by email domain and then by normal name order.
$order = " ORDER BY " . $DB->sql_substr('email', $DB->sql_position("'@'", 'email'),
$DB->sql_length('email') ) . ", $sort";
$availableusers = $DB->get_records_sql($fields . $sql . $order, $params);
if (empty($availableusers)) {
return array();
}
$mainadmin = array();
$mainadminuser = get_admin();
if ($mainadminuser && isset($availableusers[$mainadminuser->id])) {
$mainadmin = array($mainadminuser->id => $availableusers[$mainadminuser->id]);
unset($availableusers[$mainadminuser->id]);
}
$result = array();
if ($mainadmin) {
$result[get_string('mainadmin', 'core_role')] = $mainadmin;
}
if ($availableusers) {
if ($search) {
$groupname = get_string('extusersmatching', 'core_role', $search);
$result[$groupname] = $availableusers;
} else {
$groupnameprefix = get_string('extusers', 'core_role');
foreach ($availableusers as $user) {
if (isset($user->email)) {
$domain = substr($user->email, strpos($user->email, '@'));
$groupname = "$groupnameprefix $domain";
} else {
$groupname = $groupnameprefix;
}
$result[$groupname][] = $user;
}
}
}
return $result;
}
protected function get_options() {
global $CFG;
$options = parent::get_options();
$options['file'] = $CFG->admin . '/roles/lib.php';
return $options;
}
}
@@ -0,0 +1,94 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Potential admin user selector.
*
* @package core_role
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/user/selector/lib.php');
class core_role_admins_potential_selector extends user_selector_base {
/**
* Create instance.
*
* @param string $name control name
* @param array $options should have two elements with keys groupid and courseid.
*/
public function __construct($name = null, $options = array()) {
global $CFG;
if (is_null($name)) {
$name = 'addselect';
}
$options['includecustomfields'] = true;
$options['exclude'] = explode(',', $CFG->siteadmins);
parent::__construct($name, $options);
}
public function find_users($search) {
global $CFG, $DB;
[$wherecondition, $params] = $this->search_sql($search, 'u');
$params = array_merge($params, $this->userfieldsparams);
$fields = 'SELECT u.id, ' . $this->userfieldsselects;
$countfields = 'SELECT COUNT(1)';
$sql = " FROM {user} u
$this->userfieldsjoin
WHERE $wherecondition AND mnethostid = :localmnet";
// It could be dangerous to make remote users admins and also this could lead to other problems.
$params['localmnet'] = $CFG->mnet_localhost_id;
[$sort, $sortparams] = users_order_by_sql('u', $search, $this->accesscontext, $this->userfieldsmappings);
$order = ' ORDER BY ' . $sort;
// Check to see if there are too many to show sensibly.
if (!$this->is_validating()) {
$potentialcount = $DB->count_records_sql($countfields . $sql, $params);
if ($potentialcount > $this->maxusersperpage) {
return $this->too_many_results($search, $potentialcount);
}
}
$availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
if (empty($availableusers)) {
return array();
}
if ($search) {
$groupname = get_string('potusersmatching', 'core_role', $search);
} else {
$groupname = get_string('potusers', 'core_role');
}
return array($groupname => $availableusers);
}
protected function get_options() {
global $CFG;
$options = parent::get_options();
$options['file'] = $CFG->admin . '/roles/lib.php';
return $options;
}
}
+53
View File
@@ -0,0 +1,53 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Role assign matrix.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of role_allow_role_page for the Allow assigns tab.
*/
class core_role_allow_assign_page extends core_role_allow_role_page {
public function __construct() {
parent::__construct('role_allow_assign', 'allowassign');
}
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_assign_allowed($fromroleid, $targetroleid);
}
protected function get_cell_tooltip($fromrole, $targetrole) {
$a = new stdClass;
$a->fromrole = $fromrole->localname;
$a->targetrole = $targetrole->localname;
return get_string('allowroletoassign', 'core_role', $a);
}
public function get_intro_text() {
return get_string('configallowassign', 'core_admin');
}
protected function get_eventclass() {
return \core\event\role_allow_assign_updated::class;
}
}
@@ -0,0 +1,53 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Role override matrix.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of role_allow_role_page for the Allow overrides tab.
*/
class core_role_allow_override_page extends core_role_allow_role_page {
public function __construct() {
parent::__construct('role_allow_override', 'allowoverride');
}
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_override_allowed($fromroleid, $targetroleid);
}
protected function get_cell_tooltip($fromrole, $targetrole) {
$a = new stdClass;
$a->fromrole = $fromrole->localname;
$a->targetrole = $targetrole->localname;
return get_string('allowroletooverride', 'core_role', $a);
}
public function get_intro_text() {
return get_string('configallowoverride2', 'core_admin');
}
protected function get_eventclass() {
return \core\event\role_allow_override_updated::class;
}
}
+193
View File
@@ -0,0 +1,193 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Base class for allow matrices.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Base class for managing the data in the grid of checkboxes on the role allow
* allow/overrides/switch editing pages (allow.php).
*/
abstract class core_role_allow_role_page {
protected $tablename;
protected $targetcolname;
protected $roles;
protected $allowed = null;
/**
* Constructor.
*
* @param string $tablename the table where our data is stored.
* @param string $targetcolname the name of the target role id column.
*/
public function __construct($tablename, $targetcolname) {
$this->tablename = $tablename;
$this->targetcolname = $targetcolname;
$this->load_required_roles();
}
/**
* Load information about all the roles we will need information about.
*/
protected function load_required_roles() {
// Get all roles.
$this->roles = role_fix_names(get_all_roles(), context_system::instance(), ROLENAME_ORIGINAL);
}
/**
* Update the data with the new settings submitted by the user.
*/
public function process_submission() {
global $DB;
$context = context_system::instance();
$this->load_current_settings();
// Delete all records, then add back the ones that should be allowed.
$DB->delete_records($this->tablename);
foreach ($this->roles as $fromroleid => $notused) {
foreach ($this->roles as $targetroleid => $alsonotused) {
$isallowed = $this->allowed[$fromroleid][$targetroleid];
if (optional_param('s_' . $fromroleid . '_' . $targetroleid, false, PARAM_BOOL)) {
$this->set_allow($fromroleid, $targetroleid);
// Only trigger events if this role allow relationship did not exist and the checkbox element
// has been submitted.
if (!$isallowed) {
$eventclass = $this->get_eventclass();
$eventclass::create([
'context' => $context,
'objectid' => $fromroleid,
'other' => ['targetroleid' => $targetroleid, 'allow' => true]
])->trigger();
}
} else if ($isallowed) {
// When the user has deselect an existing role allow checkbox but it is in the list of roles
// allowances.
$eventclass = $this->get_eventclass();
$eventclass::create([
'context' => $context,
'objectid' => $fromroleid,
'other' => ['targetroleid' => $targetroleid, 'allow' => false]
])->trigger();
}
}
}
}
/**
* Set one allow in the database.
* @param int $fromroleid
* @param int $targetroleid
*/
abstract protected function set_allow($fromroleid, $targetroleid);
/**
* Load the current allows from the database.
*/
public function load_current_settings() {
global $DB;
// Load the current settings.
$this->allowed = array();
foreach ($this->roles as $role) {
// Make an array $role->id => false. This is probably too clever for its own good.
$this->allowed[$role->id] = array_combine(array_keys($this->roles), array_fill(0, count($this->roles), false));
}
$rs = $DB->get_recordset($this->tablename);
foreach ($rs as $allow) {
$this->allowed[$allow->roleid][$allow->{$this->targetcolname}] = true;
}
$rs->close();
}
/**
* Is target allowed?
*
* @param integer $targetroleid a role id.
* @return boolean whether the user should be allowed to select this role as a target role.
*/
protected function is_allowed_target($targetroleid) {
return true;
}
/**
* Returns structure that can be passed to print_table,
* containing one cell for each checkbox.
* @return html_table a table
*/
public function get_table() {
$table = new html_table();
$table->tablealign = 'center';
$table->cellpadding = 5;
$table->cellspacing = 0;
$table->width = '90%';
$table->align = array('left');
$table->head = array('&#xa0;');
$table->colclasses = array('');
// Add role name headers.
foreach ($this->roles as $targetrole) {
$table->head[] = $targetrole->localname;
$table->align[] = 'left';
if ($this->is_allowed_target($targetrole->id)) {
$table->colclasses[] = '';
} else {
$table->colclasses[] = 'dimmed_text';
}
}
// Now the rest of the table.
foreach ($this->roles as $fromrole) {
$row = array($fromrole->localname);
foreach ($this->roles as $targetrole) {
$checked = '';
$disabled = '';
if ($this->allowed[$fromrole->id][$targetrole->id]) {
$checked = 'checked="checked" ';
}
if (!$this->is_allowed_target($targetrole->id)) {
$disabled = 'disabled="disabled" ';
}
$name = 's_' . $fromrole->id . '_' . $targetrole->id;
$tooltip = $this->get_cell_tooltip($fromrole, $targetrole);
$row[] = '<input type="checkbox" name="' . $name . '" id="' . $name .
'" title="' . $tooltip . '" value="1" ' . $checked . $disabled . '/>' .
'<label for="' . $name . '" class="accesshide">' . $tooltip . '</label>';
}
$table->data[] = $row;
}
return $table;
}
/**
* Snippet of text displayed above the table, telling the admin what to do.
* @return string
*/
abstract public function get_intro_text();
/**
* Returns the allow class respective event class name.
* @return string
*/
abstract protected function get_eventclass();
}
+65
View File
@@ -0,0 +1,65 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Role witch matrix.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of role_allow_role_page for the Allow switches tab.
*/
class core_role_allow_switch_page extends core_role_allow_role_page {
protected $allowedtargetroles;
public function __construct() {
parent::__construct('role_allow_switch', 'allowswitch');
}
protected function load_required_roles() {
global $DB;
parent::load_required_roles();
$this->allowedtargetroles = $DB->get_records_menu('role', null, 'id');
}
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_switch_allowed($fromroleid, $targetroleid);
}
protected function is_allowed_target($targetroleid) {
return isset($this->allowedtargetroles[$targetroleid]);
}
protected function get_cell_tooltip($fromrole, $targetrole) {
$a = new stdClass;
$a->fromrole = $fromrole->localname;
$a->targetrole = $targetrole->localname;
return get_string('allowroletoswitch', 'core_role', $a);
}
public function get_intro_text() {
return get_string('configallowswitch', 'core_admin');
}
protected function get_eventclass() {
return \core\event\role_allow_switch_updated::class;
}
}
+80
View File
@@ -0,0 +1,80 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Role view matrix.
*
* @package core_role
* @copyright 2016 onwards Andrew Hancox <andrewdchancox@googlemail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of role_allow_role_page for the Allow views tab.
*
* @package core_role
* @copyright 2016 onwards Andrew Hancox <andrewdchancox@googlemail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_role_allow_view_page extends core_role_allow_role_page {
/** @var array */
protected $allowedtargetroles;
/**
* core_role_allow_view_page constructor.
*/
public function __construct() {
parent::__construct('role_allow_view', 'allowview');
}
/**
* Allow from role to view target role.
* @param int $fromroleid
* @param int $targetroleid
*/
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_view_allowed($fromroleid, $targetroleid);
}
/**
* Get tool tip for cell.
* @param stdClass $fromrole
* @param stdClass $targetrole
* @return string
*/
protected function get_cell_tooltip($fromrole, $targetrole) {
$a = new stdClass;
$a->fromrole = $fromrole->localname;
$a->targetrole = $targetrole->localname;
return get_string('allowroletoview', 'core_role', $a);
}
/**
* Get intro text for role allow view page.
* @return string
* @throws \coding_exception
*/
public function get_intro_text() {
return get_string('configallowview', 'core_admin');
}
protected function get_eventclass() {
return \core\event\role_allow_view_updated::class;
}
}
@@ -0,0 +1,62 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/user/selector/lib.php');
/**
* Base class to avoid duplicating code.
*/
abstract class core_role_assign_user_selector_base extends user_selector_base {
protected $roleid;
protected $context;
/**
* @param string $name control name
* @param array $options should have two elements with keys groupid and courseid.
*/
public function __construct($name, $options) {
global $CFG;
if (isset($options['context'])) {
$this->context = $options['context'];
} else {
$this->context = context::instance_by_id($options['contextid']);
}
$options['accesscontext'] = $this->context;
$options['includecustomfields'] = true;
parent::__construct($name, $options);
$this->roleid = $options['roleid'];
require_once($CFG->dirroot . '/group/lib.php');
}
protected function get_options() {
global $CFG;
$options = parent::get_options();
$options['file'] = $CFG->admin . '/roles/lib.php';
$options['roleid'] = $this->roleid;
$options['contextid'] = $this->context->id;
return $options;
}
}
@@ -0,0 +1,195 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Base capability table.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* This class represents a table with one row for each of a list of capabilities
* where the first cell in the row contains the capability name, and there is
* arbitrary stuff in the rest of the row. This class is used by
* admin/roles/manage.php, override.php and check.php.
*
* An ajaxy search UI shown at the top, if JavaScript is on.
*/
abstract class core_role_capability_table_base {
/** The context this table relates to. */
protected $context;
/** The capabilities to display. Initialised as $context->get_capabilities(). */
protected $capabilities = array();
/** Added as an id="" attribute to the table on output. */
protected $id;
/** Added to the class="" attribute on output. */
protected $classes = array('rolecap table-hover');
/** Default number of capabilities in the table for the search UI to be shown. */
const NUM_CAPS_FOR_SEARCH = 12;
/**
* Constructor.
* @param context $context the context this table relates to.
* @param string $id what to put in the id="" attribute.
*/
public function __construct(context $context, $id) {
$this->context = $context;
$this->capabilities = $context->get_capabilities();
$this->id = $id;
}
/**
* Use this to add class="" attributes to the table. You get the rolecap by
* default.
* @param array $classnames of class names.
*/
public function add_classes($classnames) {
$this->classes = array_unique(array_merge($this->classes, $classnames));
}
/**
* Display the table.
*/
public function display() {
if (count($this->capabilities) > self::NUM_CAPS_FOR_SEARCH) {
global $PAGE;
$jsmodule = array(
'name' => 'rolescapfilter',
'fullpath' => '/admin/roles/module.js',
'strings' => array(
array('filter', 'moodle'),
array('clear', 'moodle'), ),
'requires' => array('node', 'cookie', 'escape')
);
$PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, $this->context->id), false,
$jsmodule);
}
echo '<table class="' . implode(' ', $this->classes) . '" id="' . $this->id . '">' . "\n<thead>\n";
echo '<tr><th class="name" align="left" scope="col">' . get_string('capability', 'core_role') . '</th>';
$this->add_header_cells();
echo "</tr>\n</thead>\n<tbody>\n";
// Loop over capabilities.
$contextlevel = 0;
$component = '';
foreach ($this->capabilities as $capability) {
if ($this->skip_row($capability)) {
continue;
}
// Prints a breaker if component or name or context level has changed.
if (component_level_changed($capability, $component, $contextlevel)) {
$this->print_heading_row($capability);
}
$contextlevel = $capability->contextlevel;
$component = $capability->component;
// Start the row.
$rowattributes = $this->get_row_attributes($capability);
// Handle class attributes same as other.
$rowclasses = array_unique(array_merge(array('rolecap'), $this->get_row_classes($capability)));
if (array_key_exists('class', $rowattributes)) {
$rowclasses = array_unique(array_merge($rowclasses, array($rowattributes['class'])));
}
$rowattributes['class'] = implode(' ', $rowclasses);
// Table cell for the capability name.
$contents = '<th scope="row" class="name"><span class="cap-desc">' . get_capability_docs_link($capability) .
'<span class="cap-name">' . $capability->name . '</span></span></th>';
// Add the cells specific to this table.
$contents .= $this->add_row_cells($capability);
echo html_writer::tag('tr', $contents, $rowattributes);
}
// End of the table.
echo "</tbody>\n</table>\n";
}
/**
* Used to output a heading rows when the context level or component changes.
* @param stdClass $capability gives the new component and contextlevel.
*/
protected function print_heading_row($capability) {
echo '<tr class="rolecapheading header"><td colspan="' . (1 + $this->num_extra_columns()) . '" class="header"><strong>' .
get_component_string($capability->component, $capability->contextlevel) .
'</strong></td></tr>';
}
/**
* For subclasses to override, output header cells, after the initial capability one.
*/
abstract protected function add_header_cells();
/**
* For subclasses to override, return the number of cells that add_header_cells/add_row_cells output.
*/
abstract protected function num_extra_columns();
/**
* For subclasses to override. Allows certain capabilties
* to be left out of the table.
*
* @param object $capability the capability this row relates to.
* @return boolean. If true, this row is omitted from the table.
*/
protected function skip_row($capability) {
return false;
}
/**
* For subclasses to override. A change to reaturn class names that are added
* to the class="" attribute on the &lt;tr> for this capability.
*
* @param stdClass $capability the capability this row relates to.
* @return array of class name strings.
*/
protected function get_row_classes($capability) {
return array();
}
/**
* For subclasses to override. Additional attributes to be added to
* each table row for the capability
*
* @param stdClass $capability the capability this row relates to.
* @return array attribute names and their values.
*/
protected function get_row_attributes($capability) {
return array();
}
/**
* For subclasses to override. Output the data cells for this capability. The
* capability name cell will already have been output.
*
* You can rely on get_row_classes always being called before add_row_cells.
*
* @param stdClass $capability the capability this row relates to.
* @return string html of row cells
*/
abstract protected function add_row_cells($capability);
}
@@ -0,0 +1,194 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Capabilities table with risks.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* This subclass is the bases for both the define roles and override roles
* pages. As well as adding the risks columns, this also provides generic
* facilities for showing a certain number of permissions columns, and
* recording the current and submitted permissions for each capability.
*/
abstract class core_role_capability_table_with_risks extends core_role_capability_table_base {
protected $allrisks;
protected $allpermissions; // We don't need perms ourselves, but all our subclasses do.
protected $strperms; // Language string cache.
protected $risksurl; // URL in moodledocs about risks.
/** @var array The capabilities to highlight as default/inherited. */
protected $parentpermissions;
protected $displaypermissions;
protected $permissions;
protected $changed;
protected $roleid;
public function __construct($context, $id, $roleid) {
parent::__construct($context, $id);
$this->allrisks = get_all_risks();
$this->risksurl = get_docs_url(s(get_string('risks', 'core_role')));
$this->allpermissions = array(
CAP_INHERIT => 'inherit',
CAP_ALLOW => 'allow',
CAP_PREVENT => 'prevent' ,
CAP_PROHIBIT => 'prohibit',
);
$this->strperms = array();
foreach ($this->allpermissions as $permname) {
$this->strperms[$permname] = get_string($permname, 'core_role');
}
$this->roleid = $roleid;
$this->load_current_permissions();
// Fill in any blank permissions with an explicit CAP_INHERIT, and init a locked field.
foreach ($this->capabilities as $capid => $cap) {
if (!isset($this->permissions[$cap->name])) {
$this->permissions[$cap->name] = CAP_INHERIT;
}
$this->capabilities[$capid]->locked = false;
}
}
protected function load_current_permissions() {
global $DB;
// Load the overrides/definition in this context.
if ($this->roleid) {
$this->permissions = $DB->get_records_menu('role_capabilities', array('roleid' => $this->roleid,
'contextid' => $this->context->id), '', 'capability,permission');
} else {
$this->permissions = array();
}
}
abstract protected function load_parent_permissions();
/**
* Update $this->permissions based on submitted data, while making a list of
* changed capabilities in $this->changed.
*/
public function read_submitted_permissions() {
$this->changed = array();
foreach ($this->capabilities as $cap) {
if ($cap->locked || $this->skip_row($cap)) {
// The user is not allowed to change the permission for this capability.
continue;
}
$permission = optional_param($cap->name, null, PARAM_PERMISSION);
if (is_null($permission)) {
// A permission was not specified in submitted data.
continue;
}
// If the permission has changed, update $this->permissions and
// Record the fact there is data to save.
if ($this->permissions[$cap->name] != $permission) {
$this->permissions[$cap->name] = $permission;
$this->changed[] = $cap->name;
}
}
}
/**
* Save the new values of any permissions that have been changed.
*/
public function save_changes() {
// Set the permissions.
foreach ($this->changed as $changedcap) {
assign_capability($changedcap, $this->permissions[$changedcap],
$this->roleid, $this->context->id, true);
}
}
public function display() {
$this->load_parent_permissions();
foreach ($this->capabilities as $cap) {
if (!isset($this->parentpermissions[$cap->name])) {
$this->parentpermissions[$cap->name] = CAP_INHERIT;
}
}
parent::display();
}
protected function add_header_cells() {
global $OUTPUT;
echo '<th colspan="' . count($this->displaypermissions) . '" scope="col">' .
get_string('permission', 'core_role') . ' ' . $OUTPUT->help_icon('permission', 'core_role') . '</th>';
echo '<th class="risk" colspan="' . count($this->allrisks) . '" scope="col">' . get_string('risks', 'core_role') . '</th>';
}
protected function num_extra_columns() {
return count($this->displaypermissions) + count($this->allrisks);
}
protected function get_row_classes($capability) {
$rowclasses = array();
foreach ($this->allrisks as $riskname => $risk) {
if ($risk & (int)$capability->riskbitmask) {
$rowclasses[] = $riskname;
}
}
return $rowclasses;
}
abstract protected function add_permission_cells($capability);
protected function add_row_cells($capability) {
$cells = $this->add_permission_cells($capability);
// One cell for each possible risk.
foreach ($this->allrisks as $riskname => $risk) {
$cells .= '<td class="risk ' . str_replace('risk', '', $riskname) . '">';
if ($risk & (int)$capability->riskbitmask) {
$cells .= $this->get_risk_icon($riskname);
}
$cells .= '</td>';
}
return $cells;
}
/**
* Print a risk icon, as a link to the Risks page on Moodle Docs.
*
* @param string $type the type of risk, will be one of the keys from the
* get_all_risks array. Must start with 'risk'.
*/
public function get_risk_icon($type) {
global $OUTPUT;
$alt = get_string("{$type}short", "admin");
$title = get_string($type, "admin");
$text = $OUTPUT->pix_icon('i/' . str_replace('risk', 'risk_', $type), $alt, 'moodle', [
'title' => $title,
]);
$action = new popup_action('click', $this->risksurl, 'docspopup');
$riskicon = $OUTPUT->action_link($this->risksurl, $text, $action);
return $riskicon;
}
}
@@ -0,0 +1,85 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of core_role_capability_table_base for use on the Check permissions page.
*
* We have one additional column, Allowed, which contains yes/no.
*/
class core_role_check_capability_table extends core_role_capability_table_base {
protected $user;
protected $fullname;
protected $contextname;
protected $stryes;
protected $strno;
private $hascap;
/**
* Constructor
* @param object $context the context this table relates to.
* @param object $user the user we are generating the results for.
* @param string $contextname $context->get_context_name() - to save recomputing.
*/
public function __construct($context, $user, $contextname) {
parent::__construct($context, 'explaincaps');
$this->user = $user;
$this->fullname = fullname($user);
$this->contextname = $contextname;
$this->stryes = get_string('yes');
$this->strno = get_string('no');
$this->add_classes(['table-striped']);
}
protected function add_header_cells() {
echo '<th>' . get_string('allowed', 'core_role') . '</th>';
}
protected function num_extra_columns() {
return 1;
}
protected function get_row_classes($capability) {
$this->hascap = has_capability($capability->name, $this->context, $this->user->id);
if ($this->hascap) {
return array('yes');
} else {
return array('no');
}
}
protected function add_row_cells($capability) {
if ($this->hascap) {
$result = $this->stryes;
} else {
$result = $this->strno;
}
$a = new stdClass;
$a->fullname = $this->fullname;
$a->capability = $capability->name;
$a->context = $this->contextname;
return '<td>' . $result . '</td>';
}
}
@@ -0,0 +1,161 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* User selector.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/user/selector/lib.php');
/**
* User selector subclass for the selection of users in the check permissions page.
*
* @copyright 2012 Petr Skoda {@link http://skodak.org}
*/
class core_role_check_users_selector extends user_selector_base {
/** @var bool limit listing of users to enrolled only */
protected $onlyenrolled;
/**
* Constructor.
*
* @param string $name the control name/id for use in the HTML.
* @param array $options other options needed to construct this selector.
* You must be able to clone a userselector by doing new get_class($us)($us->get_name(), $us->get_options());
*/
public function __construct($name, $options) {
if (!isset($options['multiselect'])) {
$options['multiselect'] = false;
}
$options['includecustomfields'] = true;
parent::__construct($name, $options);
$coursecontext = $this->accesscontext->get_course_context(false);
if ($coursecontext and $coursecontext->id != SITEID and !has_capability('moodle/role:manage', $coursecontext)) {
// Prevent normal teachers from looking up all users.
$this->onlyenrolled = true;
} else {
$this->onlyenrolled = false;
}
}
public function find_users($search) {
global $DB;
list($wherecondition, $params) = $this->search_sql($search, 'u');
$params = array_merge($params, $this->userfieldsparams);
$fields = 'SELECT u.id, ' . $this->userfieldsselects;
$countfields = 'SELECT COUNT(1)';
$coursecontext = $this->accesscontext->get_course_context(false);
if ($coursecontext and $coursecontext != SITEID) {
$sql1 = " FROM {user} u
JOIN (SELECT DISTINCT subu.id
FROM {user} subu
JOIN {user_enrolments} ue ON (ue.userid = subu.id)
JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid1)
) subq ON subq.id = u.id
$this->userfieldsjoin
WHERE $wherecondition";
$params['courseid1'] = $coursecontext->instanceid;
if ($this->onlyenrolled) {
$sql2 = null;
} else {
$sql2 = " FROM {user} u
LEFT JOIN ({user_enrolments} ue
JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid2)) ON (ue.userid = u.id)
$this->userfieldsjoin
WHERE $wherecondition
AND ue.id IS NULL";
$params['courseid2'] = $coursecontext->instanceid;
}
} else {
if ($this->onlyenrolled) {
// Bad luck, current user may not view only enrolled users.
return array();
}
$sql1 = null;
$sql2 = " FROM {user} u
$this->userfieldsjoin
WHERE $wherecondition";
}
$params['contextid'] = $this->accesscontext->id;
list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext, $this->userfieldsmappings);
$order = ' ORDER BY ' . $sort;
$result = array();
if ($search) {
$groupname1 = get_string('enrolledusersmatching', 'enrol', $search);
$groupname2 = get_string('potusersmatching', 'core_role', $search);
} else {
$groupname1 = get_string('enrolledusers', 'enrol');
$groupname2 = get_string('potusers', 'core_role');
}
if ($sql1) {
$enrolleduserscount = $DB->count_records_sql($countfields . $sql1, $params);
if (!$this->is_validating() and $enrolleduserscount > $this->maxusersperpage) {
$result[$groupname1] = array();
$toomany = $this->too_many_results($search, $enrolleduserscount);
$result[implode(' - ', array_keys($toomany))] = array();
} else {
$enrolledusers = $DB->get_records_sql($fields . $sql1 . $order, array_merge($params, $sortparams));
if ($enrolledusers) {
$result[$groupname1] = $enrolledusers;
}
}
if ($sql2) {
$result[''] = array();
}
}
if ($sql2) {
$otheruserscount = $DB->count_records_sql($countfields . $sql2, $params);
if (!$this->is_validating() and $otheruserscount > $this->maxusersperpage) {
$result[$groupname2] = array();
$toomany = $this->too_many_results($search, $otheruserscount);
$result[implode(' - ', array_keys($toomany))] = array();
} else {
$otherusers = $DB->get_records_sql($fields . $sql2 . $order, array_merge($params, $sortparams));
if ($otherusers) {
$result[$groupname2] = $otherusers;
}
}
}
return $result;
}
protected function get_options() {
global $CFG;
$options = parent::get_options();
$options['file'] = $CFG->admin . '/roles/lib.php';
return $options;
}
}
@@ -0,0 +1,732 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Advanced role definition form.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* As well as tracking the permissions information about the role we are creating
* or editing, we also track the other information about the role. (This class is
* starting to be more and more like a formslib form in some respects.)
*/
class core_role_define_role_table_advanced extends core_role_capability_table_with_risks {
/** @var stdClass Used to store other information (besides permissions) about the role we are creating/editing. */
protected $role;
/** @var array Used to store errors found when validating the data. */
protected $errors;
protected $contextlevels;
protected $allcontextlevels;
protected $disabled = '';
protected $allowassign;
protected $allowoverride;
protected $allowswitch;
protected $allowview;
public function __construct($context, $roleid) {
$this->roleid = $roleid;
parent::__construct($context, 'defineroletable', $roleid);
$this->displaypermissions = $this->allpermissions;
$this->strperms[$this->allpermissions[CAP_INHERIT]] = get_string('notset', 'core_role');
$this->allcontextlevels = array();
$levels = context_helper::get_all_levels();
foreach ($levels as $level => $classname) {
$this->allcontextlevels[$level] = context_helper::get_level_name($level);
}
$this->add_classes(['table-striped']);
}
protected function load_current_permissions() {
global $DB;
if ($this->roleid) {
if (!$this->role = $DB->get_record('role', array('id' => $this->roleid))) {
throw new moodle_exception('invalidroleid');
}
$contextlevels = get_role_contextlevels($this->roleid);
// Put the contextlevels in the array keys, as well as the values.
if (!empty($contextlevels)) {
$this->contextlevels = array_combine($contextlevels, $contextlevels);
} else {
$this->contextlevels = array();
}
$this->allowassign = array_keys($this->get_allow_roles_list('assign'));
$this->allowoverride = array_keys($this->get_allow_roles_list('override'));
$this->allowswitch = array_keys($this->get_allow_roles_list('switch'));
$this->allowview = array_keys($this->get_allow_roles_list('view'));
} else {
$this->role = new stdClass;
$this->role->name = '';
$this->role->shortname = '';
$this->role->description = '';
$this->role->archetype = '';
$this->contextlevels = array();
$this->allowassign = array();
$this->allowoverride = array();
$this->allowswitch = array();
$this->allowview = array();
}
parent::load_current_permissions();
}
public function read_submitted_permissions() {
global $DB;
$this->errors = array();
// Role short name. We clean this in a special way. We want to end up
// with only lowercase safe ASCII characters.
$shortname = optional_param('shortname', null, PARAM_RAW);
if (!is_null($shortname)) {
$this->role->shortname = $shortname;
$this->role->shortname = core_text::specialtoascii($this->role->shortname);
$this->role->shortname = core_text::strtolower(clean_param($this->role->shortname, PARAM_ALPHANUMEXT));
if (empty($this->role->shortname)) {
$this->errors['shortname'] = get_string('errorbadroleshortname', 'core_role');
} else if (core_text::strlen($this->role->shortname) > 100) { // Check if it exceeds the max of 100 characters.
$this->errors['shortname'] = get_string('errorroleshortnametoolong', 'core_role');
}
}
if ($DB->record_exists_select('role', 'shortname = ? and id <> ?', array($this->role->shortname, $this->roleid))) {
$this->errors['shortname'] = get_string('errorexistsroleshortname', 'core_role');
}
// Role name.
$name = optional_param('name', null, PARAM_TEXT);
if (!is_null($name)) {
$this->role->name = $name;
// Hack: short names of standard roles are equal to archetypes, empty name means localised via lang packs.
$archetypes = get_role_archetypes();
if (!isset($archetypes[$shortname]) and html_is_blank($this->role->name)) {
$this->errors['name'] = get_string('errorbadrolename', 'core_role');
}
}
if ($this->role->name !== '' and $DB->record_exists_select('role', 'name = ? and id <> ?', array($this->role->name, $this->roleid))) {
$this->errors['name'] = get_string('errorexistsrolename', 'core_role');
}
// Description.
$description = optional_param('description', null, PARAM_RAW);
if (!is_null($description)) {
$this->role->description = $description;
}
// Legacy type.
$archetype = optional_param('archetype', null, PARAM_RAW);
if (isset($archetype)) {
$archetypes = get_role_archetypes();
if (isset($archetypes[$archetype])) {
$this->role->archetype = $archetype;
} else {
$this->role->archetype = '';
}
}
// Assignable context levels.
foreach ($this->allcontextlevels as $cl => $notused) {
$assignable = optional_param('contextlevel' . $cl, null, PARAM_BOOL);
if (!is_null($assignable)) {
if ($assignable) {
$this->contextlevels[$cl] = $cl;
} else {
unset($this->contextlevels[$cl]);
}
}
}
// Allowed roles.
$allow = optional_param_array('allowassign', null, PARAM_INT);
if (!is_null($allow)) {
$this->allowassign = array_filter($allow);
}
$allow = optional_param_array('allowoverride', null, PARAM_INT);
if (!is_null($allow)) {
$this->allowoverride = array_filter($allow);
}
$allow = optional_param_array('allowswitch', null, PARAM_INT);
if (!is_null($allow)) {
$this->allowswitch = array_filter($allow);
}
$allow = optional_param_array('allowview', null, PARAM_INT);
if (!is_null($allow)) {
$this->allowview = array_filter($allow);
}
// Now read the permissions for each capability.
parent::read_submitted_permissions();
}
public function is_submission_valid() {
return empty($this->errors);
}
/**
* Call this after the table has been initialised,
* this resets everything to that role.
*
* @param int $roleid role id or 0 for no role
* @param array $options array with following keys:
* 'name', 'shortname', 'description', 'permissions', 'archetype',
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch',
* 'allowview'
*/
public function force_duplicate($roleid, array $options) {
global $DB;
if ($roleid == 0) {
// This means reset to nothing == remove everything.
if ($options['shortname']) {
$this->role->shortname = '';
}
if ($options['name']) {
$this->role->name = '';
}
if ($options['description']) {
$this->role->description = '';
}
if ($options['archetype']) {
$this->role->archetype = '';
}
if ($options['contextlevels']) {
$this->contextlevels = array();
}
if ($options['allowassign']) {
$this->allowassign = array();
}
if ($options['allowoverride']) {
$this->allowoverride = array();
}
if ($options['allowswitch']) {
$this->allowswitch = array();
}
if ($options['allowview']) {
$this->allowview = array();
}
if ($options['permissions']) {
foreach ($this->capabilities as $capid => $cap) {
$this->permissions[$cap->name] = CAP_INHERIT;
}
}
return;
}
$role = $DB->get_record('role', array('id'=>$roleid), '*', MUST_EXIST);
if ($options['shortname']) {
$this->role->shortname = $role->shortname;
}
if ($options['name']) {
$this->role->name = $role->name;
}
if ($options['description']) {
$this->role->description = $role->description;
}
if ($options['archetype']) {
$this->role->archetype = $role->archetype;
}
if ($options['contextlevels']) {
$this->contextlevels = array();
$levels = get_role_contextlevels($roleid);
foreach ($levels as $cl) {
$this->contextlevels[$cl] = $cl;
}
}
if ($options['allowassign']) {
$this->allowassign = array_keys($this->get_allow_roles_list('assign', $roleid));
}
if ($options['allowoverride']) {
$this->allowoverride = array_keys($this->get_allow_roles_list('override', $roleid));
}
if ($options['allowswitch']) {
$this->allowswitch = array_keys($this->get_allow_roles_list('switch', $roleid));
}
if ($options['allowview']) {
$this->allowview = array_keys($this->get_allow_roles_list('view', $roleid));
}
if ($options['permissions']) {
$this->permissions = $DB->get_records_menu('role_capabilities',
array('roleid' => $roleid, 'contextid' => context_system::instance()->id),
'', 'capability,permission');
foreach ($this->capabilities as $capid => $cap) {
if (!isset($this->permissions[$cap->name])) {
$this->permissions[$cap->name] = CAP_INHERIT;
}
}
}
}
/**
* Change the role definition to match given archetype.
*
* @param string $archetype
* @param array $options array with following keys:
* 'name', 'shortname', 'description', 'permissions', 'archetype',
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch',
* 'allowview'
*/
public function force_archetype($archetype, array $options) {
$archetypes = get_role_archetypes();
if (!isset($archetypes[$archetype])) {
throw new coding_exception('Unknown archetype: '.$archetype);
}
if ($options['shortname']) {
$this->role->shortname = '';
}
if ($options['name']) {
$this->role->name = '';
}
if ($options['description']) {
$this->role->description = '';
}
if ($options['archetype']) {
$this->role->archetype = $archetype;
}
if ($options['contextlevels']) {
$this->contextlevels = array();
$defaults = get_default_contextlevels($archetype);
foreach ($defaults as $cl) {
$this->contextlevels[$cl] = $cl;
}
}
if ($options['allowassign']) {
$this->allowassign = get_default_role_archetype_allows('assign', $archetype);
}
if ($options['allowoverride']) {
$this->allowoverride = get_default_role_archetype_allows('override', $archetype);
}
if ($options['allowswitch']) {
$this->allowswitch = get_default_role_archetype_allows('switch', $archetype);
}
if ($options['allowview']) {
$this->allowview = get_default_role_archetype_allows('view', $archetype);
}
if ($options['permissions']) {
$defaultpermissions = get_default_capabilities($archetype);
foreach ($this->permissions as $k => $v) {
if (isset($defaultpermissions[$k])) {
$this->permissions[$k] = $defaultpermissions[$k];
continue;
}
$this->permissions[$k] = CAP_INHERIT;
}
}
}
/**
* Change the role definition to match given preset.
*
* @param string $xml
* @param array $options array with following keys:
* 'name', 'shortname', 'description', 'permissions', 'archetype',
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch',
* 'allowview'
*/
public function force_preset($xml, array $options) {
if (!$info = core_role_preset::parse_preset($xml)) {
throw new coding_exception('Invalid role preset');
}
if ($options['shortname']) {
if (isset($info['shortname'])) {
$this->role->shortname = $info['shortname'];
}
}
if ($options['name']) {
if (isset($info['name'])) {
$this->role->name = $info['name'];
}
}
if ($options['description']) {
if (isset($info['description'])) {
$this->role->description = $info['description'];
}
}
if ($options['archetype']) {
if (isset($info['archetype'])) {
$this->role->archetype = $info['archetype'];
}
}
if ($options['contextlevels']) {
if (isset($info['contextlevels'])) {
$this->contextlevels = $info['contextlevels'];
}
}
foreach (array('assign', 'override', 'switch', 'view') as $type) {
if ($options['allow'.$type]) {
if (isset($info['allow'.$type])) {
$this->{'allow'.$type} = $info['allow'.$type];
}
}
}
if ($options['permissions']) {
foreach ($this->permissions as $k => $v) {
// Note: do not set everything else to CAP_INHERIT here
// because the xml file might not contain all capabilities.
if (isset($info['permissions'][$k])) {
$this->permissions[$k] = $info['permissions'][$k];
}
}
}
}
public function get_role_name() {
return $this->role->name;
}
public function get_role_id() {
return $this->role->id;
}
public function get_archetype() {
return $this->role->archetype;
}
protected function load_parent_permissions() {
$this->parentpermissions = get_default_capabilities($this->role->archetype);
}
public function save_changes() {
global $DB, $USER;
if (!$this->roleid) {
// Creating role.
$this->role->id = create_role($this->role->name, $this->role->shortname, $this->role->description, $this->role->archetype);
$this->roleid = $this->role->id; // Needed to make the parent::save_changes(); call work.
} else {
// Updating role.
$DB->update_record('role', $this->role);
// Trigger role updated event.
\core\event\role_updated::create([
'userid' => $USER->id,
'objectid' => $this->role->id,
'context' => $this->context,
'other' => [
'name' => $this->role->name,
'shortname' => $this->role->shortname,
'description' => $this->role->description,
'archetype' => $this->role->archetype,
'contextlevels' => $this->contextlevels
]
])->trigger();
// This will ensure the course contacts cache is purged so name changes get updated in
// the UI. It would be better to do this only when we know that fields affected are
// updated. But thats getting into the weeds of the coursecat cache and role edits
// should not be that frequent, so here is the ugly brutal approach.
core_course_category::role_assignment_changed($this->role->id, context_system::instance());
}
// Assignable contexts.
set_role_contextlevels($this->role->id, $this->contextlevels);
// Set allowed roles.
$this->save_allow('assign');
$this->save_allow('override');
$this->save_allow('switch');
$this->save_allow('view');
// Permissions.
parent::save_changes();
}
protected function save_allow($type) {
global $DB;
$current = array_keys($this->get_allow_roles_list($type));
$wanted = $this->{'allow'.$type};
$addfunction = "core_role_set_{$type}_allowed";
$deltable = 'role_allow_'.$type;
$field = 'allow'.$type;
$eventclass = "\\core\\event\\role_allow_" . $type . "_updated";
$context = context_system::instance();
foreach ($current as $roleid) {
if (!in_array($roleid, $wanted)) {
$DB->delete_records($deltable, array('roleid'=>$this->roleid, $field=>$roleid));
$eventclass::create([
'context' => $context,
'objectid' => $this->roleid,
'other' => ['targetroleid' => $roleid, 'allow' => false]
])->trigger();
continue;
}
$key = array_search($roleid, $wanted);
unset($wanted[$key]);
}
foreach ($wanted as $roleid) {
if ($roleid == -1) {
$roleid = $this->roleid;
}
$addfunction($this->roleid, $roleid);
if (in_array($roleid, $wanted)) {
$eventclass::create([
'context' => $context,
'objectid' => $this->roleid,
'other' => ['targetroleid' => $roleid, 'allow' => true]
])->trigger();
}
}
}
protected function get_name_field($id) {
return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->name) . '"' .
' class="form-control"/>';
}
protected function get_shortname_field($id) {
return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="100" value="' . s($this->role->shortname) . '"' .
' class="form-control"/>';
}
protected function get_description_field($id) {
return '<textarea class="form-textarea form-control" id="'. s($id) .'" name="description" rows="10" cols="50">' .
htmlspecialchars($this->role->description, ENT_COMPAT) .
'</textarea>';
}
protected function get_archetype_field($id) {
$options = array();
$options[''] = get_string('none');
foreach (get_role_archetypes() as $type) {
$options[$type] = get_string('archetype'.$type, 'role');
}
return html_writer::select($options, 'archetype', $this->role->archetype, false,
array('class' => 'custom-select'));
}
protected function get_assignable_levels_control() {
$output = '';
foreach ($this->allcontextlevels as $cl => $clname) {
$extraarguments = $this->disabled;
if (in_array($cl, $this->contextlevels)) {
$extraarguments .= 'checked="checked" ';
}
if (!$this->disabled) {
$output .= '<input type="hidden" name="contextlevel' . $cl . '" value="0" />';
}
$output .= '<div class="form-check justify-content-start w-100">';
$output .= '<input class="form-check-input" type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
'" value="1" ' . $extraarguments . '/> ';
$output .= '<label class="form-check-label" for="cl' . $cl . '">' . $clname . "</label>\n";
$output .= '</div>';
}
return $output;
}
/**
* Returns an array of roles of the allowed type.
*
* @param string $type Must be one of: assign, switch, or override.
* @param int $roleid (null means current role)
* @return array
*/
protected function get_allow_roles_list($type, $roleid = null) {
global $DB;
if ($type !== 'assign' and $type !== 'switch' and $type !== 'override' and $type !== 'view') {
debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
return array();
}
if ($roleid === null) {
$roleid = $this->roleid;
}
if (empty($roleid)) {
return array();
}
$sql = "SELECT r.*
FROM {role} r
JOIN {role_allow_{$type}} a ON a.allow{$type} = r.id
WHERE a.roleid = :roleid
ORDER BY r.sortorder ASC";
return $DB->get_records_sql($sql, array('roleid'=>$roleid));
}
/**
* Returns an array of roles with the allowed type.
*
* @param string $type Must be one of: assign, switch, override or view.
* @return array Am array of role names with the allowed type
*/
protected function get_allow_role_control($type) {
if ($type !== 'assign' and $type !== 'switch' and $type !== 'override' and $type !== 'view') {
debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
return '';
}
$property = 'allow'.$type;
$selected = $this->$property;
$options = array();
foreach (role_get_names(null, ROLENAME_ALIAS) as $role) {
$options[$role->id] = $role->localname;
}
if ($this->roleid == 0) {
$options[-1] = get_string('thisnewrole', 'core_role');
}
return
html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'allow'.$type.'[]', 'value' => "")) .
html_writer::select($options, 'allow'.$type.'[]', $selected, false, array('multiple' => 'multiple',
'size' => 10, 'class' => 'form-control'));
}
/**
* Returns information about the risks associated with a role.
*
* @return string
*/
protected function get_role_risks_info() {
return '';
}
/**
* Print labels, fields and help icon on role administration page.
*
* @param string $name The field name.
* @param string $caption The field caption.
* @param string $field The field type.
* @param null|string $helpicon The help icon content.
*/
protected function print_field($name, $caption, $field, $helpicon = null) {
global $OUTPUT;
// Attempt to generate HTML like formslib.
echo '<div class="fitem row mb-3">';
echo '<div class="fitemtitle col-md-3">';
if ($name) {
echo '<label for="' . $name . '">';
}
echo $caption;
if ($name) {
echo "</label>\n";
}
if ($helpicon) {
echo '<span class="float-sm-right text-nowrap">'.$helpicon.'</span>';
}
echo '</div>';
if (isset($this->errors[$name])) {
$extraclass = ' error';
} else {
$extraclass = '';
}
echo '<div class="felement col-md-9 d-flex flex-wrap align-items-center' . $extraclass . '">';
echo $field;
if (isset($this->errors[$name])) {
echo $OUTPUT->error_text($this->errors[$name]);
}
echo '</div>';
echo '</div>';
}
protected function print_show_hide_advanced_button() {
echo '<p class="definenotice">' . get_string('highlightedcellsshowdefault', 'core_role') . ' </p>';
echo '<div class="advancedbutton">';
echo '<input type="submit" class="btn btn-secondary" name="toggleadvanced" value="' .
get_string('hideadvanced', 'form') . '" />';
echo '</div>';
}
public function display() {
global $OUTPUT;
// Extra fields at the top of the page.
echo '<div class="topfields clearfix">';
$this->print_field('shortname', get_string('roleshortname', 'core_role'),
$this->get_shortname_field('shortname'), $OUTPUT->help_icon('roleshortname', 'core_role'));
$this->print_field('name', get_string('customrolename', 'core_role'), $this->get_name_field('name'),
$OUTPUT->help_icon('customrolename', 'core_role'));
$this->print_field('edit-description', get_string('customroledescription', 'core_role'),
$this->get_description_field('description'), $OUTPUT->help_icon('customroledescription', 'core_role'));
$this->print_field('menuarchetype', get_string('archetype', 'core_role'), $this->get_archetype_field('archetype'),
$OUTPUT->help_icon('archetype', 'core_role'));
$this->print_field('', get_string('maybeassignedin', 'core_role'), $this->get_assignable_levels_control());
$this->print_field('menuallowassign', get_string('allowassign', 'core_role'), $this->get_allow_role_control('assign'));
$this->print_field('menuallowoverride', get_string('allowoverride', 'core_role'), $this->get_allow_role_control('override'));
$this->print_field('menuallowswitch', get_string('allowswitch', 'core_role'), $this->get_allow_role_control('switch'));
$this->print_field('menuallowview', get_string('allowview', 'core_role'), $this->get_allow_role_control('view'));
if ($risks = $this->get_role_risks_info()) {
$this->print_field('', get_string('rolerisks', 'core_role'), $risks);
}
echo "</div>";
$this->print_show_hide_advanced_button();
// Now the permissions table.
parent::display();
}
protected function add_permission_cells($capability) {
// One cell for each possible permission.
$content = '';
foreach ($this->displaypermissions as $perm => $permname) {
$strperm = $this->strperms[$permname];
$extraclass = '';
if ($perm == $this->parentpermissions[$capability->name]) {
$extraclass = ' capdefault';
}
$checked = '';
if ($this->permissions[$capability->name] == $perm) {
$checked = 'checked="checked" ';
}
$content .= '<td class="' . $permname . $extraclass . '">';
$content .= '<label><input type="radio" name="' . $capability->name .
'" value="' . $perm . '" ' . $checked . '/> ';
$content .= '<span class="note">' . $strperm . '</span>';
$content .= '</label></td>';
}
return $content;
}
}
@@ -0,0 +1,65 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class core_role_define_role_table_basic extends core_role_define_role_table_advanced {
protected $stradvmessage;
protected $strallow;
public function __construct($context, $roleid) {
parent::__construct($context, $roleid);
$this->displaypermissions = array(CAP_ALLOW => $this->allpermissions[CAP_ALLOW]);
$this->stradvmessage = get_string('useshowadvancedtochange', 'core_role');
$this->strallow = $this->strperms[$this->allpermissions[CAP_ALLOW]];
}
protected function print_show_hide_advanced_button() {
echo '<div class="advancedbutton">';
echo '<input type="submit" class="btn btn-secondary" name="toggleadvanced"
value="' . get_string('showadvanced', 'form') . '" />';
echo '</div>';
}
protected function add_permission_cells($capability) {
$perm = $this->permissions[$capability->name];
$permname = $this->allpermissions[$perm];
$defaultperm = $this->allpermissions[$this->parentpermissions[$capability->name]];
$content = '<td class="' . $permname . '">';
if ($perm == CAP_ALLOW || $perm == CAP_INHERIT) {
$checked = '';
if ($perm == CAP_ALLOW) {
$checked = 'checked="checked" ';
}
$content .= '<input type="hidden" name="' . $capability->name . '" value="' . CAP_INHERIT . '" />';
$content .= '<label><input type="checkbox" name="' . $capability->name .
'" value="' . CAP_ALLOW . '" ' . $checked . '/> ' . $this->strallow . '</label>';
} else {
$content .= '<input type="hidden" name="' . $capability->name . '" value="' . $perm . '" />';
$content .= $this->strperms[$permname] . '<span class="note">' . $this->stradvmessage . '</span>';
}
$content .= '</td>';
return $content;
}
}
@@ -0,0 +1,154 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Existing user selector.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* User selector subclass for the list of users who already have the role in
* question on the assign roles page.
*/
class core_role_existing_role_holders extends core_role_assign_user_selector_base {
public function find_users($search) {
global $DB;
list($wherecondition, $params) = $this->search_sql($search, 'u');
list($ctxcondition, $ctxparams) = $DB->get_in_or_equal($this->context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'ctx');
$params = array_merge($params, $ctxparams, $this->userfieldsparams);
$params['roleid'] = $this->roleid;
list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext, $this->userfieldsmappings);
$params = array_merge($params, $sortparams);
$fields = "SELECT ra.id AS raid, u.id, " . $this->userfieldsselects . ", ra.contextid, ra.component ";
$countfields = "SELECT COUNT(1) ";
$sql = "FROM {role_assignments} ra
JOIN {user} u ON u.id = ra.userid
JOIN {context} ctx ON ra.contextid = ctx.id
$this->userfieldsjoin
WHERE $wherecondition
AND ctx.id $ctxcondition
AND ra.roleid = :roleid";
$order = " ORDER BY ctx.depth DESC, ra.component, $sort";
if (!$this->is_validating()) {
$existinguserscount = $DB->count_records_sql($countfields . $sql, $params);
if ($existinguserscount > $this->maxusersperpage) {
return $this->too_many_results($search, $existinguserscount);
}
}
$contextusers = $DB->get_records_sql($fields . $sql . $order, $params);
// No users at all.
if (empty($contextusers)) {
return array();
}
// We have users. Out put them in groups by context depth.
// To help the loop below, tack a dummy user on the end of the results
// array, to trigger output of the last group.
$dummyuser = new stdClass;
$dummyuser->contextid = 0;
$dummyuser->id = 0;
$dummyuser->component = '';
$contextusers[] = $dummyuser;
$results = array(); // The results array we are building up.
$doneusers = array(); // Ensures we only list each user at most once.
$currentcontextid = $this->context->id;
$currentgroup = array();
foreach ($contextusers as $user) {
if (isset($doneusers[$user->id])) {
continue;
}
$doneusers[$user->id] = 1;
if ($user->contextid != $currentcontextid) {
// We have got to the end of the previous group. Add it to the results array.
if ($currentcontextid == $this->context->id) {
$groupname = $this->this_con_group_name($search, count($currentgroup));
} else {
$groupname = $this->parent_con_group_name($search, $currentcontextid);
}
$results[$groupname] = $currentgroup;
// Get ready for the next group.
$currentcontextid = $user->contextid;
$currentgroup = array();
}
// Add this user to the group we are building up.
unset($user->contextid);
if ($currentcontextid != $this->context->id) {
$user->disabled = true;
}
if ($user->component !== '') {
// Bad luck, you can tweak only manual role assignments.
$user->disabled = true;
}
unset($user->component);
$currentgroup[$user->id] = $user;
}
return $results;
}
protected function this_con_group_name($search, $numusers) {
if ($this->context->contextlevel == CONTEXT_SYSTEM) {
// Special case in the System context.
if ($search) {
return get_string('extusersmatching', 'core_role', $search);
} else {
return get_string('extusers', 'core_role');
}
}
$contexttype = context_helper::get_level_name($this->context->contextlevel);
if ($search) {
$a = new stdClass;
$a->search = $search;
$a->contexttype = $contexttype;
if ($numusers) {
return get_string('usersinthisxmatching', 'core_role', $a);
} else {
return get_string('noneinthisxmatching', 'core_role', $a);
}
} else {
if ($numusers) {
return get_string('usersinthisx', 'core_role', $contexttype);
} else {
return get_string('noneinthisx', 'core_role', $contexttype);
}
}
}
protected function parent_con_group_name($search, $contextid) {
$context = context::instance_by_id($contextid);
$contextname = $context->get_context_name(true, true);
if ($search) {
$a = new stdClass;
$a->contextname = $contextname;
$a->search = $search;
return get_string('usersfrommatching', 'core_role', $a);
} else {
return get_string('usersfrom', 'core_role', $contextname);
}
}
}
@@ -0,0 +1,122 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* override permissions table.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class core_role_override_permissions_table_advanced extends core_role_capability_table_with_risks {
protected $strnotset;
protected $haslockedcapabilities = false;
/**
* Constructor.
*
* This method loads loads all the information about the current state of
* the overrides, then updates that based on any submitted data. It also
* works out which capabilities should be locked for this user.
*
* @param object $context the context this table relates to.
* @param integer $roleid the role being overridden.
* @param boolean $safeoverridesonly If true, the user is only allowed to override
* capabilities with no risks.
*/
public function __construct($context, $roleid, $safeoverridesonly) {
parent::__construct($context, 'overriderolestable', $roleid);
$this->displaypermissions = $this->allpermissions;
$this->strnotset = get_string('notset', 'core_role');
// Determine which capabilities should be locked.
if ($safeoverridesonly) {
foreach ($this->capabilities as $capid => $cap) {
if (!is_safe_capability($cap)) {
$this->capabilities[$capid]->locked = true;
$this->haslockedcapabilities = true;
}
}
}
}
/**
* This method adds an additional class to a row if capability is other than inherited.
*
* @param stdClass $capability
* @return array
*/
protected function get_row_attributes($capability) {
$rowattributes = parent::get_row_attributes($capability);
if ($this->permissions[$capability->name] !== 0) {
if (empty($rowattributes['class'])) {
$rowattributes['class'] = "overriddenpermission table-warning";
} else {
$rowattributes['class'] .= " overriddenpermission table-warning";
}
}
return $rowattributes;
}
protected function load_parent_permissions() {
// Get the capabilities from the parent context, so that can be shown in the interface.
$parentcontext = $this->context->get_parent_context();
$this->parentpermissions = role_context_capabilities($this->roleid, $parentcontext);
}
public function has_locked_capabilities() {
return $this->haslockedcapabilities;
}
protected function add_permission_cells($capability) {
$disabled = '';
if ($capability->locked || $this->parentpermissions[$capability->name] == CAP_PROHIBIT) {
$disabled = ' disabled="disabled"';
}
// One cell for each possible permission.
$content = '';
foreach ($this->displaypermissions as $perm => $permname) {
$strperm = $this->strperms[$permname];
$extraclass = '';
if ($perm != CAP_INHERIT && $perm == $this->parentpermissions[$capability->name]) {
$extraclass = ' capcurrent';
}
$checked = '';
if ($this->permissions[$capability->name] == $perm) {
$checked = 'checked="checked" ';
}
$content .= '<td class="' . $permname . $extraclass . '">';
$content .= '<label><input type="radio" name="' . $capability->name .
'" value="' . $perm . '" ' . $checked . $disabled . '/> ';
if ($perm == CAP_INHERIT) {
$inherited = $this->parentpermissions[$capability->name];
if ($inherited == CAP_INHERIT) {
$inherited = $this->strnotset;
} else {
$inherited = $this->strperms[$this->allpermissions[$inherited]];
}
$strperm .= ' (' . $inherited . ')';
}
$content .= '<span class="note">' . $strperm . '</span>';
$content .= '</label></td>';
}
return $content;
}
}
@@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Allow something form.
*
* @package core_role
* @copyright 2009 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/formslib.php");
class core_role_permission_allow_form extends moodleform {
/**
* Define the form.
*/
protected function definition() {
global $CFG;
$mform = $this->_form;
list($context, $capability, $overridableroles) = $this->_customdata;
list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name);
foreach ($needed as $id => $unused) {
unset($overridableroles[$id]);
}
foreach ($forbidden as $id => $unused) {
unset($overridableroles[$id]);
}
$mform->addElement('header', 'allowheader', get_string('roleallowheader', 'core_role'));
$mform->addElement('select', 'roleid', get_string('roleselect', 'core_role'), $overridableroles);
$mform->addElement('hidden', 'capability');
$mform->setType('capability', PARAM_CAPABILITY);
$mform->setDefault('capability', $capability->name);
$mform->addElement('hidden', 'contextid');
$mform->setType('contextid', PARAM_INT);
$mform->setDefault('contextid', $context->id);
$mform->addElement('hidden', 'allow');
$mform->setType('allow', PARAM_INT);
$mform->setDefault('allow', 1);
$this->add_action_buttons(true, get_string('allow', 'core_role'));
}
}
@@ -0,0 +1,64 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Prohibit something form.
*
* @package core_role
* @copyright 2009 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/formslib.php");
class core_role_permission_prohibit_form extends moodleform {
/**
* Define the form.
*/
protected function definition() {
global $CFG;
$mform = $this->_form;
list($context, $capability, $overridableroles) = $this->_customdata;
list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name);
foreach ($forbidden as $id => $unused) {
unset($overridableroles[$id]);
}
$mform->addElement('header', 'ptohibitheader', get_string('roleprohibitheader', 'core_role'));
$mform->addElement('select', 'roleid', get_string('roleselect', 'core_role'), $overridableroles);
$mform->addElement('hidden', 'capability');
$mform->setType('capability', PARAM_CAPABILITY);
$mform->setDefault('capability', $capability->name);
$mform->addElement('hidden', 'contextid');
$mform->setType('contextid', PARAM_INT);
$mform->setDefault('contextid', $context->id);
$mform->addElement('hidden', 'prohibit');
$mform->setType('prohibit', PARAM_INT);
$mform->setDefault('prohibit', 1);
$this->add_action_buttons(true, get_string('prohibit', 'core_role'));
}
}
+177
View File
@@ -0,0 +1,177 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 2009 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of core_role_capability_table_base for use on the Permissions page.
*/
class core_role_permissions_table extends core_role_capability_table_base {
protected $contextname;
protected $allowoverrides;
protected $allowsafeoverrides;
protected $overridableroles;
protected $roles;
protected $icons = array();
/**
* Constructor.
* @param context $context the context this table relates to.
* @param string $contextname $context->get_context_name() - to save recomputing.
* @param array $allowoverrides
* @param array $allowsafeoverrides
* @param array $overridableroles
*/
public function __construct($context, $contextname, $allowoverrides, $allowsafeoverrides, $overridableroles) {
parent::__construct($context, 'permissions');
$this->contextname = $contextname;
$this->allowoverrides = $allowoverrides;
$this->allowsafeoverrides = $allowsafeoverrides;
$this->overridableroles = $overridableroles;
$roles = get_all_roles($context);
$this->roles = role_fix_names(array_reverse($roles, true), $context, ROLENAME_BOTH, true);
}
protected function add_header_cells() {
echo '<th>' . get_string('risks', 'core_role') . '</th>';
echo '<th>' . get_string('neededroles', 'core_role') . '</th>';
echo '<th>' . get_string('prohibitedroles', 'core_role') . '</th>';
}
protected function num_extra_columns() {
return 3;
}
protected function add_row_cells($capability) {
global $OUTPUT, $PAGE;
$renderer = $PAGE->get_renderer('core');
$adminurl = new moodle_url("/admin/");
$context = $this->context;
$contextid = $this->context->id;
$allowoverrides = $this->allowoverrides;
$allowsafeoverrides = $this->allowsafeoverrides;
$overridableroles = $this->overridableroles;
$roles = $this->roles;
list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name);
$neededroles = array();
$forbiddenroles = array();
$allowable = $overridableroles;
$forbitable = $overridableroles;
foreach ($neededroles as $id => $unused) {
unset($allowable[$id]);
}
foreach ($forbidden as $id => $unused) {
unset($allowable[$id]);
unset($forbitable[$id]);
}
foreach ($roles as $id => $name) {
if (isset($needed[$id])) {
$templatecontext = array("rolename" => $name, "roleid" => $id, "action" => "prevent", "spanclass" => "allowed",
"linkclass" => "preventlink", "adminurl" => $adminurl->out(), "icon" => "", "iconalt" => "");
if (isset($overridableroles[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
$templatecontext['icon'] = 't/delete';
$templatecontext['iconalt'] = get_string('deletexrole', 'core_role', $name);
}
$neededroles[$id] = $renderer->render_from_template('core/permissionmanager_role', $templatecontext);
}
}
$neededroles = implode(' ', $neededroles);
foreach ($roles as $id => $name) {
if (isset($forbidden[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
$templatecontext = array("rolename" => $name, "roleid" => $id, "action" => "unprohibit",
"spanclass" => "forbidden", "linkclass" => "unprohibitlink", "adminurl" => $adminurl->out(),
"icon" => "", "iconalt" => "");
if (isset($overridableroles[$id]) and prohibit_is_removable($id, $context, $capability->name)) {
$templatecontext['icon'] = 't/delete';
$templatecontext['iconalt'] = get_string('deletexrole', 'core_role', $name);
}
$forbiddenroles[$id] = $renderer->render_from_template('core/permissionmanager_role', $templatecontext);
}
}
$forbiddenroles = implode(' ', $forbiddenroles);
if ($allowable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
$allowurl = new moodle_url($PAGE->url, array('contextid' => $contextid,
'capability' => $capability->name, 'allow' => 1));
$allowicon = $OUTPUT->action_icon($allowurl, new pix_icon('t/add', get_string('allow', 'core_role')), null,
array('class' => 'allowlink', 'data-action' => 'allow'));
$neededroles .= html_writer::div($allowicon, 'allowmore');
}
if ($forbitable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
$prohibiturl = new moodle_url($PAGE->url, array('contextid' => $contextid,
'capability' => $capability->name, 'prohibit' => 1));
$prohibiticon = $OUTPUT->action_icon($prohibiturl, new pix_icon('t/add', get_string('prohibit', 'core_role')), null,
array('class' => 'prohibitlink', 'data-action' => 'prohibit'));
$forbiddenroles .= html_writer::div($prohibiticon, 'prohibitmore');
}
$risks = $this->get_risks($capability);
$contents = html_writer::tag('td', $risks, array('class' => 'risks text-nowrap'));
$contents .= html_writer::tag('td', $neededroles, array('class' => 'allowedroles'));
$contents .= html_writer::tag('td', $forbiddenroles, array('class' => 'forbiddenroles'));
return $contents;
}
protected function get_risks($capability) {
global $OUTPUT;
$allrisks = get_all_risks();
$risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'core_role'))));
$return = '';
foreach ($allrisks as $type => $risk) {
if ($risk & (int)$capability->riskbitmask) {
if (!isset($this->icons[$type])) {
$pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
$this->icons[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl));
}
$return .= $this->icons[$type];
}
}
return $return;
}
/**
* Add additional attributes to row
*
* @param stdClass $capability capability that this table row relates to.
* @return array key value pairs of attribute names and values.
*/
protected function get_row_attributes($capability) {
return array(
'data-id' => $capability->id,
'data-name' => $capability->name,
'data-humanname' => get_capability_string($capability->name),
);
}
}
@@ -0,0 +1,87 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* User selector subclass for the list of potential users on the assign roles page,
* when we are assigning in a context below the course level. (CONTEXT_MODULE and
* some CONTEXT_BLOCK).
*
* This returns only enrolled users in this context.
*/
class core_role_potential_assignees_below_course extends core_role_assign_user_selector_base {
public function find_users($search) {
global $DB;
list($enrolsql, $eparams) = get_enrolled_sql($this->context);
// Now we have to go to the database.
list($wherecondition, $params) = $this->search_sql($search, 'u');
$params = array_merge($params, $eparams, $this->userfieldsparams);
if ($wherecondition) {
$wherecondition = ' AND ' . $wherecondition;
}
$fields = 'SELECT u.id, ' . $this->userfieldsselects;
$countfields = 'SELECT COUNT(u.id)';
$sql = " FROM ($enrolsql) enrolled_users_view
JOIN {user} u ON u.id = enrolled_users_view.id
LEFT JOIN {role_assignments} ra ON (ra.userid = enrolled_users_view.id AND
ra.roleid = :roleid AND ra.contextid = :contextid)
$this->userfieldsjoin
WHERE ra.id IS NULL
$wherecondition";
$params['contextid'] = $this->context->id;
$params['roleid'] = $this->roleid;
list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext, $this->userfieldsmappings);
$order = ' ORDER BY ' . $sort;
// Check to see if there are too many to show sensibly.
if (!$this->is_validating()) {
$potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
if ($potentialmemberscount > $this->maxusersperpage) {
return $this->too_many_results($search, $potentialmemberscount);
}
}
// If not, show them.
$availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
if (empty($availableusers)) {
return array();
}
if ($search) {
$groupname = get_string('potusersmatching', 'core_role', $search);
} else {
$groupname = get_string('potusers', 'core_role');
}
return array($groupname => $availableusers);
}
}
@@ -0,0 +1,78 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* User selector subclass for the list of potential users on the assign roles page,
* when we are assigning in a context at or above the course level. In this case we
* show all the users in the system who do not already have the role.
*/
class core_role_potential_assignees_course_and_above extends core_role_assign_user_selector_base {
public function find_users($search) {
global $DB;
list($wherecondition, $params) = $this->search_sql($search, 'u');
$params = array_merge($params, $this->userfieldsparams);
$fields = 'SELECT u.id, ' . $this->userfieldsselects;
$countfields = 'SELECT COUNT(1)';
$sql = " FROM {user} u
$this->userfieldsjoin
WHERE $wherecondition
AND u.id NOT IN (
SELECT r.userid
FROM {role_assignments} r
WHERE r.contextid = :contextid
AND r.roleid = :roleid)";
list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext, $this->userfieldsmappings);
$order = ' ORDER BY ' . $sort;
$params['contextid'] = $this->context->id;
$params['roleid'] = $this->roleid;
if (!$this->is_validating()) {
$potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
if ($potentialmemberscount > $this->maxusersperpage) {
return $this->too_many_results($search, $potentialmemberscount);
}
}
$availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
if (empty($availableusers)) {
return array();
}
if ($search) {
$groupname = get_string('potusersmatching', 'core_role', $search);
} else {
$groupname = get_string('potusers', 'core_role');
}
return array($groupname => $availableusers);
}
}
+323
View File
@@ -0,0 +1,323 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* New role XML processing.
*
* @package core_role
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* XML role file manipulation class.
*
* @package core_role
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_role_preset {
/**
* Send role export xml file to browser.
*
* @param int $roleid
* @return void does not return, send the file to output
*/
public static function send_export_xml($roleid) {
global $CFG, $DB;
require_once($CFG->libdir . '/filelib.php');
$role = $DB->get_record('role', array('id'=>$roleid), '*', MUST_EXIST);
if ($role->shortname) {
$filename = $role->shortname.'.xml';
} else {
$filename = 'role.xml';
}
$xml = self::get_export_xml($roleid);
send_file($xml, $filename, 0, false, true, true);
die();
}
/**
* Generate role export xml file.
*
* @param $roleid
* @return string
*/
public static function get_export_xml($roleid) {
global $DB;
$role = $DB->get_record('role', array('id'=>$roleid), '*', MUST_EXIST);
$dom = new DOMDocument('1.0', 'UTF-8');
$top = $dom->createElement('role');
$dom->appendChild($top);
$top->appendChild($dom->createElement('shortname', $role->shortname));
$top->appendChild($dom->createElement('name', htmlspecialchars($role->name, ENT_COMPAT | ENT_HTML401, 'UTF-8')));
$top->appendChild($dom->createElement('description', htmlspecialchars($role->description, ENT_COMPAT | ENT_HTML401,
'UTF-8')));
$top->appendChild($dom->createElement('archetype', $role->archetype));
$contextlevels = $dom->createElement('contextlevels');
$top->appendChild($contextlevels);
foreach (get_role_contextlevels($roleid) as $level) {
$name = context_helper::get_class_for_level($level);
if (strpos($name, 'core\\context\\') === 0) {
// Use short names of standard contexts for backwards compatibility.
$value = preg_replace('/^core\\\\context\\\\/', '', $name);
} else {
// Must be a custom plugin level, use numbers to work around
// potential duplicate short names of contexts in add-ons.
$value = $level;
}
$contextlevels->appendChild($dom->createElement('level', $value));
}
foreach (array('assign', 'override', 'switch', 'view') as $type) {
$allows = $dom->createElement('allow'.$type);
$top->appendChild($allows);
$records = $DB->get_records('role_allow_'.$type, array('roleid'=>$roleid), "allow$type ASC");
foreach ($records as $record) {
if (!$ar = $DB->get_record('role', array('id'=>$record->{'allow'.$type}))) {
continue;
}
$allows->appendChild($dom->createElement('shortname', $ar->shortname));
}
}
$permissions = $dom->createElement('permissions');
$top->appendChild($permissions);
$capabilities = $DB->get_records_sql_menu(
"SELECT capability, permission
FROM {role_capabilities}
WHERE contextid = :syscontext AND roleid = :roleid
ORDER BY capability ASC",
array('syscontext'=>context_system::instance()->id, 'roleid'=>$roleid));
$allcapabilities = $DB->get_records('capabilities', array(), 'name ASC');
foreach ($allcapabilities as $cap) {
if (!isset($capabilities[$cap->name])) {
$permissions->appendChild($dom->createElement('inherit', $cap->name));
}
}
foreach ($capabilities as $capability => $permission) {
if ($permission == CAP_ALLOW) {
$permissions->appendChild($dom->createElement('allow', $capability));
}
}
foreach ($capabilities as $capability => $permission) {
if ($permission == CAP_PREVENT) {
$permissions->appendChild($dom->createElement('prevent', $capability));
}
}
foreach ($capabilities as $capability => $permission) {
if ($permission == CAP_PROHIBIT) {
$permissions->appendChild($dom->createElement('prohibit', $capability));
}
}
return $dom->saveXML();
}
/**
* Is this XML valid role preset?
*
* @param string $xml
* @return bool
*/
public static function is_valid_preset($xml) {
$dom = new DOMDocument();
if (!$dom->loadXML($xml)) {
return false;
} else {
$val = @$dom->schemaValidate(__DIR__.'/../role_schema.xml');
if (!$val) {
return false;
}
}
return true;
}
/**
* Parse role preset xml file.
*
* @param string $xml
* @return array role info, null on error
*/
public static function parse_preset($xml) {
global $DB;
$info = array();
if (!self::is_valid_preset($xml)) {
return null;
}
$dom = new DOMDocument();
$dom->loadXML($xml);
$info['shortname'] = self::get_node_value($dom, '/role/shortname');
if (isset($info['shortname'])) {
$info['shortname'] = strtolower(clean_param($info['shortname'], PARAM_ALPHANUMEXT));
}
$info['name'] = self::get_node_value($dom, '/role/name');
if (isset($value)) {
$info['name'] = clean_param($info['name'], PARAM_TEXT);
}
$info['description'] = self::get_node_value($dom, '/role/description');
if (isset($value)) {
$info['description'] = clean_param($info['description'], PARAM_CLEANHTML);
}
$info['archetype'] = self::get_node_value($dom, '/role/archetype');
if (isset($value)) {
$archetypes = get_role_archetypes();
if (!isset($archetypes[$info['archetype']])) {
$info['archetype'] = null;
}
}
$values = self::get_node_children_values($dom, '/role/contextlevels', 'level');
if (isset($values)) {
$info['contextlevels'] = array();
$levelmap = array_flip(context_helper::get_all_levels());
foreach ($values as $value) {
// Numbers and short names are supported since Moodle 4.2.
$classname = \core\context_helper::parse_external_level($value);
if ($classname) {
$cl = $classname::LEVEL;
$info['contextlevels'][$cl] = $cl;
}
}
}
foreach (array('assign', 'override', 'switch', 'view') as $type) {
$values = self::get_node_children_values($dom, '/role/allow'.$type, 'shortname');
if (!isset($values)) {
$info['allow'.$type] = null;
continue;
}
$info['allow'.$type] = array();
foreach ($values as $value) {
if ($value === $info['shortname']) {
array_unshift($info['allow'.$type], -1); // Means self.
}
if ($role = $DB->get_record('role', array('shortname'=>$value))) {
$info['allow'.$type][] = $role->id;
continue;
}
}
}
$info['permissions'] = array();
$values = self::get_node_children_values($dom, '/role/permissions', 'inherit');
if (isset($values)) {
foreach ($values as $value) {
if ($value = clean_param($value, PARAM_CAPABILITY)) {
$info['permissions'][$value] = CAP_INHERIT;
}
}
}
$values = self::get_node_children_values($dom, '/role/permissions', 'allow');
if (isset($values)) {
foreach ($values as $value) {
if ($value = clean_param($value, PARAM_CAPABILITY)) {
$info['permissions'][$value] = CAP_ALLOW;
}
}
}
$values = self::get_node_children_values($dom, '/role/permissions', 'prevent');
if (isset($values)) {
foreach ($values as $value) {
if ($value = clean_param($value, PARAM_CAPABILITY)) {
$info['permissions'][$value] = CAP_PREVENT;
}
}
}
$values = self::get_node_children_values($dom, '/role/permissions', 'prohibit');
if (isset($values)) {
foreach ($values as $value) {
if ($value = clean_param($value, PARAM_CAPABILITY)) {
$info['permissions'][$value] = CAP_PROHIBIT;
}
}
}
return $info;
}
protected static function get_node(DOMDocument $dom, $path) {
$parts = explode('/', $path);
$elname = end($parts);
$nodes = $dom->getElementsByTagName($elname);
if ($nodes->length == 0) {
return null;
}
foreach ($nodes as $node) {
if ($node->getNodePath() === $path) {
return $node;
}
}
return null;
}
protected static function get_node_value(DOMDocument $dom, $path) {
if (!$node = self::get_node($dom, $path)) {
return null;
}
return $node->nodeValue;
}
protected static function get_node_children(DOMDocument $dom, $path, $tagname) {
if (!$node = self::get_node($dom, $path)) {
return null;
}
$return = array();
foreach ($node->childNodes as $child) {
if ($child->nodeName === $tagname) {
$return[] = $child;
}
}
return $return;
}
protected static function get_node_children_values(DOMDocument $dom, $path, $tagname) {
$children = self::get_node_children($dom, $path, $tagname);
if ($children === null) {
return null;
}
$return = array();
foreach ($children as $child) {
$return[] = $child->nodeValue;
}
return $return;
}
}
+121
View File
@@ -0,0 +1,121 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Role add/reset selection form.
*
* @package core_role
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/formslib.php");
/**
* Role add/reset selection form.
*
* @package core_role
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_role_preset_form extends moodleform {
/**
* Definition of this form.
*/
protected function definition() {
$mform = $this->_form;
$data = $this->_customdata;
$options = array();
$group = get_string('other');
$options[$group] = array();
$options[$group][0] = get_string('norole', 'core_role');
$group = get_string('role', 'core');
$options[$group] = array();
foreach (role_get_names(null, ROLENAME_BOTH) as $role) {
// Allow reset to self too, it may be useful when importing incomplete XML preset.
$options[$group][$role->id] = $role->localname;
}
$group = get_string('archetype', 'core_role');
$options[$group] = array();
foreach (get_role_archetypes() as $type) {
$options[$group][$type] = get_string('archetype'.$type, 'core_role');
}
$mform->addElement('header', 'presetheader', get_string('roleresetdefaults', 'core_role'));
$mform->addElement('selectgroups', 'resettype', get_string('roleresetrole', 'core_role'), $options);
$mform->addElement('filepicker', 'rolepreset', get_string('rolerepreset', 'core_role'));
if ($data['roleid']) {
$mform->addElement('header', 'resetheader', get_string('resetrole', 'core_role'));
$mform->addElement('advcheckbox', 'shortname', get_string('roleshortname', 'core_role'));
$mform->addElement('advcheckbox', 'name', get_string('customrolename', 'core_role'));
$mform->addElement('advcheckbox', 'description', get_string('customroledescription', 'core_role'));
$mform->addElement('advcheckbox', 'archetype', get_string('archetype', 'core_role'));
$mform->addElement('advcheckbox', 'contextlevels', get_string('maybeassignedin', 'core_role'));
$mform->addElement('advcheckbox', 'allowassign', get_string('allowassign', 'core_role'));
$mform->addElement('advcheckbox', 'allowoverride', get_string('allowoverride', 'core_role'));
$mform->addElement('advcheckbox', 'allowswitch', get_string('allowswitch', 'core_role'));
$mform->addElement('advcheckbox', 'allowview', get_string('allowview', 'core_role'));
$mform->addElement('advcheckbox', 'permissions', get_string('permissions', 'core_role'));
}
$mform->addElement('hidden', 'roleid');
$mform->setType('roleid', PARAM_INT);
$mform->addElement('hidden', 'action');
$mform->setType('action', PARAM_ALPHA);
$mform->addElement('hidden', 'return');
$mform->setType('return', PARAM_ALPHA);
$this->add_action_buttons(true, get_string('continue', 'core'));
$this->set_data($data);
}
/**
* Validate this form.
*
* @param array $data submitted data
* @param array $files not used
* @return array errors
*/
public function validation($data, $files) {
$errors = parent::validation($data, $files);
if ($files = $this->get_draft_files('rolepreset')) {
/** @var stored_file $file */
$file = reset($files);
$xml = $file->get_content();
if (!core_role_preset::is_valid_preset($xml)) {
$errors['rolepreset'] = get_string('invalidpresetfile', 'core_role');
}
}
return $errors;
}
}
+459
View File
@@ -0,0 +1,459 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for core_role.
*
* @package core_role
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_role\privacy;
defined('MOODLE_INTERNAL') || die();
use \core_privacy\local\metadata\collection;
use \core_privacy\local\request\contextlist;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\transform;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\userlist;
use \core_privacy\local\request\approved_userlist;
/**
* Privacy provider for core_role.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\provider,
\core_privacy\local\request\subsystem\plugin_provider,
\core_privacy\local\request\user_preference_provider,
\core_privacy\local\request\core_userlist_provider {
/**
* Get information about the user data stored by this plugin.
*
* @param collection $collection An object for storing metadata.
* @return collection The metadata.
*/
public static function get_metadata(collection $collection): collection {
$rolecapabilities = [
'roleid' => 'privacy:metadata:role_capabilities:roleid',
'capability' => 'privacy:metadata:role_capabilities:capability',
'permission' => 'privacy:metadata:role_capabilities:permission',
'timemodified' => 'privacy:metadata:role_capabilities:timemodified',
'modifierid' => 'privacy:metadata:role_capabilities:modifierid'
];
$roleassignments = [
'roleid' => 'privacy:metadata:role_assignments:roleid',
'userid' => 'privacy:metadata:role_assignments:userid',
'timemodified' => 'privacy:metadata:role_assignments:timemodified',
'modifierid' => 'privacy:metadata:role_assignments:modifierid',
'component' => 'privacy:metadata:role_assignments:component',
'itemid' => 'privacy:metadata:role_assignments:itemid'
];
$collection->add_database_table('role_capabilities', $rolecapabilities,
'privacy:metadata:role_capabilities:tableexplanation');
$collection->add_database_table('role_assignments', $roleassignments,
'privacy:metadata:role_assignments:tableexplanation');
$collection->add_user_preference('definerole_showadvanced',
'privacy:metadata:preference:showadvanced');
return $collection;
}
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$showadvanced = get_user_preferences('definerole_showadvanced', null, $userid);
if ($showadvanced !== null) {
writer::export_user_preference('core_role',
'definerole_showadvanced',
transform::yesno($showadvanced),
get_string('privacy:metadata:preference:showadvanced', 'core_role')
);
}
}
/**
* Return all contexts for this userid.
*
* @param int $userid The user ID.
* @return contextlist The list of context IDs.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
global $DB;
$contextlist = new contextlist();
// The role_capabilities table contains user data.
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$sql = "SELECT ctx.id
FROM {context} ctx
JOIN {role_capabilities} rc
ON rc.contextid = ctx.id
AND ((ctx.contextlevel {$insql} AND rc.modifierid = :modifierid)
OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))";
$params = [
'modifierid' => $userid,
'contextlevel' => CONTEXT_USER,
'userid' => $userid
];
$params += $inparams;
$contextlist->add_from_sql($sql, $params);
// The role_assignments table contains user data.
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$params = [
'userid' => $userid,
'modifierid' => $userid
];
$params += $inparams;
$sql = "SELECT ctx.id
FROM {role_assignments} ra
JOIN {context} ctx
ON ctx.id = ra.contextid
AND ctx.contextlevel {$insql}
WHERE (ra.userid = :userid
OR ra.modifierid = :modifierid)
AND ra.component != 'tool_cohortroles'";
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users within a specific context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
if (empty($userlist)) {
return;
}
$context = $userlist->get_context();
// Include users who created or modified role capabilities.
$sql = "SELECT modifierid as userid
FROM {role_capabilities}
WHERE contextid = :contextid";
$params = [
'contextid' => $context->id
];
$userlist->add_from_sql('userid', $sql, $params);
// Include users that have a role assigned to them.
$sql = "SELECT userid
FROM {role_assignments}
WHERE contextid = :contextid";
$userlist->add_from_sql('userid', $sql, $params);
// Include users who created or modified the role assignment.
// Differentiate and exclude special cases where tool_cohortroles adds records through the
// "Assign user roles to cohort" feature into the role_assignments table.
// These records should be separately processed in tool_cohortroles.
$sql = "SELECT modifierid as userid
FROM {role_assignments}
WHERE contextid = :contextid
AND component != 'tool_cohortroles'";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The list of approved contexts for a user.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
if (empty($contextlist)) {
return;
}
$rolesnames = self::get_roles_name();
$userid = $contextlist->get_user()->id;
$ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
// Role Assignments export data.
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, $ctxfields
FROM {role_assignments} ra
JOIN {context} ctx
ON ctx.id = ra.contextid
AND ctx.contextlevel {$inctxsql}
AND (ra.userid = :userid OR ra.modifierid = :modifierid)
AND ra.component != 'tool_cohortroles'
JOIN {role} r
ON r.id = ra.roleid
WHERE ctx.id {$insql}";
$params = ['userid' => $userid, 'modifierid' => $userid];
$params += $inparams;
$params += $ctxparams;
$assignments = $DB->get_recordset_sql($sql, $params);
foreach ($assignments as $assignment) {
\context_helper::preload_from_record($assignment);
$alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
'timemodified' => transform::datetime($assignment->timemodified),
'userid' => transform::user($assignment->userid),
'modifierid' => transform::user($assignment->modifierid)
];
}
$assignments->close();
if (!empty($alldata)) {
array_walk($alldata, function($roledata, $contextid) {
$context = \context::instance_by_id($contextid);
array_walk($roledata, function($data, $rolename) use ($context) {
writer::with_context($context)->export_data(
[get_string('privacy:metadata:role_assignments', 'core_role'), $rolename],
(object)$data);
});
});
unset($alldata);
}
// Role Capabilities export data.
$strpermissions = self::get_permissions_name();
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$sql = "SELECT rc.id, rc.contextid, rc.capability, rc.permission, rc.timemodified, rc.roleid, $ctxfields
FROM {context} ctx
JOIN {role_capabilities} rc
ON rc.contextid = ctx.id
AND ((ctx.contextlevel {$inctxsql} AND rc.modifierid = :modifierid)
OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))
WHERE ctx.id {$insql}";
$params = [
'modifierid' => $userid,
'contextlevel' => CONTEXT_USER,
'userid' => $userid
];
$params += $inparams;
$params += $ctxparams;
$capabilities = $DB->get_recordset_sql($sql, $params);
foreach ($capabilities as $capability) {
\context_helper::preload_from_record($capability);
$alldata[$capability->contextid][$rolesnames[$capability->roleid]][] = (object)[
'timemodified' => transform::datetime($capability->timemodified),
'capability' => $capability->capability,
'permission' => $strpermissions[$capability->permission]
];
}
$capabilities->close();
if (!empty($alldata)) {
array_walk($alldata, function($capdata, $contextid) {
$context = \context::instance_by_id($contextid);
array_walk($capdata, function($data, $rolename) use ($context) {
writer::with_context($context)->export_data(
[get_string('privacy:metadata:role_capabilities', 'core_role'), $rolename],
(object)$data);
});
});
}
}
/**
* Exports the data relating to tool_cohortroles component on role assignments by
* Assign user roles to cohort feature.
*
* @param int $userid The user ID.
*/
public static function export_user_role_to_cohort(int $userid) {
global $DB;
$rolesnames = self::get_roles_name();
$sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, r.id as roleid
FROM {role_assignments} ra
JOIN {context} ctx
ON ctx.id = ra.contextid
AND ctx.contextlevel = :contextlevel
AND ra.component = 'tool_cohortroles'
JOIN {role} r
ON r.id = ra.roleid
WHERE ctx.instanceid = :instanceid
OR ra.userid = :userid";
$params = ['userid' => $userid, 'instanceid' => $userid, 'contextlevel' => CONTEXT_USER];
$assignments = $DB->get_recordset_sql($sql, $params);
foreach ($assignments as $assignment) {
$alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
'timemodified' => transform::datetime($assignment->timemodified),
'userid' => transform::user($assignment->userid),
'modifierid' => transform::user($assignment->modifierid)
];
}
$assignments->close();
if (!empty($alldata)) {
array_walk($alldata, function($roledata, $contextid) {
$context = \context::instance_by_id($contextid);
array_walk($roledata, function($data, $rolename) use ($context) {
writer::with_context($context)->export_related_data(
[get_string('privacy:metadata:role_cohortroles', 'core_role'), $rolename], 'cohortroles',
(object)$data);
});
});
}
}
/**
* Delete all user data for this context.
*
* @param \context $context The context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
// Don't remove data from role_capabilities.
// Because this data affects the whole Moodle, there are override capabilities.
// Don't belong to the modifier user.
// Remove data from role_assignments.
$DB->delete_records('role_assignments', ['contextid' => $context->id]);
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
// Don't remove data from role_capabilities.
// Because this data affects the whole Moodle, there are override capabilities.
// Don't belong to the modifier user.
$context = $userlist->get_context();
$userids = $userlist->get_userids();
if (empty($userids)) {
return;
}
list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$params = ['contextid' => $context->id] + $userparams;
// Remove data from role_assignments.
$DB->delete_records_select('role_assignments',
"contextid = :contextid AND userid {$usersql}", $params);
}
/**
* Delete all user data for this user only.
*
* @param approved_contextlist $contextlist The list of approved contexts for a user.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
// Don't remove data from role_capabilities.
// Because this data affects the whole Moodle, there are override capabilities.
// Don't belong to the modifier user.
// Remove data from role_assignments.
if (empty($contextlist->count())) {
return;
}
$userid = $contextlist->get_user()->id;
$contextids = $contextlist->get_contextids();
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
$params = ['userid' => $userid] + $contextparams;
// Only delete the roles assignments where the user is assigned in all contexts.
$DB->delete_records_select('role_assignments',
"userid = :userid AND contextid {$contextsql}", $params);
}
/**
* Delete user entries in role_assignments related to the feature
* Assign user roles to cohort feature.
*
* @param int $userid The user ID.
*/
public static function delete_user_role_to_cohort(int $userid) {
global $DB;
// Delete entries where userid is a mentor by tool_cohortroles.
$DB->delete_records('role_assignments', ['userid' => $userid, 'component' => 'tool_cohortroles']);
}
/**
* Get all the localised roles name in a simple array.
*
* @return array Array of name of the roles by roleid.
*/
protected static function get_roles_name() {
$roles = role_fix_names(get_all_roles(), \context_system::instance(), ROLENAME_ORIGINAL);
$rolesnames = array();
foreach ($roles as $role) {
$rolesnames[$role->id] = $role->localname;
}
return $rolesnames;
}
/**
* Get all the permissions name in a simple array.
*
* @return array Array of permissions name.
*/
protected static function get_permissions_name() {
$strpermissions = array(
CAP_INHERIT => get_string('inherit', 'role'),
CAP_ALLOW => get_string('allow', 'role'),
CAP_PREVENT => get_string('prevent', 'role'),
CAP_PROHIBIT => get_string('prohibit', 'role')
);
return $strpermissions;
}
}
@@ -0,0 +1,124 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\datasource;
use core\reportbuilder\local\entities\context;
use core_reportbuilder\datasource;
use core_reportbuilder\local\entities\user;
use core_role\reportbuilder\local\entities\{role, role_assignment};
/**
* Roles datasource
*
* @package core_role
* @copyright 2024 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class roles extends datasource {
/**
* Return user friendly name of the report source
*
* @return string
*/
public static function get_name(): string {
return get_string('roles', 'core_role');
}
/**
* Initialise report
*/
protected function initialise(): void {
$contextentity = new context();
$contextalias = $contextentity->get_table_alias('context');
$roleentity = new role();
$rolealias = $roleentity->get_table_alias('role');
// Role table.
$this->add_entity($roleentity->set_table_alias('context', $contextalias));
$this->set_main_table('role', $rolealias);
// Join role assignments.
$roleassignmententity = new role_assignment();
$roleassignmentalias = $roleassignmententity->get_table_alias('role_assignments');
$this->add_entity($roleassignmententity);
$this->add_join("JOIN {role_assignments} {$roleassignmentalias} ON {$roleassignmentalias}.roleid = {$rolealias}.id");
// Join context.
$this->add_entity($contextentity);
$this->add_join("LEFT JOIN {context} {$contextalias} ON {$contextalias}.id = {$roleassignmentalias}.contextid");
// Join user.
$userentity = new user();
$useralias = $userentity->get_table_alias('user');
$this->add_entity($userentity
->add_join("LEFT JOIN {user} {$useralias} ON {$useralias}.id = {$roleassignmentalias}.userid"));
$this->add_all_from_entities();
}
/**
* Return the columns that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_columns(): array {
return [
'context:link',
'role:originalname',
'user:fullnamewithlink',
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'context:link' => SORT_ASC,
'role:originalname' => SORT_ASC,
'user:fullnamewithlink' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_filters(): array {
return [
'context:level',
'role:name',
'user:fullname',
];
}
/**
* Return the conditions that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_conditions(): array {
return [];
}
}
@@ -0,0 +1,203 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\local\entities;
use context;
use context_helper;
use lang_string;
use stdClass;
use core_reportbuilder\local\entities\base;
use core_reportbuilder\local\filters\select;
use core_reportbuilder\local\report\{column, filter};
/**
* Role entity
*
* @package core_role
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class role extends base {
/**
* Database tables that this entity uses
*
* @return string[]
*/
protected function get_default_tables(): array {
return [
'context',
'role',
];
}
/**
* The default title for this entity
*
* @return lang_string
*/
protected function get_default_entity_title(): lang_string {
return new lang_string('role');
}
/**
* Initialise the entity
*
* @return base
*/
public function initialise(): base {
$columns = $this->get_all_columns();
foreach ($columns as $column) {
$this->add_column($column);
}
// All the filters defined by the entity can also be used as conditions.
$filters = $this->get_all_filters();
foreach ($filters as $filter) {
$this
->add_filter($filter)
->add_condition($filter);
}
return $this;
}
/**
* Returns list of all available columns
*
* @return column[]
*/
protected function get_all_columns(): array {
global $DB;
$contextalias = $this->get_table_alias('context');
$rolealias = $this->get_table_alias('role');
// Name column.
$columns[] = (new column(
'name',
new lang_string('rolefullname', 'core_role'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$rolealias}.name, {$rolealias}.shortname, {$rolealias}.id, {$contextalias}.id AS contextid")
->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
->set_is_sortable(true, [
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
THEN {$rolealias}.shortname
ELSE {$rolealias}.name
END",
])
->set_callback(static function($name, stdClass $role): string {
if ($name === null) {
return '';
}
context_helper::preload_from_record($role);
$context = context::instance_by_id($role->contextid);
return role_get_name($role, $context, ROLENAME_BOTH);
});
// Original name column.
$columns[] = (new column(
'originalname',
new lang_string('roleoriginalname', 'core_role'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$rolealias}.name, {$rolealias}.shortname")
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
->set_is_sortable(true, [
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
THEN {$rolealias}.shortname
ELSE {$rolealias}.name
END",
])
->set_callback(static function($name, stdClass $role): string {
if ($name === null) {
return '';
}
return role_get_name($role, null, ROLENAME_ORIGINAL);
});
// Short name column.
$columns[] = (new column(
'shortname',
new lang_string('roleshortname', 'core_role'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$rolealias}.shortname")
->set_is_sortable(true);
// Description column.
$descriptionfieldsql = "{$rolealias}.description";
if ($DB->get_dbfamily() === 'oracle') {
$descriptionfieldsql = $DB->sql_order_by_text($descriptionfieldsql, 1024);
}
$columns[] = (new column(
'description',
new lang_string('description'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_LONGTEXT)
->add_field($descriptionfieldsql, 'description')
->add_field("{$rolealias}.shortname")
->set_callback(static function($description, stdClass $role): string {
if ($description === null) {
return '';
}
return role_get_description($role);
});
return $columns;
}
/**
* Return list of all available filters
*
* @return filter[]
*/
protected function get_all_filters(): array {
$rolealias = $this->get_table_alias('role');
// Name filter.
$filters[] = (new filter(
select::class,
'name',
new lang_string('rolefullname', 'core_role'),
$this->get_entity_name(),
"{$rolealias}.id"
))
->add_joins($this->get_joins())
->set_options_callback(static function(): array {
return role_get_names(null, ROLENAME_ORIGINAL, true);
});
return $filters;
}
}
@@ -0,0 +1,143 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\local\entities;
use lang_string;
use core_reportbuilder\local\entities\base;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\helpers\format;
use core_reportbuilder\local\report\{column, filter};
/**
* Role assignment entity
*
* @package core_role
* @copyright 2024 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class role_assignment extends base {
/**
* Database tables that this entity uses
*
* @return string[]
*/
protected function get_default_tables(): array {
return [
'role_assignments',
];
}
/**
* The default title for this entity
*
* @return lang_string
*/
protected function get_default_entity_title(): lang_string {
return new lang_string('roleassignment', 'core_role');
}
/**
* Initialise the entity
*
* @return base
*/
public function initialise(): base {
$columns = $this->get_all_columns();
foreach ($columns as $column) {
$this->add_column($column);
}
// All the filters defined by the entity can also be used as conditions.
$filters = $this->get_all_filters();
foreach ($filters as $filter) {
$this
->add_filter($filter)
->add_condition($filter);
}
return $this;
}
/**
* Returns list of all available columns
*
* @return column[]
*/
protected function get_all_columns(): array {
$raalias = $this->get_table_alias('role_assignments');
// Time modified column.
$columns[] = (new column(
'timemodified',
new lang_string('timemodified', 'core_reportbuilder'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TIMESTAMP)
->add_field("{$raalias}.timemodified")
->set_is_sortable(true)
->set_callback([format::class, 'userdate']);
// Component column.
$columns[] = (new column(
'component',
new lang_string('plugin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_field("{$raalias}.component")
->set_is_sortable(true);
// Item ID column.
$columns[] = (new column(
'itemid',
new lang_string('pluginitemid'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_field("{$raalias}.itemid")
->set_is_sortable(true);
return $columns;
}
/**
* Return list of all available filters
*
* @return filter[]
*/
protected function get_all_filters(): array {
$raalias = $this->get_table_alias('role_assignments');
// Time modified filter.
$filters[] = (new filter(
date::class,
'timemodified',
new lang_string('timemodified', 'core_reportbuilder'),
$this->get_entity_name(),
"{$raalias}.timemodified"
))
->add_joins($this->get_joins());
return $filters;
}
}
@@ -0,0 +1,136 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library code used by the roles administration interfaces.
*
* @package core_role
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class core_role_view_role_definition_table extends core_role_define_role_table_advanced {
public function __construct($context, $roleid) {
parent::__construct($context, $roleid);
$this->displaypermissions = array(CAP_ALLOW => $this->allpermissions[CAP_ALLOW]);
$this->disabled = 'disabled="disabled" ';
}
public function save_changes() {
throw new moodle_exception('invalidaccess');
}
protected function get_name_field($id) {
return role_get_name($this->role);
}
protected function get_shortname_field($id) {
return $this->role->shortname;
}
protected function get_description_field($id) {
return role_get_description($this->role);
}
protected function get_archetype_field($id) {
if (empty($this->role->archetype)) {
return get_string('none');
} else {
return get_string('archetype'.$this->role->archetype, 'core_role');
}
}
protected function get_allow_role_control($type) {
if ($roles = $this->get_allow_roles_list($type)) {
$roles = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
return implode(', ', $roles);
} else {
return get_string('none');
}
}
protected function print_show_hide_advanced_button() {
// Do nothing.
}
/**
* Returns HTML risk icons.
*
* @return string
*/
protected function get_role_risks_info() {
global $OUTPUT;
if (empty($this->roleid)) {
return '';
}
$risks = array();
$allrisks = get_all_risks();
foreach ($this->capabilities as $capability) {
$perm = $this->permissions[$capability->name];
if ($perm != CAP_ALLOW) {
continue;
}
foreach ($allrisks as $type => $risk) {
if ($risk & (int)$capability->riskbitmask) {
$risks[$type] = $risk;
}
}
}
$risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'core_role'))));
foreach ($risks as $type => $risk) {
$pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
$risks[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl));
}
return implode(' ', $risks);
}
/**
* Returns true if the row should be skipped.
*
* @param string $capability
* @return bool
*/
protected function skip_row($capability) {
$perm = $this->permissions[$capability->name];
if ($perm == CAP_INHERIT) {
// Do not print empty rows in role overview, admins need to know quickly what is allowed and prohibited,
// if they want to see the list of all capabilities they can go to edit role page.
return true;
}
parent::skip_row($capability);
}
protected function add_permission_cells($capability) {
$perm = $this->permissions[$capability->name];
$permname = $this->allpermissions[$perm];
$defaultperm = $this->allpermissions[$this->parentpermissions[$capability->name]];
if ($permname != $defaultperm) {
$default = get_string('defaultx', 'core_role', $this->strperms[$defaultperm]);
} else {
$default = "&#xa0;";
}
return '<td class="' . $permname . '">' . $this->strperms[$permname] . '<span class="note">' .
$default . '</span></td>';
}
}