mirror of
https://github.com/flarum/core.git
synced 2025-10-18 18:26:07 +02:00
Massive refactor
- Use contextual namespaces within Flarum\Core - Clean up and docblock everything - Refactor Activity/Notification blueprint stuff - Refactor Formatter stuff - Refactor Search stuff - Upgrade to JSON-API 1.0 - Removed “addedPosts” and “removedPosts” relationships from discussion API. This was used for adding/removing event posts after renaming a discussion etc. Instead we should make an additional request to get all new posts Todo: - Fix Extenders and extensions - Get rid of repository interfaces - Fix other bugs I’ve inevitably introduced
This commit is contained in:
@@ -1,42 +1,33 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
interface NotificationInterface
|
||||
/**
|
||||
* A notification Blueprint, when instantiated, represents a notification about
|
||||
* something. The blueprint is used by the NotificationSyncer to commit the
|
||||
* notification to the database.
|
||||
*/
|
||||
interface Blueprint
|
||||
{
|
||||
/**
|
||||
* Get the model that is the subject of this activity.
|
||||
*
|
||||
* @return \Flarum\Core\Models\Model
|
||||
*/
|
||||
public function getSubject();
|
||||
|
||||
/**
|
||||
* Get the user that sent the notification.
|
||||
*
|
||||
* @return \Flarum\Core\Models\User|null
|
||||
* @return \Flarum\Core\Users\User|null
|
||||
*/
|
||||
public function getSender();
|
||||
|
||||
/**
|
||||
* Get the model that is the subject of this activity.
|
||||
*
|
||||
* @return \Flarum\Core\Model|null
|
||||
*/
|
||||
public function getSubject();
|
||||
|
||||
/**
|
||||
* Get the data to be stored in the notification.
|
||||
*
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
public function getData();
|
||||
|
||||
/**
|
||||
* Get the name of the view to construct a notification email with.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailView();
|
||||
|
||||
/**
|
||||
* Get the subject line for a notification email.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailSubject();
|
||||
|
||||
/**
|
||||
* Get the serialized type of this activity.
|
||||
*
|
||||
@@ -50,11 +41,4 @@ interface NotificationInterface
|
||||
* @return string
|
||||
*/
|
||||
public static function getSubjectModel();
|
||||
|
||||
/**
|
||||
* Whether or not the notification is able to be sent as an email.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isEmailable();
|
||||
}
|
30
src/Core/Notifications/Commands/ReadNotification.php
Normal file
30
src/Core/Notifications/Commands/ReadNotification.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php namespace Flarum\Core\Notifications\Commands;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
|
||||
class ReadNotification
|
||||
{
|
||||
/**
|
||||
* The ID of the notification to mark as read.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $notificationId;
|
||||
|
||||
/**
|
||||
* The user performing the action.
|
||||
*
|
||||
* @var User
|
||||
*/
|
||||
public $actor;
|
||||
|
||||
/**
|
||||
* @param int $notificationId The ID of the notification to mark as read.
|
||||
* @param User $actor The user performing the action.
|
||||
*/
|
||||
public function __construct($notificationId, User $actor)
|
||||
{
|
||||
$this->notificationId = $notificationId;
|
||||
$this->actor = $actor;
|
||||
}
|
||||
}
|
33
src/Core/Notifications/Commands/ReadNotificationHandler.php
Normal file
33
src/Core/Notifications/Commands/ReadNotificationHandler.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php namespace Flarum\Core\Notifications\Commands;
|
||||
|
||||
use Flarum\Core\Notifications\Notification;
|
||||
use Flarum\Core\Exceptions\PermissionDeniedException;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
|
||||
class ReadNotificationHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
|
||||
/**
|
||||
* @param ReadNotification $command
|
||||
* @return Notification
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
*/
|
||||
public function handle(ReadNotification $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
if ($actor->isGuest()) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
|
||||
$notification = Notification::where('user_id', $actor->id)->findOrFail($command->notificationId);
|
||||
|
||||
$notification->read();
|
||||
$notification->save();
|
||||
|
||||
$this->dispatchEventsFor($notification);
|
||||
|
||||
return $notification;
|
||||
}
|
||||
}
|
@@ -1,36 +1,57 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
use Flarum\Core\Models\DiscussionRenamedPost;
|
||||
use Flarum\Core\Posts\DiscussionRenamedPost;
|
||||
|
||||
class DiscussionRenamedNotification extends NotificationAbstract
|
||||
class DiscussionRenamedBlueprint implements Blueprint
|
||||
{
|
||||
/**
|
||||
* @var DiscussionRenamedPost
|
||||
*/
|
||||
protected $post;
|
||||
|
||||
/**
|
||||
* @param DiscussionRenamedPost $post
|
||||
*/
|
||||
public function __construct(DiscussionRenamedPost $post)
|
||||
{
|
||||
$this->post = $post;
|
||||
}
|
||||
|
||||
public function getSubject()
|
||||
{
|
||||
return $this->post->discussion;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSender()
|
||||
{
|
||||
return $this->post->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSubject()
|
||||
{
|
||||
return $this->post->discussion;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return ['postNumber' => (int) $this->post->number];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getType()
|
||||
{
|
||||
return 'discussionRenamed';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubjectModel()
|
||||
{
|
||||
return 'Flarum\Core\Models\Discussion';
|
31
src/Core/Notifications/EloquentNotificationRepository.php
Normal file
31
src/Core/Notifications/EloquentNotificationRepository.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
|
||||
class EloquentNotificationRepository implements NotificationRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function findByUser(User $user, $limit = null, $offset = 0)
|
||||
{
|
||||
$primaries = Notification::select(
|
||||
app('flarum.db')->raw('MAX(id) AS id'),
|
||||
app('flarum.db')->raw('SUM(is_read = 0) AS unread_count')
|
||||
)
|
||||
->where('user_id', $user->id)
|
||||
->whereIn('type', $user->getAlertableNotificationTypes())
|
||||
->where('is_deleted', false)
|
||||
->groupBy('type', 'subject_id')
|
||||
->latest('time')
|
||||
->skip($offset)
|
||||
->take($limit);
|
||||
|
||||
return Notification::with('subject')
|
||||
->select('notifications.*', 'p.unread_count')
|
||||
->mergeBindings($primaries->getQuery())
|
||||
->join(app('flarum.db')->raw('('.$primaries->toSql().') p'), 'notifications.id', '=', 'p.id')
|
||||
->latest('time')
|
||||
->get();
|
||||
}
|
||||
}
|
30
src/Core/Notifications/Events/NotificationWillBeSent.php
Normal file
30
src/Core/Notifications/Events/NotificationWillBeSent.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php namespace Flarum\Core\Notifications\Events;
|
||||
|
||||
use Flarum\Core\Notifications\Blueprint;
|
||||
|
||||
class NotificationWillBeSent
|
||||
{
|
||||
/**
|
||||
* The blueprint for the notification.
|
||||
*
|
||||
* @var Blueprint
|
||||
*/
|
||||
public $blueprint;
|
||||
|
||||
/**
|
||||
* The users that the notification will be sent to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $users;
|
||||
|
||||
/**
|
||||
* @param Blueprint $blueprint
|
||||
* @param \Flarum\Core\Users\User[] $users
|
||||
*/
|
||||
public function __construct(Blueprint $blueprint, array &$users)
|
||||
{
|
||||
$this->blueprint = $blueprint;
|
||||
$this->users = $users;
|
||||
}
|
||||
}
|
56
src/Core/Notifications/Listeners/DiscussionRenamedNotifier.php
Executable file
56
src/Core/Notifications/Listeners/DiscussionRenamedNotifier.php
Executable file
@@ -0,0 +1,56 @@
|
||||
<?php namespace Flarum\Core\Notifications\Listeners;
|
||||
|
||||
use Flarum\Core\Discussions\Events\DiscussionWasRenamed;
|
||||
use Flarum\Core\Posts\DiscussionRenamedPost;
|
||||
use Flarum\Core\Notifications\DiscussionRenamedBlueprint;
|
||||
use Flarum\Core\Notifications\NotificationSyncer;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DiscussionRenamedNotifier
|
||||
{
|
||||
/**
|
||||
* @var NotificationSyncer
|
||||
*/
|
||||
protected $notifications;
|
||||
|
||||
/**
|
||||
* @param NotificationSyncer $notifications
|
||||
*/
|
||||
public function __construct(NotificationSyncer $notifications)
|
||||
{
|
||||
$this->notifications = $notifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
*/
|
||||
public function subscribe(Dispatcher $events)
|
||||
{
|
||||
$events->listen(DiscussionWasRenamed::class, __CLASS__.'@whenDiscussionWasRenamed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DiscussionWasRenamed $event
|
||||
*/
|
||||
public function whenDiscussionWasRenamed(DiscussionWasRenamed $event)
|
||||
{
|
||||
$post = DiscussionRenamedPost::reply(
|
||||
$event->discussion->id,
|
||||
$event->actor->id,
|
||||
$event->oldTitle,
|
||||
$event->discussion->title
|
||||
);
|
||||
|
||||
$post = $event->discussion->mergePost($post);
|
||||
|
||||
if ($event->discussion->start_user_id !== $event->actor->id) {
|
||||
$blueprint = new DiscussionRenamedBlueprint($post);
|
||||
|
||||
if ($post->exists) {
|
||||
$this->notifications->sync($blueprint, [$event->discussion->startUser]);
|
||||
} else {
|
||||
$this->notifications->delete($blueprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
src/Core/Notifications/MailableBlueprint.php
Normal file
18
src/Core/Notifications/MailableBlueprint.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
interface MailableBlueprint
|
||||
{
|
||||
/**
|
||||
* Get the name of the view to construct a notification email with.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailView();
|
||||
|
||||
/**
|
||||
* Get the subject line for a notification email.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailSubject();
|
||||
}
|
137
src/Core/Notifications/Notification.php
Normal file
137
src/Core/Notifications/Notification.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
|
||||
/**
|
||||
* Models a notification record in the database.
|
||||
*
|
||||
* A notification record is associated with a user, and shows up in their
|
||||
* notification list. A notification indicates that something has happened that
|
||||
* the user should know about, like if a user's discussion was renamed by
|
||||
* someone else.
|
||||
*
|
||||
* Each notification record has a *type*. The type determines how the record
|
||||
* looks in the notifications list, and what *subject* is associated with it.
|
||||
* For example, the 'discussionRenamed' notification type represents that
|
||||
* someone renamed a user's discussion. Its subject is a discussion, of which
|
||||
* the ID is stored in the `subject_id` column.
|
||||
*/
|
||||
class Notification extends Model
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $table = 'notifications';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $dateAttributes = ['time'];
|
||||
|
||||
/**
|
||||
* A map of notification types and the model classes to use for their
|
||||
* subjects. For example, the 'discussionRenamed' notification type, which
|
||||
* represents that a user's discussion was renamed, has the subject model
|
||||
* class 'Flarum\Core\Discussions\Discussion'.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $subjectModels = [];
|
||||
|
||||
/**
|
||||
* Mark a notification as read.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
$this->is_read = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When getting the data attribute, unserialize the JSON stored in the
|
||||
* database into a plain array.
|
||||
*
|
||||
* @param string $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDataAttribute($value)
|
||||
{
|
||||
return json_decode($value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* When setting the data attribute, serialize it into JSON for storage in
|
||||
* the database.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setDataAttribute($value)
|
||||
{
|
||||
$this->attributes['data'] = json_encode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subject model for this notification record by looking up its
|
||||
* type in our subject model map.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSubjectModelAttribute()
|
||||
{
|
||||
return array_get(static::$subjectModels, $this->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the relationship with the notification's recipient.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the relationship with the notification's sender.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function sender()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'sender_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the relationship with the notification's subject.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
|
||||
*/
|
||||
public function subject()
|
||||
{
|
||||
return $this->morphTo('subject', 'subjectModel', 'subject_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type-to-subject-model map.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSubjectModels()
|
||||
{
|
||||
return static::$subjectModels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subject model for the given notification type.
|
||||
*
|
||||
* @param string $type The notification type.
|
||||
* @param string $subjectModel The class name of the subject model for that
|
||||
* type.
|
||||
* @return void
|
||||
*/
|
||||
public static function setSubjectModel($type, $subjectModel)
|
||||
{
|
||||
static::$subjectModels[$type] = $subjectModel;
|
||||
}
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
abstract class NotificationAbstract implements NotificationInterface
|
||||
{
|
||||
/**
|
||||
* Get the user that sent the notification.
|
||||
*
|
||||
* @return \Flarum\Core\Models\User|null
|
||||
*/
|
||||
public function getSender()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data to be stored in the notification.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the view to construct a notification email with.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailView()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subject line for a notification email.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailSubject()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the notification is able to be sent as an email.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isEmailable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -1,25 +1,36 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
use Flarum\Core\Models\User;
|
||||
use Flarum\Core\Models\Forum;
|
||||
use Flarum\Core\Users\User;
|
||||
use Illuminate\Contracts\Mail\Mailer;
|
||||
use Illuminate\Mail\Message;
|
||||
|
||||
class NotificationMailer
|
||||
{
|
||||
public function __construct(Mailer $mailer, Forum $forum)
|
||||
/**
|
||||
* @var Mailer
|
||||
*/
|
||||
protected $mailer;
|
||||
|
||||
/**
|
||||
* @param Mailer $mailer
|
||||
*/
|
||||
public function __construct(Mailer $mailer)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->forum = $forum;
|
||||
}
|
||||
|
||||
public function send(NotificationInterface $notification, User $user)
|
||||
/**
|
||||
* @param MailableBlueprint $blueprint
|
||||
* @param User $user
|
||||
*/
|
||||
public function send(MailableBlueprint $blueprint, User $user)
|
||||
{
|
||||
$this->mailer->send(
|
||||
$notification->getEmailView(),
|
||||
$blueprint->getEmailView(),
|
||||
compact('notification', 'user'),
|
||||
function ($message) use ($notification, $user) {
|
||||
function (Message $message) use ($blueprint, $user) {
|
||||
$message->to($user->email, $user->username)
|
||||
->subject($notification->getEmailSubject());
|
||||
->subject($blueprint->getEmailSubject());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
16
src/Core/Notifications/NotificationRepositoryInterface.php
Normal file
16
src/Core/Notifications/NotificationRepositoryInterface.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
|
||||
interface NotificationRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Find a user's notifications.
|
||||
*
|
||||
* @param User $user
|
||||
* @param int|null $count
|
||||
* @param int $start
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function findByUser(User $user, $count = null, $start = 0);
|
||||
}
|
@@ -1,23 +1,49 @@
|
||||
<?php namespace Flarum\Core\Notifications;
|
||||
|
||||
use Flarum\Core\Repositories\NotificationRepositoryInterface;
|
||||
use Flarum\Core\Models\Notification;
|
||||
use Flarum\Core\Events\NotificationWillBeSent;
|
||||
use Flarum\Core\Notifications\Events\NotificationWillBeSent;
|
||||
use Flarum\Core\Users\User;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* The Notification Syncer commits notification blueprints to the database, and
|
||||
* sends them via email depending on user preference. Where a blueprint
|
||||
* represents a single notification, the syncer associates it with a particular
|
||||
* user(s) and makes it available in their inbox.
|
||||
*/
|
||||
class NotificationSyncer
|
||||
{
|
||||
/**
|
||||
* Whether or not notifications are being limited to one per user.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $onePerUser = false;
|
||||
|
||||
/**
|
||||
* An internal list of user IDs that notifications have been sent to.
|
||||
*
|
||||
* @var int[]
|
||||
*/
|
||||
protected $sentTo = [];
|
||||
|
||||
/**
|
||||
* @var NotificationRepositoryInterface
|
||||
*/
|
||||
protected $notifications;
|
||||
|
||||
/**
|
||||
* @var NotificationMailer
|
||||
*/
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(NotificationRepositoryInterface $notifications, NotificationMailer $mailer)
|
||||
{
|
||||
/**
|
||||
* @param NotificationRepositoryInterface $notifications
|
||||
* @param NotificationMailer $mailer
|
||||
*/
|
||||
public function __construct(
|
||||
NotificationRepositoryInterface $notifications,
|
||||
NotificationMailer $mailer
|
||||
) {
|
||||
$this->notifications = $notifications;
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
@@ -27,68 +53,88 @@ class NotificationSyncer
|
||||
* visible to anyone else. If it is being made visible for the first time,
|
||||
* attempt to send the user an email.
|
||||
*
|
||||
* @param \Flarum\Core\Notifications\NotificationInterface $notification
|
||||
* @param \Flarum\Core\Models\User[] $users
|
||||
* @param Blueprint $blueprint
|
||||
* @param User[] $users
|
||||
* @return void
|
||||
*/
|
||||
public function sync(NotificationInterface $notification, array $users)
|
||||
public function sync(Blueprint $blueprint, array $users)
|
||||
{
|
||||
$attributes = $this->getAttributes($notification);
|
||||
$attributes = $this->getAttributes($blueprint);
|
||||
|
||||
// Find all existing notification records in the database matching this
|
||||
// blueprint. We will begin by assuming that they all need to be
|
||||
// deleted in order to match the provided list of users.
|
||||
$toDelete = Notification::where($attributes)->get();
|
||||
$toUndelete = [];
|
||||
$newRecipients = [];
|
||||
|
||||
// For each of the provided users, check to see if they already have
|
||||
// a notification record in the database. If they do, we will make sure
|
||||
// it isn't marked as deleted. If they don't, we will want to create a
|
||||
// new record for them.
|
||||
foreach ($users as $user) {
|
||||
$existing = $toDelete->where('user_id', $user->id)->first();
|
||||
$existing = $toDelete->first(function ($i, $notification) use ($user) {
|
||||
return $notification->user_id === $user->id;
|
||||
});
|
||||
|
||||
if (($k = $toDelete->search($existing)) !== false) {
|
||||
if ($existing) {
|
||||
$toUndelete[] = $existing->id;
|
||||
$toDelete->pull($k);
|
||||
$toDelete->forget($toDelete->search($existing));
|
||||
} elseif (! $this->onePerUser || ! in_array($user->id, $this->sentTo)) {
|
||||
$newRecipients[] = $user;
|
||||
$this->sentTo[] = $user->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all of the remaining notification records which weren't
|
||||
// removed from this collection by the above loop. Un-delete the
|
||||
// existing records that we want to keep.
|
||||
if (count($toDelete)) {
|
||||
Notification::whereIn('id', $toDelete->lists('id'))->update(['is_deleted' => true]);
|
||||
$this->setDeleted($toDelete->lists('id'), true);
|
||||
}
|
||||
|
||||
if (count($toUndelete)) {
|
||||
Notification::whereIn('id', $toUndelete)->update(['is_deleted' => false]);
|
||||
$this->setDeleted($toUndelete, false);
|
||||
}
|
||||
|
||||
// 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).
|
||||
if (count($newRecipients)) {
|
||||
$now = Carbon::now('utc')->toDateTimeString();
|
||||
|
||||
event(new NotificationWillBeSent($notification, $newRecipients));
|
||||
|
||||
Notification::insert(
|
||||
array_map(function ($user) use ($attributes, $notification, $now) {
|
||||
return $attributes + ['user_id' => $user->id, 'time' => $now];
|
||||
}, $newRecipients)
|
||||
);
|
||||
|
||||
foreach ($newRecipients as $user) {
|
||||
if ($user->shouldEmail($notification::getType())) {
|
||||
$this->mailer->send($notification, $user);
|
||||
}
|
||||
}
|
||||
$this->sendNotifications($blueprint, $newRecipients);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(NotificationInterface $notification)
|
||||
/**
|
||||
* Delete a notification for all users.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Blueprint $blueprint)
|
||||
{
|
||||
Notification::where($this->getAttributes($notification))->update(['is_deleted' => true]);
|
||||
Notification::where($this->getAttributes($blueprint))->update(['is_deleted' => true]);
|
||||
}
|
||||
|
||||
public function restore(NotificationInterface $notification)
|
||||
/**
|
||||
* Restore a notification for all users.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @return void
|
||||
*/
|
||||
public function restore(Blueprint $blueprint)
|
||||
{
|
||||
Notification::where($this->getAttributes($notification))->update(['is_deleted' => false]);
|
||||
Notification::where($this->getAttributes($blueprint))->update(['is_deleted' => false]);
|
||||
}
|
||||
|
||||
public function onePerUser(Closure $callback)
|
||||
/**
|
||||
* Limit notifications to one per user for the entire duration of the given
|
||||
* callback.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return void
|
||||
*/
|
||||
public function onePerUser(callable $callback)
|
||||
{
|
||||
$this->sentTo = [];
|
||||
$this->onePerUser = true;
|
||||
@@ -98,13 +144,75 @@ class NotificationSyncer
|
||||
$this->onePerUser = false;
|
||||
}
|
||||
|
||||
protected function getAttributes(NotificationInterface $notification)
|
||||
/**
|
||||
* Create a notification record and send an email (depending on user
|
||||
* preference) from a blueprint to a list of recipients.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @param User[] $recipients
|
||||
*/
|
||||
protected function sendNotifications(Blueprint $blueprint, array $recipients)
|
||||
{
|
||||
$now = Carbon::now('utc')->toDateTimeString();
|
||||
|
||||
event(new NotificationWillBeSent($blueprint, $recipients));
|
||||
|
||||
$attributes = $this->getAttributes($blueprint);
|
||||
|
||||
Notification::insert(
|
||||
array_map(function (User $user) use ($attributes, $now) {
|
||||
return $attributes + [
|
||||
'user_id' => $user->id,
|
||||
'time' => $now
|
||||
];
|
||||
}, $recipients)
|
||||
);
|
||||
|
||||
if ($blueprint instanceof MailableBlueprint) {
|
||||
$this->mailNotifications($blueprint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mail a notification to a list of users.
|
||||
*
|
||||
* @param MailableBlueprint $blueprint
|
||||
* @param User[] $recipients
|
||||
*/
|
||||
protected function mailNotifications(MailableBlueprint $blueprint, array $recipients)
|
||||
{
|
||||
foreach ($recipients as $user) {
|
||||
if ($user->shouldEmail($blueprint::getType())) {
|
||||
$this->mailer->send($blueprint, $user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the deleted status of a list of notification records.
|
||||
*
|
||||
* @param int[] $ids
|
||||
* @param bool $isDeleted
|
||||
*/
|
||||
protected function setDeleted(array $ids, $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 Blueprint $blueprint
|
||||
* @return array
|
||||
*/
|
||||
protected function getAttributes(Blueprint $blueprint)
|
||||
{
|
||||
return [
|
||||
'type' => $notification::getType(),
|
||||
'sender_id' => $notification->getSender()->id,
|
||||
'subject_id' => $notification->getSubject()->id,
|
||||
'data' => ($data = $notification->getData()) ? json_encode($data) : null
|
||||
'type' => $blueprint::getType(),
|
||||
'sender_id' => ($sender = $blueprint->getSender()) ? $sender->id : null,
|
||||
'subject_id' => ($subject = $blueprint->getSubject()) ? $subject->id : null,
|
||||
'data' => ($data = $blueprint->getData()) ? json_encode($data) : null
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -13,19 +13,24 @@ class NotificationsServiceProvider extends ServiceProvider
|
||||
public function boot()
|
||||
{
|
||||
$this->extend([
|
||||
(new Extend\EventSubscriber('Flarum\Core\Handlers\Events\DiscussionRenamedNotifier')),
|
||||
(new Extend\EventSubscriber('Flarum\Core\Notifications\Listeners\DiscussionRenamedNotifier')),
|
||||
|
||||
(new Extend\NotificationType('Flarum\Core\Notifications\DiscussionRenamedNotification'))
|
||||
(new Extend\NotificationType('Flarum\Core\Notifications\DiscussionRenamedBlueprint'))
|
||||
->subjectSerializer('Flarum\Api\Serializers\DiscussionBasicSerializer')
|
||||
->enableByDefault('alert')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->bind(
|
||||
'Flarum\Core\Repositories\NotificationRepositoryInterface',
|
||||
'Flarum\Core\Repositories\EloquentNotificationRepository'
|
||||
'Flarum\Core\Notifications\NotificationRepositoryInterface',
|
||||
'Flarum\Core\Notifications\EloquentNotificationRepository'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user