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 mod_bigbluebuttonbn\external;
18
 
19
use core_external\external_api;
20
use mod_bigbluebuttonbn\instance;
21
use mod_bigbluebuttonbn\test\testcase_helper_trait;
22
use require_login_exception;
23
 
24
defined('MOODLE_INTERNAL') || die();
25
 
26
global $CFG;
27
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
28
 
29
/**
30
 * Tests for the update_course class.
31
 *
32
 * @package    mod_bigbluebuttonbn
33
 * @category   test
34
 * @copyright  2021 - present, Blindside Networks Inc
35
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 * @author    Laurent David (laurent@call-learning.fr)
37
 * @covers \mod_bigbluebuttonbn\external\get_recordings
38
 */
39
class get_recordings_test extends \externallib_advanced_testcase {
40
    use testcase_helper_trait;
41
 
42
    /**
43
     * Setup for test
44
     */
45
    public function setUp(): void {
46
        parent::setUp();
47
        $this->initialise_mock_server();
48
    }
49
 
50
    /**
51
     * Helper
52
     *
53
     * @param mixed ...$params
54
     * @return array|bool|mixed
55
     */
56
    protected function get_recordings(...$params) {
57
        $recordings = get_recordings::execute(...$params);
58
 
59
        return external_api::clean_returnvalue(get_recordings::execute_returns(), $recordings);
60
    }
61
 
62
    /**
63
     * Test execute API CALL with no instance
64
     */
11 efrain 65
    public function test_execute_wrong_instance(): void {
1 efrain 66
        $this->resetAfterTest();
67
        $getrecordings = $this->get_recordings(1234);
68
 
69
        $this->assertIsArray($getrecordings);
70
        $this->assertArrayHasKey('status', $getrecordings);
71
        $this->assertEquals(false, $getrecordings['status']);
72
        $this->assertStringContainsString('nosuchinstance', $getrecordings['warnings'][0]['warningcode']);
73
    }
74
 
75
    /**
76
     * Test execute API CALL without login
77
     */
11 efrain 78
    public function test_execute_without_login(): void {
1 efrain 79
        $this->resetAfterTest();
80
 
81
        $course = $this->getDataGenerator()->create_course();
82
        $record = $this->getDataGenerator()->create_module('bigbluebuttonbn', ['course' => $course->id]);
83
        $instance = instance::get_from_instanceid($record->id);
84
 
85
        $this->expectException(require_login_exception::class);
86
        $this->get_recordings($instance->get_instance_id());
87
    }
88
 
89
    /**
90
     * Test execute API CALL with invalid login
91
     */
11 efrain 92
    public function test_execute_with_invalid_login(): void {
1 efrain 93
        $this->resetAfterTest();
94
 
95
        $generator = $this->getDataGenerator();
96
        $course = $generator->create_course();
97
        $record = $generator->create_module('bigbluebuttonbn', ['course' => $course->id]);
98
        $instance = instance::get_from_instanceid($record->id);
99
 
100
        $user = $generator->create_user();
101
        $this->setUser($user);
102
 
103
        $this->expectException(require_login_exception::class);
104
        $this->get_recordings($instance->get_instance_id());
105
    }
106
 
107
    /**
108
     * When login as a student
109
     */
11 efrain 110
    public function test_execute_with_valid_login(): void {
1 efrain 111
        $this->resetAfterTest();
112
 
113
        $generator = $this->getDataGenerator();
114
        $course = $generator->create_course();
115
        $record = $generator->create_module('bigbluebuttonbn', ['course' => $course->id]);
116
        $instance = instance::get_from_instanceid($record->id);
117
 
118
        $user = $generator->create_and_enrol($course, 'student');
119
        $this->setUser($user);
120
 
121
        $getrecordings = $this->get_recordings($instance->get_instance_id());
122
 
123
        $this->assertIsArray($getrecordings);
124
        $this->assertArrayHasKey('status', $getrecordings);
125
        $this->assertEquals(true, $getrecordings['status']);
126
        $this->assertNotEmpty($getrecordings['tabledata']);
127
        $this->assertEquals('[]', $getrecordings['tabledata']['data']);
128
    }
129
 
130
    /**
131
     * Check if tools are present for teacher/moderator
132
     */
11 efrain 133
    public function test_get_recordings_tools(): void {
1 efrain 134
        $this->resetAfterTest();
135
        $dataset = [
136
            'type' => instance::TYPE_ALL,
137
            'groups' => null,
138
            'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']],
139
            'recordingsdata' => [
140
                [['name' => 'Recording1']],
141
                [['name' => 'Recording2']]
142
            ],
143
        ];
