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
namespace report_log;
18
 
19
use context_course;
20
use core_user;
21
 
22
/**
23
 * Class report_log\renderable_test to cover functions in \report_log_renderable.
24
 *
25
 * @package    report_log
26
 * @copyright  2023 Stephan Robotta <stephan.robotta@bfh.ch>
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
28
 */
1441 ariadna 29
final class renderable_test extends \advanced_testcase {
1 efrain 30
    /**
31
     * @var int The course with separate groups.
32
     */
33
    const COURSE_SEPARATE_GROUP = 0;
34
    /**
35
     * @var int The course with separate groups.
36
     */
37
    const COURSE_VISIBLE_GROUP = 1;
38
    /**
39
     * @var int The course with separate groups.
40
     */
41
    const COURSE_NO_GROUP = 2;
42
    /**
43
     * @var array The setup of users.
44
     */
45
    const SETUP_USER_DEFS = [
46
        // Make student2 also member of group1.
47
        'student' => [
48
            'student0' => ['group0'],
49
            'student1' => ['group1'],
50
            'student2' => ['group0', 'group1'],
51
            'student3' => [],
52
        ],
53
        // Make teacher2 also member of group1.
54
        'teacher' => [
55
            'teacher0' => ['group0'],
56
            'teacher1' => ['group1'],
57
            'teacher2' => ['group0', 'group1'],
58
            'teacher3' => [],
59
        ],
60
        // Make editingteacher also member of group1.
61
        'editingteacher' => [
62
            'editingteacher0' => ['group0'],
63
            'editingteacher1' => ['group1'],
64
            'editingteacher2' => ['group0', 'group1'],
65
        ],
66
    ];
67
    /**
68
     * @var array|\stdClass all users indexed by username.
69
     */
70
    private $users = [];
71
    /**
72
     * @var array The groups by courses (array of array).
73
     */
74
    private $groupsbycourse = [];
75
    /**
76
     * @var array The courses.
77
     */
78
    private $courses;
79
 
80
    /**
81
     * Get the data provider for test_get_user_list().
82
     *
83
     * @return array
84
     */
85
    public static function get_user_visibility_list_provider(): array {
86
        return [
87
            'separategroups: student 0' => [
88
                self::COURSE_SEPARATE_GROUP,
89
                'student0',
90
                // All users in group 0.
91
                [
92
                    'student0', 'student2',
93
                    'teacher0', 'teacher2',
94
                    'editingteacher0', 'editingteacher2',
95
                ],
96
            ],
97
            'separategroups: student 1' => [
98
                self::COURSE_SEPARATE_GROUP,
99
                'student1',
100
                // All users in group1.
101
                [
102
                    'student1', 'student2',
103
                    'teacher1', 'teacher2',
104
                    'editingteacher1', 'editingteacher2',
105
                ],
106
            ],
107
            'separategroups: student 2' => [
108
                self::COURSE_SEPARATE_GROUP,
109
                'student2',
110
                // All users in group0 and group1.
111
                [
112
                    'student0', 'student1', 'student2',
113
                    'teacher0', 'teacher1', 'teacher2',
114
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
115
                ],
116
            ],
117
            'separategroups: student3' => [
118
                self::COURSE_SEPARATE_GROUP,
119
                'student3',
120
                // Student 3 is not in any group so should only see user without a group.
121
                [
122
                    'student3',
123
                    'teacher3',
124
                ],
125
            ],
126
            'separategroups: editing teacher 0' => [
127
                self::COURSE_SEPARATE_GROUP,
128
                'editingteacher0',
129
                // All users including student 3 as we can see all users (event the one not in a group).
130
                [
131
                    'student0', 'student1', 'student2', 'student3',
132
                    'teacher0', 'teacher1', 'teacher2', 'teacher3',
133
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
134
                ],
135
            ],
136
            'separategroups: teacher 0' => [
137
                self::COURSE_SEPARATE_GROUP,
138
                'teacher0',
139
                // All users in group 0.
140
                [
141
                    'student0', 'student2',
142
                    'teacher0', 'teacher2',
143
                    'editingteacher0', 'editingteacher2',
144
                ],
145
            ],
146
            'separategroups: teacher 2' => [
147
                self::COURSE_SEPARATE_GROUP,
148
                'teacher2',
149
                // All users in group0 and group1.
150
                [
151
                    'student0', 'student1', 'student2',
152
                    'teacher0', 'teacher1', 'teacher2',
153
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
154
                ],
155
            ],
156
            'separategroups: teacher 3' => [
157
                self::COURSE_SEPARATE_GROUP,
158
                'teacher3',
159
                // Teacher 3 is not in any group so should only see user without a group.
160
                [
161
                    'student3',
162
                    'teacher3',
163
                ],
164
            ],
165
            'separategroups: teacher 2 with group set to group 1' => [
166
                self::COURSE_SEPARATE_GROUP,
167
                'teacher2',
168
                // All users in group1.
169
                [
170
                    'student1', 'student2',
171
                    'teacher1', 'teacher2',
172
                    'editingteacher1', 'editingteacher2',
173
                ],
174
                'group1',
175
            ],
176
            'visiblegroup: editing teacher' => [
177
                self::COURSE_VISIBLE_GROUP,
178
                'editingteacher0',
179
                // All users.
180
                [
181
                    'student0', 'student1', 'student2', 'student3',
182
                    'teacher0', 'teacher1', 'teacher2', 'teacher3',
183
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
184
                ],
185
            ],
186
            'visiblegroup: student' => [
187
                self::COURSE_VISIBLE_GROUP,
188
                'student0',
189
                // All users.
190
                [
191
                    'student0', 'student1', 'student2', 'student3',
192
                    'teacher0', 'teacher1', 'teacher2', 'teacher3',
193
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
194
                ],
195
            ],
196
            'visiblegroup: teacher 0' => [
197
                self::COURSE_VISIBLE_GROUP,
198
                'teacher2',
199
                // All users.
200
                [
201
                    'student0', 'student1', 'student2', 'student3',
202
                    'teacher0', 'teacher1', 'teacher2', 'teacher3',
203
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
204
                ],
205
            ],
206
            'visiblegroup: editing teacher 0' => [
207
                self::COURSE_VISIBLE_GROUP,
208
                'editingteacher0',
209
                // All users.
210
                [
211
                    'student0', 'student1', 'student2', 'student3',
212
                    'teacher0', 'teacher1', 'teacher2', 'teacher3',
213
                    'editingteacher0', 'editingteacher1', 'editingteacher2',
214
                ],
215
            ],
216
            'visiblegroup: teacher 2 with group set to group 1' => [
217
                self::COURSE_VISIBLE_GROUP,
218
                'teacher2',
219
                // All users in group1.
220
                [
221
                    'student1', 'student2',
222
                    'teacher1', 'teacher2',
223
                    'editingteacher1', 'editingteacher2',
224
                ],
225
                'group1',
226
            ],
227
        ];
228
    }
229
 
230
    /**
231
     * Data provider for test_get_group_list().
232
     *
233
     * @return array
234
     */
235
    public static function get_group_list_provider(): array {
236
        return [
237
            // The student sees his own group only.
238
            'separategroup: student in one group' => [self::COURSE_SEPARATE_GROUP, 'student0', 1],
239
            'separategroup: student in two groups' => [self::COURSE_SEPARATE_GROUP, 'student2', 2],
240
            // While the teacher is not allowed to see all groups.
241
            'separategroup: teacher in one group' => [self::COURSE_SEPARATE_GROUP, 'teacher0', 1],
242
            'separategroup: teacher in two groups' => [self::COURSE_SEPARATE_GROUP, 'teacher2', 2],
243
            // But editing teacher should see all.
244
            'separategroup: editingteacher' => [self::COURSE_SEPARATE_GROUP, 'editingteacher0', 2],
245
            // The student sees all groups.
246
            'visiblegroup: student in one group' => [self::COURSE_VISIBLE_GROUP, 'student0', 2],
247
            // Same for teacher.
248
            'visiblegroup: teacher in one group' => [self::COURSE_VISIBLE_GROUP, 'teacher0', 2],
249
            // And editing teacher.
250
            'visiblegroup: editingteacher' => [self::COURSE_VISIBLE_GROUP, 'editingteacher0', 2],
251
            // No group.
252
            'nogroups: student in one group' => [self::COURSE_NO_GROUP, 'student0', 0],
253
            // Same for teacher.
254
            'nogroups: teacher in one group' => [self::COURSE_NO_GROUP, 'teacher0', 0],
255
            // And editing teacher.
256
            'nogroups: editingteacher' => [self::COURSE_NO_GROUP, 'editingteacher0', 0],
257
        ];
258
    }
259
 
260
    /**
261
     * Set up a course with two groups, three students being each in one of the groups,
262
     * two teachers each in either group while the second teacher is also member of the other group.
263
     *
264
     * @return void
265
     * @throws \coding_exception
266
     */
267
    public function setUp(): void {
1441 ariadna 268
        parent::setUp();
1 efrain 269
        $this->resetAfterTest();
270
        $this->courses[self::COURSE_SEPARATE_GROUP] = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS]);
