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.
<?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/>.

namespace mod_bigbluebuttonbn\external;

< use external_api;
> use core_external\external_api;
use mod_bigbluebuttonbn\instance; use mod_bigbluebuttonbn\test\testcase_helper_trait; use require_login_exception; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/webservice/tests/helpers.php'); /** * Tests for the update_course class. * * @package mod_bigbluebuttonbn * @category test * @copyright 2021 - present, Blindside Networks Inc * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @author Laurent David (laurent@call-learning.fr) * @covers \mod_bigbluebuttonbn\external\get_recordings */ class get_recordings_test extends \externallib_advanced_testcase { use testcase_helper_trait; /** * Setup for test */ public function setUp(): void { parent::setUp(); $this->initialise_mock_server(); } /** * Helper * * @param mixed ...$params * @return array|bool|mixed */ protected function get_recordings(...$params) { $recordings = get_recordings::execute(...$params); return external_api::clean_returnvalue(get_recordings::execute_returns(), $recordings); } /** * Test execute API CALL with no instance */ public function test_execute_wrong_instance() { $getrecordings = $this->get_recordings(1234); $this->assertIsArray($getrecordings); $this->assertArrayHasKey('status', $getrecordings); $this->assertEquals(false, $getrecordings['status']); $this->assertStringContainsString('nosuchinstance', $getrecordings['warnings'][0]['warningcode']); } /** * Test execute API CALL without login */ public function test_execute_without_login() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $record = $this->getDataGenerator()->create_module('bigbluebuttonbn', ['course' => $course->id]); $instance = instance::get_from_instanceid($record->id); $this->expectException(require_login_exception::class); $this->get_recordings($instance->get_instance_id()); } /** * Test execute API CALL with invalid login */ public function test_execute_with_invalid_login() { $this->resetAfterTest(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $record = $generator->create_module('bigbluebuttonbn', ['course' => $course->id]); $instance = instance::get_from_instanceid($record->id); $user = $generator->create_user(); $this->setUser($user); $this->expectException(require_login_exception::class); $this->get_recordings($instance->get_instance_id()); } /** * When login as a student */ public function test_execute_with_valid_login() { $this->resetAfterTest(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $record = $generator->create_module('bigbluebuttonbn', ['course' => $course->id]); $instance = instance::get_from_instanceid($record->id); $user = $generator->create_and_enrol($course, 'student'); $this->setUser($user); $getrecordings = $this->get_recordings($instance->get_instance_id()); $this->assertIsArray($getrecordings); $this->assertArrayHasKey('status', $getrecordings); $this->assertEquals(true, $getrecordings['status']); $this->assertNotEmpty($getrecordings['tabledata']); $this->assertEquals('[]', $getrecordings['tabledata']['data']); } /** * Check if tools are present for teacher/moderator */ public function test_get_recordings_tools() { $this->resetAfterTest(); $dataset = [ 'type' => instance::TYPE_ALL, 'groups' => null, 'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']], 'recordingsdata' => [ [['name' => 'Recording1']], [['name' => 'Recording2']] ], ]; $activityid = $this->create_from_dataset($dataset); $instance = instance::get_from_instanceid($activityid); $context = \context_course::instance($instance->get_course_id()); foreach ($dataset['users'] as $userdef) { $user = \core_user::get_user_by_username($userdef['username']); $this->setUser($user); $getrecordings = $this->get_recordings($instance->get_instance_id()); // Check users see or do not see recording dependings on their groups. foreach ($dataset['recordingsdata'] as $recordingdata) { foreach ($recordingdata as $recording) { if (has_capability('moodle/course:update', $context)) { $this->assertStringContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'], "User $user->username, should be able to delete the recording {$recording['name']}"); $this->assertStringContainsString('data-action=\"publish\"', $getrecordings['tabledata']['data'], "User $user->username, should be able to publish the recording {$recording['name']}"); } else { $this->assertStringNotContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'], "User $user->username, should not be able to delete the recording {$recording['name']}"); } } } } // Now without delete. foreach ($dataset['users'] as $userdef) { $user = \core_user::get_user_by_username($userdef['username']); $this->setUser($user); $getrecordings = $this->get_recordings($instance->get_instance_id(), 'protect'); // Check users see or do not see recording dependings on their groups. foreach ($dataset['recordingsdata'] as $recordingdata) { foreach ($recordingdata as $recording) { $this->assertStringNotContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'], "User $user->username, should not be able to delete the recording {$recording['name']}"); } } } } /** * Check preview is present and displayed */ public function test_get_recordings_preview() { $this->resetAfterTest(); $dataset = [ 'type' => instance::TYPE_ALL, 'additionalsettings' => [ 'recordings_preview' => 1 ], 'groups' => null, 'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']], 'recordingsdata' => [ [['name' => 'Recording1']], [['name' => 'Recording2']] ], ]; $activityid = $this->create_from_dataset($dataset); $instance = instance::get_from_instanceid($activityid); $context = \context_course::instance($instance->get_course_id()); foreach ($dataset['users'] as $userdef) { $user = \core_user::get_user_by_username($userdef['username']); $this->setUser($user); $getrecordings = $this->get_recordings($instance->get_instance_id()); $this->assertNotEmpty($getrecordings['tabledata']['columns']['3']); $this->assertEquals('preview', $getrecordings['tabledata']['columns']['3']['key']); } } /** * Check we can see all recording from a course in a room only instance * @covers \mod_bigbluebuttonbn\external\get_recordings::execute */ public function test_get_recordings_room_only() { $this->resetAfterTest(); set_config('bigbluebuttonbn_importrecordings_enabled', 1); $dataset = [ 'type' => instance::TYPE_ALL, 'groups' => null, 'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']], 'recordingsdata' => [ [['name' => 'Recording1']], [['name' => 'Recording2']] ], ]; $activityid = $this->create_from_dataset($dataset); $instance = instance::get_from_instanceid($activityid); // Now create a recording only activity. $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn'); // Now create a new activity and import the first record. $newactivity = $plugingenerator->create_instance([ 'course' => $instance->get_course_id(), 'type' => instance::TYPE_RECORDING_ONLY, 'name' => 'Example 2' ]); $plugingenerator->create_meeting([ 'instanceid' => $newactivity->id, ]); // We need to have a meeting created in order to import recordings. $newinstance = instance::get_from_instanceid($newactivity->id); $this->create_recordings_for_instance($newinstance, [['name' => 'Recording3']]); foreach ($dataset['users'] as $userdef) { $user = \core_user::get_user_by_username($userdef['username']); $this->setUser($user); $getrecordings = $this->get_recordings($newinstance->get_instance_id()); // Check users see or do not see recording dependings on their groups. $data = json_decode($getrecordings['tabledata']['data']); $this->assertCount(3, $data); } } /** * Check if we can see the imported recording in a new instance * @covers \mod_bigbluebuttonbn\external\get_recordings::execute */ public function test_get_recordings_imported() { $this->resetAfterTest(); set_config('bigbluebuttonbn_importrecordings_enabled', 1); $dataset = [ 'type' => instance::TYPE_ALL, 'groups' => null, 'users' => [['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student']], 'recordingsdata' => [ [['name' => 'Recording1']], [['name' => 'Recording2']] ], ]; $activityid = $this->create_from_dataset($dataset); $instance = instance::get_from_instanceid($activityid); $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn'); // Now create a new activity and import the first record. $newactivity = $plugingenerator->create_instance([ 'course' => $instance->get_course_id(), 'type' => instance::TYPE_ALL, 'name' => 'Example 2' ]); $plugingenerator->create_meeting([ 'instanceid' => $newactivity->id, ]); // We need to have a meeting created in order to import recordings. $newinstance = instance::get_from_instanceid($newactivity->id); $recordings = $instance->get_recordings(); foreach ($recordings as $recording) { if ($recording->get('name') == 'Recording1') { $recording->create_imported_recording($newinstance); } } foreach ($dataset['users'] as $userdef) { $user = \core_user::get_user_by_username($userdef['username']); $this->setUser($user); $getrecordings = $this->get_recordings($newinstance->get_instance_id()); // Check users see or do not see recording dependings on their groups. foreach ($dataset['recordingsdata'] as $index => $recordingdata) { foreach ($recordingdata as $recording) { if ($instance->can_manage_recordings()) { $this->assertStringContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'], "User $user->username, should be able to delete the recording {$recording['name']}"); } else { $this->assertStringNotContainsString('data-action=\"delete\"', $getrecordings['tabledata']['data'], "User $user->username, should not be able to delete the recording {$recording['name']}"); } if ($index === 0) { $this->assertStringContainsString($recording['name'], $getrecordings['tabledata']['data']); } else { $this->assertStringNotContainsString($recording['name'], $getrecordings['tabledata']['data']); } } } } } /** * Check we can see only imported recordings in a recordings only instance when "Show only imported links" enabled. * @covers \mod_bigbluebuttonbn\external\get_recordings::execute */ public function test_get_imported_recordings_only() { $this->resetAfterTest(); set_config('bigbluebuttonbn_importrecordings_enabled', 1); $dataset = [ 'type' => instance::TYPE_ALL, 'groups' => null, 'users' => [['username' => 's1', 'role' => 'student']], 'recordingsdata' => [ [['name' => 'Recording1']], [['name' => 'Recording2']] ], ]; $activityid = $this->create_from_dataset($dataset); $instance = instance::get_from_instanceid($activityid); // Now create a recording only activity. $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn'); // Now create a new activity and import the first record. $newactivity = $plugingenerator->create_instance([ 'course' => $instance->get_course_id(), 'type' => instance::TYPE_RECORDING_ONLY, 'name' => 'Example 2' ]); $plugingenerator->create_meeting([ 'instanceid' => $newactivity->id, ]); // We need to have a meeting created in order to import recordings. $newinstance = instance::get_from_instanceid($newactivity->id); $recordings = $instance->get_recordings(); foreach ($recordings as $recording) { if ($recording->get('name') == 'Recording1') { $recording->create_imported_recording($newinstance); } } $user = \core_user::get_user_by_username('s1'); $this->setUser($user); $getrecordings = $this->get_recordings($newinstance->get_instance_id()); $data = json_decode($getrecordings['tabledata']['data']); // Check that all recordings including the imported recording appear. $this->assertCount(3, $data); // Set the flags to enable "Show only imported links". set_config('bigbluebuttonbn_recordings_imported_default', 1); set_config('bigbluebuttonbn_recordings_imported_editable', 0); $getrecordings = $this->get_recordings($newinstance->get_instance_id()); $data = json_decode($getrecordings['tabledata']['data']); $this->assertCount(1, $data); } /** * Check if recording are visible/invisible depending on the group. * * @param string $type * @param array $groups * @param array $users * @param array $recordingsdata * @param array $test * @param int $coursemode * * @covers \mod_bigbluebuttonbn\external\get_recordings::execute * @dataProvider recording_group_test_data */ public function test_get_recordings_groups($type, $groups, $users, $recordingsdata, $test, $coursemode) { $this->resetAfterTest(); $dataset = compact('type', 'groups', 'users', 'recordingsdata', 'test', 'coursemode'); $activityid = $this->create_from_dataset($dataset); $instance = instance::get_from_instanceid($activityid); foreach ($dataset['users'] as $userdef) { $user = \core_user::get_user_by_username($userdef['username']); $this->setUser($user); $groups = array_values(groups_get_my_groups()); $mygroup = !empty($groups) ? end($groups) : null; $getrecordings = $this->get_recordings( $instance->get_instance_id(), null, !empty($mygroup) ? $mygroup->id : null); $allrecordingsnames = []; foreach ($recordingsdata as $groups => $rsinfo) { $rnames = array_map(function($rdata) { return $rdata['name']; }, $rsinfo); $allrecordingsnames = array_merge($allrecordingsnames, $rnames); } // Check users see or do not see recording dependings on their groups. foreach ($dataset['test'][$user->username] as $viewablerecordings) { $viewablerecordings = $dataset['test'][$user->username]; $invisiblerecordings = array_diff($allrecordingsnames, $viewablerecordings); foreach ($viewablerecordings as $viewablerecordingname) { $this->assertStringContainsString($viewablerecordingname, $getrecordings['tabledata']['data'], "User $user->username, should see recording {$viewablerecordingname}"); } foreach ($invisiblerecordings as $invisiblerecordingname) { $this->assertStringNotContainsString($invisiblerecordingname, $getrecordings['tabledata']['data'], "User $user->username, should not see recording {$viewablerecordingname}"); } } } } /** * Recording group test * * @return array[] */ public function recording_group_test_data() { return [ 'visiblegroups' => [ 'type' => instance::TYPE_ALL, 'groups' => ['G1' => ['s1'], 'G2' => ['s2']], 'users' => [ ['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student'], ['username' => 's2', 'role' => 'student'], ['username' => 's3', 'role' => 'student'] ], 'recordingsdata' => [ 'G1' => [['name' => 'Recording1']], 'G2' => [['name' => 'Recording2']], '' => [['name' => 'Recording3']] ], 'test' => [ 't1' => ['Recording1', 'Recording2', 'Recording3'], // A moderator should see all recordings. 's1' => ['Recording1'], // S1 can only see the recordings from his group. 's2' => ['Recording2'], // S2 can only see the recordings from his group. 's3' => ['Recording3', 'Recording2', 'Recording1'] // S3 should see recordings which have no groups and his groups's recording. ], 'coursemode' => VISIBLEGROUPS ], 'separategroups' => [ 'type' => instance::TYPE_ALL, 'groups' => ['G1' => ['s1'], 'G2' => ['s2']], 'users' => [ ['username' => 't1', 'role' => 'editingteacher'], ['username' => 's1', 'role' => 'student'], ['username' => 's2', 'role' => 'student'] ], 'recordingsdata' => [ 'G1' => [['name' => 'Recording1']], 'G2' => [['name' => 'Recording2']], '' => [['name' => 'Recording3']] ], 'test' => [ 't1' => ['Recording1', 'Recording2', 'Recording3'], // A moderator should see all recordings. 's1' => ['Recording1'], // S1 can only see the recordings from his group. 's2' => ['Recording2'], // S2 can only see the recordings from his group. 's3' => ['Recording3'] // S3 should see recordings which have no groups. ], 'coursemode' => SEPARATEGROUPS ] ]; } }