From b22dd3cb88335b362fdc5989e818829798d6658b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 6 Dec 2021 20:42:04 +0000 Subject: [PATCH] Added url and preview_html params to search API results Allows easy direct linking and usage of the HTML preview content we show in the UI when viewing search results. Note: preview_html content is a rough representation only, it does not match exactly what was matched in the database-search-operation which finds the results. For #3096 and #3080 --- .../Controllers/Api/SearchApiController.php | 13 ++++++-- dev/api/responses/search-all.json | 15 +++++++++ tests/Api/SearchApiTest.php | 32 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/SearchApiController.php b/app/Http/Controllers/Api/SearchApiController.php index ba960b9d2..d1c99e218 100644 --- a/app/Http/Controllers/Api/SearchApiController.php +++ b/app/Http/Controllers/Api/SearchApiController.php @@ -4,12 +4,14 @@ namespace BookStack\Http\Controllers\Api; use BookStack\Entities\Models\Entity; use BookStack\Entities\Tools\SearchOptions; +use BookStack\Entities\Tools\SearchResultsFormatter; use BookStack\Entities\Tools\SearchRunner; use Illuminate\Http\Request; class SearchApiController extends ApiController { protected $searchRunner; + protected $resultsFormatter; protected $rules = [ 'all' => [ @@ -19,9 +21,10 @@ class SearchApiController extends ApiController ], ]; - public function __construct(SearchRunner $searchRunner) + public function __construct(SearchRunner $searchRunner, SearchResultsFormatter $resultsFormatter) { $this->searchRunner = $searchRunner; + $this->resultsFormatter = $resultsFormatter; } /** @@ -45,6 +48,7 @@ class SearchApiController extends ApiController $count = min(intval($request->get('count', '0')) ?: 20, 100); $results = $this->searchRunner->searchEntities($options, 'all', $page, $count); + $this->resultsFormatter->format($results['results']->all(), $options); /** @var Entity $result */ foreach ($results['results'] as $result) { @@ -52,9 +56,14 @@ class SearchApiController extends ApiController 'id', 'name', 'slug', 'book_id', 'chapter_id', 'draft', 'template', 'created_at', 'updated_at', - 'tags', 'type', + 'tags', 'type', 'preview_html', 'url', ]); $result->setAttribute('type', $result->getType()); + $result->setAttribute('url', $result->getUrl()); + $result->setAttribute('preview_html', [ + 'name' => (string) $result->getAttribute('preview_name'), + 'content' => (string) $result->getAttribute('preview_content'), + ]); } return response()->json([ diff --git a/dev/api/responses/search-all.json b/dev/api/responses/search-all.json index 3096d6da1..2c7584e3f 100644 --- a/dev/api/responses/search-all.json +++ b/dev/api/responses/search-all.json @@ -8,6 +8,11 @@ "created_at": "2021-11-14T15:57:35.000000Z", "updated_at": "2021-11-14T15:57:35.000000Z", "type": "chapter", + "url": "https://example.com/books/my-book/chapter/a-chapter-for-cats", + "preview_html": { + "name": "A chapter for cats", + "content": "...once a bunch of cats named tony...behaviour of cats is unsuitable" + }, "tags": [] }, { @@ -21,6 +26,11 @@ "created_at": "2021-05-15T16:28:10.000000Z", "updated_at": "2021-11-14T15:56:49.000000Z", "type": "page", + "url": "https://example.com/books/my-book/page/the-hows-and-whys-of-cats", + "preview_html": { + "name": "The hows and whys of cats", + "content": "...people ask why cats? but there are...the reason that cats are fast are due to..." + }, "tags": [ { "name": "Animal", @@ -45,6 +55,11 @@ "created_at": "2020-11-29T21:55:07.000000Z", "updated_at": "2021-11-14T16:02:39.000000Z", "type": "page", + "url": "https://example.com/books/my-book/page/how-advanced-are-cats", + "preview_html": { + "name": "How advanced are cats?", + "content": "cats are some of the most advanced animals in the world." + }, "tags": [] } ], diff --git a/tests/Api/SearchApiTest.php b/tests/Api/SearchApiTest.php index 55ca0e009..eb323fdd9 100644 --- a/tests/Api/SearchApiTest.php +++ b/tests/Api/SearchApiTest.php @@ -36,6 +36,38 @@ class SearchApiTest extends TestCase $resp->assertJsonFragment(['name' => $uniqueTerm, 'type' => 'bookshelf']); } + public function test_all_endpoint_returns_entity_url() + { + /** @var Page $page */ + $page = Page::query()->first(); + $page->update(['name' => 'name with superuniquevalue within']); + $page->indexForSearch(); + + $resp = $this->actingAsApiAdmin()->getJson($this->baseEndpoint . '?query=superuniquevalue'); + $resp->assertJsonFragment([ + 'type' => 'page', + 'url' => $page->getUrl(), + ]); + } + + public function test_all_endpoint_returns_items_with_preview_html() + { + /** @var Book $book */ + $book = Book::query()->first(); + $book->update(['name' => 'name with superuniquevalue within', 'description' => 'Description with superuniquevalue within']); + $book->indexForSearch(); + + $resp = $this->actingAsApiAdmin()->getJson($this->baseEndpoint . '?query=superuniquevalue'); + $resp->assertJsonFragment([ + 'type' => 'book', + 'url' => $book->getUrl(), + 'preview_html' => [ + 'name' => 'name with superuniquevalue within', + 'content' => 'Description with superuniquevalue within', + ] + ]); + } + public function test_all_endpoint_requires_query_parameter() { $resp = $this->actingAsApiEditor()->get($this->baseEndpoint);