271
        $this->courses[self::COURSE_VISIBLE_GROUP] = $this->getDataGenerator()->create_course(['groupmode' => VISIBLEGROUPS]);
272
        $this->courses[self::COURSE_NO_GROUP] = $this->getDataGenerator()->create_course();
273
 
274
        foreach ($this->courses as $coursetype => $course) {
275
            if ($coursetype == self::COURSE_NO_GROUP) {
276
                continue;
277
            }
278
            $this->groupsbycourse[$coursetype] = [];
279
            $this->groupsbycourse[$coursetype]['group0'] =
280
                $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'group0']);
281
            $this->groupsbycourse[$coursetype]['group1'] =
282
                $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'group1']);
283
        }
284
 
285
        foreach (self::SETUP_USER_DEFS as $role => $userdefs) {
286
            foreach ($userdefs as $username => $groups) {
287
                $user = $this->getDataGenerator()->create_user(
288
                    [
289
                        'username' => $username,
290
                        'firstname' => "FN{$role}{$username}",
291
                        'lastname' => "LN{$role}{$username}",
292
                    ]);
293
                foreach ($this->courses as $coursetype => $course) {
294
                    $this->getDataGenerator()->enrol_user($user->id, $course->id, $role);
295
                    foreach ($groups as $groupname) {
296
                        if ($coursetype == self::COURSE_NO_GROUP) {
297
                            continue;
298
                        }
299
                        $this->getDataGenerator()->create_group_member([
300
                            'groupid' => $this->groupsbycourse[$coursetype][$groupname]->id,
301
                            'userid' => $user->id,
302
                        ]);
303
                    }
304
                }
305
                $this->users[$username] = $user;
306
            }
307
        }
