diff --git a/extensions/subscriptions/extend.php b/extensions/subscriptions/extend.php index 8bb29b5440..f563b6b81f 100644 --- a/extensions/subscriptions/extend.php +++ b/extensions/subscriptions/extend.php @@ -10,6 +10,7 @@ use Flarum\Api\Resource; use Flarum\Approval\Event\PostWasApproved; use Flarum\Discussion\Event\Saving; +use Flarum\Discussion\Event\Started; use Flarum\Discussion\Search\DiscussionSearcher; use Flarum\Discussion\UserState; use Flarum\Extend; @@ -60,7 +61,8 @@ ->listen(Hidden::class, Listener\DeleteNotificationWhenPostIsHiddenOrDeleted::class) ->listen(Restored::class, Listener\RestoreNotificationWhenPostIsRestored::class) ->listen(Deleted::class, Listener\DeleteNotificationWhenPostIsHiddenOrDeleted::class) - ->listen(Posted::class, Listener\FollowAfterReply::class), + ->listen(Posted::class, Listener\FollowAfterReply::class) + ->listen(Started::class, Listener\FollowAfterCreate::class), (new Extend\SearchDriver(DatabaseSearchDriver::class)) ->addFilter(DiscussionSearcher::class, SubscriptionFilter::class) @@ -68,5 +70,6 @@ (new Extend\User()) ->registerPreference('followAfterReply', 'boolval', false) + ->registerPreference('followAfterCreate', 'boolval', false) ->registerPreference('flarum-subscriptions.notify_for_all_posts', 'boolval', false), ]; diff --git a/extensions/subscriptions/js/src/@types/shims.d.ts b/extensions/subscriptions/js/src/@types/shims.d.ts index 057f872464..c166382259 100644 --- a/extensions/subscriptions/js/src/@types/shims.d.ts +++ b/extensions/subscriptions/js/src/@types/shims.d.ts @@ -1,7 +1,16 @@ import 'flarum/common/models/Discussion'; +import 'flarum/forum/components/SettingsPage'; declare module 'flarum/common/models/Discussion' { export default interface Discussion { subscription(): string; } } + +declare module 'flarum/forum/components/SettingsPage' { + export default interface SettingsPage { + followAfterReplyLoading: boolean; + followAfterCreateLoading: boolean; + notifyForAllPostsLoading: boolean; + } +} diff --git a/extensions/subscriptions/js/src/forum/addSubscriptionSettings.tsx b/extensions/subscriptions/js/src/forum/addSubscriptionSettings.tsx index e5cd93f790..5dc59df832 100644 --- a/extensions/subscriptions/js/src/forum/addSubscriptionSettings.tsx +++ b/extensions/subscriptions/js/src/forum/addSubscriptionSettings.tsx @@ -8,7 +8,7 @@ export default function () { items.add( 'followAfterReply', { this.followAfterReplyLoading = true; @@ -23,6 +23,24 @@ export default function () { ); + items.add( + 'followAfterCreate', + { + this.followAfterCreateLoading = true; + + this.user!.savePreferences({ followAfterCreate: value }).then(() => { + this.followAfterCreateLoading = false; + m.redraw(); + }); + }} + loading={this.followAfterCreateLoading} + > + {app.translator.trans('flarum-subscriptions.forum.settings.follow_after_create_label')} + + ); + items.add( 'notifyForAllPosts', actor; + + if ($actor && $actor->exists && $actor->getPreference('followAfterCreate')) { + $actor->assertRegistered(); + + $state = $event->discussion->stateFor($actor); + + $state->subscription = 'follow'; + $state->save(); + } + } +} diff --git a/extensions/subscriptions/tests/integration/api/discussions/FollowAfterCreateTest.php b/extensions/subscriptions/tests/integration/api/discussions/FollowAfterCreateTest.php new file mode 100644 index 0000000000..f88d7deff0 --- /dev/null +++ b/extensions/subscriptions/tests/integration/api/discussions/FollowAfterCreateTest.php @@ -0,0 +1,89 @@ +extension('flarum-subscriptions'); + + $this->prepareDatabase([ + User::class => [ + $this->normalUser(), + ['id' => 3, 'username' => 'acme_follow', 'email' => 'acme@machine.local', 'is_email_confirmed' => 1, 'preferences' => json_encode(['followAfterCreate' => true])], + ['id' => 4, 'username' => 'acme_no_follow', 'email' => 'acme2@machine.local', 'is_email_confirmed' => 1, 'preferences' => json_encode(['followAfterCreate' => false])], + ], + ]); + } + + #[Test] + public function user_with_preference_true_follows_after_creating_discussion() + { + $this->app(); + + $response = $this->send( + $this->request('POST', '/api/discussions', [ + 'authenticatedAs' => 3, + 'json' => [ + 'data' => [ + 'type' => 'discussions', + 'attributes' => [ + 'title' => 'Test Discussion', + 'content' => 'Test content that needs to be sufficiently long.' + ], + ], + ], + ]) + ); + + $this->assertEquals(201, $response->getStatusCode()); + + $discussionId = json_decode($response->getBody()->getContents(), true)['data']['id']; + + $this->assertEquals('follow', $this->database()->table('discussion_user')->where('discussion_id', $discussionId)->where('user_id', 3)->value('subscription')); + } + + #[Test] + public function user_with_preference_false_does_not_follow_after_creating_discussion() + { + $this->app(); + + $response = $this->send( + $this->request('POST', '/api/discussions', [ + 'authenticatedAs' => 4, + 'json' => [ + 'data' => [ + 'type' => 'discussions', + 'attributes' => [ + 'title' => 'Test Discussion', + 'content' => 'Test content that needs to be sufficiently long.' + ], + ], + ], + ]) + ); + + $this->assertEquals(201, $response->getStatusCode()); + + $discussionId = json_decode($response->getBody()->getContents(), true)['data']['id']; + + $this->assertNull($this->database()->table('discussion_user')->where('discussion_id', $discussionId)->where('user_id', 4)->value('subscription')); + } +} diff --git a/extensions/subscriptions/tests/integration/api/discussions/FollowAfterReplyTest.php b/extensions/subscriptions/tests/integration/api/discussions/FollowAfterReplyTest.php new file mode 100644 index 0000000000..e15902a01c --- /dev/null +++ b/extensions/subscriptions/tests/integration/api/discussions/FollowAfterReplyTest.php @@ -0,0 +1,98 @@ +extension('flarum-subscriptions'); + + $this->prepareDatabase([ + User::class => [ + $this->normalUser(), + ['id' => 3, 'username' => 'acme_follow', 'email' => 'acme@machine.local', 'is_email_confirmed' => 1, 'preferences' => json_encode(['followAfterReply' => true])], + ['id' => 4, 'username' => 'acme_no_follow', 'email' => 'acme2@machine.local', 'is_email_confirmed' => 1, 'preferences' => json_encode(['followAfterReply' => false])], + ], + Discussion::class => [ + ['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1, 'last_post_number' => 1, 'last_post_id' => 1], + ], + Post::class => [ + ['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::createFromDate(1975, 5, 21)->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '

