Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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;
1441 ariadna 25
use core_reportbuilder\local\models\audience as audience_model;
1 efrain 26
use core_user\reportbuilder\datasource\users;
1441 ariadna 27
use invalid_parameter_exception;
1 efrain 28
 
29
/**
30
 * Unit tests for audience helper
31
 *
32
 * @package     core_reportbuilder
33
 * @covers      \core_reportbuilder\local\helpers\audience
34
 * @copyright   2021 David Matamoros <davidmc@moodle.com>
35
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
1441 ariadna 37
final class audience_test extends advanced_testcase {
1 efrain 38
 
39
     /**
40
      * Test reports list is empty for a normal user without any audience records configured
41
      */
42
    public function test_reports_list_no_access(): void {
43
        $this->resetAfterTest();
44
 
45
        $reports = audience::user_reports_list();
46
        $this->assertEmpty($reports);
47
    }
48
 
49
    /**
50
     * Test get_base_records()
51
     */
52
    public function test_get_base_records(): void {
53
        $this->resetAfterTest();
54
 
55
        /** @var core_reportbuilder_generator $generator */
56
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
57
 
58
        // Report with no audiences.
59
        $report = $generator->create_report([
60
            'name' => 'My report',
61
            'source' => users::class,
62
            'default' => false,
63
        ]);
64
        $baserecords = audience::get_base_records($report->get('id'));
65
        $this->assertEmpty($baserecords);
66
 
67
        // Create a couple of manual audience types.
68
        $user1 = $this->getDataGenerator()->create_user();
69
        $user2 = $this->getDataGenerator()->create_user();
70
        $audience1 = $generator->create_audience([
71
            'reportid' => $report->get('id'),
72
            'classname' => manual::class,
73
            'configdata' => ['users' => [$user1->id, $user2->id]],
74
        ]);
75
 
76
        $user3 = $this->getDataGenerator()->create_user();
77
        $audience2 = $generator->create_audience([
78
            'reportid' => $report->get('id'),
79
            'classname' => manual::class,
80
            'configdata' => ['users' => [$user3->id]],
81
        ]);
82
 
83
        $baserecords = audience::get_base_records($report->get('id'));
84
        $this->assertCount(2, $baserecords);
85
        $this->assertContainsOnlyInstancesOf(manual::class, $baserecords);
86
 
87
        // Set invalid classname of first audience, should be excluded in subsequent request.
88
        $audience1->get_persistent()->set('classname', '\invalid')->save();
89
 
90
        $baserecords = audience::get_base_records($report->get('id'));
91
        $this->assertCount(1, $baserecords);
92
 
93
        $baserecord = reset($baserecords);
94
        $this->assertInstanceOf(manual::class, $baserecord);
95
        $this->assertEquals($audience2->get_persistent()->get('id'), $baserecord->get_persistent()->get('id'));
96
    }
97
 
98
    /**
99
     * Test get_allowed_reports()
100
     */
101
    public function test_get_allowed_reports(): void {
102
        $this->resetAfterTest();
103
 
104
        /** @var core_reportbuilder_generator $generator */
105
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
106
 
107
        $user1 = $this->getDataGenerator()->create_user();
108
        $user2 = $this->getDataGenerator()->create_user();
109
        self::setUser($user1);
110
 
111
        // No reports.
112
        $reports = audience::get_allowed_reports();
113
        $this->assertEmpty($reports);
114
 
115
        $report1 = $generator->create_report([
116
            'name' => 'My report',
117
            'source' => users::class,
118
            'default' => false,
119
        ]);
120
        $report2 = $generator->create_report([
121
            'name' => 'My report',
122
            'source' => users::class,
123
            'default' => false,
124
        ]);
125
        $report3 = $generator->create_report([
126
            'name' => 'My report',
127
            'source' => users::class,
128
            'default' => false,
129
        ]);
130
 
131
        // Reports with no audiences set.
132
        $reports = audience::get_allowed_reports();
133
        $this->assertEmpty($reports);
134
 
135
        $generator->create_audience([
136
            'reportid' => $report1->get('id'),
137
            'classname' => manual::class,
138
            'configdata' => ['users' => [$user1->id, $user2->id]],
139
        ]);
140
        $generator->create_audience([
141
            'reportid' => $report2->get('id'),
142
            'classname' => manual::class,
143
            'configdata' => ['users' => [$user2->id]],
144
        ]);
145
        $generator->create_audience([
146
            'reportid' => $report3->get('id'),
147
            'classname' => manual::class,
148
            'configdata' => ['users' => [$user1->id]],
149
        ]);
150
 
151
        // Purge cache, to ensure allowed reports are re-calculated.
152
        audience::purge_caches();
153
 
154
        $reports = audience::get_allowed_reports();
155
        $this->assertEqualsCanonicalizing([$report1->get('id'), $report3->get('id')], $reports);
156
 
157
        // User2 can access report1 and report2.
158
        $reports = audience::get_allowed_reports((int) $user2->id);
159
        $this->assertEqualsCanonicalizing([$report1->get('id'), $report2->get('id')], $reports);
160
 
161
        // Purge cache, to ensure allowed reports are re-calculated.
162
        audience::purge_caches();
163
 
164
        // Now delete one of our users, ensure they no longer have any allowed reports.
165
        delete_user($user2);
166
 
167
        $reports = audience::get_allowed_reports((int) $user2->id);
168
        $this->assertEmpty($reports);
169
    }
