Skip to content

Commit

Permalink
Merge branch 'MDL-72588' of git://github.com/dravek/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
junpataleta committed Nov 1, 2021
2 parents 3535fcc + 0188af3 commit 6f7defe
Show file tree
Hide file tree
Showing 88 changed files with 3,947 additions and 131 deletions.
175 changes: 175 additions & 0 deletions cohort/classes/reportbuilder/audience/cohortmember.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<?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_cohort\reportbuilder\audience;

use context;
use context_system;
use core_course_category;
use stdClass;
use core_reportbuilder\local\audiences\base;
use core_reportbuilder\local\helpers\database;
use MoodleQuickForm;

/**
* The backend class for Cohort member audience type
*
* @package core_reportbuilder
* @copyright 2021 David Matamoros <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cohortmember extends base {

/**
* Adds audience's elements to the given mform
*
* @param MoodleQuickForm $mform The form to add elements to
*/
public function get_config_form(MoodleQuickForm $mform): void {
$cohorts = self::get_cohorts();
$mform->addElement('autocomplete', 'cohorts', get_string('selectfromcohort', 'cohort'),
$cohorts, ['multiple' => true]);
$mform->addRule('cohorts', null, 'required', null, 'client');
}

/**
* Helps to build SQL to retrieve users that matches the current report audience
*
* @param string $usertablealias
* @return array array of three elements [$join, $where, $params]
*/
public function get_sql(string $usertablealias): array {
global $DB;

$cm = database::generate_alias();
$cohorts = $this->get_configdata()['cohorts'];
$prefix = database::generate_param_name() . '_';
[$insql, $inparams] = $DB->get_in_or_equal($cohorts, SQL_PARAMS_NAMED, $prefix);

$join = "JOIN {cohort_members} {$cm}
ON ({$cm}.userid = {$usertablealias}.id)";

return [$join, "{$cm}.cohortid " . $insql, $inparams];
}

/**
* Return user friendly name of this audience type
*
* @return string
*/
public function get_name(): string {
return get_string('memberofcohort', 'cohort');
}

/**
* Return the description for the audience.
*
* @return string
*/
public function get_description(): string {
global $DB;

$cohortlist = [];

$cohortids = $this->get_configdata()['cohorts'];
$cohorts = $DB->get_records_list('cohort', 'id', $cohortids, 'name');
foreach ($cohorts as $cohort) {
$cohortlist[] = format_string($cohort->name, true, ['context' => $cohort->contextid, 'escape' => false]);
}

return $this->format_description_for_multiselect($cohortlist);
}

/**
* If the current user is able to add this audience.
*
* @return bool
*/
public function user_can_add(): bool {
// Check system context first.
if (has_capability('moodle/cohort:view', context_system::instance())) {
return true;
}
// If there is at least one category with given permissions, user can add.
return !empty(core_course_category::make_categories_list('moodle/cohort:view'));
}

/**
* Returns if this audience type is available for the user
*
* Check if there are available cohorts in the system for this user to use.
*
* @return bool
*/
public function is_available(): bool {
return !empty(self::get_cohorts());
}

/**
* If the current user is able to edit this audience.
*
* @return bool
*/
public function user_can_edit(): bool {
global $DB;

$canedit = true;
$cohortids = $this->get_configdata()['cohorts'];
$cohorts = $DB->get_records_list('cohort', 'id', $cohortids);
foreach ($cohorts as $cohort) {
$context = context::instance_by_id($cohort->contextid, MUST_EXIST);
$canedit = $canedit && has_capability('moodle/cohort:view', $context);
if ($canedit === false) {
break;
}
}

return $canedit;
}

/**
* Cohorts selector.
*
* @return array
*/
private static function get_cohorts(): array {
global $CFG;

require_once($CFG->dirroot.'/cohort/lib.php');

$cohortslist = [];

// Search cohorts user can view.
$usercohorts = cohort_get_all_cohorts(0, 0);

// The previous method doesn't check cohorts on system context.
$syscontext = context_system::instance();
$cohorts = array_filter($usercohorts['cohorts'], static function(stdClass $cohort) use ($syscontext): bool {
return ($cohort->contextid != $syscontext->id) || has_capability('moodle/cohort:view', $syscontext);
});

foreach ($cohorts as $cohort) {
$cohortslist[$cohort->id] = format_string($cohort->name, true, [
'context' => $cohort->contextid,
'escape' => false,
]);
}

return $cohortslist;
}
}
193 changes: 193 additions & 0 deletions cohort/tests/reportbuilder/audience/cohortmember_test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

declare(strict_types=1);

namespace core_cohort\reportbuilder\audience;

use advanced_testcase;
use context;
use core_reportbuilder_generator;
use core_user\reportbuilder\datasource\users;

/**
* Unit tests for cohort member report audience type
*
* @package core_reportbuilder
* @covers \core_cohort\reportbuilder\audience\cohortmember
* @copyright 2021 David Matamoros <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cohortmember_test extends advanced_testcase {

/**
* Test that this audience type description is generated correctly
*/
public function test_get_description(): void {
$this->resetAfterTest();

/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');

$report = $generator->create_report([
'name' => 'My report',
'source' => users::class,
'default' => false,
]);

$cohort = self::getDataGenerator()->create_cohort();
$audience = cohortmember::create($report->get('id'), ['cohorts' => [$cohort->id]]);
$this->assertEquals($cohort->name, $audience->get_description());
}

