From 93d1fa64ec4fca0a5fdd356ff55eded68a1daeb8 Mon Sep 17 00:00:00 2001 From: IanM <16573496+imorland@users.noreply.github.com> Date: Wed, 6 Nov 2024 23:11:28 +0000 Subject: [PATCH] feat: add a solution filter for the posts endpoint (#109) * feat: add a solution filter for the posts endpoint * Apply fixes from StyleCI * constrain to within Q&A tags --------- Co-authored-by: StyleCI Bot --- extend.php | 4 ++ src/Search/BestAnswerPostFilter.php | 66 +++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/Search/BestAnswerPostFilter.php diff --git a/extend.php b/extend.php index e2ff0b4..cb0e77d 100644 --- a/extend.php +++ b/extend.php @@ -23,6 +23,7 @@ use Flarum\Discussion\Filter\DiscussionFilterer; use Flarum\Discussion\Search\DiscussionSearcher; use Flarum\Extend; +use Flarum\Post\Filter\PostFilterer; use Flarum\Post\Post; use Flarum\Settings\Event\Saving as SettingsSaving; use Flarum\Tags\Api\Serializer\TagSerializer; @@ -127,6 +128,9 @@ (new Extend\Filter(DiscussionFilterer::class)) ->addFilter(Search\BestAnswerFilterGambit::class), + (new Extend\Filter(PostFilterer::class)) + ->addFilter(Search\BestAnswerPostFilter::class), + (new Extend\ApiSerializer(TagSerializer::class)) ->attributes(function (TagSerializer $serializer, Tag $tag, array $attributes) { $attributes['isQnA'] = (bool) $tag->is_qna; diff --git a/src/Search/BestAnswerPostFilter.php b/src/Search/BestAnswerPostFilter.php new file mode 100644 index 0000000..feccc62 --- /dev/null +++ b/src/Search/BestAnswerPostFilter.php @@ -0,0 +1,66 @@ +constrain($filterState->getQuery(), $filterState->getActor(), $negate); + } + + protected function constrain(Builder $query, User $actor, bool $negate) + { + // Join the `discussions` table to access `best_answer_post_id`. + $query->join('discussions', 'posts.discussion_id', '=', 'discussions.id') + ->where('posts.type', 'comment'); + + if ($negate) { + // Exclude posts that are marked as the best answer + $query->where(function ($query) { + $query->whereNull('discussions.best_answer_post_id') + ->orWhereColumn('posts.id', '!=', 'discussions.best_answer_post_id'); + }); + } else { + // Include only posts that are marked as the best answer + $query->whereNotNull('discussions.best_answer_post_id') + ->whereColumn('posts.id', '=', 'discussions.best_answer_post_id'); + } + + // Constrain to discussions within the allowed Q&A tags + $query->whereIn('discussions.id', function ($subQuery) use ($actor) { + $subQuery->select('discussion_id') + ->from('discussion_tag') + ->whereIn('tag_id', $this->allowedQnATags($actor)); + }); + } + + protected function allowedQnATags(User $actor): Collection + { + return Tag::query() + ->whereVisibleTo($actor) + ->where('is_qna', true) + ->pluck('id'); + } +}