170
 
171
    /**
172
     * Test user_reports_list()
173
     */
174
    public function test_user_reports_list(): void {
175
        $this->resetAfterTest();
176
 
177
        /** @var core_reportbuilder_generator $generator */
178
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
179
 
180
        $user1 = $this->getDataGenerator()->create_user();
181
        $user2 = $this->getDataGenerator()->create_user();
182
        $user3 = $this->getDataGenerator()->create_user();
183
        self::setUser($user1);
184
 
185
        $reports = audience::user_reports_list();
186
        $this->assertEmpty($reports);
187
 
188
        $report1 = $generator->create_report([
189
            'name' => 'My report',
190
            'source' => users::class,
191
            'default' => false,
192
        ]);
193
        $report2 = $generator->create_report([
194
            'name' => 'My report',
195
            'source' => users::class,
196
            'default' => false,
197
        ]);
198
        $report3 = $generator->create_report([
199
            'name' => 'My report',
200
            'source' => users::class,
201
            'default' => false,
202
        ]);
203
 
204
        $generator->create_audience([
205
            'reportid' => $report1->get('id'),
206
            'classname' => manual::class,
207
            'configdata' => ['users' => [$user1->id, $user2->id]],
208
        ]);
209
        $generator->create_audience([
210
            'reportid' => $report2->get('id'),
211
            'classname' => manual::class,
212
            'configdata' => ['users' => [$user2->id]],
213
        ]);
214
        $generator->create_audience([
215
            'reportid' => $report3->get('id'),
216
            'classname' => manual::class,
217
            'configdata' => ['users' => [$user1->id]],
218
        ]);
219
 
220
        // Purge cache, to ensure allowed reports are re-calculated.
221
        audience::purge_caches();
222
 
223
        // User1 can access report1 and report3.
224
        $reports = audience::user_reports_list();
225
        $this->assertEqualsCanonicalizing([$report1->get('id'), $report3->get('id')], $reports);
226
 
227
        // User2 can access report1 and report2.
228
        $reports = audience::user_reports_list((int) $user2->id);
229
        $this->assertEqualsCanonicalizing([$report1->get('id'), $report2->get('id')], $reports);
230
 
231
        // User3 can not access any report.
232
        $reports = audience::user_reports_list((int) $user3->id);
233
        $this->assertEmpty($reports);
234
    }
235
 
236
    /**
237
     * Test retrieving full list of reports that user can access
238
     */
