diff --git a/extensions/tags/src/Api/Controller/ShowTagController.php b/extensions/tags/src/Api/Controller/ShowTagController.php index 4ae528783..19f23fda3 100644 --- a/extensions/tags/src/Api/Controller/ShowTagController.php +++ b/extensions/tags/src/Api/Controller/ShowTagController.php @@ -49,11 +49,26 @@ class ShowTagController extends AbstractShowController $slug = Arr::get($request->getQueryParams(), 'slug'); $actor = RequestUtil::getActor($request); $include = $this->extractInclude($request); + $setParentOnChildren = false; - return $this->tags + if (in_array('parent.children.parent', $include, true)) { + $setParentOnChildren = true; + $include[] = 'parent.children'; + $include = array_unique(array_diff($include, ['parent.children.parent'])); + } + + $tag = $this->tags ->with($include, $actor) ->whereVisibleTo($actor) ->where('slug', $slug) ->firstOrFail(); + + if ($setParentOnChildren && $tag->parent) { + foreach ($tag->parent->children as $child) { + $child->parent = $tag->parent; + } + } + + return $tag; } } diff --git a/extensions/tags/src/TagRepository.php b/extensions/tags/src/TagRepository.php index ba877ca92..89a0b06ff 100644 --- a/extensions/tags/src/TagRepository.php +++ b/extensions/tags/src/TagRepository.php @@ -14,7 +14,7 @@ use Illuminate\Database\Eloquent\Builder; class TagRepository { - private const TAG_RELATIONS = ['children', 'parent']; + private const TAG_RELATIONS = ['children', 'parent', 'parent.children']; /** * Get a new query builder for the tags table. diff --git a/extensions/tags/tests/integration/api/tags/ListTest.php b/extensions/tags/tests/integration/api/tags/ListTest.php index c33efa790..6fad63158 100644 --- a/extensions/tags/tests/integration/api/tags/ListTest.php +++ b/extensions/tags/tests/integration/api/tags/ListTest.php @@ -83,15 +83,16 @@ class ListTest extends TestCase } /** + * @dataProvider listTagsIncludes * @test */ - public function user_sees_where_allowed_with_included_tags() + public function user_sees_where_allowed_with_included_tags(string $include, array $expectedIncludes) { $response = $this->send( $this->request('GET', '/api/tags', [ 'authenticatedAs' => 2, ])->withQueryParams([ - 'include' => 'children' + 'include' => $include ]) ); @@ -106,7 +107,7 @@ class ListTest extends TestCase // 6, 7, 8 aren't included because child access shouldnt work unless parent // access is also given. $this->assertEquals(['1', '2', '3', '4', '9', '10', '11'], Arr::pluck($data, 'id')); - $this->assertEquals(['3', '4'], Arr::pluck($included, 'id')); + $this->assertEquals($expectedIncludes, Arr::pluck($included, 'id')); } /** @@ -125,4 +126,12 @@ class ListTest extends TestCase $ids = Arr::pluck($data, 'id'); $this->assertEquals(['1', '2', '3', '4', '9', '10'], $ids); } + + public function listTagsIncludes(): array + { + return [ + ['children', ['3', '4']], + ['parent', ['2']], + ]; + } } diff --git a/extensions/tags/tests/integration/api/tags/ShowTest.php b/extensions/tags/tests/integration/api/tags/ShowTest.php new file mode 100644 index 000000000..959c99a08 --- /dev/null +++ b/extensions/tags/tests/integration/api/tags/ShowTest.php @@ -0,0 +1,75 @@ +extension('flarum-tags'); + + $this->prepareDatabase([ + 'tags' => $this->tags(), + 'users' => [ + $this->normalUser(), + ], + 'group_permission' => [ + ['group_id' => Group::MEMBER_ID, 'permission' => 'tag8.viewForum'], + ['group_id' => Group::MEMBER_ID, 'permission' => 'tag11.viewForum'] + ] + ]); + } + + /** + * @dataProvider showTagIncludes + * @test + */ + public function user_sees_tag_relations_where_allowed(string $include, array $expectedIncludes) + { + $response = $this->send( + $this->request('GET', '/api/tags/primary-2-child-2', [ + 'authenticatedAs' => 2, + ])->withQueryParams([ + 'include' => $include + ]) + ); + + $this->assertEquals(200, $response->getStatusCode()); + + $responseBody = json_decode($response->getBody()->getContents(), true); + + $included = $responseBody['included'] ?? []; + $this->assertEqualsCanonicalizing($expectedIncludes, Arr::pluck($included, 'id')); + } + + public function showTagIncludes(): array + { + return [ + ['children', []], + ['parent', ['2']], + ['parent.children', ['3', '2']], + ['parent.children.parent', ['3', '2']], + ]; + } +}