From b540a59e55beed488f34fc0926829f5fe0c2fbf4 Mon Sep 17 00:00:00 2001 From: Juan Leyva Date: Fri, 24 Mar 2023 15:53:50 +0100 Subject: [PATCH] MDL-76792 webservice: Avoid exception when missing component --- lang/en/deprecated.txt | 1 + lang/en/webservice.php | 3 +- webservice/externallib.php | 5 +-- webservice/tests/externallib_test.php | 62 +++++++++++++++++++++++++++ webservice/upgrade.txt | 4 ++ 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/lang/en/deprecated.txt b/lang/en/deprecated.txt index 29ce9633b3c..04d27b9a946 100644 --- a/lang/en/deprecated.txt +++ b/lang/en/deprecated.txt @@ -88,3 +88,4 @@ showcalculations,core_grades showcalculations_help,core_grades studentsperpage,core_grades studentsperpage_help,core_grades +missingversionfile,core_webservice diff --git a/lang/en/webservice.php b/lang/en/webservice.php index 8636e501e5c..24f26168757 100644 --- a/lang/en/webservice.php +++ b/lang/en/webservice.php @@ -126,7 +126,6 @@ $string['missingcaps_help'] = 'List of capabilities declared by the service whic $string['missingpassword'] = 'Missing password'; $string['missingrequiredcapability'] = 'The capability {$a} is required.'; $string['missingusername'] = 'Missing username'; -$string['missingversionfile'] = 'Coding error: version.php file is missing for the component {$a}'; $string['nameexists'] = 'This name is already in use by another service'; $string['nocapabilitytouseparameter'] = 'The user does not have the required capability to use the parameter {$a}'; $string['nofunctions'] = 'This service has no functions.'; @@ -235,3 +234,5 @@ $string['wsusername'] = 'Web service username'; // Deprecated since Moodle 3.11. $string['usernameoridnousererror'] = 'No users were found with this username/user id.'; $string['usernameoridoccurenceerror'] = 'More than one user was found with this username. Please enter the user id.'; +// Deprecated since Moodle 4.2. +$string['missingversionfile'] = 'Coding error: version.php file is missing for the component {$a}'; diff --git a/webservice/externallib.php b/webservice/externallib.php index 591debdf9b7..95ec4cbb8d0 100644 --- a/webservice/externallib.php +++ b/webservice/externallib.php @@ -142,9 +142,8 @@ class core_webservice_external extends \core_external\external_api { $version = $componentversions[$function->component]; } } else { - // Function component should always have a version.php, - // otherwise the function should have been described with component => 'moodle'. - throw new moodle_exception('missingversionfile', 'webservice', '', $function->component); + // Ignore this component or plugin, it was probably incorrectly uninstalled. + continue; } } $functioninfo['version'] = $version; diff --git a/webservice/tests/externallib_test.php b/webservice/tests/externallib_test.php index a46a32ec78a..d4f9e425c86 100644 --- a/webservice/tests/externallib_test.php +++ b/webservice/tests/externallib_test.php @@ -208,4 +208,66 @@ class externallib_test extends externallib_advanced_testcase { $this->assertEquals(PHP_INT_MAX, $result['userquota']); } + /** + * Test get_site_info with missing components. + */ + public function test_get_site_missing_components() { + global $USER, $DB; + + $this->resetAfterTest(true); + $this->setAdminUser(); + + // Add a web service and token. + $webservice = new \stdClass(); + $webservice->name = 'Test web service'; + $webservice->enabled = true; + $webservice->restrictedusers = false; + $webservice->component = 'moodle'; + $webservice->timecreated = time(); + $webservice->downloadfiles = true; + $webservice->uploadfiles = true; + $externalserviceid = $DB->insert_record('external_services', $webservice); + + // Add a function to the service (missing plugin). + $DB->insert_record('external_functions', + [ + 'component' => 'mod_random', + 'name' => 'mod_random_get_info' + ] + ); + + // Insert one from missing component. + $DB->insert_record('external_services_functions', + [ + 'externalserviceid' => $externalserviceid, + 'functionname' => 'mod_random_get_info' + ] + ); + // Insert a core one. + $DB->insert_record('external_services_functions', + [ + 'externalserviceid' => $externalserviceid, + 'functionname' => 'core_user_get_users' + ] + ); + + $_POST['wstoken'] = 'testtoken'; + $externaltoken = new \stdClass(); + $externaltoken->token = 'testtoken'; + $externaltoken->tokentype = 0; + $externaltoken->userid = $USER->id; + $externaltoken->externalserviceid = $externalserviceid; + $externaltoken->contextid = 1; + $externaltoken->creatorid = $USER->id; + $externaltoken->timecreated = time(); + $DB->insert_record('external_tokens', $externaltoken); + + // Execution should complete. + $result = \core_webservice_external::get_site_info(); + $result = external_api::clean_returnvalue(\core_webservice_external::get_site_info_returns(), $result); + // Check we ignore the missing component function. + $this->assertCount(1, $result['functions']); + $this->assertEquals('core_user_get_users', $result['functions'][0]['name']); + } + } diff --git a/webservice/upgrade.txt b/webservice/upgrade.txt index 8662cd753ed..5d0bc2bc2d8 100644 --- a/webservice/upgrade.txt +++ b/webservice/upgrade.txt @@ -3,6 +3,10 @@ information provided here is intended especially for developers. This information is intended for authors of webservices, not people writing webservice clients. +=== 4.2 === + +* External function core_webservice_external::get_site_info() does not throw exceptions for missing components anymore. + === 4.1 === * The XMLRPC webservice (protocol) has been completely removed. It's now available in the plugins directory.