239
    public function test_user_reports_list_access_sql(): void {
240
        global $DB;
241
 
242
        $this->resetAfterTest();
243
 
244
        $userone = $this->getDataGenerator()->create_user();
245
        $usertwo = $this->getDataGenerator()->create_user();
246
        $userthree = $this->getDataGenerator()->create_user();
247
        $userfour = $this->getDataGenerator()->create_user();
248
 
249
        /** @var core_reportbuilder_generator $generator */
250
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
251
 
252
        // Manager role gives users one and two capability to create own reports.
253
        $managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
254
        role_assign($managerrole, $userone->id, context_system::instance());
255
        role_assign($managerrole, $usertwo->id, context_system::instance());
256
 
257
        // Admin creates a report, no audience.
258
        $this->setAdminUser();
259
        $useradminreport = $generator->create_report(['name' => 'Admin report', 'source' => users::class]);
260
 
261
        // User one creates a report, adds users two and three to audience.
262
        $this->setUser($userone);
263
        $useronereport = $generator->create_report(['name' => 'User one report', 'source' => users::class]);
264
        $generator->create_audience(['reportid' => $useronereport->get('id'), 'classname' => manual::class, 'configdata' => [
265
            'users' => [$usertwo->id, $userthree->id],
266
        ]]);
267
 
268
        // User two creates a report, no audience.
269
        $this->setUser($usertwo);
270
        $usertworeport = $generator->create_report(['name' => 'User two report', 'source' => users::class]);
271
 
272
        // User one sees only the report they created.
273
        [$where, $params] = audience::user_reports_list_access_sql('r', (int) $userone->id);
274
        $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
275
        $this->assertEquals([$useronereport->get('id')], $reports);
276
 
277
        // User two see the report they created and the one they are in the audience of.
278
        [$where, $params] = audience::user_reports_list_access_sql('r', (int) $usertwo->id);
279
        $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
280
        $this->assertEqualsCanonicalizing([$useronereport->get('id'), $usertworeport->get('id')], $reports);
281
 
282
        // User three sees the report they are in the audience of.
283
        [$where, $params] = audience::user_reports_list_access_sql('r', (int) $userthree->id);
284
        $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
285
        $this->assertEquals([$useronereport->get('id')], $reports);
286
 
287
        // User four sees no reports.
288
        [$where, $params] = audience::user_reports_list_access_sql('r', (int) $userfour->id);
289
        $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
290
        $this->assertEmpty($reports);
291
    }
292
 
293
    /**
294
     * Data provider for {@see test_user_reports_list_access_sql_with_capability}
295
     *
296
     * @return array[]
297
     */
298
    public static function user_reports_list_access_sql_with_capability_provider(): array {
299
        return [
300
            ['moodle/reportbuilder:editall'],
301
            ['moodle/reportbuilder:viewall'],
302
        ];
303
    }
304
 
305
    /**
306
     * Test retrieving list of reports that user can access observes capability to view all reports
307
     *
308
     * @param string $capability
309
     *
310
     * @dataProvider user_reports_list_access_sql_with_capability_provider
311
     */
312
    public function test_user_reports_list_access_sql_with_capability(string $capability): void {
313
        global $DB;
314
 
315
        $this->resetAfterTest();
316
 
317
        // Admin creates a report, no audience.
318
        $this->setAdminUser();
319
 
320
        /** @var core_reportbuilder_generator $generator */
321
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
322
        $report = $generator->create_report(['name' => 'Admin report', 'source' => users::class]);
323
 
324
        // Switch to new user, assign capability.
325
        $user = $this->getDataGenerator()->create_user();
326
        $this->setUser($user);
327
 
328
        $userrole = $DB->get_field('role', 'id', ['shortname' => 'user']);
329
        assign_capability($capability, CAP_ALLOW, $userrole, context_system::instance());
330
 
331
        [$where, $params] = audience::user_reports_list_access_sql('r');
332
        $reports = $DB->get_fieldset_sql("SELECT r.id FROM {reportbuilder_report} r WHERE {$where}", $params);
333
        $this->assertEquals([$report->get('id')], $reports);
334
    }
335
 
336
    /**
1441 ariadna 337
     * Test retrieving SQL for single audience
338
     */
339
    public function test_user_audience_single_sql(): void {
340
        global $DB;
341
 
342
        $this->resetAfterTest();
343
 
344
        $userone = $this->getDataGenerator()->create_user();
345
        $usertwo = $this->getDataGenerator()->create_user();
346
        $userthree = $this->getDataGenerator()->create_user();
347
 
348
        /** @var core_reportbuilder_generator $generator */
349
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
350
        $report = $generator->create_report(['name' => 'My report', 'source' => users::class]);
351
 
352
        $audience = $generator->create_audience(['reportid' => $report->get('id'), 'classname' => manual::class,
353
            'configdata' => [
354
                'users' => [$userone->id, $usertwo->id],
355
            ],
356
        ]);
357
 
358
        [$select, $params] = audience::user_audience_single_sql($audience->get_persistent(), 'u.id');
359
        $users = $DB->get_fieldset_sql("SELECT u.id FROM {user} u WHERE {$select}", $params);
360
        $this->assertEqualsCanonicalizing([$userone->id, $usertwo->id], $users);
361
    }
362
 
363
    /**
364
     * Test retrieving SQL for multiple audiences
365
     */