308
    }
309
 
310
    /**
311
     * Test report_log_renderable::get_user_list().
312
     *
313
     * @param int $courseindex
314
     * @param string $username
315
     * @param array $expectedusers
316
     * @param string|null $groupname
317
     * @covers       \report_log_renderable::get_user_list
318
     * @dataProvider get_user_visibility_list_provider
319
     * @return void
320
     */
321
    public function test_get_user_list(int $courseindex, string $username, array $expectedusers,
1441 ariadna 322
        ?string $groupname = null): void {
1 efrain 323
        global $PAGE, $CFG;
324
        $currentcourse = $this->courses[$courseindex];
325
        $PAGE->set_url('/report/log/index.php?id=' . $currentcourse->id);
326
        // Fetch all users of group 1 and the guest user.
327
        $currentuser = $this->users[$username];
328
        $this->setUser($currentuser->id);
329
        $groupid = 0;
330
        if ($groupname) {
331
            $groupid = $this->groupsbycourse[$courseindex][$groupname]->id;
332
        }
333
        $renderable = new \report_log_renderable(
334
            "", (int) $currentcourse->id, $currentuser->id, 0, '', $groupid);
335
        $userlist = $renderable->get_user_list();
336
        unset($userlist[$CFG->siteguest]); // We ignore guest.
337
        $usersid = array_keys($userlist);
338
 
339
        $users = array_map(function($userid) {
340
            return core_user::get_user($userid);
341
        }, $usersid);
342
 
343
        // Now check that the users are the expected ones.
344
        asort($expectedusers);
345
        $userlistbyname = array_column($users, 'username');
346
        asort($userlistbyname);
347
        $this->assertEquals(array_values($expectedusers), array_values($userlistbyname));
348
 
349
        // Check that users are in order lastname > firstname > id.
350
        $sortedusers = $users;
351
        // Sort user by lastname > firstname > id.
352
        usort($sortedusers, function($a, $b) {
353
            if ($a->lastname != $b->lastname) {
354
                return $a->lastname <=> $b->lastname;
355
            }
356
            if ($a->firstname != $b->firstname) {
357
                return $a->firstname <=> $b->firstname;
358
            }
359
            return $a->id <=> $b->id;
360
        });
361
 
362
        $sortedusernames = array_column($sortedusers, 'username');
363
        $userlistbyname = array_column($users, 'username');
364
        $this->assertEquals($sortedusernames, $userlistbyname);
365
 
366
    }
367
 
368
    /**
369
     * Test report_log_renderable::get_group_list().
370
     *
371
     * @covers       \report_log_renderable::get_group_list
372
     * @dataProvider get_group_list_provider
373
     * @return void
374
     */
