feat: add option for filtering read stickied on all discussions page (#4073)

Co-authored-by: Adrian McCay <2762877+adrianmccay@users.noreply.github.com>
This commit is contained in:
Sami Mazouz 2024-10-17 13:26:30 +01:00 committed by GitHub
parent db17253ccd
commit 876a964e1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 91 additions and 14 deletions

View File

@ -50,4 +50,8 @@ return [
(new Extend\SearchDriver(DatabaseSearchDriver::class)) (new Extend\SearchDriver(DatabaseSearchDriver::class))
->addFilter(DiscussionSearcher::class, StickyFilter::class) ->addFilter(DiscussionSearcher::class, StickyFilter::class)
->addMutator(DiscussionSearcher::class, PinStickiedDiscussionsToTop::class), ->addMutator(DiscussionSearcher::class, PinStickiedDiscussionsToTop::class),
(new Extend\Settings())
->default('flarum-sticky.only_sticky_unread_discussions', true)
->serializeToForum('onlyStickyUnreadDiscussions', 'flarum-sticky.only_sticky_unread_discussions', 'boolval'),
]; ];

View File

@ -5,13 +5,21 @@ import commonExtend from '../common/extend';
export default [ export default [
...commonExtend, ...commonExtend,
new Extend.Admin().permission( new Extend.Admin()
() => ({ .permission(
icon: 'fas fa-thumbtack', () => ({
label: app.translator.trans('flarum-sticky.admin.permissions.sticky_discussions_label'), icon: 'fas fa-thumbtack',
permission: 'discussion.sticky', label: app.translator.trans('flarum-sticky.admin.permissions.sticky_discussions_label'),
}), permission: 'discussion.sticky',
'moderate', }),
95 'moderate',
), 95
)
.setting(() => ({
setting: 'flarum-sticky.only_sticky_unread_discussions',
name: 'onlyStickyUnreadDiscussions',
type: 'boolean',
label: app.translator.trans('flarum-sticky.admin.settings.only_sticky_unread_discussions_label'),
help: app.translator.trans('flarum-sticky.admin.settings.only_sticky_unread_discussions_help'),
})),
]; ];

View File

@ -6,6 +6,9 @@ flarum-sticky:
# Translations in this namespace are used by the admin interface. # Translations in this namespace are used by the admin interface.
admin: admin:
settings:
only_sticky_unread_discussions_label: Only sticky unread discussions
only_sticky_unread_discussions_help: On the All Discussions page, unread sticky discussions pin to the top, while read sticky discussions follow the regular order.
# These translations are used in the Permissions page of the admin interface. # These translations are used in the Permissions page of the admin interface.
permissions: permissions:

View File

@ -12,15 +12,30 @@ namespace Flarum\Sticky;
use DateTime; use DateTime;
use Flarum\Search\Database\DatabaseSearchState; use Flarum\Search\Database\DatabaseSearchState;
use Flarum\Search\SearchCriteria; use Flarum\Search\SearchCriteria;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\Tags\Search\Filter\TagFilter; use Flarum\Tags\Search\Filter\TagFilter;
use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Builder;
class PinStickiedDiscussionsToTop class PinStickiedDiscussionsToTop
{ {
public function __construct(
protected SettingsRepositoryInterface $settings
) {
}
public function __invoke(DatabaseSearchState $state, SearchCriteria $criteria): void public function __invoke(DatabaseSearchState $state, SearchCriteria $criteria): void
{ {
if ($criteria->sortIsDefault && ! $state->isFulltextSearch()) { if ($criteria->sortIsDefault && ! $state->isFulltextSearch()) {
$query = $state->getQuery()->getQuery(); $query = $state->getQuery()->getQuery();
$onlyStickyUnread = $this->settings->get('flarum-sticky.only_sticky_unread_discussions');
// If only sticky unread discussions is disabled, then pin all stickied
// discussions to the top whether they are read or not.
if (! $onlyStickyUnread) {
$this->pinStickiedToTop($query);
return;
}
// If we are viewing a specific tag, then pin all stickied // If we are viewing a specific tag, then pin all stickied
// discussions to the top no matter what. // discussions to the top no matter what.
@ -28,11 +43,7 @@ class PinStickiedDiscussionsToTop
if ($count = count($filters)) { if ($count = count($filters)) {
if ($count === 1 && $filters[0] instanceof TagFilter) { if ($count === 1 && $filters[0] instanceof TagFilter) {
if (! is_array($query->orders)) { $this->pinStickiedToTop($query);
$query->orders = [];
}
array_unshift($query->orders, ['column' => 'is_sticky', 'direction' => 'desc']);
} }
return; return;
@ -76,4 +87,21 @@ class PinStickiedDiscussionsToTop
unset($query->offset, $sticky->offset); unset($query->offset, $sticky->offset);
} }
} }
/**
* Pin all stickied discussions to the top of the query.
* This is done by prepending an order clause to the query.
*
* @param $query
*
* @return void
*/
protected function pinStickiedToTop($query): void
{
if (! is_array($query->orders)) {
$query->orders = [];
}
array_unshift($query->orders, ['column' => 'is_sticky', 'direction' => 'desc']);
}
} }

View File

@ -104,6 +104,40 @@ class ListDiscussionsTest extends TestCase
$this->assertEqualsCanonicalizing([2, 4, 3, 1], Arr::pluck($data['data'], 'id')); $this->assertEqualsCanonicalizing([2, 4, 3, 1], Arr::pluck($data['data'], 'id'));
} }
#[Test]
public function list_discussions_sticky_first_all_read_as_user_filter_read_off()
{
$this->setting('flarum-sticky.only_sticky_unread_discussions', false);
$response = $this->send(
$this->request('GET', '/api/discussions', [
'authenticatedAs' => 3
])
);
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode($response->getBody()->getContents(), true);
$this->assertEquals([3, 1, 2, 4], Arr::pluck($data['data'], 'id'));
}
#[Test]
public function list_discussions_sticky_first_all_read_as_user_filter_read_on()
{
$this->setting('flarum-sticky.only_sticky_unread_discussions', true);
$response = $this->send(
$this->request('GET', '/api/discussions', [
'authenticatedAs' => 3
])
);
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode($response->getBody()->getContents(), true);
$this->assertEquals([2, 4, 3, 1], Arr::pluck($data['data'], 'id'));
}
#[Test] #[Test]
public function list_discussions_shows_stick_first_on_a_tag() public function list_discussions_shows_stick_first_on_a_tag()
{ {