366
    public function test_user_audience_sql(): void {
367
        global $DB;
368
 
369
        $this->resetAfterTest();
370
 
371
        $userone = $this->getDataGenerator()->create_user();
372
        $usertwo = $this->getDataGenerator()->create_user();
373
        $userthree = $this->getDataGenerator()->create_user();
374
        $userfour = $this->getDataGenerator()->create_user();
375
 
376
        /** @var core_reportbuilder_generator $generator */
377
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
378
        $report = $generator->create_report(['name' => 'My report', 'source' => users::class]);
379
 
380
        $audienceone = $generator->create_audience(['reportid' => $report->get('id'), 'classname' => manual::class,
381
            'configdata' => [
382
                'users' => [$userone->id, $usertwo->id],
383
            ],
384
        ]);
385
        $audiencetwo = $generator->create_audience(['reportid' => $report->get('id'), 'classname' => manual::class,
386
            'configdata' => [
387
                'users' => [$usertwo->id, $userthree->id],
388
            ],
389
        ]);
390
 
391
        [$selects, $params] = audience::user_audience_sql([$audienceone->get_persistent(), $audiencetwo->get_persistent()]);
392
        $users = $DB->get_fieldset_sql("SELECT u.id FROM {user} u WHERE " . implode(' OR ', $selects), $params);
393
        $this->assertEqualsCanonicalizing([$userone->id, $usertwo->id, $userthree->id], $users);
394
    }
395
 
396
    /**
1 efrain 397
     * Test getting list of audiences in use within schedules for a report
398
     */
399
    public function test_get_audiences_for_report_schedules(): void {
400
        $this->resetAfterTest();
401
 
402
        /** @var core_reportbuilder_generator $generator */
403
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
404
        $report = $generator->create_report(['name' => 'My report', 'source' => users::class]);
405
 
406
        $audienceone = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
407
        $audiencetwo = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
408
        $audiencethree = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
409
 
410
        // The first schedule contains audience one and two.
411
        $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'Schedule one', 'audiences' =>
412
            json_encode([$audienceone->get_persistent()->get('id'), $audiencetwo->get_persistent()->get('id')])
413
        ]);
414
 
415
        // Second schedule contains only audience one.
416
        $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'Schedule two', 'audiences' =>
417
            json_encode([$audienceone->get_persistent()->get('id')])
418
        ]);
419
 
420
        // The first two audiences should be returned, the third omitted.
421
        $audiences = audience::get_audiences_for_report_schedules($report->get('id'));
422
        $this->assertEqualsCanonicalizing([
423
            $audienceone->get_persistent()->get('id'),
424
            $audiencetwo->get_persistent()->get('id'),
425
        ], $audiences);
426
    }
1441 ariadna 427
 
428
    /**
429
     * Testing deleting report audience
430
     */
431
    public function test_delete_report_audience(): void {
432
        $this->resetAfterTest();
433
        $this->setAdminUser();
434
 
435
        /** @var core_reportbuilder_generator $generator */
436
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
437
 
438
        $report = $generator->create_report(['name' => 'My report', 'source' => users::class, 'default' => false]);
439
        $audienceone = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
440
        $audiencetwo = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]);
441
 
442
        $audiences = audience_model::get_records(['reportid' => $report->get('id')]);
443
        $this->assertCount(2, $audiences);
444
 
445
        // Delete the first audience.
446
        $result = audience::delete_report_audience($report->get('id'), $audienceone->get_persistent()->get('id'));
447
        $this->assertTrue($result);
448
 
449
        // We should be left with only the second audience.
450
        $audiences = audience_model::get_records(['reportid' => $report->get('id')]);
451
        $this->assertCount(1, $audiences);
452
        $this->assertEquals($audiencetwo->get_persistent()->get('id'), reset($audiences)->get('id'));
453
    }
454
 
455
    /**
456
     * Testing deleting invalid report audience
457
     */
458
    public function test_delete_report_audience_invalid(): void {
459
        $this->resetAfterTest();
460
        $this->setAdminUser();
461
 
462
        /** @var core_reportbuilder_generator $generator */
463
        $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
464
 
465
        $reportone = $generator->create_report(['name' => 'Report one', 'source' => users::class, 'default' => false]);
466
        $audienceone = $generator->create_audience(['reportid' => $reportone->get('id'), 'configdata' => []]);
467
 
468
        $reporttwo = $generator->create_report(['name' => 'Report two', 'source' => users::class, 'default' => false]);
469
 
470
        $this->expectException(invalid_parameter_exception::class);
471
        $this->expectExceptionMessage('Invalid audience');
472
        audience::delete_report_audience($reporttwo->get('id'), $audienceone->get_persistent()->get('id'));
473
    }
1 efrain 474
}