144
        $activityid = $this->create_from_dataset($dataset);
145
        $instance = instance::get_from_instanceid($activityid);
146
 
147
        $context = \context_course::instance($instance->get_course_id());
148
        foreach ($dataset['users'] as $userdef) {
149
            $user = \core_user::get_user_by_username($userdef['username']);
150
            $this->setUser($user);
151
            $getrecordings = $this->get_recordings($instance->get_instance_id());
152
            // Check users see or do not see recording dependings on their groups.
153
            foreach ($dataset['recordingsdata'] as $recordingdata) {
154
                foreach ($recordingdata as $recording) {
155
                    if (has_capability('moodle/course:update', $context)) {
156
                        $this->assertStringContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'],
157
                            "User $user->username, should be able to delete the recording {$recording['name']}");
158
                        $this->assertStringContainsString('data-action=\"publish\"', $getrecordings['tabledata']['data'],
159
                            "User $user->username, should be able to publish the recording {$recording['name']}");
160
                    } else {
161
                        $this->assertStringNotContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'],
162
                            "User $user->username, should not be able to delete the recording {$recording['name']}");
163
                    }
164
                }
165
            }
166
        }
167
        // Now without delete.
168
        foreach ($dataset['users'] as $userdef) {
169
            $user = \core_user::get_user_by_username($userdef['username']);
170
            $this->setUser($user);
171
            $getrecordings = $this->get_recordings($instance->get_instance_id(), 'protect');
172
            // Check users see or do not see recording dependings on their groups.
173
            foreach ($dataset['recordingsdata'] as $recordingdata) {
174
                foreach ($recordingdata as $recording) {
175
                    $this->assertStringNotContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'],
176
                        "User $user->username, should not be able to delete the recording {$recording['name']}");
177
                }
178
            }
179
        }
180
    }
181
 
182
    /**
183
     * Check preview is present and displayed
184
     */
11 efrain 185
    public function test_get_recordings_preview(): void {
1 efrain 186
        $this->resetAfterTest();
187
        $dataset = [
188
            'type' => instance::TYPE_ALL,
189
            'additionalsettings' => [
190
                'recordings_preview' => 1
191
            ],
192
            'groups' => null,
193
            'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']],
194
            'recordingsdata' => [
195
                [['name' => 'Recording1']],
196
                [['name' => 'Recording2']]
197
            ],
198
        ];
199
        $activityid = $this->create_from_dataset($dataset);
200
        $instance = instance::get_from_instanceid($activityid);
201
 
202
        $context = \context_course::instance($instance->get_course_id());
203
        foreach ($dataset['users'] as $userdef) {
204
            $user = \core_user::get_user_by_username($userdef['username']);
205
            $this->setUser($user);
206
            $getrecordings = $this->get_recordings($instance->get_instance_id());
207
            $this->assertNotEmpty($getrecordings['tabledata']['columns']['3']);
208
            $this->assertEquals('preview', $getrecordings['tabledata']['columns']['3']['key']);
209
        }
210
    }
211
 
212
    /**
213
     * Check we can see all recording from a course in a room only instance
214
     * @covers \mod_bigbluebuttonbn\external\get_recordings::execute
215
     */
