From 58c4e749cd85805e60a5eaaffd83bd2edd354f10 Mon Sep 17 00:00:00 2001 From: Elke Kreim Date: Fri, 10 Jan 2025 17:31:14 +0100 Subject: [PATCH 1/6] Fixes Opencast-Moodle/moodle-filter_opencast#54 --- classes/local/lti_helper.php | 29 ++++++++++++++++++++++++++++- lang/en/filter_opencast.php | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/classes/local/lti_helper.php b/classes/local/lti_helper.php index b7ba615..ced02ea 100644 --- a/classes/local/lti_helper.php +++ b/classes/local/lti_helper.php @@ -24,8 +24,11 @@ namespace filter_opencast\local; +use core\check\performance\debugging; use oauth_helper; use tool_opencast\local\settings_api; +use tool_opencast\local\api; +use moodle_exception; /** * LTI helper class for filter opencast. @@ -151,7 +154,8 @@ public static function is_lti_credentials_configured(int $ocinstanceid) { */ public static function get_lti_set_object(int $ocinstanceid) { $lticredentials = self::get_lti_credentials($ocinstanceid); - $baseurl = settings_api::get_apiurl($ocinstanceid); + // get url of the engage.ui + $baseurl = self::get_engage_url($ocinstanceid); return (object) [ 'ocinstanceid' => $ocinstanceid, @@ -188,4 +192,27 @@ public static function get_filter_lti_launch_url(int $ocinstanceid, int $coursei } return $ltilaunchurl; } + + /** + * Calls the URL of the presention node of opencast. + * + * This function calls an api endpoint because the url of the engage.ui is different depending on + * the installation (All-In-One or Multiple Servers). + * + * @param int $ocinstancid + * @return string $url the url of the engage.ui of the opencast installation + * @throws \moodle_exception + */ + public static function get_engage_url(int $ocinstancid) { + $api = api::get_instance($ocinstancid); + // Endpoint to call the engage.ui url of presentation node. + // Make sure the api user has the rights to call that api endpoint. + $engageurlendpoint = '/api/info/organization/properties/engageuiurl'; + $result = json_decode($api->oc_get($engageurlendpoint), true); + $url = $result['org.opencastproject.engage.ui.url']; + if (!$url) { + throw new \moodle_exception('no_engageurl_error', 'filter_opencast'); + } + return $url; + } } diff --git a/lang/en/filter_opencast.php b/lang/en/filter_opencast.php index 373f916..52b6afc 100644 --- a/lang/en/filter_opencast.php +++ b/lang/en/filter_opencast.php @@ -35,3 +35,4 @@ $string['setting_uselti_desc'] = 'When enabled, Opencast videos are delivered through LTI authentication using the default Opencast video player. This is typically used alongside Secure Static Files in Opencast for enhanced security.'; $string['setting_uselti_nolti_desc'] = 'To enable LTI Authentication for Opencast, you must configure the required credentials (Consumer Key and Consumer Secret) for this instance. Please do so via this link: {$a}'; $string['setting_uselti_ocinstance_name'] = 'Opencast API {$a} Instance'; +$string['no_engageurl_error'] = 'No URL available. Please check if the api endpoint is available and if the api user has the proper rights.'; From 55141fc09f887b2b6de8815f74d764531ed8c826 Mon Sep 17 00:00:00 2001 From: FarbodZamani <53179227+ferishili@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:24:50 +0100 Subject: [PATCH 2/6] read paella json data properly from mod, (#57) fixes #56 --- classes/text_filter.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/classes/text_filter.php b/classes/text_filter.php index 08b7c26..26e4908 100644 --- a/classes/text_filter.php +++ b/classes/text_filter.php @@ -212,7 +212,7 @@ protected function render_player(int $ocinstanceid, string $episodeid, bool $sho int $playerid, $width = null, $height = null) { global $OUTPUT, $PAGE, $COURSE; - $data = paella_transform::get_paella_data_json($ocinstanceid, $episodeid); + list($data, $errormessage) = paella_transform::get_paella_data_json($ocinstanceid, $episodeid); if (!$data) { return null; @@ -253,9 +253,10 @@ protected function render_player(int $ocinstanceid, string $episodeid, bool $sho $renderer = $PAGE->get_renderer('filter_opencast'); return $renderer->render_player($mustachedata); } else { + $notificationmessage = !empty($errormessage) ? $errormessage : get_string('erroremptystreamsources', 'mod_opencast'); return $OUTPUT->render(new \core\output\notification( - get_string('erroremptystreamsources', 'mod_opencast'), - \core\output\notification::NOTIFY_ERROR + $notificationmessage, + \core\output\notification::NOTIFY_ERROR )); } } From b02ea27a15bc0f1758a53173c73148127dc4795a Mon Sep 17 00:00:00 2001 From: Elke Kreim Date: Wed, 15 Jan 2025 15:35:09 +0100 Subject: [PATCH 3/6] Use Opencast PHP Library for api call Change error message --- classes/local/lti_helper.php | 21 +++++++++++---------- lang/en/filter_opencast.php | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/classes/local/lti_helper.php b/classes/local/lti_helper.php index ced02ea..190e4ac 100644 --- a/classes/local/lti_helper.php +++ b/classes/local/lti_helper.php @@ -24,7 +24,6 @@ namespace filter_opencast\local; -use core\check\performance\debugging; use oauth_helper; use tool_opencast\local\settings_api; use tool_opencast\local\api; @@ -199,20 +198,22 @@ public static function get_filter_lti_launch_url(int $ocinstanceid, int $coursei * This function calls an api endpoint because the url of the engage.ui is different depending on * the installation (All-In-One or Multiple Servers). * - * @param int $ocinstancid + * @param int $ocinstanceid * @return string $url the url of the engage.ui of the opencast installation * @throws \moodle_exception */ - public static function get_engage_url(int $ocinstancid) { - $api = api::get_instance($ocinstancid); + public static function get_engage_url(int $ocinstanceid) { + $api = api::get_instance($ocinstanceid); // Endpoint to call the engage.ui url of presentation node. // Make sure the api user has the rights to call that api endpoint. - $engageurlendpoint = '/api/info/organization/properties/engageuiurl'; - $result = json_decode($api->oc_get($engageurlendpoint), true); - $url = $result['org.opencastproject.engage.ui.url']; - if (!$url) { - throw new \moodle_exception('no_engageurl_error', 'filter_opencast'); + $response = $api->opencastapi->baseApi->getOrgEngageUIUrl(); + if ($response['code'] != 200) { + global $CFG; + $supportemail = $CFG->supportemail; + throw new \moodle_exception('no_engageurl_error', 'filter_opencast', '', $supportemail); + } else { + $engageui = $response['body']; + return $engageui->{'org.opencastproject.engage.ui.url'}; } - return $url; } } diff --git a/lang/en/filter_opencast.php b/lang/en/filter_opencast.php index 52b6afc..ffe78cb 100644 --- a/lang/en/filter_opencast.php +++ b/lang/en/filter_opencast.php @@ -35,4 +35,4 @@ $string['setting_uselti_desc'] = 'When enabled, Opencast videos are delivered through LTI authentication using the default Opencast video player. This is typically used alongside Secure Static Files in Opencast for enhanced security.'; $string['setting_uselti_nolti_desc'] = 'To enable LTI Authentication for Opencast, you must configure the required credentials (Consumer Key and Consumer Secret) for this instance. Please do so via this link: {$a}'; $string['setting_uselti_ocinstance_name'] = 'Opencast API {$a} Instance'; -$string['no_engageurl_error'] = 'No URL available. Please check if the api endpoint is available and if the api user has the proper rights.'; +$string['no_engageurl_error'] = 'Opencast API call for Engage URL not successful. Please contact your support {$a}.'; From 16022a8553ddc5c4b034f3629096378c5d471b98 Mon Sep 17 00:00:00 2001 From: ferishili Date: Thu, 16 Jan 2025 14:05:47 +0100 Subject: [PATCH 4/6] make sure lti launch gets a proper base url in both allinone and multi-nodes opencast instances --- classes/local/lti_helper.php | 83 ++++++++++++++++++++++++++++-------- lang/en/filter_opencast.php | 1 - 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/classes/local/lti_helper.php b/classes/local/lti_helper.php index 190e4ac..caca8c7 100644 --- a/classes/local/lti_helper.php +++ b/classes/local/lti_helper.php @@ -25,6 +25,7 @@ namespace filter_opencast\local; use oauth_helper; +use tool_opencast\exception\opencast_api_response_exception; use tool_opencast\local\settings_api; use tool_opencast\local\api; use moodle_exception; @@ -149,11 +150,11 @@ public static function is_lti_credentials_configured(int $ocinstanceid) { * - ocinstanceid: The ID of the Opencast instance. * - consumerkey: The LTI consumer key for the instance. * - consumersecret: The LTI consumer secret for the instance. - * - baseurl: The API URL for the Opencast instance. + * - baseurl: The API URL for the presentation node of Opencast instance. */ public static function get_lti_set_object(int $ocinstanceid) { $lticredentials = self::get_lti_credentials($ocinstanceid); - // get url of the engage.ui + // Get url of the engage.ui. $baseurl = self::get_engage_url($ocinstanceid); return (object) [ @@ -193,27 +194,75 @@ public static function get_filter_lti_launch_url(int $ocinstanceid, int $coursei } /** - * Calls the URL of the presention node of opencast. + * Retrieves the Engage URL for a given Opencast instance. * - * This function calls an api endpoint because the url of the engage.ui is different depending on - * the installation (All-In-One or Multiple Servers). + * This function attempts to fetch the Engage URL through multiple methods: + * 1. Using the 'org.opencastproject.engage.ui.player.redirect' service. + * 2. Falling back to the API URL if the first method fails. + * 3. Attempting to retrieve the Engage UI URL as a secondary fallback by getting from getOrgEngageUIUrl method. * - * @param int $ocinstanceid - * @return string $url the url of the engage.ui of the opencast installation - * @throws \moodle_exception + * @param int $ocinstanceid The ID of the Opencast instance. + * + * @return string The Engage URL for the specified Opencast instance. + * + * @throws opencast_api_response_exception If there's an error in the API response. */ public static function get_engage_url(int $ocinstanceid) { $api = api::get_instance($ocinstanceid); - // Endpoint to call the engage.ui url of presentation node. - // Make sure the api user has the rights to call that api endpoint. + $response = $api->opencastapi->services->getServiceJSON('org.opencastproject.engage.ui.player.redirect'); + $code = $response['code']; + + // Make sure everything goes fine. + if ($code != 200 && $code != 404) { + throw new opencast_api_response_exception($response); + } + + $engageurl = null; + + // Get the services object from the get call. + $servicesobj = $response['body']; + // Check if the get call returns any services, if not we return the default oc instance api. + if (property_exists($servicesobj, 'services') && property_exists($servicesobj->services, 'service') + && !empty($servicesobj->services->service)) { + // Parse the service object to array, which is easier to use! + $engageservice = (array) $servicesobj->services->service; + if (!empty($engageservice['host'])) { + $engageurl = preg_replace(["/\/docs/"], [''], $engageservice['host']); + } + } + + // If we have a valid engage url, we return it. + if (!empty($engageurl)) { + return $engageurl; + } + + // As a default fallback, we assume that the engage node url is the same as the api url. + $engageurl = settings_api::get_apiurl($ocinstanceid); + + // Try to get the engage url from engage ui url once more, as secondary fallback method. $response = $api->opencastapi->baseApi->getOrgEngageUIUrl(); - if ($response['code'] != 200) { - global $CFG; - $supportemail = $CFG->supportemail; - throw new \moodle_exception('no_engageurl_error', 'filter_opencast', '', $supportemail); - } else { - $engageui = $response['body']; - return $engageui->{'org.opencastproject.engage.ui.url'}; + $code = $response['code']; + // If something went wrong, we throw opencast_api_response_exception exception. + if ($code != 200) { + throw new opencast_api_response_exception($response); } + + // Get the engage ui object from the get call. + $engageuiobj = (array) $response['body']; + + // Check if we have a valid engage ui url. + if (isset($engageuiobj['org.opencastproject.engage.ui.url'])) { + $engageuiurl = $engageuiobj['org.opencastproject.engage.ui.url']; + + // Check if the engage ui url is not empty and not a localhost url. + if (!empty($engageuiurl) && + strpos($engageuiurl, 'http://') === false && + strpos($engageuiurl, 'localhost') === false ) { + $engageurl = $engageuiurl; + } + } + + // Finally, we return it. + return $engageurl; } } diff --git a/lang/en/filter_opencast.php b/lang/en/filter_opencast.php index ffe78cb..373f916 100644 --- a/lang/en/filter_opencast.php +++ b/lang/en/filter_opencast.php @@ -35,4 +35,3 @@ $string['setting_uselti_desc'] = 'When enabled, Opencast videos are delivered through LTI authentication using the default Opencast video player. This is typically used alongside Secure Static Files in Opencast for enhanced security.'; $string['setting_uselti_nolti_desc'] = 'To enable LTI Authentication for Opencast, you must configure the required credentials (Consumer Key and Consumer Secret) for this instance. Please do so via this link: {$a}'; $string['setting_uselti_ocinstance_name'] = 'Opencast API {$a} Instance'; -$string['no_engageurl_error'] = 'Opencast API call for Engage URL not successful. Please contact your support {$a}.'; From 6ec7ab2b1af2f3c2e6348a9fa9b0cc2755311d35 Mon Sep 17 00:00:00 2001 From: ferishili Date: Thu, 16 Jan 2025 15:12:26 +0100 Subject: [PATCH 5/6] change the service to search and make sure it is active --- classes/local/lti_helper.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/local/lti_helper.php b/classes/local/lti_helper.php index caca8c7..e272644 100644 --- a/classes/local/lti_helper.php +++ b/classes/local/lti_helper.php @@ -209,7 +209,7 @@ public static function get_filter_lti_launch_url(int $ocinstanceid, int $coursei */ public static function get_engage_url(int $ocinstanceid) { $api = api::get_instance($ocinstanceid); - $response = $api->opencastapi->services->getServiceJSON('org.opencastproject.engage.ui.player.redirect'); + $response = $api->opencastapi->services->getServiceJSON('org.opencastproject.search'); $code = $response['code']; // Make sure everything goes fine. @@ -225,9 +225,9 @@ public static function get_engage_url(int $ocinstanceid) { if (property_exists($servicesobj, 'services') && property_exists($servicesobj->services, 'service') && !empty($servicesobj->services->service)) { // Parse the service object to array, which is easier to use! - $engageservice = (array) $servicesobj->services->service; - if (!empty($engageservice['host'])) { - $engageurl = preg_replace(["/\/docs/"], [''], $engageservice['host']); + $searchservice = (array) $servicesobj->services->service; + if (!empty($searchservice['host']) && $searchservice['active'] && $searchservice['online']) { + $engageurl = preg_replace(["/\/docs/"], [''], $searchservice['host']); } } From f4ac5a8c185970c7b79ecaf7c64f6ab068cac02e Mon Sep 17 00:00:00 2001 From: ferishili Date: Thu, 16 Jan 2025 16:06:19 +0100 Subject: [PATCH 6/6] get rid of services --- classes/local/lti_helper.php | 40 +++++++----------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/classes/local/lti_helper.php b/classes/local/lti_helper.php index e272644..f332d9d 100644 --- a/classes/local/lti_helper.php +++ b/classes/local/lti_helper.php @@ -193,48 +193,22 @@ public static function get_filter_lti_launch_url(int $ocinstanceid, int $coursei return $ltilaunchurl; } + /** - * Retrieves the Engage URL for a given Opencast instance. + * Retrieves the engage URL for a given Opencast instance. * - * This function attempts to fetch the Engage URL through multiple methods: - * 1. Using the 'org.opencastproject.engage.ui.player.redirect' service. - * 2. Falling back to the API URL if the first method fails. - * 3. Attempting to retrieve the Engage UI URL as a secondary fallback by getting from getOrgEngageUIUrl method. + * This function attempts to get the engage URL for the specified Opencast instance. + * It first tries to fetch the URL from the Opencast API. If that fails, it falls back + * to using the API URL as the engage URL. * * @param int $ocinstanceid The ID of the Opencast instance. * - * @return string The Engage URL for the specified Opencast instance. + * @return string The engage URL for the Opencast instance. * - * @throws opencast_api_response_exception If there's an error in the API response. + * @throws opencast_api_response_exception If the API request fails. */ public static function get_engage_url(int $ocinstanceid) { $api = api::get_instance($ocinstanceid); - $response = $api->opencastapi->services->getServiceJSON('org.opencastproject.search'); - $code = $response['code']; - - // Make sure everything goes fine. - if ($code != 200 && $code != 404) { - throw new opencast_api_response_exception($response); - } - - $engageurl = null; - - // Get the services object from the get call. - $servicesobj = $response['body']; - // Check if the get call returns any services, if not we return the default oc instance api. - if (property_exists($servicesobj, 'services') && property_exists($servicesobj->services, 'service') - && !empty($servicesobj->services->service)) { - // Parse the service object to array, which is easier to use! - $searchservice = (array) $servicesobj->services->service; - if (!empty($searchservice['host']) && $searchservice['active'] && $searchservice['online']) { - $engageurl = preg_replace(["/\/docs/"], [''], $searchservice['host']); - } - } - - // If we have a valid engage url, we return it. - if (!empty($engageurl)) { - return $engageurl; - } // As a default fallback, we assume that the engage node url is the same as the api url. $engageurl = settings_api::get_apiurl($ocinstanceid);