Newer
Older

Oliver Davies
committed
<?php

Oleksandr Akerman
committed
namespace Drupal\private_message_notify\Service;

Oliver Davies
committed
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;

Oleksandr Akerman
committed
use Drupal\Core\Extension\ModuleHandlerInterface;

Saiyad Zaryab Haider
committed
use Drupal\Core\Logger\LoggerChannelFactoryInterface;

Oliver Davies
committed
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\message_notify\MessageNotifier;

Oliver Davies
committed
use Drupal\private_message\Entity\PrivateMessageInterface;
use Drupal\private_message\Entity\PrivateMessageThreadInterface;

Oleksandr Akerman
committed
use Drupal\private_message\Service\PrivateMessageServiceInterface;
use Drupal\user\UserDataInterface;

Oliver Davies
committed
/**
* A service class for sending notifications of private messages.

Oliver Davies
committed
*/
class PrivateMessageNotifier implements PrivateMessageNotifierInterface {

Oliver Davies
committed
/**
* The private message service.
*
* @var \Drupal\private_message\Service\PrivateMessageServiceInterface
*/
protected $privateMessageService;

Oliver Davies
committed
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;

Oliver Davies
committed
/**
* The user data service.
*
* @var \Drupal\user\UserDataInterface
*/
protected $userData;

Oliver Davies
committed
/**
* The configuration factory service.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**

Oleh Lopukhovych
committed
* The entity type manager.

Oleh Lopukhovych
committed
* @var \Drupal\Core\Entity\EntityTypeManagerInterface

Oleh Lopukhovych
committed
protected $entityTypeManager;
/**
* The message notification service.
*
* @var \Drupal\message_notify\MessageNotifier
*/
protected $messageNotifier;

Oliver Davies
committed
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;

Saiyad Zaryab Haider
committed
/**
* The logger service for private message notifications.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;

Oliver Davies
committed
/**
* Constructs a new PrivateMessageNotifier object.

Oliver Davies
committed
*
* @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
* The private message service.
* @param \Drupal\Core\Session\AccountProxyInterface $currentUser
* The current user.
* @param \Drupal\user\UserDataInterface $userData
* The user data service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* The configuration factory service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager service.
* @param \Drupal\message_notify\MessageNotifier $messageNotifier
* The message notification service.

Oleksandr Akerman
committed
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
* The module handler service.

Saiyad Zaryab Haider
committed
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
* The logger channel factory.

Oliver Davies
committed
*/
public function __construct(
PrivateMessageServiceInterface $privateMessageService,
AccountProxyInterface $currentUser,
UserDataInterface $userData,
ConfigFactoryInterface $configFactory,
EntityTypeManagerInterface $entityTypeManager,

Oleksandr Akerman
committed
MessageNotifier $messageNotifier,
ModuleHandlerInterface $moduleHandler,

Saiyad Zaryab Haider
committed
LoggerChannelFactoryInterface $loggerFactory,

Oliver Davies
committed
) {
$this->privateMessageService = $privateMessageService;
$this->currentUser = $currentUser;
$this->userData = $userData;
$this->config = $configFactory->get('private_message.settings');

Oleh Lopukhovych
committed
$this->entityTypeManager = $entityTypeManager;
$this->messageNotifier = $messageNotifier;

Oleksandr Akerman
committed
$this->moduleHandler = $moduleHandler;

Saiyad Zaryab Haider
committed
$this->logger = $loggerFactory->get('private_message_notify');

Oliver Davies
committed
}
/**
* {@inheritdoc}
*/

Oleksandr Akerman
committed
public function notify(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
$members = $this->getNotificationRecipients($message, $thread);

Oliver Davies
committed
foreach ($members as $member) {

Saiyad Zaryab Haider
committed
// Skip the current user and any member without a valid email.
if ($member->id() == $this->currentUser->id()) {
continue;
}

Saiyad Zaryab Haider
committed
// Assuming getEmail() method exists.
$email = $member->getEmail();
if (empty($email)) {
// Log a warning if the email is missing, then skip this member.
$this->logger->warning('Notification not sent to user ID @uid due to missing email.', ['@uid' => $member->id()]);
continue;

Oliver Davies
committed
}

Saiyad Zaryab Haider
committed
// Check if the notification should be sent.
if (!$this->shouldSend($member, $message, $thread)) {
continue;
}
// Create and send the notification.
$notification = $this->entityTypeManager
->getStorage('message')
->create(
[
'template' => 'private_message_notification',
'uid' => $member->id(),
]
);
$notification->set('field_message_private_message', $message);
$notification->set('field_message_pm_thread', $thread);
$notification->setLanguage($member->getPreferredLangcode());
$notification->save();
$this->messageNotifier->send($notification);

Oliver Davies
committed
}
}
/**
* Determines if the message should be sent.
*
* Checks individual user preferences as well as system defaults.
*
* @param \Drupal\Core\Session\AccountInterface $recipient
* The potential recipient.

Jay Friendly
committed
* @param \Drupal\private_message\Entity\PrivateMessageInterface $message
* The private message for which a notification is being sent.
* @param \Drupal\private_message\Entity\PrivateMessageThreadInterface $thread
* The private message thread.

Oliver Davies
committed
*
* @return bool
* A boolean indicating whether or not the message should be sent.
*/

Jay Friendly
committed
private function shouldSend(AccountInterface $recipient, PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {

Oliver Davies
committed

Jay Friendly
committed
// Don't notify the user by default.
$notify = FALSE;
// Check if notifications have been enabled.
if ($this->config->get('enable_notifications')) {
// Eligibility to receive notifications will be checked.

Jay Friendly
committed
$eligible_to_receive = FALSE;
// Get the user default.
$user_default = $this->userData->get('private_message', $recipient->id(), 'receive_notification');
// Check if the user default is to notify.
if ($user_default) {
$eligible_to_receive = TRUE;
}
// Check if the user has not made any selection, and the system default is
// to send:
elseif (is_null($user_default) && $this->config->get('notify_by_default')) {
$eligible_to_receive = TRUE;
}
// If the user is eligible to receive notification, user and system

Jay Friendly
committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// settings are used to determine whether or not the notification should
// be sent.
if ($eligible_to_receive) {
// Determine whether a user should always be notified of every message,
// or if they should only be notified when they aren't viewing a thread.
$notify_when_using = $this->userData->get('private_message', $recipient->id(), 'notify_when_using');
// Check if the user has not yet set a value.
if (is_null($notify_when_using)) {
// The user has not yet set a value, so use the system default.
$notify_when_using = $this->config->get('notify_when_using');
}
// Get the number of seconds a user has set in their profile, after
// which they should be considered 'away' from the thread.
$away_time = $this->userData->get('private_message', $recipient->id(), 'number_of_seconds_considered_away');
// Check if the user has not yet set a value.
if (is_null($away_time)) {
// The user has not yet set a value, so use the system default.
$away_time = $this->config->get('number_of_seconds_considered_away');
}
// Check if users should always be notified.
if ($notify_when_using == 'yes') {
$notify = TRUE;
}
// Check if users have been away for long enough to be considered away:
elseif (($message->getCreatedTime() - $thread->getLastAccessTimestamp($recipient)) > $away_time) {
$notify = TRUE;
}
}
}
return $notify;

Oliver Davies
committed
}

Oleksandr Akerman
committed
/**
* The users to receive notifications.
*
* @return \Drupal\Core\Session\AccountInterface[]
* An array of Account objects of the thread members who are to receive
* the notification.
*/
public function getNotificationRecipients(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
$recipients = $thread->getMembers();
$exclude = [];
// Allow other modules to alter notification recipients.
$this->moduleHandler->invokeAll(
'private_message_notify_exclude', [
$message,
$thread,
&$exclude,

Oleksandr Akerman
committed
]
);
// @phpstan-ignore-next-line

Oleksandr Akerman
committed
if (empty($exclude)) {
return $recipients;
}
return array_filter(
$recipients, static function (AccountInterface $account) use ($exclude) {
// If this user is in the excluded list, filter them from the recipients
// list, so they do not receive the notification.
return !in_array($account->id(), $exclude);
}
);

Oleksandr Akerman
committed
}