11 efrain 216
    public function test_get_recordings_room_only(): void {
1 efrain 217
        $this->resetAfterTest();
218
        set_config('bigbluebuttonbn_importrecordings_enabled', 1);
219
        $dataset = [
220
            'type' => instance::TYPE_ALL,
221
            'groups' => null,
222
            'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']],
223
            'recordingsdata' => [
224
                [['name' => 'Recording1']],
225
                [['name' => 'Recording2']]
226
            ],
227
        ];
228
        $activityid = $this->create_from_dataset($dataset);
229
        $instance = instance::get_from_instanceid($activityid);
230
 
231
        // Now create a recording only activity.
232
        $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
233
        // Now create a new activity and import the first record.
234
        $newactivity = $plugingenerator->create_instance([
235
            'course' => $instance->get_course_id(),
236
            'type' => instance::TYPE_RECORDING_ONLY,
237
            'name' => 'Example 2'
238
        ]);
239
        $plugingenerator->create_meeting([
240
            'instanceid' => $newactivity->id,
241
        ]); // We need to have a meeting created in order to import recordings.
242
        $newinstance = instance::get_from_instanceid($newactivity->id);
243
        $this->create_recordings_for_instance($newinstance, [['name' => 'Recording3']]);
244
 
245
        foreach ($dataset['users'] as $userdef) {
246
            $user = \core_user::get_user_by_username($userdef['username']);
247
            $this->setUser($user);
248
            $getrecordings = $this->get_recordings($newinstance->get_instance_id());
249
            // Check users see or do not see recording dependings on their groups.
250
            $data = json_decode($getrecordings['tabledata']['data']);
251
            $this->assertCount(3, $data);
252
        }
253
    }
254
 
255
    /**
256
     * Check if we can see the imported recording in a new instance
257
     * @covers \mod_bigbluebuttonbn\external\get_recordings::execute
258
     */
11 efrain 259
    public function test_get_recordings_imported(): void {
1 efrain 260
        $this->resetAfterTest();
261
        set_config('bigbluebuttonbn_importrecordings_enabled', 1);
262
        $dataset = [
263
            'type' => instance::TYPE_ALL,
264
            'groups' => null,
265
            'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']],
266
            'recordingsdata' => [
267
                [['name' => 'Recording1']],
268
                [['name' => 'Recording2']]
269
            ],
270
        ];
271
 
272
        $activityid = $this->create_from_dataset($dataset);
273
        $instance = instance::get_from_instanceid($activityid);
274
 
275
        $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
276
        // Now create a new activity and import the first record.
277
        $newactivity = $plugingenerator->create_instance([
278
            'course' => $instance->get_course_id(),
279
            'type' => instance::TYPE_ALL,
280
            'name' => 'Example 2'
281
        ]);
282
        $plugingenerator->create_meeting([
283
            'instanceid' => $newactivity->id,
284
        ]); // We need to have a meeting created in order to import recordings.
285
        $newinstance = instance::get_from_instanceid($newactivity->id);
286
        $recordings = $instance->get_recordings();
287
        foreach ($recordings as $recording) {
288
            if ($recording->get('name') == 'Recording1') {
289
                $recording->create_imported_recording($newinstance);
290
            }
291
        }
292
 
293
        foreach ($dataset['users'] as $userdef) {
294
            $user = \core_user::get_user_by_username($userdef['username']);
295
            $this->setUser($user);
296
            $getrecordings = $this->get_recordings($newinstance->get_instance_id());
297
            // Check users see or do not see recording dependings on their groups.
298
            foreach ($dataset['recordingsdata'] as $index => $recordingdata) {
299
                foreach ($recordingdata as $recording) {
300
                    if ($instance->can_manage_recordings()) {
301
                        $this->assertStringContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'],
302
                            "User $user->username, should be able to delete the recording {$recording['name']}");
303
                    } else {
304
                        $this->assertStringNotContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'],
305
                            "User $user->username, should not be able to delete the recording {$recording['name']}");
306
                    }
307
                    if ($index === 0) {
308
                        $this->assertStringContainsString($recording['name'], $getrecordings['tabledata']['data']);
309
                    } else {
310
                        $this->assertStringNotContainsString($recording['name'], $getrecordings['tabledata']['data']);
311
                    }
312
                }