foo bar

', 'number' => 1], + ], + ]); + } + + #[Test] + public function user_with_preference_true_follows_after_replying_to_discussion() + { + $this->app(); + + $response = $this->send( + $this->request('POST', '/api/posts', [ + 'authenticatedAs' => 3, + 'json' => [ + 'data' => [ + 'type' => 'posts', + 'attributes' => [ + 'content' => 'reply with predetermined content for automated testing' + ], + 'relationships' => [ + 'discussion' => ['data' => ['id' => 1]], + ], + ], + ], + ]) + ); + + $this->assertEquals(201, $response->getStatusCode()); + + $this->assertEquals('follow', $this->database()->table('discussion_user')->where('discussion_id', 1)->where('user_id', 3)->value('subscription')); + } + + #[Test] + public function user_with_preference_false_does_not_follow_after_replying_to_discussion() + { + $this->app(); + + $response = $this->send( + $this->request('POST', '/api/posts', [ + 'authenticatedAs' => 4, + 'json' => [ + 'data' => [ + 'type' => 'posts', + 'attributes' => [ + 'content' => 'reply with predetermined content for automated testing' + ], + 'relationships' => [ + 'discussion' => ['data' => ['id' => 1]], + ], + ], + ], + ]) + ); + + $this->assertEquals(201, $response->getStatusCode()); + + $this->assertNull($this->database()->table('discussion_user')->where('discussion_id', 1)->where('user_id', 4)->value('subscription')); + } +}