mirror of
https://github.com/flarum/core.git
synced 2025-07-24 02:01:19 +02:00
Merge pull request #1931 from flarum/dk/1869-queue-notifications
Notifications into the queue
This commit is contained in:
@@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
namespace Flarum\Notification\Blueprint;
|
namespace Flarum\Notification\Blueprint;
|
||||||
|
|
||||||
|
use Flarum\Database\AbstractModel;
|
||||||
|
use Flarum\User\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A notification BlueprintInterface, when instantiated, represents a notification about
|
* A notification BlueprintInterface, when instantiated, represents a notification about
|
||||||
* something. The blueprint is used by the NotificationSyncer to commit the
|
* something. The blueprint is used by the NotificationSyncer to commit the
|
||||||
@@ -19,24 +22,35 @@ interface BlueprintInterface
|
|||||||
/**
|
/**
|
||||||
* Get the user that sent the notification.
|
* Get the user that sent the notification.
|
||||||
*
|
*
|
||||||
* @return \Flarum\User\User|null
|
* @deprecated Will be removed for beta.14
|
||||||
|
* @return User|null
|
||||||
*/
|
*/
|
||||||
public function getFromUser();
|
public function getFromUser();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the model that is the subject of this activity.
|
* Get the model that is the subject of this activity.
|
||||||
*
|
*
|
||||||
* @return \Flarum\Database\AbstractModel|null
|
* @deprecated Will be removed for beta.14
|
||||||
|
* @return AbstractModel|null
|
||||||
*/
|
*/
|
||||||
public function getSubject();
|
public function getSubject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data to be stored in the notification.
|
* Get the data to be stored in the notification.
|
||||||
*
|
*
|
||||||
|
* @deprecated Will be removed for beta.14
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getData();
|
public function getData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attributes that uniquely identify a notification, plus metadata.
|
||||||
|
* TODO: Uncomment this for beta.14.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
//public function getAttributes(): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the serialized type of this activity.
|
* Get the serialized type of this activity.
|
||||||
*
|
*
|
||||||
|
@@ -51,6 +51,19 @@ class DiscussionRenamedBlueprint implements BlueprintInterface
|
|||||||
return ['postNumber' => (int) $this->post->number];
|
return ['postNumber' => (int) $this->post->number];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'type' => static::getType(),
|
||||||
|
'from_user_id' => $this->post->user ? $this->post->user->id : null,
|
||||||
|
'subject_id' => $this->post->discussion ? $this->post->discussion->id : null,
|
||||||
|
'data' => json_encode(['postNumber' => (int) $this->post->number]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
36
framework/core/src/Notification/BlueprintBC.php
Normal file
36
framework/core/src/Notification/BlueprintBC.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?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\Notification;
|
||||||
|
|
||||||
|
use Flarum\Notification\Blueprint\BlueprintInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A backwards compatibility layer for notification blueprints.
|
||||||
|
*
|
||||||
|
* Will be removed for Beta 14 in favor of BlueprintInterface::getAttributes().
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
class BlueprintBC
|
||||||
|
{
|
||||||
|
public static function getAttributes(BlueprintInterface $blueprint): array
|
||||||
|
{
|
||||||
|
if (method_exists($blueprint, 'getAttributes')) {
|
||||||
|
return $blueprint->getAttributes();
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
'type' => $blueprint::getType(),
|
||||||
|
'from_user_id' => ($fromUser = $blueprint->getFromUser()) ? $fromUser->id : null,
|
||||||
|
'subject_id' => ($subject = $blueprint->getSubject()) ? $subject->id : null,
|
||||||
|
'data' => ($data = $blueprint->getData()) ? json_encode($data) : null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -23,7 +23,7 @@ class Sending
|
|||||||
/**
|
/**
|
||||||
* The users that the notification will be sent to.
|
* The users that the notification will be sent to.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array|int[]
|
||||||
*/
|
*/
|
||||||
public $users;
|
public $users;
|
||||||
|
|
||||||
|
@@ -0,0 +1,39 @@
|
|||||||
|
<?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\Notification\Job;
|
||||||
|
|
||||||
|
use Flarum\Notification\MailableInterface;
|
||||||
|
use Flarum\Notification\NotificationMailer;
|
||||||
|
use Flarum\Queue\AbstractJob;
|
||||||
|
use Flarum\User\User;
|
||||||
|
|
||||||
|
class SendEmailNotificationJob extends AbstractJob
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var MailableInterface
|
||||||
|
*/
|
||||||
|
private $blueprint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var User
|
||||||
|
*/
|
||||||
|
private $recipient;
|
||||||
|
|
||||||
|
public function __construct(MailableInterface $blueprint, User $recipient)
|
||||||
|
{
|
||||||
|
$this->blueprint = $blueprint;
|
||||||
|
$this->recipient = $recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(NotificationMailer $mailer)
|
||||||
|
{
|
||||||
|
$mailer->send($this->blueprint, $this->recipient);
|
||||||
|
}
|
||||||
|
}
|
55
framework/core/src/Notification/Job/SendNotificationsJob.php
Normal file
55
framework/core/src/Notification/Job/SendNotificationsJob.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?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\Notification\Job;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Flarum\Notification\Blueprint\BlueprintInterface;
|
||||||
|
use Flarum\Notification\BlueprintBC;
|
||||||
|
use Flarum\Notification\Event\Sending;
|
||||||
|
use Flarum\Notification\Notification;
|
||||||
|
use Flarum\Queue\AbstractJob;
|
||||||
|
use Flarum\User\User;
|
||||||
|
|
||||||
|
class SendNotificationsJob extends AbstractJob
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var BlueprintInterface
|
||||||
|
*/
|
||||||
|
private $blueprint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var User[]
|
||||||
|
*/
|
||||||
|
private $recipients;
|
||||||
|
|
||||||
|
public function __construct(BlueprintInterface $blueprint, array $recipients = [])
|
||||||
|
{
|
||||||
|
$this->blueprint = $blueprint;
|
||||||
|
$this->recipients = $recipients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$now = Carbon::now('utc')->toDateTimeString();
|
||||||
|
|
||||||
|
event(new Sending($this->blueprint, $this->recipients));
|
||||||
|
|
||||||
|
$attributes = BlueprintBC::getAttributes($this->blueprint);
|
||||||
|
|
||||||
|
Notification::insert(
|
||||||
|
array_map(function (User $user) use ($attributes, $now) {
|
||||||
|
return $attributes + [
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'created_at' => $now
|
||||||
|
];
|
||||||
|
}, $this->recipients)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -9,10 +9,11 @@
|
|||||||
|
|
||||||
namespace Flarum\Notification;
|
namespace Flarum\Notification;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Flarum\Notification\Blueprint\BlueprintInterface;
|
use Flarum\Notification\Blueprint\BlueprintInterface;
|
||||||
use Flarum\Notification\Event\Sending;
|
use Flarum\Notification\Job\SendEmailNotificationJob;
|
||||||
|
use Flarum\Notification\Job\SendNotificationsJob;
|
||||||
use Flarum\User\User;
|
use Flarum\User\User;
|
||||||
|
use Illuminate\Contracts\Queue\Queue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Notification Syncer commits notification blueprints to the database, and
|
* The Notification Syncer commits notification blueprints to the database, and
|
||||||
@@ -37,25 +38,13 @@ class NotificationSyncer
|
|||||||
protected static $sentTo = [];
|
protected static $sentTo = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var NotificationRepository
|
* @var Queue
|
||||||
*/
|
*/
|
||||||
protected $notifications;
|
protected $queue;
|
||||||
|
|
||||||
/**
|
public function __construct(Queue $queue)
|
||||||
* @var NotificationMailer
|
{
|
||||||
*/
|
$this->queue = $queue;
|
||||||
protected $mailer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param NotificationRepository $notifications
|
|
||||||
* @param NotificationMailer $mailer
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
NotificationRepository $notifications,
|
|
||||||
NotificationMailer $mailer
|
|
||||||
) {
|
|
||||||
$this->notifications = $notifications;
|
|
||||||
$this->mailer = $mailer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +58,7 @@ class NotificationSyncer
|
|||||||
*/
|
*/
|
||||||
public function sync(Blueprint\BlueprintInterface $blueprint, array $users)
|
public function sync(Blueprint\BlueprintInterface $blueprint, array $users)
|
||||||
{
|
{
|
||||||
$attributes = $this->getAttributes($blueprint);
|
$attributes = BlueprintBC::getAttributes($blueprint);
|
||||||
|
|
||||||
// Find all existing notification records in the database matching this
|
// Find all existing notification records in the database matching this
|
||||||
// blueprint. We will begin by assuming that they all need to be
|
// blueprint. We will begin by assuming that they all need to be
|
||||||
@@ -87,7 +76,7 @@ class NotificationSyncer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$existing = $toDelete->first(function ($notification, $i) use ($user) {
|
$existing = $toDelete->first(function ($notification) use ($user) {
|
||||||
return $notification->user_id === $user->id;
|
return $notification->user_id === $user->id;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -113,9 +102,14 @@ class NotificationSyncer
|
|||||||
|
|
||||||
// Create a notification record, and send an email, for all users
|
// Create a notification record, and send an email, for all users
|
||||||
// receiving this notification for the first time (we know because they
|
// receiving this notification for the first time (we know because they
|
||||||
// didn't have a record in the database).
|
// didn't have a record in the database). As both operations can be
|
||||||
|
// intensive on resources (database and mail server), we queue them.
|
||||||
if (count($newRecipients)) {
|
if (count($newRecipients)) {
|
||||||
$this->sendNotifications($blueprint, $newRecipients);
|
$this->queue->push(new SendNotificationsJob($blueprint, $newRecipients));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($blueprint instanceof MailableInterface) {
|
||||||
|
$this->mailNotifications($blueprint, $newRecipients);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +121,7 @@ class NotificationSyncer
|
|||||||
*/
|
*/
|
||||||
public function delete(BlueprintInterface $blueprint)
|
public function delete(BlueprintInterface $blueprint)
|
||||||
{
|
{
|
||||||
Notification::where($this->getAttributes($blueprint))->update(['is_deleted' => true]);
|
Notification::where(BlueprintBC::getAttributes($blueprint))->update(['is_deleted' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,7 +132,7 @@ class NotificationSyncer
|
|||||||
*/
|
*/
|
||||||
public function restore(BlueprintInterface $blueprint)
|
public function restore(BlueprintInterface $blueprint)
|
||||||
{
|
{
|
||||||
Notification::where($this->getAttributes($blueprint))->update(['is_deleted' => false]);
|
Notification::where(BlueprintBC::getAttributes($blueprint))->update(['is_deleted' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,35 +152,6 @@ class NotificationSyncer
|
|||||||
static::$onePerUser = false;
|
static::$onePerUser = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a notification record and send an email (depending on user
|
|
||||||
* preference) from a blueprint to a list of recipients.
|
|
||||||
*
|
|
||||||
* @param \Flarum\Notification\Blueprint\BlueprintInterface $blueprint
|
|
||||||
* @param User[] $recipients
|
|
||||||
*/
|
|
||||||
protected function sendNotifications(Blueprint\BlueprintInterface $blueprint, array $recipients)
|
|
||||||
{
|
|
||||||
$now = Carbon::now('utc')->toDateTimeString();
|
|
||||||
|
|
||||||
event(new Sending($blueprint, $recipients));
|
|
||||||
|
|
||||||
$attributes = $this->getAttributes($blueprint);
|
|
||||||
|
|
||||||
Notification::insert(
|
|
||||||
array_map(function (User $user) use ($attributes, $now) {
|
|
||||||
return $attributes + [
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'created_at' => $now
|
|
||||||
];
|
|
||||||
}, $recipients)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($blueprint instanceof MailableInterface) {
|
|
||||||
$this->mailNotifications($blueprint, $recipients);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mail a notification to a list of users.
|
* Mail a notification to a list of users.
|
||||||
*
|
*
|
||||||
@@ -197,7 +162,7 @@ class NotificationSyncer
|
|||||||
{
|
{
|
||||||
foreach ($recipients as $user) {
|
foreach ($recipients as $user) {
|
||||||
if ($user->shouldEmail($blueprint::getType())) {
|
if ($user->shouldEmail($blueprint::getType())) {
|
||||||
$this->mailer->send($blueprint, $user);
|
$this->queue->push(new SendEmailNotificationJob($blueprint, $user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,21 +177,4 @@ class NotificationSyncer
|
|||||||
{
|
{
|
||||||
Notification::whereIn('id', $ids)->update(['is_deleted' => $isDeleted]);
|
Notification::whereIn('id', $ids)->update(['is_deleted' => $isDeleted]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct an array of attributes to be stored in a notification record in
|
|
||||||
* the database, given a notification blueprint.
|
|
||||||
*
|
|
||||||
* @param \Flarum\Notification\Blueprint\BlueprintInterface $blueprint
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getAttributes(Blueprint\BlueprintInterface $blueprint)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'type' => $blueprint::getType(),
|
|
||||||
'from_user_id' => ($fromUser = $blueprint->getFromUser()) ? $fromUser->id : null,
|
|
||||||
'subject_id' => ($subject = $blueprint->getSubject()) ? $subject->id : null,
|
|
||||||
'data' => ($data = $blueprint->getData()) ? json_encode($data) : null
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
22
framework/core/src/Queue/AbstractJob.php
Normal file
22
framework/core/src/Queue/AbstractJob.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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\Queue;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class AbstractJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use InteractsWithQueue;
|
||||||
|
use Queueable;
|
||||||
|
use SerializesModels;
|
||||||
|
}
|
Reference in New Issue
Block a user