313
            }
314
 
315
        }
316
    }
317
 
318
    /**
319
     * Check we can see only imported recordings in a recordings only instance when "Show only imported links" enabled.
320
     * @covers \mod_bigbluebuttonbn\external\get_recordings::execute
321
     */
11 efrain 322
    public function test_get_imported_recordings_only(): void {
1 efrain 323
        $this->resetAfterTest();
324
        set_config('bigbluebuttonbn_importrecordings_enabled', 1);
325
        $dataset = [
326
            'type' => instance::TYPE_ALL,
327
            'groups' => null,
328
            'users' => [['username' => 's1', 'role' => 'student']],
329
            'recordingsdata' => [
330
                [['name' => 'Recording1']],
331
                [['name' => 'Recording2']]
332
            ],
333
        ];
334
        $activityid = $this->create_from_dataset($dataset);
335
        $instance = instance::get_from_instanceid($activityid);
336
 
337
        // Now create a recording only activity.
338
        $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
339
        // Now create a new activity and import the first record.
340
        $newactivity = $plugingenerator->create_instance([
341
            'course' => $instance->get_course_id(),
342
            'type' => instance::TYPE_RECORDING_ONLY,
343
            'name' => 'Example 2'
344
        ]);
345
        $plugingenerator->create_meeting([
346
            'instanceid' => $newactivity->id,
347
        ]); // We need to have a meeting created in order to import recordings.
348
        $newinstance = instance::get_from_instanceid($newactivity->id);
349
        $recordings = $instance->get_recordings();
350
        foreach ($recordings as $recording) {
351
            if ($recording->get('name') == 'Recording1') {
352
                $recording->create_imported_recording($newinstance);
353
            }
354
        }
355
        $user = \core_user::get_user_by_username('s1');
356
        $this->setUser($user);
357
        $getrecordings = $this->get_recordings($newinstance->get_instance_id());
358
        $data = json_decode($getrecordings['tabledata']['data']);
359
        // Check that all recordings including the imported recording appear.
360
        $this->assertCount(3, $data);
361
        // Set the flags to enable "Show only imported links".
362
        set_config('bigbluebuttonbn_recordings_imported_default', 1);
363
        set_config('bigbluebuttonbn_recordings_imported_editable', 0);
364
        $getrecordings = $this->get_recordings($newinstance->get_instance_id());
365
        $data = json_decode($getrecordings['tabledata']['data']);
366
        $this->assertCount(1, $data);
367
    }
368
 
369
    /**
370
     * Check if recording are visible/invisible depending on the group.
371
     *
372
     * @param string $type
373
     * @param array $groups
374
     * @param array $users
375
     * @param array $recordingsdata
376
     * @param array $test
377
     * @param int $coursemode
378
     *
379
     * @covers   \mod_bigbluebuttonbn\external\get_recordings::execute
380
     * @dataProvider recording_group_test_data
381
     */
