MDL-79270 admin: new filter type for filtering users by course role.

Use in the new browse users system report, to which it is quite
specific. The filter itself is a like for like replacement of the
pre-existing filter on the same page, and is really a combination
of existing role/category/course filters.
This commit is contained in:
Paul Holden 2023-11-08 12:46:35 +00:00 committed by David Carrillo
parent f76a518cb1
commit c25882e8df
No known key found for this signature in database
GPG Key ID: F805F8542D4C72CD
3 changed files with 232 additions and 1 deletions

View File

@ -0,0 +1,107 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_admin\reportbuilder\local\filters;
use core\context\system;
use core_course_category;
use MoodleQuickForm;
use core_reportbuilder\local\filters\base;
use core_reportbuilder\local\helpers\database;
/**
* Course role report filter (by role, category, course)
*
* The provided filter field SQL must refer/return an expression for the user ID (e.g. "{$user}.id")
*
* @package core_admin
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class courserole extends base {
/**
* Setup form
*
* @param MoodleQuickForm $mform
*/
public function setup_form(MoodleQuickForm $mform): void {
$elements = [];
// Role.
$elements['role'] = $mform->createElement('select', "{$this->name}_role", get_string('rolefullname', 'core_role'),
[0 => get_string('anyrole', 'core_filters')] + get_default_enrol_roles(system::instance()));
// Category.
$elements['category'] = $mform->createElement('select', "{$this->name}_category", get_string('category'),
[0 => get_string('anycategory', 'core_filters')] + core_course_category::make_categories_list());
// Course.
$elements['course'] = $mform->createElement('text', "{$this->name}_course", get_string('shortnamecourse'));
$mform->setType("{$this->name}_course", PARAM_RAW);
$mform->addElement('group', "{$this->name}_group", '', $elements, '', false);
}
/**
* Return filter SQL
*
* @param array $values
* @return array
*/
public function get_sql_filter(array $values): array {
[$fieldsql, $params] = $this->filter->get_field_sql_and_params();
[$contextalias, $rolealias, $coursealias] = database::generate_aliases(3);
[$roleparam, $categoryparam, $courseparam] = database::generate_param_names(3);
// Role.
$role = (int) ($values["{$this->name}_role"] ?? 0);
if ($role > 0) {
$selects[] = "{$rolealias}.roleid = :{$roleparam}";
$params[$roleparam] = $role;
}
// Category.
$category = (int) ($values["{$this->name}_category"] ?? 0);
if ($category > 0) {
$selects[] = "{$coursealias}.category = :{$categoryparam}";
$params[$categoryparam] = $category;
}
// Course.
$course = $values["{$this->name}_course"] ?? '';
if ($course !== '') {
$selects[] = "{$coursealias}.shortname = :{$courseparam}";
$params[$courseparam] = $course;
}
// Filter values are not set.
if (empty($selects)) {
return ['', []];
}
return ["{$fieldsql} IN (
SELECT {$rolealias}.userid
FROM {role_assignments} {$rolealias}
JOIN {context} {$contextalias} ON {$contextalias}.id = {$rolealias}.contextid AND {$contextalias}.contextlevel = 50
JOIN {course} {$coursealias} ON {$coursealias}.id = {$contextalias}.instanceid
WHERE " . implode(' AND ', $selects) . "
)", $params];
}
}

View File

@ -16,6 +16,7 @@
namespace core_admin\reportbuilder\local\systemreports;
use core_admin\reportbuilder\local\filters\courserole;
use core\context\system;
use core_cohort\reportbuilder\local\entities\cohort;
use core_cohort\reportbuilder\local\entities\cohort_member;
@ -218,7 +219,17 @@ class users extends system_report {
$now1 => $now,
$now2 => $now,
])
->add_joins($this->get_joins()));
);
// Course role filter.
$this->add_filter((new filter(
courserole::class,
'courserole',
new lang_string('courserole', 'filters'),
$this->get_entity('user')->get_entity_name(),
))
->set_field_sql("{$entityuseralias}.id")
);
// Add user profile fields filters.
$userprofilefields = new user_profile_fields($entityuseralias . '.id', $entityuser->get_entity_name());

View File

@ -0,0 +1,113 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_admin\reportbuilder\local\filters;
use advanced_testcase;
use lang_string;
use core_reportbuilder\local\report\filter;
/**
* Unit tests for course role report filter
*
* @package core_admin
* @covers \core_admin\reportbuilder\local\filters\courserole
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class courserole_test extends advanced_testcase {
/**
* Data provider for {@see test_get_sql_filter}
*
* @return array[]
*/
public static function get_sql_filter_provider(): array {
return [
'Empty filter' => ['', '', '', ['admin', 'guest', 'user1', 'user2', 'user3', 'user4']],
'Filter by role' => ['editingteacher', '', '', ['user1', 'user3', 'user4']],
'Filter by role in category' => ['editingteacher', 'cat2', '', ['user1', 'user3']],
'Filter by role in category and course' => ['editingteacher', 'cat2', 'course2', ['user1']],
'Filter by role in course' => ['student', '', 'course2', ['user2']],
'Filter by category' => ['', 'cat2', '', ['user1', 'user2', 'user3']],
'Filter by category and course' => ['', 'cat2', 'course2', ['user1', 'user2']],
'Filter by course' => ['', '', 'course3', ['user3']],
];
}
/**
* Test getting filter SQL
*
* @param string $rolename
* @param string $categoryname
* @param string $course
* @param string[] $expectedusers
*
* @dataProvider get_sql_filter_provider
*/
public function test_get_sql_filter(
string $rolename,
string $categoryname,
string $course,
array $expectedusers,
): void {
global $DB;
$this->resetAfterTest();
// Create categories/course structure (categoryone: courseone; categorytwo: coursetwo/coursethree).
$categoryone = $this->getDataGenerator()->create_category(['name' => 'cat1']);
$courseone = $this->getDataGenerator()->create_course(['category' => $categoryone->id, 'shortname' => 'course1']);
$categorytwo = $this->getDataGenerator()->create_category(['name' => 'cat2']);
$coursetwo = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course2']);
$coursethree = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course3']);
// User one is a teacher in courseone/coursetwo.
$userone = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user1']);
$this->getDataGenerator()->enrol_user($userone->id, $coursetwo->id, 'editingteacher');
// User two is a student in coursetwo.
$usertwo = $this->getDataGenerator()->create_and_enrol($coursetwo, 'student', ['username' => 'user2']);
// User three is a teacher in courseone/coursethree.
$userthree = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user3']);
$this->getDataGenerator()->enrol_user($userthree->id, $coursethree->id, 'editingteacher');
// User four is a teacher in courseone.
$userfour = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user4']);
$filter = new filter(
courserole::class,
'test',
new lang_string('yes'),
'testentity',
'id',
);
// Create instance of our filter, passing given operators (with lookups for role/category).
[$select, $params] = courserole::create($filter)->get_sql_filter([
$filter->get_unique_identifier() . '_role' => $DB->get_field('role', 'id', ['shortname' => $rolename]),
$filter->get_unique_identifier() . '_category' => $DB->get_field('course_categories', 'id', ['name' => $categoryname]),
$filter->get_unique_identifier() . '_course' => $course,
]);
$users = $DB->get_fieldset_select('user', 'username', $select, $params);
$this->assertEqualsCanonicalizing($expectedusers, $users);
}
}