From 927ea4eec5c7154174307aac5b6baedb40bd1d43 Mon Sep 17 00:00:00 2001 From: Sami Mazouz Date: Tue, 19 Jan 2021 20:40:19 +0100 Subject: [PATCH] Add Notification extender beforeSending method (#2533) --- src/Extend/Notification.php | 18 +++++++ src/Notification/NotificationSyncer.php | 17 ++++++ .../extenders/NotificationTest.php | 52 +++++++++++++++++-- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/Extend/Notification.php b/src/Extend/Notification.php index fd0f59a1b..1a6a9cbfa 100644 --- a/src/Extend/Notification.php +++ b/src/Extend/Notification.php @@ -10,6 +10,8 @@ namespace Flarum\Extend; use Flarum\Extension\Extension; +use Flarum\Foundation\ContainerUtil; +use Flarum\Notification\NotificationSyncer; use Illuminate\Contracts\Container\Container; class Notification implements ExtenderInterface @@ -18,6 +20,7 @@ class Notification implements ExtenderInterface private $serializers = []; private $drivers = []; private $typesEnabledByDefault = []; + private $beforeSendingCallbacks = []; /** * @param string $blueprint The ::class attribute of the blueprint class. @@ -51,6 +54,17 @@ class Notification implements ExtenderInterface return $this; } + /** + * @param callable|string $callback + * @return self + */ + public function beforeSending($callback) + { + $this->beforeSendingCallbacks[] = $callback; + + return $this; + } + public function extend(Container $container, Extension $extension = null) { $container->extend('flarum.notification.blueprints', function ($existingBlueprints) { @@ -74,5 +88,9 @@ class Notification implements ExtenderInterface $container->extend('flarum.notification.drivers', function ($existingDrivers) { return array_merge($existingDrivers, $this->drivers); }); + + foreach ($this->beforeSendingCallbacks as $callback) { + NotificationSyncer::beforeSending(ContainerUtil::wrapCallback($callback, $container)); + } } } diff --git a/src/Notification/NotificationSyncer.php b/src/Notification/NotificationSyncer.php index b6c40ead2..7e7a5c4ff 100644 --- a/src/Notification/NotificationSyncer.php +++ b/src/Notification/NotificationSyncer.php @@ -43,6 +43,11 @@ class NotificationSyncer */ protected static $notificationDrivers = []; + /** + * @var array + */ + protected static $beforeSendingCallbacks = []; + /** * Sync a notification so that it is visible to the specified users, and not * visible to anyone else. If it is being made visible for the first time, @@ -94,6 +99,10 @@ class NotificationSyncer $this->setDeleted($toUndelete, false); } + foreach (static::$beforeSendingCallbacks as $callback) { + $newRecipients = $callback($blueprint, $newRecipients); + } + // Create a notification record, and send an email, for all users // receiving this notification for the first time (we know because they // didn't have a record in the database). As both operations can be @@ -176,4 +185,12 @@ class NotificationSyncer { return static::$notificationDrivers; } + + /** + * @param callable|string $callback + */ + public static function beforeSending($callback): void + { + static::$beforeSendingCallbacks[] = $callback; + } } diff --git a/tests/integration/extenders/NotificationTest.php b/tests/integration/extenders/NotificationTest.php index 2fd8ad46f..5f3aea281 100644 --- a/tests/integration/extenders/NotificationTest.php +++ b/tests/integration/extenders/NotificationTest.php @@ -14,10 +14,14 @@ use Flarum\Notification\Blueprint\BlueprintInterface; use Flarum\Notification\Driver\NotificationDriverInterface; use Flarum\Notification\Notification; use Flarum\Notification\NotificationSyncer; +use Flarum\Tests\integration\RetrievesAuthorizedUsers; use Flarum\Tests\integration\TestCase; +use Flarum\User\User; class NotificationTest extends TestCase { + use RetrievesAuthorizedUsers; + /** * @test */ @@ -119,23 +123,61 @@ class NotificationTest extends TestCase $this->assertContains('secondCustomDriver', $blueprints[SecondCustomNotificationType::class]); $this->assertEmpty($blueprints[ThirdCustomNotificationType::class]); } + + /** + * @test + */ + public function notification_before_sending_callback_works_if_added() + { + $this->extend( + (new Extend\Notification) + ->type(CustomNotificationType::class, 'customNotificationTypeSerializer') + ->driver('customNotificationDriver', CustomNotificationDriver::class) + ->beforeSending(function ($blueprint, $users) { + if ($blueprint instanceof CustomNotificationType) { + unset($users[1]); + } + + return $users; + }) + ); + + $this->prepareDatabase([ + 'users' => [ + $this->adminUser(), + $this->normalUser(), + ['id' => 3, 'username' => 'hani'] + ], + ]); + + $this->app(); + + $users = User::whereIn('id', [1, 2, 3])->get()->all(); + + $notificationSyncer = $this->app()->getContainer()->make(NotificationSyncer::class); + $notificationSyncer->sync(new CustomNotificationType(), $users); + + $this->assertEquals('potato', $users[0]->username); + $this->assertEquals('normal', $users[1]->username); + $this->assertEquals('potato', $users[2]->username); + } } class CustomNotificationType implements BlueprintInterface { public function getFromUser() { - // ... + return null; } public function getSubject() { - // ... + return null; } public function getData() { - // ... + return []; } public static function getType() @@ -169,7 +211,9 @@ class CustomNotificationDriver implements NotificationDriverInterface { public function send(BlueprintInterface $blueprint, array $users): void { - // ... + foreach ($users as $user) { + $user->username = 'potato'; + } } public function registerType(string $blueprintClass, array $driversEnabledByDefault): void