11 efrain 382
    public function test_get_recordings_groups($type, $groups, $users, $recordingsdata, $test, $coursemode): void {
1 efrain 383
        $this->resetAfterTest();
384
        $dataset = compact('type', 'groups', 'users', 'recordingsdata', 'test', 'coursemode');
385
        $activityid = $this->create_from_dataset($dataset);
386
        $instance = instance::get_from_instanceid($activityid);
387
 
388
        foreach ($dataset['users'] as $userdef) {
389
            $user = \core_user::get_user_by_username($userdef['username']);
390
            $this->setUser($user);
391
            $groups = array_values(groups_get_my_groups());
392
            $mygroup = !empty($groups) ? end($groups) : null;
393
 
394
            $getrecordings = $this->get_recordings(
395
                $instance->get_instance_id(), null, !empty($mygroup) ? $mygroup->id : null);
396
            $allrecordingsnames = [];
397
            foreach ($recordingsdata as $groups => $rsinfo) {
398
                $rnames = array_map(function($rdata) {
399
                    return $rdata['name'];
400
                }, $rsinfo);
401
                $allrecordingsnames = array_merge($allrecordingsnames, $rnames);
402
            }
403
            // Check users see or do not see recording dependings on their groups.
404
            foreach ($dataset['test'][$user->username] as $viewablerecordings) {
405
                $viewablerecordings = $dataset['test'][$user->username];
406
                $invisiblerecordings = array_diff($allrecordingsnames, $viewablerecordings);
407
                foreach ($viewablerecordings as $viewablerecordingname) {
408
                    $this->assertStringContainsString($viewablerecordingname, $getrecordings['tabledata']['data'],
409
                        "User $user->username, should see recording {$viewablerecordingname}");
410
                }
411
                foreach ($invisiblerecordings as $invisiblerecordingname) {
412
                    $this->assertStringNotContainsString($invisiblerecordingname, $getrecordings['tabledata']['data'],
413
                        "User $user->username, should not see recording {$viewablerecordingname}");
414
                }
415
            }
416
        }
417
    }
418
 
419
    /**
420
     * Recording group test
421
     *
422
     * @return array[]
423
     */
424
    public function recording_group_test_data() {
425
        return [
426
            'visiblegroups' => [
427
                'type' => instance::TYPE_ALL,
428
                'groups' => ['G1' => ['s1'], 'G2' => ['s2']],
429
                'users' => [
430
                    ['username' => 't1', 'role' => 'editingteacher'],
431
                    ['username' => 's1', 'role' => 'student'],
432
                    ['username' => 's2', 'role' => 'student'],
433
                    ['username' => 's3', 'role' => 'student']
434
                ],
435
                'recordingsdata' => [
436
                    'G1' => [['name' => 'Recording1']],
437
                    'G2' => [['name' => 'Recording2']],
438
                    '' => [['name' => 'Recording3']]
439
                ],
440
                'test' => [
441
                    't1' => ['Recording1', 'Recording2', 'Recording3'], // A moderator should see all recordings.
442
                    's1' => ['Recording1'], // S1 can only see the recordings from his group.
443
                    's2' => ['Recording2'], // S2 can only see the recordings from his group.
444
                    's3' => ['Recording3', 'Recording2', 'Recording1']
445
                    // S3 should see recordings which have no groups and his groups's recording.
446
                ],
447
                'coursemode' => VISIBLEGROUPS
448
            ],
449
            'separategroups' => [
450
                'type' => instance::TYPE_ALL,
451
                'groups' => ['G1' => ['s1'], 'G2' => ['s2']],
452
                'users' => [
453
                    ['username' => 't1', 'role' => 'editingteacher'],
454
                    ['username' => 's1', 'role' => 'student'],
455
                    ['username' => 's2', 'role' => 'student']
456
                ],
457
                'recordingsdata' => [
458
                    'G1' => [['name' => 'Recording1']],
459
                    'G2' => [['name' => 'Recording2']],
460
                    '' => [['name' => 'Recording3']]
461
                ],
462
                'test' => [
463
                    't1' => ['Recording1', 'Recording2', 'Recording3'], // A moderator should see all recordings.
464
                    's1' => ['Recording1'], // S1 can only see the recordings from his group.
465
                    's2' => ['Recording2'], // S2 can only see the recordings from his group.
466
                    's3' => ['Recording3'] // S3 should see recordings which have no groups.
467
                ],
468
                'coursemode' => SEPARATEGROUPS
469
            ]
470
        ];
471
    }
472
}