Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  declare(strict_types=1);
  18  
  19  namespace core_reportbuilder\local\helpers;
  20  
  21  use advanced_testcase;
  22  use context_system;
  23  use core_reportbuilder_generator;
  24  use core_reportbuilder\reportbuilder\audience\manual;
  25  use core_user\reportbuilder\datasource\users;
  26  
  27  /**
  28   * Unit tests for audience helper
  29   *
  30   * @package     core_reportbuilder
  31   * @covers      \core_reportbuilder\local\helpers\audience
  32   * @copyright   2021 David Matamoros <davidmc@moodle.com>
  33   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class audience_test extends advanced_testcase {
  36  
  37       /**
  38        * Test reports list is empty for a normal user without any audience records configured
  39        */
  40      public function test_reports_list_no_access(): void {
  41          $this->resetAfterTest();
  42  
  43          $reports = audience::user_reports_list();
  44          $this->assertEmpty($reports);
  45      }
  46  
  47      /**
  48       * Test get_base_records()
  49       */
  50      public function test_get_base_records(): void {
  51          $this->resetAfterTest();
  52  
  53          /** @var core_reportbuilder_generator $generator */
  54          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
  55  
  56          // Report with no audiences.
  57          $report = $generator->create_report([
  58              'name' => 'My report',
  59              'source' => users::class,
  60              'default' => false,
  61          ]);
  62          $baserecords = audience::get_base_records($report->get('id'));
  63          $this->assertEmpty($baserecords);
  64  
  65          // Create a couple of manual audience types.
  66          $user1 = $this->getDataGenerator()->create_user();
  67          $user2 = $this->getDataGenerator()->create_user();
  68          $audience1 = $generator->create_audience([
  69              'reportid' => $report->get('id'),
  70              'classname' => manual::class,
  71              'configdata' => ['users' => [$user1->id, $user2->id]],
  72          ]);
  73  
  74          $user3 = $this->getDataGenerator()->create_user();
  75          $audience2 = $generator->create_audience([
  76              'reportid' => $report->get('id'),
  77              'classname' => manual::class,
  78              'configdata' => ['users' => [$user3->id]],
  79          ]);
  80  
  81          $baserecords = audience::get_base_records($report->get('id'));
  82          $this->assertCount(2, $baserecords);
  83          $this->assertContainsOnlyInstancesOf(manual::class, $baserecords);
  84  
  85          // Set invalid classname of first audience, should be excluded in subsequent request.
  86          $audience1->get_persistent()->set('classname', '\invalid')->save();
  87  
  88          $baserecords = audience::get_base_records($report->get('id'));
  89          $this->assertCount(1, $baserecords);
  90  
  91          $baserecord = reset($baserecords);
  92          $this->assertInstanceOf(manual::class, $baserecord);
  93          $this->assertEquals($audience2->get_persistent()->get('id'), $baserecord->get_persistent()->get('id'));
  94      }
  95  
  96      /**
  97       * Test get_allowed_reports()
  98       */
  99      public function test_get_allowed_reports(): void {
 100          $this->resetAfterTest();
 101  
 102          /** @var core_reportbuilder_generator $generator */
 103          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 104  
 105          $user1 = $this->getDataGenerator()->create_user();
 106          $user2 = $this->getDataGenerator()->create_user();
 107          self::setUser($user1);
 108  
 109          // No reports.
 110          $reports = audience::get_allowed_reports();
 111          $this->assertEmpty($reports);
 112  
 113          $report1 = $generator->create_report([
 114              'name' => 'My report',
 115              'source' => users::class,
 116              'default' => false,
 117          ]);
 118          $report2 = $generator->create_report([
 119              'name' => 'My report',
 120              'source' => users::class,
 121              'default' => false,
 122          ]);
 123          $report3 = $generator->create_report([
 124              'name' => 'My report',
 125              'source' => users::class,
 126              'default' => false,
 127          ]);
 128  
 129          // Reports with no audiences set.
 130          $reports = audience::get_allowed_reports();
 131          $this->assertEmpty($reports);
 132  
 133          $generator->create_audience([
 134              'reportid' => $report1->get('id'),
 135              'classname' => manual::class,
 136              'configdata' => ['users' => [$user1->id, $user2->id]],
 137          ]);
 138          $generator->create_audience([
 139              'reportid' => $report2->get('id'),
 140              'classname' => manual::class,
 141              'configdata' => ['users' => [$user2->id]],
 142          ]);
 143          $generator->create_audience([
 144              'reportid' => $report3->get('id'),
 145              'classname' => manual::class,
 146              'configdata' => ['users' => [$user1->id]],
 147          ]);
 148  
 149          // Purge cache, to ensure allowed reports are re-calculated.
 150          audience::purge_caches();
 151  
 152          $reports = audience::get_allowed_reports();
 153          $this->assertEqualsCanonicalizing([$report1->get('id'), $report3->get('id')], $reports);
 154  
 155          // User2 can access report1 and report2.
 156          $reports = audience::get_allowed_reports((int) $user2->id);
 157          $this->assertEqualsCanonicalizing([$report1->get('id'), $report2->get('id')], $reports);
 158  
 159          // Purge cache, to ensure allowed reports are re-calculated.
 160          audience::purge_caches();
 161  
 162          // Now delete one of our users, ensure they no longer have any allowed reports.
 163          delete_user($user2);
 164  
 165          $reports = audience::get_allowed_reports((int) $user2->id);
 166          $this->assertEmpty($reports);
 167      }
 168  
 169      /**
 170       * Test user_reports_list()
 171       */
 172      public function test_user_reports_list(): void {
 173          $this->resetAfterTest();
 174  
 175          /** @var core_reportbuilder_generator $generator */
 176          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 177  
 178          $user1 = $this->getDataGenerator()->create_user();
 179          $user2 = $this->getDataGenerator()->create_user();
 180          $user3 = $this->getDataGenerator()->create_user();
 181          self::setUser($user1);
 182  
 183          $reports = audience::user_reports_list();
 184          $this->assertEmpty($reports);
 185  
 186          $report1 = $generator->create_report([
 187              'name' => 'My report',
 188              'source' => users::class,
 189              'default' => false,
 190          ]);
 191          $report2 = $generator->create_report([
 192              'name' => 'My report',
 193              'source' => users::class,
 194              'default' => false,
 195          ]);
 196          $report3 = $generator->create_report([
 197              'name' => 'My report',
 198              'source' => users::class,
 199              'default' => false,
 200          ]);
 201  
 202          $generator->create_audience([
 203              'reportid' => $report1->get('id'),
 204              'classname' => manual::class,
 205              'configdata' => ['users' => [$user1->id, $user2->id]],
 206          ]);
 207          $generator->create_audience([
 208              'reportid' => $report2->get('id'),
 209              'classname' => manual::class,
 210              'configdata' => ['users' => [$user2->id]],
 211          ]);
 212          $generator->create_audience([
 213              'reportid' => $report3->get('id'),
 214              'classname' => manual::class,
 215              'configdata' => ['users' => [$user1->id]],
 216          ]);
 217  
 218          // Purge cache, to ensure allowed reports are re-calculated.
 219          audience::purge_caches();
 220  
 221          // User1 can access report1 and report3.
 222          $reports = audience::user_reports_list();
 223          $this->assertEqualsCanonicalizing([$report1->get('id'), $report3->get('id')], $reports);
 224  
 225          // User2 can access report1 and report2.
 226          $reports = audience::user_reports_list((int) $user2->id);
 227          $this->assertEqualsCanonicalizing([$report1->get('id'), $report2->get('id')], $reports);
 228  
 229          // User3 can not access any report.
 230          $reports = audience::user_reports_list((int) $user3->id);
 231          $this->assertEmpty($reports);
 232      }
 233  
 234      /**
 235       * Test retrieving full list of reports that user can access
 236       */
 237      public function test_user_reports_list_access_sql(): void {
 238          global $DB;
 239  
 240          $this->resetAfterTest();
 241  
 242          $userone = $this->getDataGenerator()->create_user();
 243          $usertwo = $this->getDataGenerator()->create_user();
 244          $userthree = $this->getDataGenerator()->create_user();
 245          $userfour = $this->getDataGenerator()->create_user();
 246  
 247          /** @var core_reportbuilder_generator $generator */
 248          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 249  
 250          // Manager role gives users one and two capability to create own reports.
 251          $managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
 252          role_assign($managerrole, $userone->id, context_system::instance());
 253          role_assign($managerrole, $usertwo->id, context_system::instance());
 254  
 255          // Admin creates a report, no audience.
 256          $this->setAdminUser();
 257          $useradminreport = $generator->create_report(['name' => 'Admin report', 'source' => users::class]);
 258  
 259          // User one creates a report, adds users two and three to audience.
 260          $this->setUser($userone);
 261          $useronereport = $generator->create_report(['name' => 'User one report', 'source' => users::class]);
 262          $generator->create_audience(['reportid' => $useronereport->get('id'), 'classname' => manual::class, 'configdata' => [
 263              'users' => [$usertwo->id, $userthree->id],
 264          ]]);
 265  
 266          // User two creates a report, no audience.
 267          $this->setUser($usertwo);
 268          $usertworeport = $generator->create_report(['name' => 'User two report', 'source' => users::class]);
 269  
 270          // Admin user sees all reports.
 271          $this->setAdminUser();
 272          [$where, $params] = audience::user_reports_list_access_sql('r');
 273          $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
 274          $this->assertEqualsCanonicalizing([
 275              $useradminreport->get('id'),
 276              $useronereport->get('id'),
 277              $usertworeport->get('id'),
 278          ], $reports);
 279  
 280          // User one sees only the report they created.
 281          [$where, $params] = audience::user_reports_list_access_sql('r', (int) $userone->id);
 282          $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
 283          $this->assertEquals([$useronereport->get('id')], $reports);
 284  
 285          // User two see the report they created and the one they are in the audience of.
 286          [$where, $params] = audience::user_reports_list_access_sql('r', (int) $usertwo->id);
 287          $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
 288          $this->assertEqualsCanonicalizing([$useronereport->get('id'), $usertworeport->get('id')], $reports);
 289  
 290          // User three sees the report they are in the audience of.
 291          [$where, $params] = audience::user_reports_list_access_sql('r', (int) $userthree->id);
 292          $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
 293          $this->assertEquals([$useronereport->get('id')], $reports);
 294  
 295          // User four sees no reports.
 296          [$where, $params] = audience::user_reports_list_access_sql('r', (int) $userfour->id);
 297          $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
 298          $this->assertEmpty($reports);
 299      }
 300  
 301      /**
 302       * Test getting list of audiences in use within schedules for a report
 303       */
 304      public function test_get_audiences_for_report_schedules(): void {
 305          $this->resetAfterTest();
 306  
 307          /** @var core_reportbuilder_generator $generator */
 308          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 309          $report = $generator->create_report(['name' => 'My report', 'source' => users::class]);
 310  
 311          $audienceone = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
 312          $audiencetwo = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
 313          $audiencethree = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
 314  
 315          // The first schedule contains audience one and two.
 316          $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'Schedule one', 'audiences' =>
 317              json_encode([$audienceone->get_persistent()->get('id'), $audiencetwo->get_persistent()->get('id')])
 318          ]);
 319  
 320          // Second schedule contains only audience one.
 321          $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'Schedule two', 'audiences' =>
 322              json_encode([$audienceone->get_persistent()->get('id')])
 323          ]);
 324  
 325          // The first two audiences should be returned, the third omitted.
 326          $audiences = audience::get_audiences_for_report_schedules($report->get('id'));
 327          $this->assertEqualsCanonicalizing([
 328              $audienceone->get_persistent()->get('id'),
 329              $audiencetwo->get_persistent()->get('id'),
 330          ], $audiences);
 331      }
 332  }