375
    public function test_get_group_list($courseindex, $username, $expectedcount): void {
376
        global $PAGE;
377
        $PAGE->set_url('/report/log/index.php?id=' . $this->courses[$courseindex]->id);
378
        $this->setUser($this->users[$username]->id);
379
        $renderable = new \report_log_renderable("", (int) $this->courses[$courseindex]->id, $this->users[$username]->id);
380
        $groups = $renderable->get_group_list();
381
        $this->assertCount($expectedcount, $groups);
382
    }
383
 
384
    /**
385
     * Test table_log
386
     *
387
     * @param int $courseindex
388
     * @param string $username
389
     * @param array $expectedusers
390
     * @param string|null $groupname
391
     * @covers       \report_log_renderable::get_user_list
392
     * @dataProvider get_user_visibility_list_provider
393
     * @return void
394
     */
395
    public function test_get_table_logs(int $courseindex, string $username, array $expectedusers, ?string $groupname = null): void {
396
        global $DB, $PAGE;
397
        $this->preventResetByRollback(); // This is to ensure that we can actually trigger event and record them in the log store.
398
        // Configure log store.
399
        set_config('enabled_stores', 'logstore_standard', 'tool_log');
400
        $manager = get_log_manager(true);
401
        $DB->delete_records('logstore_standard_log');
402
 
403
        foreach ($this->courses as $course) {
404
            foreach ($this->users as $user) {
405
                $eventdata = [
406
                    'context' => context_course::instance($course->id),
407
                    'userid' => $user->id,
408
                ];
409
                $event = \core\event\course_viewed::create($eventdata);
410
                $event->trigger();
411
            }
412
        }
413
        $stores = $manager->get_readers();
414
        $store = $stores['logstore_standard'];
415
        // Build the report.
416
        $currentuser = $this->users[$username];
417
        $this->setUser($currentuser->id);
418
        $groupid = 0;
419
        if ($groupname) {
420
            $groupid = $this->groupsbycourse[$courseindex][$groupname]->id;
421
        }
422
        $PAGE->set_url('/report/log/index.php?id=' . $this->courses[$courseindex]->id);
423
        $renderable = new \report_log_renderable("", (int) $this->courses[$courseindex]->id, 0, 0, '', $groupid);
424
        $renderable->setup_table();
425
        $table = $renderable->tablelog;
426
        $store->flush();
427
        $table->query_db(100);
428
        $usernames = [];
429
        foreach ($table->rawdata as $event) {
430
            if (get_class($event) !== \core\event\course_viewed::class) {
431
                continue;
432
            }
433
            $user = core_user::get_user($event->userid, '*', MUST_EXIST);
434
            $usernames[] = $user->username;
435
        }
436
        sort($expectedusers);
437
        sort($usernames);
438
        $this->assertEquals($expectedusers, $usernames);
439
    }
1441 ariadna 440
 
441
    /**
442
     * Test getting logs for deleted courses.
443
     *
444
     * @covers \report_log_renderable::setup_table
445
     * @return void
446
     */
447
    public function test_get_deleted_course_logs(): void {
448
        global $DB, $PAGE;
449
        $this->preventResetByRollback(); // Ensure events can be recorded in log store.
450
 
451
        // Configure log store and user.
452
        set_config('enabled_stores', 'logstore_standard', 'tool_log');
453
        $manager = get_log_manager(true);
454
        $stores = $manager->get_readers();
455
        $store = $stores['logstore_standard'];
456
        $this->setUser(get_admin());
457
 
458
        // Set and delete course.
459
        $course = reset($this->courses);
460
        $deletedcourseid = $course->id;
461
        delete_course($course, false);
462
        $this->assertFalse($DB->record_exists('course', ['id' => $deletedcourseid]));
463
 
464
        // Test rendering.
465
        $PAGE->set_url('/report/log/index.php?id=' . $deletedcourseid);
466
        $renderable = new \report_log_renderable('', (int) $deletedcourseid);
467
        $renderable->setup_table();
468
        $store->flush();
469
        $table = $renderable->tablelog;
470
        $table->query_db(100);
471
 
472
        // Confirm we have logs for the course deletion and that the filtering is correct.
473
        $this->assertNotEmpty($table->totalrows);
474
        $expectedrows = count($DB->get_records('logstore_standard_log', ['courseid' => $deletedcourseid]));
475
        $this->assertEquals($expectedrows, $table->totalrows);
476
    }
1 efrain 477
}