Current File : /home/pacjaorg/www/nsa/administrator/components/com_akeebabackup/src/Helper/PushMessages.php |
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace Akeeba\Component\AkeebaBackup\Administrator\Helper;
use Akeeba\Component\AkeebaBackup\Administrator\Model\PushModel;
use Akeeba\Engine\Platform;
use Akeeba\WebPush\NotificationOptions;
use Akeeba\WebPush\WebPush\MessageSentReport;
use Akeeba\WebPush\WebPush\WebPush;
use Joomla\CMS\Factory;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseDriver;
/**
* A replacement push notifications helper for the Akeeba Engine. This one is Web Push API aware.
*
* @since 9.3.1
*/
class PushMessages
{
/**
* @since 9.3.1
* @var \Joomla\CMS\MVC\Factory\MVCFactoryInterface
*/
public static $mvcFactory;
/**
* User IDs who have Web Push enabled
*
* @since 9.3.1
* @var array|null
*/
private static $webPushUsers = null;
/**
* The classic push messages handler
*
* @since 9.3.1
* @var \Akeeba\Engine\Util\PushMessages|null
*/
private $corePush = null;
private $hasWebPush = false;
/**
* Public constructor.
*
* Decides which push method to use.
*
* @since 9.3.1
*/
public function __construct()
{
$pushPreference = Platform::getInstance()->get_platform_configuration_option('push_preference', '0');
$this->hasWebPush = class_exists(WebPush::class);
/**
* Fall back to the classic push handler if we're not using Web Push or if the integration is not available.
*/
if (!$this->hasWebPush || $pushPreference !== 'webpush')
{
$this->corePush = new \Akeeba\Engine\Util\PushMessages();
}
}
/**
* Sends a push message, containing a URL/URI, to all connected devices. The URL will be rendered as something
* clickable on most devices.
*
* @param string $url The URL/URI
* @param string $subject The subject of the message, shown in the lock screen. Keep it short.
* @param string $details Long(er) description of what the message is about. Plain text (no HTML).
*
* @return void
* @since 9.3.1
*/
public function link($url, $subject, $details = null)
{
if (is_object($this->corePush))
{
$this->corePush->link($url, $subject, $details);
return;
}
if (!$this->hasWebPush)
{
return;
}
$details = $details ?? '';
$details .= empty($details) ? '' : ' ';
$this->message($subject, $details . $url);
}
/**
* Sends a push message to all connected devices. The intent is to provide the user with an information message,
* e.g. notify them about the progress of the backup.
*
* @param string $subject The subject of the message, shown in the lock screen. Keep it short.
* @param string $details Long(er) description of what the message is about. Plain text (no HTML).
*
* @return void
* @since 9.3.1
*/
public function message($subject, $details = null)
{
if (is_object($this->corePush))
{
$this->corePush->message($subject, $details);
return;
}
if (!$this->hasWebPush)
{
return;
}
$logger = \Akeeba\Engine\Factory::getLog();
$model = $this->getPushModel();
if (empty($model))
{
$logger->notice('[Web Push] Cannot get the Web Push model or no push users are subscribed; aborted');
return;
}
$options = new NotificationOptions();
$options->tag = 'com_akeebabackup';
if ($details)
{
$options->body = $details;
}
foreach ($this->getWebPushUsers() as $uid)
{
$logger->debug(sprintf('[Web Push] Notifying user ID %d', $uid));
try
{
$reports = $model->sendNotification($subject, $options->toArray(), $uid);
}
catch (\ErrorException $e)
{
$logger->notice(sprintf('[Web Push] PHP Error: %s', $e->getMessage()));
}
$failed = 0;
$total = 0;
/** @var MessageSentReport $report */
foreach ($reports as $report)
{
$total++;
if (!$report->isSuccess())
{
$failed++;
$logger->debug(sprintf('[Web Push] Partial failure: %s', $report->getReason()));
}
}
if ($failed === $total)
{
$logger->debug(sprintf('[Web Push] Failed to notify user ID %s on %d subscription(s)', $uid, $total));
}
if ($failed > 0)
{
$logger->debug(sprintf('[Web Push] Partially notified user ID %d on %d subscription(s), %d of which failed', $uid, $total, $failed));
}
else
{
$logger->debug(sprintf('[Web Push] Successfully notified user ID %d on %d subscription(s)', $uid, $total));
}
}
}
/**
* Get the PushModel object, if possible
*
* @return PushModel|null
*
* @since 9.3.1
*/
private function getPushModel(): ?PushModel
{
if (empty(self::$mvcFactory))
{
return null;
}
$userIDs = $this->getWebPushUsers();
if (empty($userIDs))
{
return null;
}
try
{
/** @var PushModel|null $model */
$model = self::$mvcFactory->createModel('Push', 'Administrator');
}
catch (\Throwable $e)
{
return null;
}
if (!is_object($model) || !method_exists($model, 'sendNotification'))
{
return null;
}
return $model;
}
/**
* Get the user IDs which should be receiving push messages.
*
* @return int[]
*
* @since 9.3.1
*/
private function getWebPushUsers(): array
{
if (!is_null(self::$webPushUsers))
{
return self::$webPushUsers;
}
self::$webPushUsers = [];
try
{
/** @var DatabaseDriver $db */
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true)
->select($db->quoteName('user_id'))
->from($db->quoteName('#__user_profiles'))
->where($db->quoteName('profile_key') . ' = ' . $db->quote('com_akeebabackup.webPushSubscription'));
self::$webPushUsers = array_filter(
$db->setQuery($query)->loadColumn() ?: [],
function ($uid) {
/** @var User|null; $user */
$user = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById($uid);
return ($user instanceof User)
&& $user->authorise('core.manage', 'com_akeebabackup');
}
);
}
catch (\Exception $e)
{
// Ignore errors. We just don't send push messages.
}
return self::$webPushUsers;
}
}