diff --git a/extend.php b/extend.php
index 74d873e..7c9ab5e 100644
--- a/extend.php
+++ b/extend.php
@@ -77,6 +77,7 @@
}),
(new Extend\ApiResource(Resource\PostResource::class))
+ ->fields(Api\PostAttributes::class)
->endpoint(Endpoint\Index::class, function (Endpoint\Index $endpoint) {
return $endpoint
->addDefaultInclude(['discussion.bestAnswerPost', 'discussion.bestAnswerUser', 'discussion.bestAnswerPost.user']); // @todo: same
diff --git a/js/src/@types/shims.d.ts b/js/src/@types/shims.d.ts
index 072f558..b1468dd 100644
--- a/js/src/@types/shims.d.ts
+++ b/js/src/@types/shims.d.ts
@@ -14,7 +14,6 @@ declare module 'flarum/common/models/Discussion' {
hasBestAnswer(): boolean | undefined;
bestAnswerPost(): Post | null;
bestAnswerUser(): User | null;
- canSelectBestAnswer(): boolean;
bestAnswerSetAt(): Date | null;
}
}
@@ -37,3 +36,9 @@ declare module 'flarum/common/models/User' {
bestAnswerCount(): number;
}
}
+
+declare module 'flarum/common/models/Post' {
+ export default interface Post {
+ canSelectAsBestAnswer(): boolean;
+ }
+}
diff --git a/js/src/admin/components/BestAnswerSettingsPage.tsx b/js/src/admin/components/BestAnswerSettingsPage.tsx
index 7e475ee..93a3886 100644
--- a/js/src/admin/components/BestAnswerSettingsPage.tsx
+++ b/js/src/admin/components/BestAnswerSettingsPage.tsx
@@ -31,12 +31,6 @@ export default class BestAnswerSettingsPage extends ExtensionPage {
{app.translator.trans('fof-best-answer.admin.settings.label.general')}
- {this.buildSettingComponent({
- type: 'boolean',
- setting: 'fof-best-answer.allow_select_own_post',
- label: app.translator.trans('fof-best-answer.admin.settings.allow_select_own_post'),
- help: app.translator.trans('fof-best-answer.admin.settings.allow_select_own_post_help'),
- })}
{this.buildSettingComponent({
type: 'boolean',
setting: 'fof-best-answer.use_alternative_ui',
diff --git a/js/src/admin/extend.ts b/js/src/admin/extend.ts
index ea9d9dc..0b9b050 100644
--- a/js/src/admin/extend.ts
+++ b/js/src/admin/extend.ts
@@ -1,3 +1,4 @@
+import app from 'flarum/admin/app';
import Extend from 'flarum/common/extenders';
import BestAnswerSettingsPage from './components/BestAnswerSettingsPage';
import commonExtend from '../common/extend';
@@ -22,5 +23,13 @@ export default [
permission: 'discussion.selectBestAnswerNotOwnDiscussion',
}),
'reply'
+ )
+ .permission(
+ () => ({
+ icon: 'fas fa-check',
+ label: app.translator.trans('fof-best-answer.admin.permissions.allow_select_own_post'),
+ permission: 'discussion.fof-best-answer.allow_select_own_post',
+ }),
+ 'reply'
),
];
diff --git a/js/src/forum/addBestAnswerAction.tsx b/js/src/forum/addBestAnswerAction.tsx
index fd476bc..9a83985 100644
--- a/js/src/forum/addBestAnswerAction.tsx
+++ b/js/src/forum/addBestAnswerAction.tsx
@@ -10,18 +10,13 @@ import extractText from 'flarum/common/utils/extractText';
export default function addBestAnswerAction() {
const ineligible = (discussion: Discussion, post: Post) => {
- return post.isHidden() || post.number() === 1 || !discussion.canSelectBestAnswer() || !app.session.user;
- };
-
- const blockSelectOwnPost = (post: Post): boolean => {
- const user = post.user();
- return !app.forum.attribute
('canSelectBestAnswerOwnPost') && user !== false && user.id() === app.session.user?.id();
+ return post.isHidden() || post.number() === 1 || !post.canSelectAsBestAnswer() || !app.session.user;
};
const isThisBestAnswer = (discussion: Discussion, post: Post): boolean => {
- const bAPost = discussion.bestAnswerPost();
+ const bAPost = discussion.bestAnswerPost?.();
const hasBestAnswer = discussion.hasBestAnswer();
- return hasBestAnswer !== undefined && hasBestAnswer && bAPost !== null && bAPost.id() === post.id();
+ return hasBestAnswer !== undefined && hasBestAnswer && bAPost !== null && bAPost.id?.() === post.id();
};
const actionLabel = (isBestAnswer: boolean): string => {
@@ -72,7 +67,7 @@ export default function addBestAnswerAction() {
if (post.contentType() !== 'comment') return;
- if (ineligible(discussion, post) || blockSelectOwnPost(post) || !app.current.matches(DiscussionPage)) return;
+ if (ineligible(discussion, post) || !app.current.matches(DiscussionPage)) return;
items.add(
'bestAnswer',
@@ -101,7 +96,7 @@ export default function addBestAnswerAction() {
post.pushAttributes({ isBestAnswer });
- if (ineligible(discussion, post) || blockSelectOwnPost(post) || !app.current.matches(DiscussionPage)) return;
+ if (ineligible(discussion, post) || !app.current.matches(DiscussionPage)) return;
items.add(
'bestAnswer',
diff --git a/js/src/forum/extend.ts b/js/src/forum/extend.ts
index 38c5cd3..6df7b8d 100644
--- a/js/src/forum/extend.ts
+++ b/js/src/forum/extend.ts
@@ -1,7 +1,7 @@
import Discussion from 'flarum/common/models/Discussion';
import commonExtend from '../common/extend';
import Extend from 'flarum/common/extenders';
-import type Post from 'flarum/common/models/Post';
+import Post from 'flarum/common/models/Post';
import User from 'flarum/common/models/User';
import Model from 'flarum/common/Model';
@@ -12,9 +12,11 @@ export default [
.hasOne('bestAnswerPost')
.hasOne('bestAnswerUser')
.attribute('hasBestAnswer')
- .attribute('canSelectBestAnswer')
.attribute('bestAnswerSetAt', Model.transformDate),
new Extend.Model(User) //
.attribute('bestAnswerCount'),
+
+ new Extend.Model(Post) //
+ .attribute('canSelectAsBestAnswer'),
];
diff --git a/resources/locale/en.yml b/resources/locale/en.yml
index 711eb6a..d54fcec 100644
--- a/resources/locale/en.yml
+++ b/resources/locale/en.yml
@@ -3,6 +3,7 @@ fof-best-answer:
permissions:
best_answer: Select Best Answer (own Discussion)
best_answer_not_own_discussion: Select Best Answer (not own Discussion)
+ allow_select_own_post: Select own post as Best Answer
settings:
label:
tags: Best Answer Tags
@@ -10,8 +11,6 @@ fof-best-answer:
reminders: Reminders
advanced: Advanced
reminders_notice: For reminders to function, you must have set up the Flarum scheduler correctly.
- allow_select_own_post: Select own post
- allow_select_own_post_help: Allow a user to select their own post as a best answer to a discussion
show_max_lines_label: Max lines to show in post preview
show_max_lines_help: Set to 0 to disable. If a post is longer than the configured amount of lines, it will be truncated in the post preview with a fade out effect.
select_best_answer_reminder_days: Reminder frequency
diff --git a/src/Api/ForumAttributes.php b/src/Api/ForumAttributes.php
index 13c4dc7..ed05485 100644
--- a/src/Api/ForumAttributes.php
+++ b/src/Api/ForumAttributes.php
@@ -24,9 +24,6 @@ public function __construct(
public function __invoke(): array
{
return [
- Schema\Boolean::make('canSelectBestAnswerOwnPost')
- ->get(fn () => (bool) $this->settings->get('fof-best-answer.allow_select_own_post')),
-
Schema\Boolean::make('bestAnswerDiscussionSidebarJumpButton')
->get(fn () => (bool) $this->settings->get('fof-best-answer.discussion_sidebar_jump_button')),
diff --git a/src/Api/PostAttributes.php b/src/Api/PostAttributes.php
new file mode 100644
index 0000000..ff094ab
--- /dev/null
+++ b/src/Api/PostAttributes.php
@@ -0,0 +1,33 @@
+get(fn (Post $post, Context $context) => $this->bestAnswerRepository->canSelectPostAsBestAnswer($context->getActor(), $post)),
+ ];
+ }
+}
diff --git a/src/Console/NotifyCommand.php b/src/Console/NotifyCommand.php
index cc8e33d..43ed413 100644
--- a/src/Console/NotifyCommand.php
+++ b/src/Console/NotifyCommand.php
@@ -40,7 +40,6 @@ public function __construct(private SettingsRepositoryInterface $settings, priva
public function handle()
{
$days = (int) $this->settings->get('fof-best-answer.select_best_answer_reminder_days');
- $canSelectOwn = (bool) (int) $this->settings->get('fof-best-answer.allow_select_own_post');
$time = Carbon::now()->subDays($days);
// set a max time period to go back, so we don't spam really old discussions too.
@@ -76,11 +75,12 @@ public function handle()
$errors = [];
- $query->chunkById(20, function ($discussions) use ($canSelectOwn, &$errors) {
+ $query->chunkById(20, function ($discussions) use (&$errors) {
// Filter out discussions where the user can't select a post as best answer.
// - The user must have permission to select a best answer on their own discussion
// - The user must be able to select a post, whether they can select any post (including their own) or not.
- $discussions = $discussions->filter(function ($d) use ($canSelectOwn) {
+ $discussions = $discussions->filter(function ($d) {
+ $canSelectOwn = $d->user->can('fof-best-answer.allow_select_own_post', $d);
$hasPermission = $d->user->can('selectBestAnswerOwnDiscussion', $d);
$canSelectPosts = $canSelectOwn || $d->posts()->where('user_id', '!=', $d->user_id)->count() != 0;
diff --git a/src/Repository/BestAnswerRepository.php b/src/Repository/BestAnswerRepository.php
index 01e34c0..d5d70f8 100644
--- a/src/Repository/BestAnswerRepository.php
+++ b/src/Repository/BestAnswerRepository.php
@@ -50,7 +50,7 @@ public function canSelectPostAsBestAnswer(User $user, Post $post): bool
}
if ($user->id === $post->user_id) {
- return (bool) $this->settings->get('fof-best-answer.allow_select_own_post');
+ return $user->can('fof-best-answer.allow_select_own_post', $post->discussion);
}
return true;
diff --git a/tests/integration/api/SetBestAnswerTest.php b/tests/integration/api/SetBestAnswerTest.php
index e6defdb..491f27f 100644
--- a/tests/integration/api/SetBestAnswerTest.php
+++ b/tests/integration/api/SetBestAnswerTest.php
@@ -59,6 +59,7 @@ public function setUp(): void
],
'group_permission' => [
['group_id' => 4, 'permission' => 'discussion.selectBestAnswerNotOwnDiscussion', 'created_at' => Carbon::now()],
+ ['group_id' => 4, 'permission' => 'discussion.fof-best-answer.allow_select_own_post', 'created_at' => Carbon::now()],
],
'group_user' => [
['user_id' => 4, 'group_id' => 4],
@@ -166,20 +167,36 @@ public function user_without_permission_cannot_set_best_answer(int $userId)
$this->assertEquals(403, $response->getStatusCode());
}
+ public static function unauthorizedUsersOwnPostProvider(): array
+ {
+ return [
+ [2],
+ [3],
+ ];
+ }
+
#[Test]
- public function user_cannot_set_own_post_as_best_answer_if_not_permitted()
+ #[DataProvider('unauthorizedUsersOwnPostProvider')]
+ public function user_cannot_set_own_post_as_best_answer_if_not_permitted(int $userId)
{
- $response = $this->setBestAnswer(3, 5, 2);
+ $response = $this->setBestAnswer($userId, 5, 2);
$this->assertEquals(403, $response->getStatusCode());
}
- #[Test]
- public function user_can_set_own_post_as_best_answer_if_permitted()
+ public static function permittedUsersOwnPostProvider(): array
{
- $this->setting('fof-best-answer.allow_select_own_post', true);
+ return [
+ [1],
+ [4],
+ ];
+ }
- $response = $this->setBestAnswer(3, 5, 2);
+ #[Test]
+ #[DataProvider('permittedUsersOwnPostProvider')]
+ public function user_can_set_own_post_as_best_answer_if_permitted(int $userId)
+ {
+ $response = $this->setBestAnswer($userId, 5, 2);
$this->assertEquals(200, $response->getStatusCode());