Skip to content

Commit

Permalink
Merge branch 'MDL-80548' of https://github.com/marinaglancy/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
junpataleta committed Mar 5, 2024
2 parents 5a7caff + d395925 commit e3160bf
Show file tree
Hide file tree
Showing 23 changed files with 298 additions and 35 deletions.
10 changes: 10 additions & 0 deletions admin/amd/build/bulk_user_actions.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions admin/amd/build/bulk_user_actions.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 91 additions & 0 deletions admin/amd/src/bulk_user_actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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 bulk actions to the users list report
*
* @module core_admin/bulk_user_actions
* @copyright 2024 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

import * as reportSelectors from 'core_reportbuilder/local/selectors';
import * as tableEvents from 'core_table/local/dynamic/events';
import * as FormChangeChecker from 'core_form/changechecker';
import * as CustomEvents from 'core/custom_interaction_events';
import jQuery from 'jquery';

const Selectors = {
bulkActionsForm: 'form#user-bulk-action-form',
userReportWrapper: '[data-region="report-user-list-wrapper"]',
checkbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',
masterCheckbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',
checkedRows: '[data-togglegroup="report-select-all"][data-toggle="slave"]:checked',
};

/**
* Initialise module
*/
export const init = () => {

const userBulkForm = document.querySelector(Selectors.bulkActionsForm);
const userReport = userBulkForm?.closest(Selectors.userReportWrapper)?.querySelector(reportSelectors.regions.report);
if (!userBulkForm || !userReport) {
return;
}
const actionSelect = userBulkForm.querySelector('select');
CustomEvents.define(actionSelect, [CustomEvents.events.accessibleChange]);

jQuery(actionSelect).on(CustomEvents.events.accessibleChange, event => {
if (event.target.value && `${event.target.value}` !== "0") {
const e = new Event('submit', {cancelable: true});
userBulkForm.dispatchEvent(e);
if (!e.defaultPrevented) {
FormChangeChecker.markFormSubmitted(userBulkForm);
userBulkForm.submit();
}
}
});

// Every time the checkboxes in the report are changed, update the list of users in the form values
// and enable/disable the action select.
const updateUserIds = () => {
const selectedUsers = [...userReport.querySelectorAll(Selectors.checkedRows)];
const selectedUserIds = selectedUsers.map(check => parseInt(check.value));
userBulkForm.querySelector('[name="userids"]').value = selectedUserIds.join(',');
actionSelect.disabled = selectedUsers.length === 0;
const selectedUsersNames = selectedUsers.map(check => document.querySelector(`label[for="${check.id}"]`).textContent);
// Add the user ids and names to the form data attributes so they can be available from the
// other JS modules that listen to the form submit event.
userBulkForm.data = {userids: selectedUserIds, usernames: selectedUsersNames};
};

updateUserIds();

document.addEventListener('change', event => {
// When checkboxes are checked next to individual users or the master toggle (Select all/none).
if ((event.target.matches(Selectors.checkbox) || event.target.matches(Selectors.masterCheckbox))
&& userReport.contains(event.target)) {
updateUserIds();
}
});

document.addEventListener(tableEvents.tableContentRefreshed, event => {
// When the report contents is updated (i.e. page is changed, filters applied, etc).
if (userReport.contains(event.target)) {
updateUserIds();
}
});
};
7 changes: 7 additions & 0 deletions admin/classes/reportbuilder/local/systemreports/users.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ protected function initialise(): void {
$this->add_base_fields("{$entityuseralias}.id, {$entityuseralias}.confirmed, {$entityuseralias}.mnethostid,
{$entityuseralias}.suspended, {$entityuseralias}.username, " . implode(', ', $fullnamefields));

if ($this->get_parameter('withcheckboxes', false, PARAM_BOOL)) {
$canviewfullnames = has_capability('moodle/site:viewfullnames', \context_system::instance());
$this->set_checkbox_toggleall(static function(\stdClass $row) use ($canviewfullnames): array {
return [$row->id, fullname($row, $canviewfullnames)];
});
}

$paramguest = database::generate_param_name();
$this->add_base_condition_sql("{$entityuseralias}.deleted <> 1 AND {$entityuseralias}.id <> :{$paramguest}",
[$paramguest => $CFG->siteguest]);
Expand Down
26 changes: 26 additions & 0 deletions admin/tests/behat/browse_users.feature
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,29 @@ Feature: An administrator can browse user accounts
Then I should see "Username"
And I should see "User picture"
And I should see "Additional names"

@javascript
Scenario: Browse user list as a person with limited capabilities
Given the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | manager@example.com |
And the following "roles" exist:
| name | shortname | description | archetype |
| Custom manager | custom1 | My custom role 1 | |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/site:configview | Allow | custom1 | System | |
| moodle/user:update | Allow | custom1 | System | |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | custom1 | System | |
When I log in as "manager"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "User One" "checkbox"
And the "Bulk user actions" select box should contain "Confirm"
And the "Bulk user actions" select box should not contain "Delete"
And I set the field "Bulk user actions" to "Force password change"
And I should see "Are you absolutely sure you want to force a password change to User One ?"
And I press "Yes"
And I press "Continue"
And I should see "Browse list of users"
3 changes: 3 additions & 0 deletions admin/tool/mfa/classes/local/form/reset_factor.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public function definition(): void {
$mform->addElement('hidden', 'bulkaction', $bulkaction);
$mform->setType('bulkaction', PARAM_BOOL);

$mform->addElement('hidden', 'returnurl');
$mform->setType('returnurl', PARAM_LOCALURL);

$factors = array_map(function ($element) {
return $element->get_display_name();
}, $factors);
Expand Down
3 changes: 3 additions & 0 deletions admin/tool/mfa/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ function tool_mfa_after_config(): void {
* @return array
*/
function tool_mfa_bulk_user_actions(): array {
if (!has_capability('moodle/site:config', context_system::instance())) {
return [];
}
return [
'tool_mfa_reset_factors' => new action_link(
new moodle_url('/admin/tool/mfa/reset_factor.php'),
Expand Down
16 changes: 9 additions & 7 deletions admin/tool/mfa/reset_factor.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@
admin_externalpage_setup('tool_mfa_resetfactor');

$bulk = !empty($SESSION->bulk_users);
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);

$factors = \tool_mfa\plugininfo\factor::get_factors();
$form = new \tool_mfa\local\form\reset_factor(null, ['factors' => $factors, 'bulk' => $bulk]);
if ($bulk) {
$form->set_data(['returnurl' => $returnurl]);
$return = new moodle_url($returnurl ?: '/admin/user/user_bulk.php');
} else {
$return = new moodle_url('/admin/category.php', ['category' => 'toolmfafolder']);
}

if ($form->is_cancelled()) {
if ($bulk) {
$url = new moodle_url('/admin/user/user_bulk.php');
} else {
$url = new moodle_url('/admin/category.php', ['category' => 'toolmfafolder']);
}
redirect($url);
redirect($return);
} else if ($fromform = $form->get_data()) {
// Get factor from select index.
if ($fromform->factor !== 'all') {
Expand Down Expand Up @@ -82,7 +84,7 @@
\core\notification::success(get_string('resetsuccessbulk', 'tool_mfa', $stringvar));
unset($SESSION->bulk_users);
// Redirect to bulk actions page.
redirect(new moodle_url('/admin/user/user_bulk.php'));
redirect($return);
}

echo $OUTPUT->header();
Expand Down
18 changes: 17 additions & 1 deletion admin/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/authlib.php');
require_once($CFG->dirroot.'/user/lib.php');
require_once($CFG->dirroot.'/'.$CFG->admin.'/user/user_bulk_forms.php');

$delete = optional_param('delete', 0, PARAM_INT);
$confirm = optional_param('confirm', '', PARAM_ALPHANUM); //md5 confirmation hash
Expand Down Expand Up @@ -172,8 +173,23 @@
echo html_writer::end_div();
}

echo html_writer::start_div('', ['data-region' => 'report-user-list-wrapper']);

$bulkactions = new user_bulk_action_form(new moodle_url('/admin/user/user_bulk.php'),
['excludeactions' => ['displayonpage'], 'passuserids' => true, 'hidesubmit' => true],
'post', '',
['id' => 'user-bulk-action-form']);
$bulkactions->set_data(['returnurl' => $PAGE->url->out_as_local_url(false)]);

$report = \core_reportbuilder\system_report_factory::create(\core_admin\reportbuilder\local\systemreports\users::class,
context_system::instance());
context_system::instance(), parameters: ['withcheckboxes' => $bulkactions->has_bulk_actions()]);
echo $report->output();

if ($bulkactions->has_bulk_actions()) {
$PAGE->requires->js_call_amd('core_admin/bulk_user_actions', 'init');
$bulkactions->display();
}

echo html_writer::end_div();

echo $OUTPUT->footer();
Loading

0 comments on commit e3160bf

Please sign in to comment.