/**
* Test if user can add this audience type to the report
*/
public function test_user_can_add(): void {
$this->resetAfterTest();

/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');

$report = $generator->create_report([
'name' => 'My report',
'source' => users::class,
'default' => false,
]);

// Admin user.
self::setAdminUser();

$cohort = self::getDataGenerator()->create_cohort();
$context = context::instance_by_id($cohort->contextid);
$audience = cohortmember::create($report->get('id'), ['cohorts' => [$cohort->id]]);

$this->assertTrue($audience->user_can_add());

// Non-priveleged user.
$user = self::getDataGenerator()->create_user();
self::setUser($user);
$this->assertFalse($audience->user_can_add());

// Grant priveleges to user (moodle/cohort:view).
$roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
assign_capability('moodle/cohort:view', CAP_ALLOW, $roleid, $context->id);
role_assign($roleid, $user->id, $context->id);
$this->assertTrue($audience->user_can_add());
}

/**
* Test if user can edit this audience type
*/
public function test_user_can_edit(): void {
$this->resetAfterTest();

/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');

$report = $generator->create_report([
'name' => 'My report',
'source' => users::class,
'default' => false,
]);

$cohort = self::getDataGenerator()->create_cohort();
$context = context::instance_by_id($cohort->contextid);
$audience = cohortmember::create($report->get('id'), ['cohorts' => [$cohort->id]]);

// Admin user.
self::setAdminUser();
$this->assertTrue($audience->user_can_edit());

// Non-priveleged user.
$user = self::getDataGenerator()->create_user();
self::setUser($user);
$this->assertFalse($audience->user_can_edit());

// Grant priveleges to user (moodle/cohort:view).
$roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
assign_capability('moodle/cohort:view', CAP_ALLOW, $roleid, $context->id);
role_assign($roleid, $user->id, $context->id);
$this->assertTrue($audience->user_can_edit());
}

/**
* Test that sql generated is correct
*/
public function test_get_sql(): void {
global $DB;
$this->resetAfterTest();

/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');

$report = $generator->create_report([
'name' => 'My report',
'source' => users::class,
'default' => false,
]);

$cohort = self::getDataGenerator()->create_cohort();

$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();

// Add user1 into cohort.
cohort_add_member($cohort->id, $user1->id);
// Add user3 into cohort.
cohort_add_member($cohort->id, $user3->id);

$audience = cohortmember::create($report->get('id'), ['cohorts' => [$cohort->id]]);

[$join, $where, $params] = $audience->get_sql('u');
$query = 'SELECT u.* FROM {user} u ' . $join . ' WHERE ' . $where;
$records = $DB->get_records_sql($query, $params);

$this->assertEqualsCanonicalizing([$user1->id, $user3->id], array_column($records, 'id'));
}

/**
* Test if this audience type is available to use
*/
public function test_is_available(): void {
$this->resetAfterTest();

/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');

self::setAdminUser();

// Check with no cohorts available in the system.
$report = $generator->create_report([
'name' => 'My report',
'source' => users::class,
'default' => false,
]);
$audience = cohortmember::create($report->get('id'), ['cohorts' => []]);
$this->assertFalse($audience->is_available());

// Check with cohorts available in the system.
self::getDataGenerator()->create_cohort();
$report = $generator->create_report([
'name' => 'My report',
'source' => users::class,
'default' => false,
]);
$audience2 = cohortmember::create($report->get('id'), ['cohorts' => []]);
$this->assertTrue($audience2->is_available());
}
}
1 change: 1 addition & 0 deletions lang/en/cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
$string['cachedef_tagindexbuilder'] = 'Search results for tagged items';
$string['cachedef_questiondata'] = 'Question definitions';
$string['cachedef_recommendation_favourite_course_content_items'] = 'Recommendation of course content items';
$string['cachedef_reportbuilder_allowed_reports'] = 'Users allowed reports according to audience';
$string['cachedef_repositories'] = 'Repositories instances data';
$string['cachedef_roledefs'] = 'Role definitions';
$string['cachedef_grade_categories'] = 'Grade category queries';
Expand Down
1 change: 1 addition & 0 deletions lang/en/cohort.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
$string['external'] = 'External cohort';
$string['invalidtheme'] = 'Cohort theme does not exist';
$string['idnumber'] = 'Cohort ID';
$string['memberofcohort'] = 'Member of cohort';
$string['memberscount'] = 'Cohort size';
$string['name'] = 'Name';
$string['namecolumnmissing'] = 'There is something wrong with the format of the CSV file. Please check that it includes the correct column names. To add users to a cohort, go to \'Upload users\' in the Site administration.';
Expand Down
1 change: 1 addition & 0 deletions lang/en/langconfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
$string['iso6392'] = 'eng';
$string['labelsep'] = ': ';
$string['listsep'] = ',';
$string['listitemssep'] = ', ';
$string['locale'] = 'en_AU.UTF-8';
$string['localecldr'] = 'en-AU';
$string['localewin'] = 'English_Australia.1252';
Expand Down
Loading

0 comments on commit 6f7defe

Please sign in to comment.