diff --git a/mod/bigbluebuttonbn/classes/extension.php b/mod/bigbluebuttonbn/classes/extension.php index c1eb66ea8eb..3162b43426e 100644 --- a/mod/bigbluebuttonbn/classes/extension.php +++ b/mod/bigbluebuttonbn/classes/extension.php @@ -42,17 +42,23 @@ class extension { * @param string $action * @param array $data * @param array $metadata + * @param int|null $instanceid * @return array associative array with the additional data and metadata (indexed by 'data' and * 'metadata' keys). */ - public static function action_url_addons(string $action = '', array $data = [], array $metadata = []): array { + public static function action_url_addons( + string $action = '', + array $data = [], + array $metadata = [], + ?int $instanceid = null + ): array { $allmutationclass = self::get_instances_implementing(action_url_addons::class); $additionaldata = []; $additionalmetadata = []; foreach ($allmutationclass as $mutationclass) { // Here we intentionally just pass data and metadata and not the result as we // do not want subplugin to assume that another subplugin is doing a modification. - ['data' => $newdata, 'metadata' => $newmetadata] = $mutationclass->execute($action, $data, $metadata); + ['data' => $newdata, 'metadata' => $newmetadata] = $mutationclass->execute($action, $data, $metadata, $instanceid); $additionaldata = array_merge($additionaldata, $newdata ?? []); $additionalmetadata = array_merge($additionalmetadata, $newmetadata ?? []); } @@ -62,6 +68,52 @@ class extension { ]; } + /** + * Get new instance of classes that are named on the base of this classname and implementing this class + * + * @param string $classname + * @param array|null $newparameters additional parameters for the constructor. + * @return array + */ + protected static function get_instances_implementing(string $classname, ?array $newparameters = []): array { + $classes = self::get_classes_implementing($classname); + sort($classes); // Make sure all extension classes are returned in the same order. This is arbitrarily in + // alphabetical order and depends on the classname but this one way to ensure consistency across calls. + return array_map(function($targetclassname) use ($newparameters) { + // If $newparameters is null, the constructor will be called without parameters. + return new $targetclassname(...$newparameters); + }, $classes); + } + + /** + * Get classes are named on the base of this classname and implementing this class + * + * @param string $classname + * @return array + */ + protected static function get_classes_implementing(string $classname): array { + // Get the class basename without Reflection API. + $classnamecomponents = explode("\\", $classname); + $classbasename = end($classnamecomponents); + $allsubs = core_plugin_manager::instance()->get_plugins_of_type(self::BBB_EXTENSION_PLUGIN_NAME); + $extensionclasses = []; + foreach ($allsubs as $sub) { + if (!$sub->is_enabled()) { + continue; + } + $targetclassname = "\\bbbext_{$sub->name}\\bigbluebuttonbn\\$classbasename"; + if (!class_exists($targetclassname)) { + continue; + } + if (!is_subclass_of($targetclassname, $classname)) { + debugging("The class $targetclassname should extend $classname in the subplugin {$sub->name}. Ignoring."); + continue; + } + $extensionclasses[] = $targetclassname; + } + return $extensionclasses; + } + /** * Get all mod_form addons classes instances * @@ -142,50 +194,4 @@ class extension { $fmclass->delete_instance($id); } } - - /** - * Get new instance of classes that are named on the base of this classname and implementing this class - * - * @param string $classname - * @param array|null $newparameters additional parameters for the constructor. - * @return array - */ - protected static function get_instances_implementing(string $classname, ?array $newparameters = []): array { - $classes = self::get_classes_implementing($classname); - sort($classes); // Make sure all extension classes are returned in the same order. This is arbitrarily in - // alphabetical order and depends on the classname but this one way to ensure consistency across calls. - return array_map(function($targetclassname) use ($newparameters) { - // If $newparameters is null, the constructor will be called without parameters. - return new $targetclassname(...$newparameters); - }, $classes); - } - - /** - * Get classes are named on the base of this classname and implementing this class - * - * @param string $classname - * @return array - */ - protected static function get_classes_implementing(string $classname): array { - // Get the class basename without Reflection API. - $classnamecomponents = explode("\\", $classname); - $classbasename = end($classnamecomponents); - $allsubs = core_plugin_manager::instance()->get_plugins_of_type(self::BBB_EXTENSION_PLUGIN_NAME); - $extensionclasses = []; - foreach ($allsubs as $sub) { - if (!$sub->is_enabled()) { - continue; - } - $targetclassname = "\\bbbext_{$sub->name}\\bigbluebuttonbn\\$classbasename"; - if (!class_exists($targetclassname)) { - continue; - } - if (!is_subclass_of($targetclassname, $classname)) { - debugging("The class $targetclassname should extend $classname in the subplugin {$sub->name}. Ignoring."); - continue; - } - $extensionclasses[] = $targetclassname; - } - return $extensionclasses; - } } diff --git a/mod/bigbluebuttonbn/classes/local/proxy/bigbluebutton_proxy.php b/mod/bigbluebuttonbn/classes/local/proxy/bigbluebutton_proxy.php index 0c0c9f5b23d..c0c0a8c0879 100644 --- a/mod/bigbluebuttonbn/classes/local/proxy/bigbluebutton_proxy.php +++ b/mod/bigbluebuttonbn/classes/local/proxy/bigbluebutton_proxy.php @@ -125,7 +125,7 @@ class bigbluebutton_proxy extends proxy_base { $data['avatarURL'] = self::get_avatar_url($user)->out(false); } } - return self::action_url('join', $data); + return self::action_url('join', $data, [], $instance->get_instance_id()); } /** @@ -464,6 +464,7 @@ class bigbluebutton_proxy extends proxy_base { * @param array $metadata * @param string|null $presentationname * @param string|null $presentationurl + * @param int|null $instanceid * @return array * @throws bigbluebutton_exception */ @@ -471,9 +472,10 @@ class bigbluebutton_proxy extends proxy_base { array $data, array $metadata, ?string $presentationname = null, - ?string $presentationurl = null + ?string $presentationurl = null, + ?int $instanceid = null ): array { - $createmeetingurl = self::action_url('create', $data, $metadata); + $createmeetingurl = self::action_url('create', $data, $metadata, $instanceid); $curl = new curl(); if (!is_null($presentationname) && !is_null($presentationurl)) { @@ -507,10 +509,11 @@ class bigbluebutton_proxy extends proxy_base { * Get meeting info for a given meeting id * * @param string $meetingid + * @param int|null $instanceid * @return array */ - public static function get_meeting_info(string $meetingid): array { - $xmlinfo = self::fetch_endpoint_xml('getMeetingInfo', ['meetingID' => $meetingid]); + public static function get_meeting_info(string $meetingid, ?int $instanceid = null): array { + $xmlinfo = self::fetch_endpoint_xml('getMeetingInfo', ['meetingID' => $meetingid], [], $instanceid); self::assert_returned_xml($xmlinfo, ['meetingid' => $meetingid]); return (array) $xmlinfo; } @@ -520,9 +523,10 @@ class bigbluebutton_proxy extends proxy_base { * * @param string $meetingid * @param string $modpw + * @param int|null $instanceid */ - public static function end_meeting(string $meetingid, string $modpw): void { - $xml = self::fetch_endpoint_xml('end', ['meetingID' => $meetingid, 'password' => $modpw]); + public static function end_meeting(string $meetingid, string $modpw, ?int $instanceid = null): void { + $xml = self::fetch_endpoint_xml('end', ['meetingID' => $meetingid, 'password' => $modpw], [], $instanceid); self::assert_returned_xml($xml, ['meetingid' => $meetingid]); } diff --git a/mod/bigbluebuttonbn/classes/local/proxy/proxy_base.php b/mod/bigbluebuttonbn/classes/local/proxy/proxy_base.php index 2fd0d1b7c6e..ae21aa13f41 100644 --- a/mod/bigbluebuttonbn/classes/local/proxy/proxy_base.php +++ b/mod/bigbluebuttonbn/classes/local/proxy/proxy_base.php @@ -52,11 +52,18 @@ abstract class proxy_base { * @param string $action * @param array $data * @param array $metadata + * @param int|null $instanceid * @return string */ - protected static function action_url(string $action = '', array $data = [], array $metadata = []): string { + protected static function action_url( + string $action = '', + array $data = [], + array $metadata = [], + ?int $instanceid = null + ): string { $baseurl = self::sanitized_url() . $action . '?'; - ['data' => $additionaldata, 'metadata' => $additionalmetadata] = extension::action_url_addons($action, $data, $metadata); + ['data' => $additionaldata, 'metadata' => $additionalmetadata] = + extension::action_url_addons($action, $data, $metadata, $instanceid); $data = array_merge($data, $additionaldata ?? []); $metadata = array_merge($metadata, $additionalmetadata ?? []); @@ -168,12 +175,14 @@ abstract class proxy_base { * @param string $action * @param array $data * @param array $metadata + * @param int|null $instanceid * @return null|bool|\SimpleXMLElement */ protected static function fetch_endpoint_xml( string $action, array $data = [], - array $metadata = [] + array $metadata = [], + ?int $instanceid = null ) { if (PHPUNIT_TEST && !defined('TEST_MOD_BIGBLUEBUTTONBN_MOCK_SERVER')) { return true; // In case we still use fetch and mock server is not defined, this prevents @@ -181,7 +190,7 @@ abstract class proxy_base { // for example. } $curl = new curl(); - return $curl->get(self::action_url($action, $data, $metadata)); + return $curl->get(self::action_url($action, $data, $metadata, $instanceid)); } /** diff --git a/mod/bigbluebuttonbn/classes/local/proxy/recording_proxy.php b/mod/bigbluebuttonbn/classes/local/proxy/recording_proxy.php index 777f277badd..f3df3de5d11 100644 --- a/mod/bigbluebuttonbn/classes/local/proxy/recording_proxy.php +++ b/mod/bigbluebuttonbn/classes/local/proxy/recording_proxy.php @@ -49,7 +49,7 @@ class recording_proxy extends proxy_base { * @param string $recordid a recording id * @return bool */ - public static function delete_recording(string $recordid): bool { + public static function delete_recording(string $recordid, ?int $instanceid = null): bool { $result = self::fetch_endpoint_xml('deleteRecordings', ['recordID' => $recordid]); if (!$result || $result->returncode != 'SUCCESS') { return false; diff --git a/mod/bigbluebuttonbn/classes/meeting.php b/mod/bigbluebuttonbn/classes/meeting.php index 83ca31807d8..71449bb5e80 100644 --- a/mod/bigbluebuttonbn/classes/meeting.php +++ b/mod/bigbluebuttonbn/classes/meeting.php @@ -166,7 +166,13 @@ class meeting { $presentation = $this->instance->get_presentation_for_bigbluebutton_upload(); // The URL must contain nonce. $presentationname = $presentation['name'] ?? null; $presentationurl = $presentation['url'] ?? null; - $response = bigbluebutton_proxy::create_meeting($data, $metadata, $presentationname, $presentationurl); + $response = bigbluebutton_proxy::create_meeting( + $data, + $metadata, + $presentationname, + $presentationurl, + $this->instance->get_instance_id() + ); // New recording management: Insert a recordingID that corresponds to the meeting created. if ($this->instance->is_recorded()) { $recording = new recording(0, (object) [ @@ -184,7 +190,11 @@ class meeting { * Send an end meeting message to BBB server */ public function end_meeting() { - bigbluebutton_proxy::end_meeting($this->instance->get_meeting_id(), $this->instance->get_moderator_password()); + bigbluebutton_proxy::end_meeting( + $this->instance->get_meeting_id(), + $this->instance->get_moderator_password(), + $this->instance->get_instance_id() + ); } /** @@ -240,7 +250,7 @@ class meeting { $meetinginfo->statusrunning = false; $meetinginfo->createtime = null; - $info = self::retrieve_cached_meeting_info($this->instance->get_meeting_id(), $updatecache); + $info = self::retrieve_cached_meeting_info($this->instance, $updatecache); if (!empty($info)) { $meetinginfo->statusrunning = $info['running'] === 'true'; $meetinginfo->createtime = $info['createTime'] ?? null; @@ -322,12 +332,13 @@ class meeting { /** * Gets a meeting info object cached or fetched from the live session. * - * @param string $meetingid + * @param instance $instance * @param bool $updatecache * * @return array */ - protected static function retrieve_cached_meeting_info($meetingid, $updatecache = false) { + protected static function retrieve_cached_meeting_info(instance $instance, $updatecache = false) { + $meetingid = $instance->get_meeting_id(); $cachettl = (int) config::get('waitformoderator_cache_ttl'); $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache'); $result = $cache->get($meetingid); diff --git a/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/action_url_addons.php b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/action_url_addons.php index 9919e8e9ef4..3cf64854dd3 100644 --- a/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/action_url_addons.php +++ b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/action_url_addons.php @@ -31,13 +31,28 @@ class action_url_addons extends \mod_bigbluebuttonbn\local\extension\action_url_ * @param string $action * @param array $data * @param array $metadata + * @param int|null $instanceid * @return array associative array with the additional data and metadata (indexed by 'data' and * 'metadata' keys) */ - public function execute(string $action = '', array $data = [], array $metadata = []): array { + public function execute( + string $action = '', + array $data = [], + array $metadata = [], + ?int $instanceid = null + ): array { + if ($action == 'create' || $action == 'join') { + global $DB; + $record = $DB->get_record('bbbext_simple', [ + 'bigbluebuttonbnid' => $instanceid, + ]); + if ($record) { + $metadata['newfield'] = $record->newfield ?? ''; + } + } return [ - 'data' => $action == 'create' ? [] : ['a', 'b'], - 'metadata' => in_array('Test', $metadata) ? ['c', 'd'] : [] + 'data' => $data, + 'metadata' => $metadata, ]; } } diff --git a/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/mod_instance_helper.php b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/mod_instance_helper.php index af79fe7e4bf..813996a66be 100644 --- a/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/mod_instance_helper.php +++ b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/classes/bigbluebuttonbn/mod_instance_helper.php @@ -53,10 +53,10 @@ class mod_instance_helper extends \mod_bigbluebuttonbn\local\extension\mod_insta if (empty($record)) { $record = new stdClass(); $record->bigbluebuttonbnid = $bigbluebuttonbn->id; - $record->newfield = $bigbluebuttonbn->newfield; + $record->newfield = $bigbluebuttonbn->newfield ?? ''; $DB->insert_record('bbbext_simple', $record); } else { - $record->newfield = $bigbluebuttonbn->newfield; + $record->newfield = $bigbluebuttonbn->newfield ?? ''; $DB->update_record('bbbext_simple', $record); } } diff --git a/mod/bigbluebuttonbn/tests/local/extension_test.php b/mod/bigbluebuttonbn/tests/local/extension_test.php index f7827373174..be907af02a9 100644 --- a/mod/bigbluebuttonbn/tests/local/extension_test.php +++ b/mod/bigbluebuttonbn/tests/local/extension_test.php @@ -18,7 +18,9 @@ namespace mod_bigbluebuttonbn\local; use backup; use backup_controller; use mod_bigbluebuttonbn\extension; +use mod_bigbluebuttonbn\instance; use mod_bigbluebuttonbn\local\extension\mod_instance_helper; +use mod_bigbluebuttonbn\meeting; use mod_bigbluebuttonbn\test\subplugins_test_helper_trait; use mod_bigbluebuttonbn\test\testcase_helper_trait; use restore_controller; @@ -152,17 +154,40 @@ class extension_test extends \advanced_testcase { public function test_action_url_addons() { // Enable plugin. $this->enable_plugins(true); - // Set a random var here. - $var1 = []; - $var2 = ['Test']; - ['data' => $additionalvar1, 'metadata' => $additionalvar2] = extension::action_url_addons('create', [], ['Test']); + $course = $this->get_course(); + [$cm, $cminfo, $bbactivity] = $this->create_instance($course); + $bbactivity->newfield = 4; + extension::update_instance($bbactivity); + ['data' => $additionalvar1, 'metadata' => $additionalvar2] = + extension::action_url_addons('create', [], ['bbb-meta' => 'Test'], $bbactivity->id); $this->assertEmpty($additionalvar1); $this->assertCount(2, $additionalvar2); + $this->assertEquals($additionalvar2['newfield'], 4); ['data' => $additionalvar1, 'metadata' => $additionalvar2] = extension::action_url_addons('delete'); - $this->assertNotEmpty($additionalvar1); + $this->assertEmpty($additionalvar1); $this->assertEmpty($additionalvar2); } + /** + * Test the action_url_addons with plugin enabled + * + * @return void + * @covers \mod_bigbluebuttonbn\extension::action_url_addons + */ + public function test_join_url_with_additional_field() { + $this->initialise_mock_server(); + // Enable plugin. + $this->enable_plugins(true); + $course = $this->get_course(); + [$cm, $cminfo, $bbactivity] = $this->create_instance($course); + $bbactivity->newfield = 4; + extension::update_instance($bbactivity); + $instance = instance::get_from_instanceid($bbactivity->id); + $meeting = new meeting($instance); + $meetingjoinurl = $meeting->get_join_url(); + $this->assertStringContainsString('newfield=4', $meetingjoinurl); + } + /** * Test backup restore (with extension) *