From 7d3477bfec6524edb903ca87fde4c0f557da1538 Mon Sep 17 00:00:00 2001 From: Juan Leyva Date: Wed, 19 Apr 2023 16:32:30 +0200 Subject: [PATCH] MDL-56020 search: New WS core_search_view_results --- lib/db/services.php | 7 ++ search/classes/external/view_results.php | 125 ++++++++++++++++++++ search/tests/external/view_results_test.php | 72 +++++++++++ 3 files changed, 204 insertions(+) create mode 100644 search/classes/external/view_results.php create mode 100644 search/tests/external/view_results_test.php diff --git a/lib/db/services.php b/lib/db/services.php index 3971faca7ee..99eaef2e37b 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1713,6 +1713,13 @@ $functions = array( 'capabilities' => 'moodle/search:query', 'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE], ), + 'core_search_view_results' => array( + 'classname' => '\core_search\external\view_results', + 'description' => 'Trigger view search results event.', + 'type' => 'write', + 'capabilities' => 'moodle/search:query', + 'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE], + ), 'core_tag_get_tagindex' => array( 'classname' => 'core_tag_external', 'methodname' => 'get_tagindex', diff --git a/search/classes/external/view_results.php b/search/classes/external/view_results.php new file mode 100644 index 00000000000..ea0077cc5f5 --- /dev/null +++ b/search/classes/external/view_results.php @@ -0,0 +1,125 @@ +. + +namespace core_search\external; + +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_single_structure; +use core_external\external_multiple_structure; +use core_external\external_value; +use core_external\external_warnings; +use moodle_exception; + +/** + * External function for trigger view search results event. + * + * @package core_search + * @copyright 2023 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 4.3 + */ +class view_results extends external_api { + + /** + * Webservice parameters. + * + * @return external_function_parameters + */ + public static function execute_parameters(): external_function_parameters { + return new external_function_parameters( + [ + 'query' => new external_value(PARAM_NOTAGS, 'the search query'), + 'filters' => new external_single_structure( + [ + 'title' => new external_value(PARAM_NOTAGS, 'result title', VALUE_OPTIONAL), + 'areaids' => new external_multiple_structure( + new external_value(PARAM_RAW, 'areaid'), 'restrict results to these areas', VALUE_DEFAULT, [] + ), + 'courseids' => new external_multiple_structure( + new external_value(PARAM_INT, 'courseid'), 'restrict results to these courses', VALUE_DEFAULT, [] + ), + 'timestart' => new external_value(PARAM_INT, 'docs modified after this date', VALUE_DEFAULT, 0), + 'timeend' => new external_value(PARAM_INT, 'docs modified before this date', VALUE_DEFAULT, 0) + ], 'filters to apply', VALUE_DEFAULT, [] + ), + 'page' => new external_value(PARAM_INT, 'results page number starting from 0, defaults to the first page', + VALUE_DEFAULT, 0) + ] + ); + } + + /** + * Trigger view results event. + * + * @param string $query the search query + * @param array $filters filters to apply + * @param int $page results page + * @return array status and warnings + */ + public static function execute(string $query, array $filters = [], int $page = 0): array { + + $params = self::validate_parameters(self::execute_parameters(), + [ + 'query' => $query, + 'filters' => $filters, + 'page' => $page, + ] + ); + + $system = \context_system::instance(); + external_api::validate_context($system); + + require_capability('moodle/search:query', $system); + + if (\core_search\manager::is_global_search_enabled() === false) { + throw new moodle_exception('globalsearchdisabled', 'search'); + } + + $filters = new \stdClass(); + $filters->title = $params['filters']['title'] ?? ''; + $filters->timestart = $params['filters']['timestart'] ?? 0; + $filters->timeend = $params['filters']['timeend'] ?? 0; + $filters->areaids = $params['filters']['areaids'] ?? []; + $filters->courseids = $params['filters']['courseids'] ?? []; + + \core_search\manager::trigger_search_results_viewed([ + 'q' => $params['query'], + 'page' => $params['page'], + 'title' => !empty($filters->title) ? $filters->title : '', + 'areaids' => !empty($filters->areaids) ? $filters->areaids : [], + 'courseids' => !empty($filters->courseids) ? $filters->courseids : [], + 'timestart' => isset($filters->timestart) ? $filters->timestart : 0, + 'timeend' => isset($filters->timeend) ? $filters->timeend : 0 + ]); + + return ['status' => true, 'warnings' => []]; + } + + /** + * Webservice returns. + * + * @return external_single_structure + */ + public static function execute_returns(): external_single_structure { + return new external_single_structure( + [ + 'status' => new external_value(PARAM_BOOL, 'status: true if success'), + 'warnings' => new external_warnings() + ] + ); + } +} diff --git a/search/tests/external/view_results_test.php b/search/tests/external/view_results_test.php new file mode 100644 index 00000000000..76ba009833d --- /dev/null +++ b/search/tests/external/view_results_test.php @@ -0,0 +1,72 @@ +. + +namespace core_search\external; + +use core_external\external_api; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/webservice/tests/helpers.php'); + +/** + * Tests for the view_results external function. + * + * @package core_search + * @category test + * @copyright 2023 Juan Leyva (juan@moodle.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \core_search\external\view_results + */ +class view_results_test extends \externallib_advanced_testcase { + + public function setUp(): void { + $this->resetAfterTest(); + } + + /** + * test external api + * @covers ::execute + * @return void + */ + public function test_external_view_results(): void { + + set_config('enableglobalsearch', true); + + $this->setAdminUser(); + // Trigger and capture the event. + $sink = $this->redirectEvents(); + + $result = view_results::execute('forum post', ['title' => 'My progress'], 1); + $result = external_api::clean_returnvalue(view_results::execute_returns(), $result); + $this->assertEmpty($result['warnings']); + $this->assertTrue($result['status']); + + $events = $sink->get_events(); + $this->assertCount(1, $events); + $event = array_shift($events); + $sink->close(); + + // Checking that the event contains the expected values. + $this->assertInstanceOf('core\event\search_results_viewed', $event); + $this->assertEventContextNotUsed($event); + $this->assertNotEmpty($event->get_name()); + $this->assertEquals('forum post', $event->get_data()['other']['q']); + $this->assertEquals('My progress', $event->get_data()['other']['title']); + $this->assertEquals(1, $event->get_data()['other']['page']); + } +}