Skip to content

Commit 5164375

Browse files
committed
Merge branch 'rashadkhan359/development' into development
2 parents 18ab38a + fec4445 commit 5164375

File tree

5 files changed

+121
-25
lines changed

5 files changed

+121
-25
lines changed

app/Api/ApiEntityListFormatter.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace BookStack\Api;
44

5+
use BookStack\Entities\Models\BookChild;
56
use BookStack\Entities\Models\Entity;
7+
use BookStack\Entities\Models\Page;
68

79
class ApiEntityListFormatter
810
{
@@ -20,8 +22,16 @@ class ApiEntityListFormatter
2022
* @var array<string|int, string|callable>
2123
*/
2224
protected array $fields = [
23-
'id', 'name', 'slug', 'book_id', 'chapter_id', 'draft',
24-
'template', 'priority', 'created_at', 'updated_at',
25+
'id',
26+
'name',
27+
'slug',
28+
'book_id',
29+
'chapter_id',
30+
'draft',
31+
'template',
32+
'priority',
33+
'created_at',
34+
'updated_at',
2535
];
2636

2737
public function __construct(array $list)
@@ -62,6 +72,28 @@ public function withTags(): self
6272
return $this;
6373
}
6474

75+
/**
76+
* Include parent book/chapter info in the formatted data.
77+
*/
78+
public function withParents(): self
79+
{
80+
$this->withField('book', function (Entity $entity) {
81+
if ($entity instanceof BookChild && $entity->book) {
82+
return $entity->book->only(['id', 'name', 'slug']);
83+
}
84+
return null;
85+
});
86+
87+
$this->withField('chapter', function (Entity $entity) {
88+
if ($entity instanceof Page && $entity->chapter) {
89+
return $entity->chapter->only(['id', 'name', 'slug']);
90+
}
91+
return null;
92+
});
93+
94+
return $this;
95+
}
96+
6597
/**
6698
* Format the data and return an array of formatted content.
6799
* @return array[]

app/Search/SearchApiController.php

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,18 @@
99

1010
class SearchApiController extends ApiController
1111
{
12-
protected SearchRunner $searchRunner;
13-
protected SearchResultsFormatter $resultsFormatter;
14-
1512
protected $rules = [
1613
'all' => [
17-
'query' => ['required'],
18-
'page' => ['integer', 'min:1'],
19-
'count' => ['integer', 'min:1', 'max:100'],
14+
'query' => ['required'],
15+
'page' => ['integer', 'min:1'],
16+
'count' => ['integer', 'min:1', 'max:100'],
2017
],
2118
];
2219

23-
public function __construct(SearchRunner $searchRunner, SearchResultsFormatter $resultsFormatter)
24-
{
25-
$this->searchRunner = $searchRunner;
26-
$this->resultsFormatter = $resultsFormatter;
20+
public function __construct(
21+
protected SearchRunner $searchRunner,
22+
protected SearchResultsFormatter $resultsFormatter
23+
) {
2724
}
2825

2926
/**
@@ -50,16 +47,16 @@ public function all(Request $request)
5047
$this->resultsFormatter->format($results['results']->all(), $options);
5148

5249
$data = (new ApiEntityListFormatter($results['results']->all()))
53-
->withType()->withTags()
50+
->withType()->withTags()->withParents()
5451
->withField('preview_html', function (Entity $entity) {
5552
return [
56-
'name' => (string) $entity->getAttribute('preview_name'),
53+
'name' => (string) $entity->getAttribute('preview_name'),
5754
'content' => (string) $entity->getAttribute('preview_content'),
5855
];
5956
})->format();
6057

6158
return response()->json([
62-
'data' => $data,
59+
'data' => $data,
6360
'total' => $results['total'],
6461
]);
6562
}

dev/api/requests/search-all.http

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
GET /api/search?query=cats+{created_by:me}&page=1&count=2
1+
GET /api/search?query=cats+{created_by:me}&page=1&count=2

dev/api/responses/search-all.json

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
"created_at": "2021-11-14T15:57:35.000000Z",
99
"updated_at": "2021-11-14T15:57:35.000000Z",
1010
"type": "chapter",
11-
"url": "https://example.com/books/my-book/chapter/a-chapter-for-cats",
11+
"url": "https://example.com/books/cats/chapter/a-chapter-for-cats",
12+
"book": {
13+
"id": 1,
14+
"name": "Cats",
15+
"slug": "cats"
16+
},
1217
"preview_html": {
1318
"name": "A chapter for <strong>cats</strong>",
1419
"content": "...once a bunch of <strong>cats</strong> named tony...behaviour of <strong>cats</strong> is unsuitable"
@@ -26,7 +31,17 @@
2631
"created_at": "2021-05-15T16:28:10.000000Z",
2732
"updated_at": "2021-11-14T15:56:49.000000Z",
2833
"type": "page",
29-
"url": "https://example.com/books/my-book/page/the-hows-and-whys-of-cats",
34+
"url": "https://example.com/books/cats/page/the-hows-and-whys-of-cats",
35+
"book": {
36+
"id": 1,
37+
"name": "Cats",
38+
"slug": "cats"
39+
},
40+
"chapter": {
41+
"id": 75,
42+
"name": "A chapter for cats",
43+
"slug": "a-chapter-for-cats"
44+
},
3045
"preview_html": {
3146
"name": "The hows and whys of <strong>cats</strong>",
3247
"content": "...people ask why <strong>cats</strong>? but there are...the reason that <strong>cats</strong> are fast are due to..."
@@ -55,7 +70,17 @@
5570
"created_at": "2020-11-29T21:55:07.000000Z",
5671
"updated_at": "2021-11-14T16:02:39.000000Z",
5772
"type": "page",
58-
"url": "https://example.com/books/my-book/page/how-advanced-are-cats",
73+
"url": "https://example.com/books/big-cats/page/how-advanced-are-cats",
74+
"book": {
75+
"id": 13,
76+
"name": "Big Cats",
77+
"slug": "big-cats"
78+
},
79+
"chapter": {
80+
"id": 73,
81+
"name": "A chapter for bigger cats",
82+
"slug": "a-chapter-for-bigger-cats"
83+
},
5984
"preview_html": {
6085
"name": "How advanced are <strong>cats</strong>?",
6186
"content": "<strong>cats</strong> are some of the most advanced animals in the world."
@@ -64,4 +89,4 @@
6489
}
6590
],
6691
"total": 3
67-
}
92+
}

tests/Api/SearchApiTest.php

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class SearchApiTest extends TestCase
1313
{
1414
use TestsApi;
1515

16-
protected $baseEndpoint = '/api/search';
16+
protected string $baseEndpoint = '/api/search';
1717

1818
public function test_all_endpoint_returns_search_filtered_results_with_query()
1919
{
@@ -45,7 +45,7 @@ public function test_all_endpoint_returns_entity_url()
4545
$resp = $this->actingAsApiAdmin()->getJson($this->baseEndpoint . '?query=superuniquevalue');
4646
$resp->assertJsonFragment([
4747
'type' => 'page',
48-
'url' => $page->getUrl(),
48+
'url' => $page->getUrl(),
4949
]);
5050
}
5151

@@ -57,10 +57,10 @@ public function test_all_endpoint_returns_items_with_preview_html()
5757

5858
$resp = $this->actingAsApiAdmin()->getJson($this->baseEndpoint . '?query=superuniquevalue');
5959
$resp->assertJsonFragment([
60-
'type' => 'book',
61-
'url' => $book->getUrl(),
60+
'type' => 'book',
61+
'url' => $book->getUrl(),
6262
'preview_html' => [
63-
'name' => 'name with <strong>superuniquevalue</strong> within',
63+
'name' => 'name with <strong>superuniquevalue</strong> within',
6464
'content' => 'Description with <strong>superuniquevalue</strong> within',
6565
],
6666
]);
@@ -74,4 +74,46 @@ public function test_all_endpoint_requires_query_parameter()
7474
$resp = $this->actingAsApiEditor()->get($this->baseEndpoint . '?query=myqueryvalue');
7575
$resp->assertOk();
7676
}
77+
78+
public function test_all_endpoint_includes_parent_details_where_visible()
79+
{
80+
$page = $this->entities->pageWithinChapter();
81+
$chapter = $page->chapter;
82+
$book = $page->book;
83+
84+
$page->update(['name' => 'name with superextrauniquevalue within']);
85+
$page->indexForSearch();
86+
87+
$editor = $this->users->editor();
88+
$this->actingAsApiEditor();
89+
$resp = $this->getJson($this->baseEndpoint . '?query=superextrauniquevalue');
90+
$resp->assertJsonFragment([
91+
'id' => $page->id,
92+
'type' => 'page',
93+
'book' => [
94+
'id' => $book->id,
95+
'name' => $book->name,
96+
'slug' => $book->slug,
97+
],
98+
'chapter' => [
99+
'id' => $chapter->id,
100+
'name' => $chapter->name,
101+
'slug' => $chapter->slug,
102+
],
103+
]);
104+
105+
$this->permissions->disableEntityInheritedPermissions($chapter);
106+
$this->permissions->setEntityPermissions($page, ['view'], [$editor->roles()->first()]);
107+
108+
$resp = $this->getJson($this->baseEndpoint . '?query=superextrauniquevalue');
109+
$resp->assertJsonPath('data.0.id', $page->id);
110+
$resp->assertJsonPath('data.0.book.name', $book->name);
111+
$resp->assertJsonMissingPath('data.0.chapter');
112+
113+
$this->permissions->disableEntityInheritedPermissions($book);
114+
115+
$resp = $this->getJson($this->baseEndpoint . '?query=superextrauniquevalue');
116+
$resp->assertJsonPath('data.0.id', $page->id);
117+
$resp->assertJsonMissingPath('data.0.book.name');
118+
}
77119
}

0 commit comments

Comments
 (0)