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
+10
View File
@@ -0,0 +1,10 @@
define("tool_capability/search",["exports","core/pending","core/utils"],(function(_exports,_pending,_utils){var obj;
/**
* Add search filtering of capabilities
*
* @module tool_capability/search
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};const Selectors_capabilityOverviewForm="#capability-overview-form",Selectors_capabilitySelect='[data-search="capability"]',Selectors_capabilitySearch='[data-action="search"]';_exports.init=()=>{const capabilityOverviewForm=document.querySelector(Selectors_capabilityOverviewForm);if(!capabilityOverviewForm)return;const capabilitySelect=capabilityOverviewForm.querySelector(Selectors_capabilitySelect),capabilitySearch=capabilityOverviewForm.querySelector(Selectors_capabilitySearch),capabilitySelectFilter=searchTerm=>{const pendingPromise=new _pending.default("tool_capability/search:filter");let capabilitySelected=[];capabilitySelect.querySelectorAll("option").forEach((option=>{option.selected&&capabilitySelected.push(option.value),option.remove()}));const availableCapabilities=JSON.parse(capabilitySelect.dataset.availableCapabilities),filteredCapabilities=Object.keys(availableCapabilities).reduce(((matches,capability)=>(availableCapabilities[capability].toLowerCase().includes(searchTerm)&&(matches[capability]=availableCapabilities[capability]),matches)),[]);Object.entries(filteredCapabilities).forEach((_ref=>{let[capability,capabilityText]=_ref;const option=document.createElement("option");option.value=capability,option.innerText=capabilityText,option.selected=capabilitySelected.indexOf(capability)>-1,capabilitySelect.append(option)})),pendingPromise.resolve()},availableCapabilities={};capabilitySelect.querySelectorAll("option").forEach((option=>{availableCapabilities[option.value]=option.text})),capabilitySelect.dataset.availableCapabilities=JSON.stringify(availableCapabilities);const capabilitySearchDebounce=(0,_utils.debounce)(capabilitySelectFilter,250);capabilitySearch.addEventListener("keyup",(event=>{const pendingPromise=new _pending.default("tool_capability/search:keyup");capabilitySearchDebounce(event.target.value.toLowerCase()),setTimeout((()=>{pendingPromise.resolve()}),250)})),""!==capabilitySearch.value&&capabilitySelectFilter(capabilitySearch.value.toLowerCase())}}));
//# sourceMappingURL=search.min.js.map
File diff suppressed because one or more lines are too long
+102
View File
@@ -0,0 +1,102 @@
// 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/>.
/**
* Add search filtering of capabilities
*
* @module tool_capability/search
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Pending from 'core/pending';
import {debounce} from 'core/utils';
const Selectors = {
capabilityOverviewForm: '#capability-overview-form',
capabilitySelect: '[data-search="capability"]',
capabilitySearch: '[data-action="search"]',
};
const debounceTimer = 250;
/**
* Initialize module
*/
export const init = () => {
const capabilityOverviewForm = document.querySelector(Selectors.capabilityOverviewForm);
if (!capabilityOverviewForm) {
return;
}
const capabilitySelect = capabilityOverviewForm.querySelector(Selectors.capabilitySelect);
const capabilitySearch = capabilityOverviewForm.querySelector(Selectors.capabilitySearch);
const capabilitySelectFilter = searchTerm => {
const pendingPromise = new Pending('tool_capability/search:filter');
// Remove existing options, remembering which were previously selected.
let capabilitySelected = [];
capabilitySelect.querySelectorAll('option').forEach(option => {
if (option.selected) {
capabilitySelected.push(option.value);
}
option.remove();
});
// Filter for matching capabilities.
const availableCapabilities = JSON.parse(capabilitySelect.dataset.availableCapabilities);
const filteredCapabilities = Object.keys(availableCapabilities).reduce((matches, capability) => {
if (availableCapabilities[capability].toLowerCase().includes(searchTerm)) {
matches[capability] = availableCapabilities[capability];
}
return matches;
}, []);
// Re-create filtered options.
Object.entries(filteredCapabilities).forEach(([capability, capabilityText]) => {
const option = document.createElement('option');
option.value = capability;
option.innerText = capabilityText;
option.selected = capabilitySelected.indexOf(capability) > -1;
capabilitySelect.append(option);
});
pendingPromise.resolve();
};
// Cache initial capability options.
const availableCapabilities = {};
capabilitySelect.querySelectorAll('option').forEach(option => {
availableCapabilities[option.value] = option.text;
});
capabilitySelect.dataset.availableCapabilities = JSON.stringify(availableCapabilities);
// Debounce the event listener on the search element to allow user to finish typing.
const capabilitySearchDebounce = debounce(capabilitySelectFilter, debounceTimer);
capabilitySearch.addEventListener('keyup', event => {
const pendingPromise = new Pending('tool_capability/search:keyup');
capabilitySearchDebounce(event.target.value.toLowerCase());
setTimeout(() => {
pendingPromise.resolve();
}, debounceTimer);
});
// Ensure filter is applied on form load.
if (capabilitySearch.value !== '') {
capabilitySelectFilter(capabilitySearch.value.toLowerCase());
}
};
@@ -0,0 +1,74 @@
<?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/>.
/**
* The tool_capability report viewed event.
*
* @package tool_capability
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_capability\event;
/**
* The tool_capability report viewed event class.
*
* @package tool_capability
* @since Moodle 2.7
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class report_viewed extends \core\event\base {
/**
* Init method.
*
* @return void
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->context = \context_system::instance();
}
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventreportviewed', 'tool_capability');
}
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' viewed the capability overview report.";
}
/**
* Returns relevant URL.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/admin/tool/capability/index.php');
}
}
@@ -0,0 +1,46 @@
<?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 tool_capability.
*
* @package tool_capability
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_capability\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_capability implementing null_provider.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
@@ -0,0 +1,73 @@
<?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/>.
/**
* Capability tool settings form.
*
* Do no include this file, it is automatically loaded by the class loader!
*
* @package tool_capability
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->libdir.'/formslib.php');
/**
* Class tool_capability_settings_form
*
* The settings form for the comparison of roles/capabilities.
*
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_capability_settings_form extends moodleform {
/**
* The form definition.
*/
public function definition() {
$form = $this->_form;
$capabilities = $this->_customdata['capabilities'];
$roles = $this->_customdata['roles'];
// Set the form ID.
$form->setAttributes(array('id' => 'capability-overview-form') + $form->getAttributes());
$form->addElement('header', 'reportsettings', get_string('reportsettings', 'tool_capability'));
$form->addElement('html', html_writer::tag('p', get_string('intro', 'tool_capability'), array('id' => 'intro')));
$attributes = array('multiple' => 'multiple', 'size' => 10, 'data-search' => 'capability');
$form->addElement('select', 'capability', get_string('capabilitylabel', 'tool_capability'), $capabilities, $attributes);
$form->setType('capability', PARAM_CAPABILITY);
$strsearch = get_string('search');
$form->addElement('text', 'search', $strsearch, ['data-action' => 'search', 'placeholder' => $strsearch])
->setHiddenLabel(true);
$form->setType('search', PARAM_TEXT);
$attributes = array('multiple' => 'multiple', 'size' => 10);
$form->addElement('select', 'roles', get_string('roleslabel', 'tool_capability'), $roles, $attributes);
$form->setType('roles', PARAM_TEXT);
$filters = [];
$filters[] = $form->createElement('checkbox', 'onlydiff', get_string('onlydiff', 'tool_capability'));
$form->setType('onlydiff', PARAM_BOOL);
$form->addGroup($filters, 'filters', get_string('filters', 'tool_capability'), array('<br>'), false);
$form->addElement('submit', 'submitbutton', get_string('getreport', 'tool_capability'));
}
}
+169
View File
@@ -0,0 +1,169 @@
<?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/>.
/**
* For a given capability, show what permission it has for every role, and everywhere that it is overridden.
*
* @package tool_capability
* @copyright 2008 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../config.php');
require_once($CFG->dirroot.'/'.$CFG->admin.'/tool/capability/locallib.php');
require_once($CFG->libdir.'/adminlib.php');
// Get URL parameters.
$systemcontext = context_system::instance();
$contextid = optional_param('context', $systemcontext->id, PARAM_INT);
// Check permissions.
list($context, $course, $cm) = get_context_info_array($contextid);
require_login($course, false, $cm);
require_capability('moodle/role:manage', $context);
// Print the header.
admin_externalpage_setup('toolcapability');
// Prepare the list of capabilities to choose from.
$capabilitychoices = array();
foreach ($context->get_capabilities('name') as $cap) {
$capabilitychoices[$cap->name] = $cap->name . ': ' . get_capability_string($cap->name);
}
$allroles = role_fix_names(get_all_roles($context));
// Prepare the list of roles to choose from.
$rolechoices = array('0' => get_string('all'));
foreach ($allroles as $role) {
$rolechoices[$role->id] = $role->localname;
}
$form = new tool_capability_settings_form(null, array(
'capabilities' => $capabilitychoices,
'roles' => $rolechoices
));
$PAGE->requires->js_call_amd('tool_capability/search', 'init');
// Log.
$capabilities = array();
$rolestoshow = array();
$roleids = array('0');
$cleanedroleids = array();
$onlydiff = false;
if ($data = $form->get_data()) {
$roleids = array();
if (!empty($data->roles)) {
$roleids = $data->roles;
}
$capabilities = array();
if (!empty($data->capability)) {
$capabilities = $data->capability;
}
if (in_array('0', $roleids)) {
$rolestoshow = $allroles;
} else {
$cleanedroleids = array_intersect(array_keys($allroles), $roleids);
if (count($cleanedroleids) === 0) {
$rolestoshow = $allroles;
} else {
foreach ($cleanedroleids as $id) {
$rolestoshow[$id] = $allroles[$id];
}
}
}
if (isset($data->onlydiff)) {
$onlydiff = $data->onlydiff;
}
}
\tool_capability\event\report_viewed::create()->trigger();
$renderer = $PAGE->get_renderer('tool_capability');
echo $OUTPUT->header();
$form->display();
// If we have a capability, generate the report.
if (count($capabilities) && count($rolestoshow)) {
/* @var tool_capability_renderer $renderer */
echo $renderer->capability_comparison_table($capabilities, $context->id, $rolestoshow, $onlydiff);
}
// Footer.
echo $OUTPUT->footer();
function print_report_tree($contextid, $contexts, $allroles) {
global $CFG;
// Array for holding lang strings.
static $strpermissions = null;
if (is_null($strpermissions)) {
$strpermissions = array(
CAP_INHERIT => get_string('notset','role'),
CAP_ALLOW => get_string('allow','role'),
CAP_PREVENT => get_string('prevent','role'),
CAP_PROHIBIT => get_string('prohibit','role')
);
}
// Start the list item, and print the context name as a link to the place to
// make changes.
if ($contextid == context_system::instance()->id) {
$url = "$CFG->wwwroot/$CFG->admin/roles/manage.php";
$title = get_string('changeroles', 'tool_capability');
} else {
$url = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid";
$title = get_string('changeoverrides', 'tool_capability');
}
$context = context::instance_by_id($contextid);
echo '<h3><a href="' . $url . '" title="' . $title . '">', $context->get_context_name(), '</a></h3>';
// If there are any role overrides here, print them.
if (!empty($contexts[$contextid]->rolecapabilities)) {
$rowcounter = 0;
echo '<table class="generaltable table-striped"><tbody>';
foreach ($allroles as $role) {
if (isset($contexts[$contextid]->rolecapabilities[$role->id])) {
$permission = $contexts[$contextid]->rolecapabilities[$role->id];
echo '<tr class="r' . ($rowcounter % 2) . '"><th class="cell">', $role->localname,
'</th><td class="cell">' . $strpermissions[$permission] . '</td></tr>';
$rowcounter++;
}
}
echo '</tbody></table>';
}
// After we have done the site context, change the string for CAP_INHERIT
// from 'notset' to 'inherit'.
$strpermissions[CAP_INHERIT] = get_string('inherit','role');
// If there are any child contexts, print them recursively.
if (!empty($contexts[$contextid]->children)) {
echo '<ul>';
foreach ($contexts[$contextid]->children as $childcontextid) {
echo '<li>';
print_report_tree($childcontextid, $contexts, $allroles);
echo '</li>';
}
echo '</ul>';
}
}
@@ -0,0 +1,40 @@
<?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/>.
/**
* Strings for component 'tool_capability', language 'en', branch 'MOODLE_22_STABLE'
*
* @package tool_capability
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['onlydiff'] = 'Show differences only';
$string['capabilitylabel'] = 'Capability:';
$string['capabilityreport'] = 'Capability overview';
$string['eventreportviewed'] = 'Report viewed';
$string['filters'] = 'Filter results';
$string['forroles'] = 'For roles {$a}';
$string['getreport'] = 'Get the overview';
$string['changeoverrides'] = 'Change overrides in this context';
$string['changeroles'] = 'Change role definitions';
$string['intro'] = 'This report shows, for a particular capability, what permission that capability has in the definition of every role (or a selection of roles), and everywhere in the site where that capability is overridden.';
$string['pluginname'] = 'Capability overview';
$string['nodifferences'] = 'There are no differences to show between selected roles in this context';
$string['reportforcapability'] = 'Report for capability \'{$a}\'';
$string['reportsettings'] = 'Report settings';
$string['roleslabel'] = 'Roles:';
$string['privacy:metadata'] = 'The Capability overview plugin does not store any personal data.';
+111
View File
@@ -0,0 +1,111 @@
<?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/>.
/**
* Functions used by the capability tool.
*
* @package tool_capability
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Calculates capability data organised by context for the given roles.
*
* @param string $capability The capability to get data for.
* @param array $roles An array of roles to get data for.
* @return context[] An array of contexts.
*/
function tool_capability_calculate_role_data($capability, array $roles) {
global $DB;
$systemcontext = context_system::instance();
$roleids = array_keys($roles);
// Work out the bits needed for the SQL WHERE clauses.
$params = array($capability);
list($sqlroletest, $roleparams) = $DB->get_in_or_equal($roleids);
$params = array_merge($params, $roleparams);
$sqlroletest = 'AND roleid ' . $sqlroletest;
// Get all the role_capabilities rows for this capability - that is, all
// role definitions, and all role overrides.
$sql = 'SELECT id, roleid, contextid, permission
FROM {role_capabilities}
WHERE capability = ? '.$sqlroletest;
$rolecaps = $DB->get_records_sql($sql, $params);
// In order to display a nice tree of contexts, we need to get all the
// ancestors of all the contexts in the query we just did.
$sql = 'SELECT DISTINCT con.path, 1
FROM {context} con
JOIN {role_capabilities} rc ON rc.contextid = con.id
WHERE capability = ? ' .
$sqlroletest .
// Context path should never be null, but can happen in old database with
// bad data (e.g. a course_module where the corresponding course no longer exists).
// We need to leave these out of the report to prevent errors.
' AND con.path IS NOT NULL';
$relevantpaths = $DB->get_records_sql_menu($sql, $params);
$requiredcontexts = array($systemcontext->id);
foreach ($relevantpaths as $path => $notused) {
$requiredcontexts = array_merge($requiredcontexts, explode('/', trim($path, '/')));
}
$requiredcontexts = array_unique($requiredcontexts);
// Now load those contexts.
list($sqlcontexttest, $contextparams) = $DB->get_in_or_equal($requiredcontexts);
$contexts = get_sorted_contexts('ctx.id ' . $sqlcontexttest, $contextparams);
// Prepare some empty arrays to hold the data we are about to compute.
foreach ($contexts as $conid => $con) {
$contexts[$conid]->children = array();
$contexts[$conid]->rolecapabilities = array();
}
// Put the contexts into a tree structure.
foreach ($contexts as $conid => $con) {
$context = context::instance_by_id($conid);
try {
$parentcontext = $context->get_parent_context();
if ($parentcontext) { // Will be false if $context is the system context.
$contexts[$parentcontext->id]->children[] = $conid;
}
} catch (dml_missing_record_exception $e) {
// Ignore corrupt context tree structure here. Don't let it break
// showing the rest of the report.
continue;
}
}
// Put the role capabilities into the context tree.
foreach ($rolecaps as $rolecap) {
if (!isset($contexts[$rolecap->contextid])) {
// Skip capabilities in orphaned contexts that are not in the tree.
continue;
}
$contexts[$rolecap->contextid]->rolecapabilities[$rolecap->roleid] = $rolecap->permission;
}
// Fill in any missing rolecaps for the system context.
foreach ($roleids as $roleid) {
if (!isset($contexts[$systemcontext->id]->rolecapabilities[$roleid])) {
$contexts[$systemcontext->id]->rolecapabilities[$roleid] = CAP_INHERIT;
}
}
return $contexts;
}
+158
View File
@@ -0,0 +1,158 @@
<?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/>.
/**
* Capability tool renderer.
*
* @package tool_capability
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* The primary renderer for the capability tool.
*
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_capability_renderer extends plugin_renderer_base {
/**
* Returns an array of permission strings.
*
* @return lang_string[]
*/
protected function get_permission_strings() {
static $strpermissions;
if (!$strpermissions) {
$strpermissions = array(
CAP_INHERIT => new lang_string('inherit', 'role'),
CAP_ALLOW => new lang_string('allow', 'role'),
CAP_PREVENT => new lang_string('prevent', 'role'),
CAP_PROHIBIT => new lang_string('prohibit', 'role')
);
}
return $strpermissions;
}
/**
* Returns an array of permission CSS classes.
*
* @return string[]
*/
protected function get_permission_classes() {
static $permissionclasses;
if (!$permissionclasses) {
$permissionclasses = array(
CAP_INHERIT => 'inherit',
CAP_ALLOW => 'allow',
CAP_PREVENT => 'prevent',
CAP_PROHIBIT => 'prohibit',
);
}
return $permissionclasses;
}
/**
* Produces a table to visually compare roles and capabilities.
*
* @param array $capabilities An array of capabilities to show comparison for.
* @param int $contextid The context we are displaying for.
* @param array $roles An array of roles to show comparison for.
* @param bool $onlydiff show only different permissions
* @return string
*/
public function capability_comparison_table(array $capabilities, $contextid, array $roles, $onlydiff=false) {
static $capabilitycontexts = array();
$strpermissions = $this->get_permission_strings();
$permissionclasses = $this->get_permission_classes();
if ($contextid === context_system::instance()->id) {
$strpermissions[CAP_INHERIT] = new lang_string('notset', 'role');
}
$table = new html_table();
$table->attributes['class'] = 'comparisontable';
$table->head = array('&nbsp;');
foreach ($roles as $role) {
$url = new moodle_url('/admin/roles/define.php', array('action' => 'view', 'roleid' => $role->id));
$table->head[] = html_writer::div(html_writer::link($url, $role->localname));
}
$table->data = array();
$childcontextsids = [];
foreach ($capabilities as $capability) {
if (empty($capabilitycontexts[$capability])) {
$capabilitycontexts[$capability] = tool_capability_calculate_role_data($capability, $roles);
}
$contexts = $capabilitycontexts[$capability];
$captitle = new html_table_cell(get_capability_string($capability) . html_writer::span($capability));
$captitle->header = true;
$row = new html_table_row(array($captitle));
$permissiontypes = array();
foreach ($roles as $role) {
if (isset($contexts[$contextid]->rolecapabilities[$role->id])) {
$permission = $contexts[$contextid]->rolecapabilities[$role->id];
} else {
$permission = CAP_INHERIT;
}
if (!in_array($permission, $permissiontypes)) {
$permissiontypes[] = $permission;
}
$cell = new html_table_cell($strpermissions[$permission]);
$cell->attributes['class'] = $permissionclasses[$permission];
$row->cells[] = $cell;
}
if (!$onlydiff || count($permissiontypes) > 1) {
$table->data[] = $row;
}
if (!empty($contexts[$contextid]->children)) {
$childcontextsids = array_merge($childcontextsids, $contexts[$contextid]->children);
$childcontextsids = array_unique($childcontextsids);
}
}
// Start the list item, and print the context name as a link to the place to make changes.
$context = context::instance_by_id($contextid);
if ($context instanceof context_system) {
$url = new moodle_url('/admin/roles/manage.php');
} else {
$url = new moodle_url('/admin/roles/permissions.php', ['contextid' => $contextid]);
}
$title = get_string('permissionsincontext', 'core_role', $context->get_context_name());
$html = $this->output->heading(html_writer::link($url, $title), 3);
if (!empty($table->data)) {
$html .= html_writer::table($table);
} else {
$html .= html_writer::tag('p', get_string('nodifferences', 'tool_capability'));
}
// If there are any child contexts, print them recursively.
if (!empty($childcontextsids)) {
foreach ($childcontextsids as $childcontextid) {
$html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles, $onlydiff);
}
}
return $html;
}
}
+32
View File
@@ -0,0 +1,32 @@
<?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/>.
/**
* Capability overview settings
*
* @package tool_capability
* @copyright 2008 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
$ADMIN->add('roles', new admin_externalpage(
'toolcapability',
get_string('pluginname', 'tool_capability'),
"$CFG->wwwroot/$CFG->admin/tool/capability/index.php",
'moodle/role:manage'
));
+78
View File
@@ -0,0 +1,78 @@
.path-admin-tool-capability [data-search="capability"] {
min-width: 675px;
}
.path-admin-tool-capability .comparisontable {
margin-top: 150px;
}
.path-admin-tool-capability .comparisontable th,
.path-admin-tool-capability .comparisontable td {
vertical-align: middle;
padding: 0.4em 0.5em 0.3em;
}
.path-admin-tool-capability .comparisontable thead th {
vertical-align: bottom;
background: none;
}
.path-admin-tool-capability .comparisontable thead th div {
position: relative;
}
.path-admin-tool-capability .comparisontable thead th div > a {
position: absolute;
top: -1.75em;
left: 1em;
width: 150px;
text-align: left;
margin-bottom: 1em;
text-indent: -1.45em;
-webkit-transform-origin: top left;
-moz-transform-origin: top left;
-ms-transform-origin: top left;
-o-transform-origin: top left;
-webkit-transform: rotate(315deg);
-moz-transform: rotate(315deg);
-ms-transform: rotate(315deg);
-o-transform: rotate(315deg);
}
.path-admin-tool-capability .comparisontable tbody th {
background-color: #eee;
text-align: right;
border: 1px solid #dfdfdf;
}
.path-admin-tool-capability .comparisontable tbody th span {
display: block;
color: #666;
font-size: 80%;
}
.path-admin-tool-capability .comparisontable tbody td {
border: 1px solid #dfdfdf;
}
.path-admin-tool-capability .comparisontable .inherit {
color: #666;
}
.path-admin-tool-capability .comparisontable .allow {
background-color: #060;
font-weight: bold;
color: white;
}
.path-admin-tool-capability .comparisontable .prevent {
background-color: #ad6704;
font-weight: bold;
color: white;
}
.path-admin-tool-capability .comparisontable .prohibit {
background-color: #800;
font-weight: bold;
color: white;
}
@@ -0,0 +1,103 @@
@tool @tool_capability
Feature: show capabilities for selected roles
In order to check roles capabilities
As an admin
I need to be able to customize capabilities report viewing only specific roles and capabilities
Background:
Given the following "roles" exist:
| shortname | name | archetype |
| studenteq | Studenteq | student |
| studentdf | Studentdf | student |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/course:changefullname | Allow | studentdf | System | |
| moodle/course:changeshortname | Prohibit | studentdf | System | |
| moodle/course:changeidnumber | Prevent | studentdf | System | |
And I log in as "admin"
And I navigate to "Users > Permissions > Capability overview" in site administration
Scenario: visualize capabilities table with a limited number of capabilities
When I set the following fields to these values:
| Capability: | moodle/course:changefullname, moodle/course:changeshortname |
| Roles: | Studentdf |
And I click on "Get the overview" "button"
Then I should see "moodle/course:changefullname" in the "comparisontable" "table"
And I should see "moodle/course:changeshortname" in the "comparisontable" "table"
And I should not see "moodle/course:changecategory" in the "comparisontable" "table"
Scenario: visualize an allow capability
When I set the following fields to these values:
| Capability: | moodle/course:changefullname |
| Roles: | Studentdf |
And I click on "Get the overview" "button"
Then I should see "Allow" in the "comparisontable" "table"
And I should not see "Prevent" in the "comparisontable" "table"
And I should not see "Prohibit" in the "comparisontable" "table"
And I should not see "Not set" in the "comparisontable" "table"
Scenario: visualize a prohibit capability
When I set the following fields to these values:
| Capability: | moodle/course:changeshortname |
| Roles: | Studentdf |
And I click on "Get the overview" "button"
Then I should not see "Allow" in the "comparisontable" "table"
And I should not see "Prevent" in the "comparisontable" "table"
And I should see "Prohibit" in the "comparisontable" "table"
And I should not see "Not set" in the "comparisontable" "table"
Scenario: visualize a not set capability
When I set the following fields to these values:
| Capability: | moodle/course:changecategory |
| Roles: | Studentdf |
And I click on "Get the overview" "button"
Then I should not see "Allow" in the "comparisontable" "table"
And I should not see "Prevent" in the "comparisontable" "table"
And I should not see "Prohibit" in the "comparisontable" "table"
And I should see "Not set" in the "comparisontable" "table"
Scenario: visualize more than one role
When I set the following fields to these values:
| Capability: | moodle/course:changecategory |
| Roles: | Student, Studentdf |
And I click on "Get the overview" "button"
Then I should see "Student" in the "comparisontable" "table"
And I should see "Studentdf" in the "comparisontable" "table"
And I should not see "Teacher" in the "comparisontable" "table"
Scenario: visualize all roles without selecting any role
When I set the following fields to these values:
| Capability: | moodle/course:changecategory |
And I click on "Get the overview" "button"
Then I should see "Student" in the "comparisontable" "table"
And I should see "Studentdf" in the "comparisontable" "table"
And I should see "Teacher" in the "comparisontable" "table"
Scenario: visualize all roles by selecting All option
When I set the following fields to these values:
| Capability: | moodle/course:changecategory |
| Roles: | All |
And I click on "Get the overview" "button"
Then I should see "Student" in the "comparisontable" "table"
And I should see "Studentdf" in the "comparisontable" "table"
And I should see "Teacher" in the "comparisontable" "table"
@javascript
Scenario: filter capability list using javascript
Given I should see "moodle/site:config" in the "Capability" "field"
And I should see "moodle/course:change" in the "Capability" "field"
And I set the field "Search" in the "#capability-overview-form" "css_element" to "moodle/course:change"
Then I should see "moodle/course:change" in the "Capability" "field"
And I should not see "moodle/site:config" in the "Capability" "field"
@javascript
Scenario: selecting capabilities using filters
Given I should see "moodle/course:change" in the "Capability" "field"
And I set the field "Search" in the "#capability-overview-form" "css_element" to "moodle/course:change"
And I wait "1" seconds
When I set the following fields to these values:
| Capability: | moodle/course:changecategory |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "moodle/course:changecategory" in the "comparisontable" "table"
And the field "Capability:" matches value "moodle/course:changecategory"
@@ -0,0 +1,133 @@
@tool @tool_capability
Feature: Show capabilities for multiple contexts
In order to check roles capabilities
As an admin
I need to be able to see capability overrides on several contexts
Background:
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| Course 2 | C2 | 0 |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| enrol/category:config | Allow | student | Course | C1 |
| enrol/cohort:unenrol | Allow | student | Course | C2 |
And I log in as "admin"
And I navigate to "Users > Permissions > Capability overview" in site administration
Scenario: Show capabilities table with one capability with overrides
When I set the following fields to these values:
| Capability: | enrol/category:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with one capability without overrides
When I set the following fields to these values:
| Capability: | enrol/cohort:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should not see "Permissions in Category: Category 1"
And I should not see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with two capabilities, 1st without overrides and 2nd with
When I set the following fields to these values:
| Capability: | enrol/category:synchronised, enrol/category:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with two capabilities, 1st with overrides and 2nd without
When I set the following fields to these values:
| Capability: | enrol/category:config, enrol/cohort:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with two capabilities, none with overrides
When I set the following fields to these values:
| Capability: | enrol/category:synchronised, enrol/cohort:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should not see "Permissions in Category: Category 1"
And I should not see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with capability with override and no role selected
When I set the following fields to these values:
| Capability: | enrol/category:config |
| Roles: | |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with capability without override and no role selected
When I set the following fields to these values:
| Capability: | enrol/cohort:config |
| Roles: | |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should not see "Permissions in Category: Category 1"
And I should not see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with capability with two overrides on different contexts
When I set the following fields to these values:
| Capability: | enrol/category:config, enrol/cohort:unenrol |
| Roles: | |
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "Permissions in Course: Course 1"
And I should see "Permissions in Course: Course 2"
Scenario: Show capabilities table with capability with override and only diff
When I set the following fields to these values:
| Capability: | enrol/category:config |
| Roles: | Student, Teacher |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "There are no differences to show between selected roles in this context"
And I should see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with capability without override and only diff and same capability
When I set the following fields to these values:
| Capability: | enrol/category:synchronised |
| Roles: | Student, Teacher |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "There are no differences to show between selected roles in this context"
And I should not see "Permissions in Category: Category 1"
And I should not see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
Scenario: Show capabilities table with two capabilities only one override and only diff checked
When I set the following fields to these values:
| Capability: | enrol/category:config, enrol/cohort:config |
| Roles: | Student, Teacher |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "Permissions in System"
And I should see "Permissions in Category: Category 1"
And I should see "There are no differences to show between selected roles in this context"
And I should see "Permissions in Course: Course 1"
And I should not see "Permissions in Course: Course 2"
@@ -0,0 +1,67 @@
@tool @tool_capability
Feature: show only differences between roles for selected capabilities
In order to check roles capabilities
As an admin
I need to be able to filter capabilities report viewing only role differences
Background:
Given the following "roles" exist:
| shortname | name | archetype |
| studenteq | Studenteq | student |
| studentdf | Studentdf | student |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/course:changefullname | Allow | studentdf | System | |
| moodle/course:changeshortname | Prohibit | studentdf | System | |
And I log in as "admin"
And I navigate to "Users > Permissions > Capability overview" in site administration
Scenario: Compare identical roles
When I set the following fields to these values:
| Capability: | moodle/course:changefullname, moodle/course:changeshortname, moodle/course:changeidnumber, moodle/course:changesummary |
| Roles: | Student, Studenteq |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "There are no differences to show between selected roles in this context"
Scenario: Compare different roles
When I set the following fields to these values:
| Capability: | moodle/course:changefullname, moodle/course:changeshortname, moodle/course:changeidnumber, moodle/course:changesummary |
| Roles: | Student, Studentdf |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should not see "There are no differences to show between selected roles in this context"
And I should see "moodle/course:changefullname" in the "comparisontable" "table"
And I should see "moodle/course:changeshortname" in the "comparisontable" "table"
And I should not see "moodle/course:changesummary" in the "comparisontable" "table"
Scenario: Compare different roles but comparing capabilities that are equals on both
When I set the following fields to these values:
| Capability: | moodle/course:changeidnumber, moodle/course:changesummary |
| Roles: | Student, Studentdf |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "There are no differences to show between selected roles in this context"
Scenario: Compare all roles without selecting specific role
When I set the following fields to these values:
| Capability: | moodle/course:changefullname, moodle/site:config |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should not see "moodle/site:config" in the "comparisontable" "table"
And I should see "moodle/course:changefullname" in the "comparisontable" "table"
Scenario: Compare all roles without selecting specific role on not defined capability
When I set the following fields to these values:
| Capability: | moodle/site:config |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "There are no differences to show between selected roles in this context"
Scenario: Comparing only one role
When I set the following fields to these values:
| Capability: | moodle/course:changefullname, moodle/course:changeshortname, moodle/course:changeidnumber, moodle/course:changesummary |
| Roles: | Student |
And I set the field "Show differences only" to "1"
And I click on "Get the overview" "button"
Then I should see "There are no differences to show between selected roles in this context"
@@ -0,0 +1,63 @@
<?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/>.
/**
* Tests for capability overview events.
*
* @package tool_capability
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace tool_capability\event;
/**
* Class for capability overview events.
*
* @package tool_capability
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
class events_test extends \advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
$this->setAdminUser();
$this->resetAfterTest();
}
/**
* Test the report viewed event.
*/
public function test_report_viewed(): void {
$event = \tool_capability\event\report_viewed::create();
// Trigger and capture the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$event = reset($events);
$this->assertInstanceOf('\tool_capability\event\report_viewed', $event);
$this->assertEquals(\context_system::instance(), $event->get_context());
$this->assertEventContextNotUsed($event);
$url = new \moodle_url('/admin/tool/capability/index.php');
$this->assertEquals($url, $event->get_url());
$event->get_name();
}
}
@@ -0,0 +1,89 @@
<?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/>.
/**
* Tests for the capability overview helper functions.
*
* @package tool_capability
* @copyright 2021 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace tool_capability;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/capability/locallib.php');
/**
* Tests for the capability overview helper functions.
*/
class locallib_test extends \advanced_testcase {
/**
* Test the function that gets the data - simple case.
*/
public function test_tool_capability_calculate_role_data(): void {
global $DB;
$data = tool_capability_calculate_role_data('mod/quiz:attempt', get_all_roles());
$systcontext = \context_system::instance();
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
$this->assertArrayHasKey($systcontext->id, $data);
$this->assertCount(1, $data);
foreach ($data[$systcontext->id]->rolecapabilities as $roleid => $permission) {
if ($roleid == $studentroleid) {
$this->assertEquals(CAP_ALLOW, $permission);
} else {
$this->assertEquals(CAP_INHERIT, $permission);
}
}
}
/**
* Test the function that gets the data - simple case.
*/
public function test_tool_capability_calculate_role_data_orphan_contexts(): void {
global $DB;
$this->resetAfterTest();
// This simulates a situation that seems to happen sometimes, where
// we end up with contexts with path = NULL in the database.
$systcontext = \context_system::instance();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$coursecontext = \context_course::instance($course->id);
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
role_change_permission($studentroleid, $coursecontext, 'mod/quiz:attempt', CAP_PREVENT);
// This is where we simulate the breakage.
$DB->set_field('context', 'path', null, ['id' => $coursecontext->id]);
// Now call the function. We mainly just want to know there is no exception.
$data = tool_capability_calculate_role_data('mod/quiz:attempt', get_all_roles());
$this->assertArrayHasKey($systcontext->id, $data);
$this->assertCount(1, $data);
foreach ($data[$systcontext->id]->rolecapabilities as $roleid => $permission) {
if ($roleid == $studentroleid) {
$this->assertEquals(CAP_ALLOW, $permission);
} else {
$this->assertEquals(CAP_INHERIT, $permission);
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
<?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/>.
/**
* Version details.
*
* @package tool_capability
* @copyright 2011 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).