MDL-79270 user: New 'Browse list of users' system report

- The report 'Browse list of users' has been converted to use Report
Builder.
- Behat tests have been fixed and some test have been deleted for not
being relevant anymore.
This commit is contained in:
David Carrillo
2023-12-11 12:36:54 +01:00
parent b0c89b310e
commit f76a518cb1
17 changed files with 707 additions and 666 deletions
@@ -0,0 +1,366 @@
<?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/>.
namespace core_admin\reportbuilder\local\systemreports;
use core\context\system;
use core_cohort\reportbuilder\local\entities\cohort;
use core_cohort\reportbuilder\local\entities\cohort_member;
use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\helpers\database;
use core_reportbuilder\local\helpers\user_profile_fields;
use core_reportbuilder\local\report\action;
use core_reportbuilder\local\report\filter;
use core_reportbuilder\system_report;
use core_role\reportbuilder\local\entities\role;
use lang_string;
use moodle_url;
use pix_icon;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/authlib.php');
require_once($CFG->libdir.'/enrollib.php');
require_once($CFG->dirroot.'/user/lib.php');
/**
* Browse users system report class implementation
*
* @package core_admin
* @copyright 2023 David Carrillo <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class users extends system_report {
/**
* Initialise report, we need to set the main table, load our entities and set columns/filters
*/
protected function initialise(): void {
global $CFG;
// Our main entity, it contains all of the column definitions that we need.
$entityuser = new user();
$entityuseralias = $entityuser->get_table_alias('user');
$this->set_main_table('user', $entityuseralias);
$this->add_entity($entityuser);
// Any columns required by actions should be defined here to ensure they're always available.
$this->add_base_fields("{$entityuseralias}.id, {$entityuseralias}.confirmed, {$entityuseralias}.mnethostid,
{$entityuseralias}.suspended, {$entityuseralias}.username");
$paramguest = database::generate_param_name();
$this->add_base_condition_sql("{$entityuseralias}.deleted <> 1 AND {$entityuseralias}.id <> :{$paramguest}",
[$paramguest => $CFG->siteguest]);
$entitycohortmember = new cohort_member();
$entitycohortmemberalias = $entitycohortmember->get_table_alias('cohort_members');
$this->add_entity($entitycohortmember
->add_joins($entitycohortmember->get_joins())
->add_join("LEFT JOIN {cohort_members} {$entitycohortmemberalias}
ON {$entityuseralias}.id = {$entitycohortmemberalias}.userid")
);
$entitycohort = new cohort();
$entitycohortalias = $entitycohort->get_table_alias('cohort');
$this->add_entity($entitycohort
->add_joins($entitycohort->get_joins())
->add_joins($entitycohortmember->get_joins())
->add_join("LEFT JOIN {cohort} {$entitycohortalias}
ON {$entitycohortalias}.id = {$entitycohortmemberalias}.cohortid")
);
// Join the role entity (Needed for the system role filter).
$roleentity = new role();
$role = $roleentity->get_table_alias('role');
$this->add_entity($roleentity
->add_join("LEFT JOIN (
SELECT DISTINCT r0.id, ras.userid
FROM {role} r0
JOIN {role_assignments} ras ON ras.roleid = r0.id
WHERE ras.contextid = ".SYSCONTEXTID."
) {$role} ON {$role}.userid = {$entityuseralias}.id")
);
// Now we can call our helper methods to add the content we want to include in the report.
$this->add_columns();
$this->add_filters();
$this->add_actions();
// Set if report can be downloaded.
$this->set_downloadable(false);
}
/**
* Validates access to view this report
*
* @return bool
*/
protected function can_view(): bool {
return has_any_capability(['moodle/user:update', 'moodle/user:delete'], system::instance());
}
/**
* Adds the columns we want to display in the report
*
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
* unique identifier
*/
public function add_columns(): void {
$entityuser = $this->get_entity('user');
$entityuseralias = $entityuser->get_table_alias('user');
$this->add_column($entityuser->get_column('fullnamewithlink'));
// Include identity field columns.
$identitycolumns = $entityuser->get_identity_columns($this->get_context(), ['city', 'country', 'lastaccesstime']);
foreach ($identitycolumns as $identitycolumn) {
$this->add_column($identitycolumn);
}
// These columns are always shown in the users list.
$this->add_column($entityuser->get_column('city'));
$this->add_column($entityuser->get_column('country'));
$this->add_column(($entityuser->get_column('lastaccess'))
->set_callback(static function ($value, \stdClass $row): string {
if ($row->lastaccess) {
return format_time(time() - $row->lastaccess);
}
return get_string('never');
})
);
if ($column = $this->get_column('user:fullnamewithlink')) {
$column
->add_fields("{$entityuseralias}.suspended, {$entityuseralias}.confirmed")
->add_callback(static function(string $fullname, \stdClass $row): string {
if ($row->suspended) {
$fullname .= ' ' . \html_writer::tag('span', get_string('suspended', 'moodle'),
['class' => 'badge badge-secondary ml-1']);
}
if (!$row->confirmed) {
$fullname .= ' ' . \html_writer::tag('span', get_string('confirmationpending', 'admin'),
['class' => 'badge badge-danger ml-1']);
}
return $fullname;
});
}
$this->set_initial_sort_column('user:fullnamewithlink', SORT_ASC);
$this->set_default_no_results_notice(new lang_string('nousersfound', 'moodle'));
}
/**
* Adds the filters we want to display in the report
*
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
* unique identifier
*/
protected function add_filters(): void {
$entityuser = $this->get_entity('user');
$entityuseralias = $entityuser->get_table_alias('user');
$filters = [
'user:firstname',
'user:lastname',
'user:username',
'user:idnumber',
'user:email',
'user:department',
'user:institution',
'user:city',
'user:country',
'user:confirmed',
'user:suspended',
'user:timecreated',
'user:lastaccess',
'user:timemodified',
'user:auth',
'user:lastip',
'cohort:idnumber',
'role:name',
];
$this->add_filters_from_entities($filters);
// Enrolled in any course filter.
$ue = database::generate_alias();
[$now1, $now2] = database::generate_param_names(2);
$now = time();
$sql = "CASE WHEN ({$entityuseralias}.id IN (
SELECT userid FROM {user_enrolments} {$ue}
WHERE {$ue}.status = " . ENROL_USER_ACTIVE . "
AND ({$ue}.timestart = 0 OR {$ue}.timestart < :{$now1})
AND ({$ue}.timeend = 0 OR {$ue}.timeend > :{$now2})
)) THEN 1 ELSE 0 END";
$this->add_filter((new filter(
boolean_select::class,
'enrolledinanycourse',
new lang_string('anycourses', 'filters'),
$this->get_entity('user')->get_entity_name(),
))
->set_field_sql($sql, [
$now1 => $now,
$now2 => $now,
])
->add_joins($this->get_joins()));
// Add user profile fields filters.
$userprofilefields = new user_profile_fields($entityuseralias . '.id', $entityuser->get_entity_name());
foreach ($userprofilefields->get_filters() as $filter) {
$this->add_filter($filter);
}
// Set options for system role filter.
if ($filter = $this->get_filter('role:name')) {
$filter
->set_header(new lang_string('globalrole', 'role'))
->set_options(get_assignable_roles(system::instance()));
}
}
/**
* Add the system report actions. An extra column will be appended to each row, containing all actions added here
*
* Note the use of ":id" placeholder which will be substituted according to actual values in the row
*/
protected function add_actions(): void {
global $DB, $USER;
$contextsystem = system::instance();
// Action to edit users.
$this->add_action((new action(
new moodle_url('/user/editadvanced.php', ['id' => ':id', 'course' => get_site()->id]),
new pix_icon('t/edit', ''),
[],
false,
new lang_string('edit', 'moodle'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && (is_siteadmin($USER) || !is_siteadmin($row));
}));
// Action to suspend users (non mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['suspend' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/show', ''),
[],
false,
new lang_string('suspenduser', 'admin'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended && !is_mnet_remote_user($row) &&
!($row->id == $USER->id || is_siteadmin($row));
}));
// Action to unsuspend users (non mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['unsuspend' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/hide', ''),
[],
false,
new lang_string('unsuspenduser', 'admin'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && $row->suspended && !is_mnet_remote_user($row) &&
!($row->id == $USER->id || is_siteadmin($row));
}));
// Action to unlock users (non mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['unlock' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/unlock', ''),
[],
false,
new lang_string('unlockaccount', 'admin'),
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && !is_mnet_remote_user($row) &&
login_is_lockedout($row);
}));
// Action to suspend users (mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'deny']),
new pix_icon('t/show', ''),
[],
false,
new lang_string('denyaccess', 'mnet'),
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
$acl = $DB->get_record('mnet_sso_access_control', ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]);
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
is_mnet_remote_user($row) && $acl->accessctrl == 'allow';
}));
// Action to unsuspend users (mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'allow']),
new pix_icon('t/hide', ''),
[],
false,
new lang_string('allowaccess', 'mnet'),
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
$acl = $DB->get_record('mnet_sso_access_control', ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]);
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
is_mnet_remote_user($row) && $acl->accessctrl == 'deny';
}));
// Action to delete users.
$this->add_action((new action(
new moodle_url('/admin/user.php', ['delete' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/delete', ''),
['class' => 'text-danger'],
false,
new lang_string('delete', 'moodle'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:delete', $contextsystem) &&
!is_mnet_remote_user($row) && $row->id != $USER->id && !is_siteadmin($row);
}));
$this->add_action_divider();
// Action to confirm users.
$this->add_action((new action(
new moodle_url('/admin/user.php', ['confirmuser' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/check', ''),
[],
false,
new lang_string('confirmaccount', 'moodle'),
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && !$row->confirmed;
}));
// Action to resend email.
$this->add_action((new action(
new moodle_url('/admin/user.php', ['resendemail' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/email', ''),
[],
false,
new lang_string('resendemail', 'moodle'),
))->add_callback(static function(\stdclass $row): bool {
return !$row->confirmed && !is_mnet_remote_user($row);
}));
}
/**
* Row class
*
* @param \stdClass $row
* @return string
*/
public function get_row_class(\stdClass $row): string {
return $row->suspended ? 'text-muted' : '';
}
}
+147 -10
View File
@@ -1,4 +1,4 @@
@core @core_admin
@core @core_admin @core_reportbuilder
Feature: An administrator can browse user accounts
In order to find the user accounts I am looking for
As an admin
@@ -17,23 +17,23 @@ Feature: An administrator can browse user accounts
Scenario: User accounts display default fields
When I navigate to "Users > Accounts > Browse list of users" in site administration
# Name field always present, email field is default for showidentity.
Then the following should exist in the "users" table:
Then the following should exist in the "reportbuilder-table" table:
| First name / Last name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
# Should not see other identity fields or non-default name fields.
And I should not see "Department" in the "table" "css_element"
And I should not see "Attack"
And I should not see "Favourite frog" in the "table" "css_element"
And I should not see "Kermit"
And I should not see "First name - phonetic" in the "table" "css_element"
And I should not see "Yoozare"
And I should not see "Department" in the "reportbuilder-table" "table"
And I should not see "Attack" in the "reportbuilder-table" "table"
And I should not see "Favourite frog" in the "reportbuilder-table" "table"
And I should not see "Kermit" in the "reportbuilder-table" "table"
And I should not see "First name - phonetic" in the "reportbuilder-table" "table"
And I should not see "Yoozare" in the "reportbuilder-table" "table"
Scenario: User accounts with extra name fields
Given the following config values are set as admin:
| alternativefullnameformat | firstnamephonetic lastname |
When I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "users" table:
Then the following should exist in the "reportbuilder-table" table:
| First name - phonetic / Last name | Email address |
| Yewzer One | one@example.com |
| Yoozare Two | two@example.com |
@@ -42,13 +42,14 @@ Feature: An administrator can browse user accounts
Given the following config values are set as admin:
| showuseridentity | department,profile_field_frog |
When I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "users" table:
Then the following should exist in the "reportbuilder-table" table:
| First name / Last name | Favourite frog | Department |
| User One | Kermit | Attack |
| User Two | Tree | Defence |
And I should not see "Email address" in the "table" "css_element"
And I should not see "one@example.com"
@javascript
Scenario: Sort user accounts by custom profile field
Given the following config values are set as admin:
| showuseridentity | profile_field_frog |
@@ -57,3 +58,139 @@ Feature: An administrator can browse user accounts
Then "Kermit" "text" should appear before "Tree" "text"
And I follow "Favourite frog"
Then "Tree" "text" should appear before "Kermi" "text"
@javascript
Scenario: Edit user information
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Edit" action in the "User One" report row
And I set the field "Last name" to "OneOne"
And I press "Update profile"
Then I should see "User OneOne"
@javascript
Scenario: Suspend and activate user account
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Suspend user account" action in the "User One" report row
And I should see "Suspended" in the "User One" "table_row"
And I press "Activate user account" action in the "User One" report row
Then I should not see "Suspended" in the "User One" "table_row"
@javascript
Scenario: Delete a user account
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Delete" action in the "User One" report row
And I should see "Are you absolutely sure you want to completely delete the user 'User One'"
And I press "Delete"
Then I should not see "User One" in the "reportbuilder-table" "table"
@javascript
Scenario: Resend email and confirm a user account
Given the following "users" exist:
| username | firstname | lastname | email | confirmed |
| user3 | User | Three | three@example.com | 0 |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "Confirmation pending" in the "User Three" "table_row"
And I press "Resend email" action in the "User Three" report row
And I should see "Confirmation email sent successfully"
And I press "Confirm" action in the "User Three" report row
And I should not see "Confirmation pending" in the "User Three" "table_row"
@javascript
Scenario: User report filters
Given the following "users" exist:
| username | firstname | lastname | email | profile_field_frog |
| user3 | User | Three | three@example.com | Glass |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name / Last name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
| User Three | three@example.com |
And I click on "Filters" "button"
And I set the following fields in the "Last name" "core_reportbuilder > Filter" to these values:
| Last name operator | Is equal to |
| Last name value | Three |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
| Favourite frog operator | Is equal to |
| Favourite frog value | Kermit |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
@javascript
Scenario: User report enrolled in any course filter
Given the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user2 | C1 | student |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name / Last name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
And I click on "Filters" "button"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | Yes |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
@javascript
Scenario: User report system role and course role filters
Given the following "users" exist:
| username | firstname | lastname | email |
| user3 | User | Three | three@example.com |
And the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | editingteacher |
| user3 | C1 | student |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| user1 | coursecreator | system | |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name / Last name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
| User Three | three@example.com |
And I click on "Filters" "button"
And I set the following fields in the "System role" "core_reportbuilder > Filter" to these values:
| System role operator | Is equal to |
| System role value | Course creator |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
| Role name | Teacher |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
Scenario: Add a new user
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "Add a new user" "link"
Then I should see "Username"
And I should see "User picture"
And I should see "Additional names"
+116 -96
View File
@@ -1,4 +1,4 @@
@core @core_admin
@core @core_admin @core_reportbuilder
Feature: An administrator can filter user accounts by role, cohort and other profile fields
In order to find the user accounts I am looking for
As an admin
@@ -33,109 +33,129 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
@javascript
Scenario: Filter user accounts by role and cohort
When I set the following fields to these values:
| courserole_rl | Student |
| courserole_ct | any category |
| courserole | C1 |
And I press "Add filter"
Then I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should not see "User Four"
And I set the following fields to these values:
| cohort | CH1 |
And I press "Add filter"
And I should not see "User One"
And I should see "User Two"
And I should see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should see "User Four"
When I click on "Filters" "button"
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
| Role name | Student |
| Course short name | C1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Cohort ID" "core_reportbuilder > Filter" to these values:
| Cohort ID operator | Is equal to |
| Cohort ID value | CH1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter user accounts by confirm and authentication method
When I set the following fields to these values:
| Confirmed | No |
And I press "Add filter"
Then I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should see "User Four"
And I set the following fields to these values:
| Authentication | manual |
And I press "Add filter"
And I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should not see "User Four"
When I click on "Filters" "button"
And I set the following fields in the "Confirmed" "core_reportbuilder > Filter" to these values:
| Confirmed operator | No |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Authentication" "core_reportbuilder > Filter" to these values:
| Authentication operator | Is equal to |
| Authentication value | Manual accounts |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter user accounts by enrolled in any course
When I set the following fields to these values:
| id_anycourses | Yes |
And I press "Add filter"
Then I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I set the following fields to these values:
| id_anycourses | No |
And I press "Add filter"
And I should not see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should see "User Four"
When I click on "Filters" "button"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | Yes |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | No |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter user accounts by last IP address
When I set the following fields to these values:
| id_lastip | 127.0.1.1 |
And I press "Add filter"
Then I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I set the following fields to these values:
| id_lastip | 127.0.1.2 |
And I press "Add filter"
And I should not see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should see "User Four"
And I press "Remove all filters"
And I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should see "User Four"
When I click on "Filters" "button"
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
| Last IP address operator | Is equal to |
| Last IP address value | 127.0.1.1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
| Last IP address operator | Is equal to |
| Last IP address value | 127.0.1.2 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter users by institution and department
When I set the field "id_institution" to "moodle"
And I press "Add filter"
Then I should see "User One"
And I should see "User Two"
And I should not see "User Three"
And I should not see "User Four"
And I set the field "id_department" to "red"
And I press "Add filter"
And I should see "User One"
And I should not see "User Two"
When I click on "Filters" "button"
And I set the following fields in the "Institution" "core_reportbuilder > Filter" to these values:
| Institution operator | Is equal to |
| Institution value | moodle |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Department" "core_reportbuilder > Filter" to these values:
| Department operator | Is equal to |
| Department value | red |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter users by custom profile field (specific or any)
When I set the field "id_profile_fld" to "Favourite frog"
And I set the field "id_profile" to "Kermit"
And I press "Add filter"
Then I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I set the field "id_profile_fld" to "any field"
And I set the field "id_profile" to "Zombie"
And I press "Add filter"
And I should see "User Two"
And I should not see "User One"
And I should not see "User Three"
And I should not see "User Four"
When I click on "Filters" "button"
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
| Favourite frog operator | Is equal to |
| Favourite frog value | Kermit |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Type of undead" "core_reportbuilder > Filter" to these values:
| Type of undead operator | Is equal to |
| Type of undead value | Zombie |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
@@ -1,150 +0,0 @@
@core @core_admin @javascript
Feature: An administrator can configure the available user list filters
In order to have all needed user filters instantly at hand
As an admin
I want to configure the filters which are shown as default
Scenario: Do not change the user filter default configuration
When I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
Scenario: Change the user filter default configuration to something else
Given the following config values are set as admin:
| userfiltersdefault | realname,username,email |
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should see "Username" in the "New filter" "fieldset"
And I should see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should see "Username" in the "New filter" "fieldset"
And I should see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
Scenario: Change the user filter default configuration to no filter at all
Given the following config values are set as admin:
| userfiltersdefault | |
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
+12 -272
View File
@@ -3,18 +3,11 @@
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/authlib.php');
require_once($CFG->dirroot.'/user/filters/lib.php');
require_once($CFG->dirroot.'/user/lib.php');
$delete = optional_param('delete', 0, PARAM_INT);
$confirm = optional_param('confirm', '', PARAM_ALPHANUM); //md5 confirmation hash
$confirmuser = optional_param('confirmuser', 0, PARAM_INT);
$sort = optional_param('sort', 'name', PARAM_ALPHANUMEXT);
$dir = optional_param('dir', 'ASC', PARAM_ALPHA);
$page = optional_param('page', 0, PARAM_INT);
$perpage = optional_param('perpage', 30, PARAM_INT); // how many per page
$ru = optional_param('ru', '2', PARAM_INT); // show remote users
$lu = optional_param('lu', '2', PARAM_INT); // show local users
$acl = optional_param('acl', '0', PARAM_INT); // id of user to tweak mnet ACL (requires $access)
$suspend = optional_param('suspend', 0, PARAM_INT);
$unsuspend = optional_param('unsuspend', 0, PARAM_INT);
@@ -30,17 +23,7 @@
throw new \moodle_exception('nopermissions', 'error', '', 'edit/delete users');
}
$stredit = get_string('edit');
$strdelete = get_string('delete');
$strdeletecheck = get_string('deletecheck');
$strshowallusers = get_string('showallusers');
$strsuspend = get_string('suspenduser', 'admin');
$strunsuspend = get_string('unsuspenduser', 'admin');
$strunlock = get_string('unlockaccount', 'admin');
$strconfirm = get_string('confirm');
$strresendemail = get_string('resendemail');
$returnurl = new moodle_url('/admin/user.php', array('sort' => $sort, 'dir' => $dir, 'perpage' => $perpage, 'page'=>$page));
$returnurl = new moodle_url('/admin/user.php');
$PAGE->set_primary_active_tab('siteadminnode');
$PAGE->navbar->add(get_string('userlist', 'admin'), $PAGE->url);
@@ -177,263 +160,20 @@
redirect($returnurl);
}
// create the user filter form
$ufiltering = new user_filtering();
echo $OUTPUT->header();
// Carry on with the user listing
$context = context_system::instance();
// These columns are always shown in the users list.
$requiredcolumns = array('city', 'country', 'lastaccess');
// Extra columns containing the extra user fields, excluding the required columns (city and country, to be specific).
$userfields = \core_user\fields::for_identity($context, true)->excluding(...$requiredcolumns);
$extracolumns = $userfields->get_required_fields();
// Get all user name fields as an array, but with firstname and lastname first.
$allusernamefields = \core_user\fields::get_name_fields(true);
$columns = array_merge($allusernamefields, $extracolumns, $requiredcolumns);
foreach ($columns as $column) {
$string[$column] = \core_user\fields::get_display_name($column);
if ($sort != $column) {
$columnicon = "";
if ($column == "lastaccess") {
$columndir = "DESC";
} else {
$columndir = "ASC";
}
} else {
$columndir = $dir == "ASC" ? "DESC":"ASC";
if ($column == "lastaccess") {
$columnicon = ($dir == "ASC") ? "sort_desc" : "sort_asc";
} else {
$columnicon = ($dir == "ASC") ? "sort_asc" : "sort_desc";
}
$columnicon = $OUTPUT->pix_icon('t/' . $columnicon, get_string(strtolower($columndir)), 'core',
['class' => 'iconsort']);
}
$$column = "<a href=\"user.php?sort=$column&amp;dir=$columndir\">".$string[$column]."</a>$columnicon";
}
// We need to check that alternativefullnameformat is not set to '' or language.
// We don't need to check the fullnamedisplay setting here as the fullname function call further down has
// the override parameter set to true.
$fullnamesetting = $CFG->alternativefullnameformat;
// If we are using language or it is empty, then retrieve the default user names of just 'firstname' and 'lastname'.
if ($fullnamesetting == 'language' || empty($fullnamesetting)) {
// Set $a variables to return 'firstname' and 'lastname'.
$a = new stdClass();
$a->firstname = 'firstname';
$a->lastname = 'lastname';
// Getting the fullname display will ensure that the order in the language file is maintained.
$fullnamesetting = get_string('fullnamedisplay', null, $a);
}
// Order in string will ensure that the name columns are in the correct order.
$usernames = order_in_string($allusernamefields, $fullnamesetting);
$fullnamedisplay = array();
foreach ($usernames as $name) {
// Use the link from $$column for sorting on the user's name.
$fullnamedisplay[] = ${$name};
}
// All of the names are in one column. Put them into a string and separate them with a /.
$fullnamedisplay = implode(' / ', $fullnamedisplay);
// If $sort = name then it is the default for the setting and we should use the first name to sort by.
if ($sort == "name") {
// Use the first item in the array.
$sort = reset($usernames);
}
list($extrasql, $params) = $ufiltering->get_sql_filter();
$users = get_users_listing($sort, $dir, $page*$perpage, $perpage, '', '', '',
$extrasql, $params, $context);
$usercount = get_users(false);
$usersearchcount = get_users(false, '', false, null, "", '', '', '', '', '*', $extrasql, $params);
if ($extrasql !== '') {
echo $OUTPUT->heading("$usersearchcount / $usercount ".get_string('users'));
$usercount = $usersearchcount;
} else {
echo $OUTPUT->heading("$usercount ".get_string('users'));
}
$strall = get_string('all');
$baseurl = new moodle_url('/admin/user.php', array('sort' => $sort, 'dir' => $dir, 'perpage' => $perpage));
echo $OUTPUT->paging_bar($usercount, $page, $perpage, $baseurl);
flush();
if (!$users) {
$match = array();
echo $OUTPUT->heading(get_string('nousersfound'));
$table = NULL;
} else {
$countries = get_string_manager()->get_list_of_countries(true);
if (empty($mnethosts)) {
$mnethosts = $DB->get_records('mnet_host', null, 'id', 'id,wwwroot,name');
}
foreach ($users as $key => $user) {
if (isset($countries[$user->country])) {
$users[$key]->country = $countries[$user->country];
}
}
if ($sort == "country") {
// Need to resort by full country name, not code.
foreach ($users as $user) {
$susers[$user->id] = $user->country;
}
// Sort by country name, according to $dir.
if ($dir === 'DESC') {
arsort($susers);
} else {
asort($susers);
}
foreach ($susers as $key => $value) {
$nusers[] = $users[$key];
}
$users = $nusers;
}
$table = new html_table();
$table->head = array ();
$table->colclasses = array();
$table->head[] = $fullnamedisplay;
$table->attributes['class'] = 'admintable generaltable table-sm';
foreach ($extracolumns as $field) {
$table->head[] = ${$field};
}
$table->head[] = $city;
$table->head[] = $country;
$table->head[] = $lastaccess;
$table->head[] = get_string('edit');
$table->colclasses[] = 'centeralign';
$table->head[] = "";
$table->colclasses[] = 'centeralign';
$table->id = "users";
foreach ($users as $user) {
$buttons = array();
$lastcolumn = '';
// delete button
if (has_capability('moodle/user:delete', $sitecontext)) {
if (is_mnet_remote_user($user) or $user->id == $USER->id or is_siteadmin($user)) {
// no deleting of self, mnet accounts or admins allowed
} else {
$url = new moodle_url($returnurl, array('delete'=>$user->id, 'sesskey'=>sesskey()));
$buttons[] = html_writer::link($url, $OUTPUT->pix_icon('t/delete', $strdelete));
}
}
// suspend button
if (has_capability('moodle/user:update', $sitecontext)) {
if (is_mnet_remote_user($user)) {
// mnet users have special access control, they can not be deleted the standard way or suspended
$accessctrl = 'allow';
if ($acl = $DB->get_record('mnet_sso_access_control', array('username'=>$user->username, 'mnet_host_id'=>$user->mnethostid))) {
$accessctrl = $acl->accessctrl;
}
$changeaccessto = ($accessctrl == 'deny' ? 'allow' : 'deny');
$buttons[] = " (<a href=\"?acl={$user->id}&amp;accessctrl=$changeaccessto&amp;sesskey=".sesskey()."\">".get_string($changeaccessto, 'mnet') . " access</a>)";
} else {
if ($user->suspended) {
$url = new moodle_url($returnurl, array('unsuspend'=>$user->id, 'sesskey'=>sesskey()));
$buttons[] = html_writer::link($url, $OUTPUT->pix_icon('t/show', $strunsuspend));
} else {
if ($user->id == $USER->id or is_siteadmin($user)) {
// no suspending of admins or self!
} else {
$url = new moodle_url($returnurl, array('suspend'=>$user->id, 'sesskey'=>sesskey()));
$buttons[] = html_writer::link($url, $OUTPUT->pix_icon('t/hide', $strsuspend));
}
}
if (login_is_lockedout($user)) {
$url = new moodle_url($returnurl, array('unlock'=>$user->id, 'sesskey'=>sesskey()));
$buttons[] = html_writer::link($url, $OUTPUT->pix_icon('t/unlock', $strunlock));
}
}
}
// edit button
if (has_capability('moodle/user:update', $sitecontext)) {
// prevent editing of admins by non-admins
if (is_siteadmin($USER) or !is_siteadmin($user)) {
$url = new moodle_url('/user/editadvanced.php', array('id'=>$user->id, 'course'=>$site->id));
$buttons[] = html_writer::link($url, $OUTPUT->pix_icon('t/edit', $stredit));
}
}
// the last column - confirm or mnet info
if (is_mnet_remote_user($user)) {
// all mnet users are confirmed, let's print just the name of the host there
if (isset($mnethosts[$user->mnethostid])) {
$lastcolumn = get_string($accessctrl, 'mnet').': '.$mnethosts[$user->mnethostid]->name;
} else {
$lastcolumn = get_string($accessctrl, 'mnet');
}
} else if ($user->confirmed == 0) {
if (has_capability('moodle/user:update', $sitecontext)) {
$lastcolumn = html_writer::link(new moodle_url($returnurl, array('confirmuser'=>$user->id, 'sesskey'=>sesskey())), $strconfirm);
} else {
$lastcolumn = "<span class=\"dimmed_text\">".get_string('confirm')."</span>";
}
$lastcolumn .= ' | ' . html_writer::link(new moodle_url($returnurl,
[
'resendemail' => $user->id,
'sesskey' => sesskey()
]
), $strresendemail);
}
if ($user->lastaccess) {
$strlastaccess = format_time(time() - $user->lastaccess);
} else {
$strlastaccess = get_string('never');
}
$fullname = fullname($user, true);
$row = array ();
$row[] = "<a href=\"../user/view.php?id=$user->id&amp;course=$site->id\">$fullname</a>";
foreach ($extracolumns as $field) {
$row[] = s($user->{$field});
}
$row[] = $user->city;
$row[] = $user->country;
$row[] = $strlastaccess;
if ($user->suspended) {
foreach ($row as $k=>$v) {
$row[$k] = html_writer::tag('span', $v, array('class'=>'usersuspended'));
}
}
$row[] = implode(' ', $buttons);
$row[] = $lastcolumn;
$table->data[] = $row;
}
}
// add filters
$ufiltering->display_add();
$ufiltering->display_active();
if (!empty($table)) {
echo html_writer::start_tag('div', array('class'=>'no-overflow'));
echo html_writer::table($table);
echo html_writer::end_tag('div');
echo $OUTPUT->paging_bar($usercount, $page, $perpage, $baseurl);
}
if (has_capability('moodle/user:create', $sitecontext)) {
$url = new moodle_url('/user/editadvanced.php', array('id' => -1));
echo $OUTPUT->single_button($url, get_string('addnewuser'), 'get');
echo html_writer::start_div('d-flex mb-2');
$url = new moodle_url('/user/editadvanced.php', ['id' => -1]);
echo html_writer::link($url, get_string('addnewuser', 'moodle'), [
'class' => 'btn btn-primary ml-auto',
'data-action' => 'add-user',
]);
echo html_writer::end_div();
}
$report = \core_reportbuilder\system_report_factory::create(\core_admin\reportbuilder\local\systemreports\users::class,
context_system::instance());
echo $report->output();
echo $OUTPUT->footer();
+2 -1
View File
@@ -415,6 +415,7 @@ $string['configvisiblecourses'] = 'Display courses in hidden categories normally
$string['configwarning'] = 'Be careful modifying these settings - strange values could cause problems.';
$string['configyuicomboloading'] = 'This options enables combined file loading optimisation for YUI libraries. This setting should be enabled on production sites for performance reasons.';
$string['confirmation'] = 'Confirmation';
$string['confirmationpending'] = 'Confirmation pending';
$string['confirmcontextlock'] = '{$a->contextname} is currently unfrozen. Freezing it will make it read-only and prevent users from making changes. Are you sure you wish to continue?';
$string['confirmcontextunlock'] = '{$a->contextname} is currently frozen. Unfreezing it will allow users to make changes. Are you sure you wish to continue?';
$string['confirmdeletecomments'] = 'Are you sure you want to delete the selected comment(s)?';
@@ -1575,7 +1576,7 @@ $string['userimagesdisabled'] = 'Profile user images are disabled';
$string['userlist'] = 'Browse list of users';
$string['userdefaultpreferences'] = 'User default preferences';
$string['userfiltersdefault'] = 'Default user filters';
$string['userfiltersdefault_desc'] = 'Select the filters that should be shown on the \'Browse list of users\' page and on the \'Bulk user actions\' page. Hold down the Ctrl key to select multiple items. Any filters not selected will be available by clicking the \'Show more\' link.';
$string['userfiltersdefault_desc'] = 'Choose the filters you want to display on the \'Bulk user actions\' page. To select multiple filters, hold down the Ctrl key. Filters not selected will still be accessible through the \'Show more\' link';
$string['usermanagement'] = 'User management';
$string['userpreference'] = 'User preference';
$string['userpolicies'] = 'User policies';
+1
View File
@@ -118,3 +118,4 @@ copycourseheading,core_backup
backupcourse,core_backup
linkcoursesections,core_admin
linkcoursesections_help,core_admin
showallusers,core
+2
View File
@@ -30,6 +30,7 @@ $string['addtoacl'] = 'Add to access control';
$string['allhosts'] = 'All hosts';
$string['allhosts_no_options'] = 'No options are available when viewing multiple hosts';
$string['allow'] = 'Allow';
$string['allowaccess'] = 'Allow access';
$string['applicationtype'] = 'Application type';
$string['authfail_nosessionexists'] = 'Authorisation failed: the mnet session does not exist.';
$string['authfail_sessiontimedout'] = 'Authorisation failed: the mnet session has timed out.';
@@ -54,6 +55,7 @@ $string['deleteoutoftime'] = 'Your 60-second window for deleting this key has ex
$string['deleteuserrecord'] = 'SSO ACL: delete record for user \'{$a->user}\' from {$a->host}.';
$string['deletewrongkeyvalue'] = 'An error has occurred. If you were not trying to delete your server\'s SSL key, it is possible you have been the subject of a malicious attack. No action has been taken.';
$string['deny'] = 'Deny';
$string['denyaccess'] = 'Deny access';
$string['description'] = 'Description';
$string['duplicate_usernames'] = 'We failed to create an index on the columns "mnethostid" and "username" in your user table.<br />This can occur when you have <a href="{$a}" target="_blank">duplicate usernames in your user table</a>.<br />Your upgrade should still complete successfully. Click on the link above, and instructions on fixing this problem will appear in a new window. You can attend to that at the end of the upgrade.<br />';
$string['enabled_for_all'] = '(This service has been enabled for all hosts).';
+3 -2
View File
@@ -288,6 +288,7 @@ $string['completed'] = 'Completed';
$string['completereport'] = 'Complete report';
$string['configuration'] = 'Configuration';
$string['confirm'] = 'Confirm';
$string['confirmaccount'] = 'Confirm account';
$string['confirmdeletesection'] = 'Are you absolutely sure you want to completely delete "{$a}" and all the activities it contains?';
$string['confirmed'] = 'Your registration has been confirmed';
$string['confirmednot'] = 'Your registration has not yet been confirmed. Please check your mailbox for a confirmation email.';
@@ -1862,7 +1863,7 @@ $string['requestreason'] = 'Reason for course request';
$string['requests'] = 'Requests';
$string['required'] = 'Required';
$string['requirespayment'] = 'This course requires payment for access';
$string['resendemail'] = 'Resend email';
$string['resendemail'] = 'Resend confirmation email';
$string['reset'] = 'Reset';
$string['resetcomponent'] = 'Component';
$string['resetcourse'] = 'Reset course';
@@ -2045,7 +2046,6 @@ $string['showadvancededitor'] = 'Advanced';
$string['showadvancedsettings'] = 'Show advanced settings';
$string['showall'] = 'Show all {$a}';
$string['showallcourses'] = 'Show all courses';
$string['showallusers'] = 'Show all users';
$string['showblockcourse'] = 'Show list of courses containing block';
$string['showcategory'] = 'Show {$a}';
$string['showchartdata'] = 'Show chart data';
@@ -2499,3 +2499,4 @@ $string['passwordsent'] = 'Password has been sent';
$string['passwordrecovery'] = 'Yes, help me log in';
$string['passwordconfirmchange'] = 'Confirm password change';
$string['passwordnohelp'] = 'No help is available to find your lost password. Please contact your Moodle administrator.';
$string['showallusers'] = 'Show all users';
@@ -444,6 +444,7 @@ class user extends base {
'username' => new lang_string('username'),
'moodlenetprofile' => new lang_string('moodlenetprofile', 'user'),
'timecreated' => new lang_string('timecreated', 'core_reportbuilder'),
'timemodified' => new lang_string('timemodified', 'core_reportbuilder'),
'lastip' => new lang_string('lastip'),
];
}
@@ -465,6 +466,7 @@ class user extends base {
break;
case 'lastaccess':
case 'timecreated':
case 'timemodified':
$fieldtype = column::TYPE_TIMESTAMP;
break;
default:
+1 -1
View File
@@ -7,7 +7,7 @@ Feature: Administration nav tabs
And I click on "Site administration" "link"
And I click on "Users" "link"
And I click on "Browse list of users" "link"
And I should see "New filter"
And I should see "Add a new user"
When I press the "back" button in the browser
Then I should see "Cohorts"
+7 -4
View File
@@ -77,10 +77,13 @@ Feature: Bulk enrolments
And I set the field "Available" to "Student 2"
And I press "Add to selection"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I set the following fields to these values:
| username | student1 |
And I press "Add filter"
And I click on "Delete" "link"
And I click on "Filters" "button"
And I set the following fields in the "Username" "core_reportbuilder > Filter" to these values:
| Username operator | Is equal to |
| Username value | student1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I press "Delete" action in the "Student 1" report row
And I press "Delete"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
And I set the field "id_action" to "Add to cohort"
+7 -4
View File
@@ -100,10 +100,13 @@ Feature: Deleting users
And I press "Add to selection"
Then I should see "User One"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I set the following fields to these values:
| username | user1 |
And I press "Add filter"
And I click on "Delete" "link"
And I click on "Filters" "button"
And I set the following fields in the "Username" "core_reportbuilder > Filter" to these values:
| Username operator | Is equal to |
| Username value | user1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I press "Delete" action in the "User One" report row
And I press "Delete"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should not see "User One"
+37 -33
View File
@@ -17,43 +17,47 @@ Feature: Filter users by idnumber
@javascript
Scenario: Filtering id numbers - with case "is empty"
# We should see see admin on the user list, the following e-mail is admin's e-mail.
Then I should see "moodle@example.com" in the "users" "table"
And I should see "Teacher" in the "users" "table"
And I should see "Student1" in the "users" "table"
And I should see "Student2" in the "users" "table"
And I should see "Student3" in the "users" "table"
And I follow "Show more..."
And I set the field "id_idnumber_op" to "is empty"
When I press "Add filter"
Then I should see "moodle@example.com" in the "reportbuilder-table" "table"
And I should see "Teacher" in the "reportbuilder-table" "table"
And I should see "Student1" in the "reportbuilder-table" "table"
And I should see "Student2" in the "reportbuilder-table" "table"
And I should see "Student3" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I set the following fields in the "ID number" "core_reportbuilder > Filter" to these values:
| ID number operator | Is empty |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
# We should see admin on the user list, the following e-mail is admin's e-mail.
Then I should see "moodle@example.com" in the "users" "table"
And I should not see "Teacher" in the "users" "table"
And I should not see "Student1" in the "users" "table"
And I should not see "Student2" in the "users" "table"
And I should not see "Student3" in the "users" "table"
Then I should see "moodle@example.com" in the "reportbuilder-table" "table"
And I should not see "Teacher" in the "reportbuilder-table" "table"
And I should not see "Student1" in the "reportbuilder-table" "table"
And I should not see "Student2" in the "reportbuilder-table" "table"
And I should not see "Student3" in the "reportbuilder-table" "table"
@javascript
Scenario Outline: Filtering id numbers - with all other cases
# We should see see admin on the user list, the following e-mail is admin's e-mail.
Then I should see "moodle@example.com" in the "users" "table"
And I should see "Teacher" in the "users" "table"
And I should see "Student1" in the "users" "table"
And I should see "Student2" in the "users" "table"
And I should see "Student3" in the "users" "table"
And I follow "Show more..."
And I set the field "id_idnumber_op" to "<Category>"
And I set the field "idnumber" to "<Argument>"
When I press "Add filter"
Then I should <Admin's Visibility> "moodle@example.com" in the "users" "table"
And I should <Teacher's Vis> "Teacher" in the "users" "table"
And I should <S1's Vis> "Student1" in the "users" "table"
And I should <S2's Vis> "Student2" in the "users" "table"
And I should <S3's Vis> "Student3" in the "users" "table"
Then I should see "moodle@example.com" in the "reportbuilder-table" "table"
And I should see "Teacher" in the "reportbuilder-table" "table"
And I should see "Student1" in the "reportbuilder-table" "table"
And I should see "Student2" in the "reportbuilder-table" "table"
And I should see "Student3" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I set the following fields in the "ID number" "core_reportbuilder > Filter" to these values:
| ID number operator | <Category> |
| ID number value | <Argument> |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
Then I should <Admin's Visibility> "moodle@example.com" in the "reportbuilder-table" "table"
And I should <Teacher's Vis> "Teacher" in the "reportbuilder-table" "table"
And I should <S1's Vis> "Student1" in the "reportbuilder-table" "table"
And I should <S2's Vis> "Student2" in the "reportbuilder-table" "table"
And I should <S3's Vis> "Student3" in the "reportbuilder-table" "table"
Examples:
| Category | Argument | Admin's Visibility | Teacher's Vis | S1's Vis | S2's Vis | S3's Vis |
| contains | 0 | not see | see | see | see | see |
| doesn't contain | 2 | see | not see | see | not see | see |
| is equal to | 2000000 | not see | not see | not see | see | not see |
| starts with | 0 | not see | see | see | not see | not see |
| ends with | 0 | not see | not see | not see | see | see |
| Category | Argument | Admin's Visibility | Teacher's Vis | S1's Vis | S2's Vis | S3's Vis |
| Contains | 0 | not see | see | see | see | see |
| Does not contain | 2 | see | not see | see | not see | see |
| Is equal to | 2000000 | not see | not see | not see | see | not see |
| Starts with | 0 | not see | see | see | not see | not see |
| Ends with | 0 | not see | not see | not see | see | see |
@@ -1,52 +0,0 @@
@core @core_user
Feature: Filter users by time created
In order to find users created relative to a date
As an admin
I need to be able to filter users by their time created date
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| user01 | User | One | user01@example.com |
@javascript
Scenario Outline: Matching user filter by time created
Given I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I follow "Show more..."
# Set the filter fields, excluding admin.
When I set the following fields to these values:
| <enablefield>[enabled] | 1 |
| <enablefield>[year] | <year> |
| Username field limiter | doesn't contain |
| Username value | admin |
And I press "Add filter"
Then I should see "User One" in the "users" "table"
And I should see "1 / 2 Users"
Examples:
| enablefield | year |
# Time created, is after.
| timecreated_sdt | ## -1 year ## %Y ## |
# Time created, is before.
| timecreated_edt | ## +1 year ## %Y ## |
@javascript
Scenario Outline: Non-matching user filter by time created
Given I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I follow "Show more..."
# Set the filter fields, excluding admin.
When I set the following fields to these values:
| <enablefield>[enabled] | 1 |
| <enablefield>[year] | <year> |
| Username field limiter | doesn't contain |
| Username value | admin |
And I press "Add filter"
Then "Users" "table" should not exist
And I should see "0 / 2 Users"
Examples:
| enablefield | year |
# Time created, is after.
| timecreated_sdt | ## +1 year ## %Y ## |
# Time created, is before.
| timecreated_edt | ## -1 year ## %Y ## |
-37
View File
@@ -1,37 +0,0 @@
@core @core_user
Feature: Trim entered user filters
As a system administrator
I need to be able to filter users ignoring whitespace
So that I can find users even when entered data has surrounding whitespace.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher@example.com |
| student1 | Student | 1 | student@example.com |
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
@javascript
Scenario: Filtering username - with case "contains"
When I set the field "id_realname_op" to "contains"
And I set the field "id_realname" to " Teacher "
And I press "Add filter"
# We should see the teacher user, with the trimmed string present.
Then I should see "User full name contains \"Teacher\""
And I should see "Teacher" in the "users" "table"
And I should not see "Student" in the "users" "table"
@javascript
Scenario: Filtering username - with case "contains" and a whitespace string
When I set the field "id_realname_op" to "contains"
And I set the field "id_realname" to " "
And I press "Add filter"
Then I should see "User full name contains \" \""
@javascript
Scenario: Filtering username - with case "is equal to"
When I set the field "id_realname_op" to "is equal to"
And I set the field "id_realname" to " Teacher"
And I press "Add filter"
Then I should see "User full name is equal to \" Teacher\""
+4 -4
View File
@@ -19,7 +19,7 @@ Feature: Tables can be sorted by additional names
@javascript
Scenario: All user names are show and sortable in the administration user list.
Given I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "users" table:
Then the following should exist in the "reportbuilder-table" table:
| First name / Middle name / Alternate name / Last name | Email address |
| Admin User | moodle@example.com |
| Annie Faith Anne Edison | student1@example.com |
@@ -34,11 +34,11 @@ Feature: Tables can be sorted by additional names
And "George David Gman Bradley" "table_row" should appear after "Annie Faith Anne Edison" "table_row"
And "Annie Faith Anne Edison" "table_row" should appear after "Travis Peter Mr T Sutcliff" "table_row"
And I follow "Alternate name"
And "Annie Faith Anne Edison" "table_row" should appear before "George David Gman Bradley" "table_row"
And "George David Gman Bradley" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
And I follow "Alternate name"
And "Annie Faith Anne Edison" "table_row" should appear after "George David Gman Bradley" "table_row"
And "George David Gman Bradley" "table_row" should appear after "Travis Peter Mr T Sutcliff" "table_row"
And I follow "Alternate name"
And "Annie Faith Anne Edison" "table_row" should appear before "George David Gman Bradley" "table_row"
And "George David Gman Bradley" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"
And I follow "Last name"
And "George David Gman Bradley" "table_row" should appear before "Annie Faith Anne Edison" "table_row"
And "Annie Faith Anne Edison" "table_row" should appear before "Travis Peter Mr T Sutcliff" "table_row"