Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion extensions/subscriptions/extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -60,13 +61,15 @@
->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)
->addMutator(DiscussionSearcher::class, HideIgnoredFromAllDiscussionsPage::class),

(new Extend\User())
->registerPreference('followAfterReply', 'boolval', false)
->registerPreference('followAfterCreate', 'boolval', false)
->registerPreference('flarum-subscriptions.notify_for_all_posts', 'boolval', false),
];
9 changes: 9 additions & 0 deletions extensions/subscriptions/js/src/@types/shims.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ export default function () {
</Switch>
);

items.add(
'followAfterCreate',
<Switch
state={this.user.preferences().followAfterCreate}
onchange={(value) => {
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')}
</Switch>
);

items.add(
'notifyForAllPosts',
<Switch
Expand Down
1 change: 1 addition & 0 deletions extensions/subscriptions/locale/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ flarum-subscriptions:
# These translations are used in the Settings page.
settings:
follow_after_reply_label: Automatically follow discussions that I reply to
follow_after_create_label: Automatically follow discussions that I create
notify_for_all_posts_label: Notify about every new post instead of only the last in a discussion
notify_new_post_label: Someone posts in a discussion I'm following

Expand Down
29 changes: 29 additions & 0 deletions extensions/subscriptions/src/Listener/FollowAfterCreate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/

namespace Flarum\Subscriptions\Listener;

use Flarum\Discussion\Event\Started;

class FollowAfterCreate
{
public function handle(Started $event): void
{
$actor = $event->actor;

if ($actor && $actor->exists && $actor->getPreference('followAfterCreate')) {
$actor->assertRegistered();

$state = $event->discussion->stateFor($actor);

$state->subscription = 'follow';
$state->save();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/

namespace Flarum\Subscriptions\Tests\integration\api\discussions;

use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
use PHPUnit\Framework\Attributes\Test;

class FollowAfterCreateTest extends TestCase
{
use RetrievesAuthorizedUsers;

protected function setUp(): void
{
parent::setUp();

$this->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'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/

namespace Flarum\Subscriptions\Tests\integration\api\discussions;

use Carbon\Carbon;
use Flarum\Discussion\Discussion;
use Flarum\Post\Post;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
use PHPUnit\Framework\Attributes\Test;

class FollowAfterReplyTest extends TestCase
{
use RetrievesAuthorizedUsers;

protected function setUp(): void
{
parent::setUp();

$this->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' => '<t><p>foo bar</p></t>', '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'));
}
}