Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\SystemNotification\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\SystemNotification\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\SystemNotification\Exception\RuntimeException;
|
||||
|
||||
final class NotificationService implements NotificationServiceInterface
|
||||
{
|
||||
/** @var array $validMessageTypes */
|
||||
private static $validMessageTypes = [
|
||||
self::TYPE_DEFAULT,
|
||||
self::TYPE_NOTICE,
|
||||
self::TYPE_SUCESS,
|
||||
self::TYPE_WARNING,
|
||||
self::TYPE_ERROR,
|
||||
self::TYPE_PUSH,
|
||||
];
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a notification
|
||||
*
|
||||
* @param int $userId
|
||||
* @param string $type
|
||||
* @param string $title
|
||||
* @param string|null $message
|
||||
* @param bool $priority Play sound and make notification sticky
|
||||
* @param array $options
|
||||
* @param array $tags
|
||||
*
|
||||
* @throws InvalidArgumentException|RuntimeException
|
||||
*
|
||||
* @return int|false Created Notification-ID
|
||||
*/
|
||||
public function create(
|
||||
$userId,
|
||||
$type,
|
||||
$title,
|
||||
$message = null,
|
||||
$priority = false,
|
||||
$options = [],
|
||||
$tags = []
|
||||
) {
|
||||
if (!in_array($type, self::$validMessageTypes, true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'"%s" is not a valid message type. Valid types are: %s', $type, implode(', ', self::$validMessageTypes)
|
||||
));
|
||||
}
|
||||
if (!$this->isValidUser($userId)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'User #%s is not a valid user.', $userId
|
||||
));
|
||||
}
|
||||
|
||||
// Truncate long messages
|
||||
$message = $this->truncateMessage($message);
|
||||
|
||||
// Sanitize buttons
|
||||
if (is_array($options['buttons']) && count($options['buttons']) > 0) {
|
||||
foreach ($options['buttons'] as $index => $button) {
|
||||
if (empty($button['text']) || empty($button['link'])) {
|
||||
unset($options['buttons'][$index]);
|
||||
}
|
||||
if (empty($button['id'])) {
|
||||
$options['buttons'][$index]['id'] = uniqid('notification-button-', false); // Set Html-Id attribute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create notification
|
||||
$this->db->perform(
|
||||
'INSERT INTO `notification_message` (`user_id`, `type`, `title`, `message`, `options_json`, `tags`, `priority`, `created_at`)
|
||||
VALUES (:user_id, :type, :title, :message, :options_json, :tags, :priority, NOW())',
|
||||
[
|
||||
'user_id' => (int)$userId,
|
||||
'type' => $type,
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'priority' => (int)$priority,
|
||||
'options_json' => !empty($options) ? json_encode($options) : null,
|
||||
'tags' => !empty($tags) ? $this->transformTagsArrayToString($tags) : null,
|
||||
]
|
||||
);
|
||||
$insertId = (int)$this->db->lastInsertId();
|
||||
if ($insertId === 0) {
|
||||
throw new RuntimeException('Notification message could not be created.');
|
||||
}
|
||||
|
||||
return $insertId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create push notification
|
||||
*
|
||||
* @param int $userId
|
||||
* @param string $title
|
||||
* @param string $message
|
||||
* @param bool $priority
|
||||
*
|
||||
* @return int Created ID
|
||||
*/
|
||||
public function createPushNotification($userId, $title, $message, $priority = false)
|
||||
{
|
||||
// strip_tags ist notwendig, da HTML von Browser-Benachrichtigungen nicht unterstützt wird.
|
||||
return $this->create($userId, self::TYPE_PUSH, strip_tags($title), strip_tags($message), $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @param NotificationMessageData $data
|
||||
*
|
||||
* @return int|false Created ID
|
||||
*/
|
||||
public function createFromData($userId, NotificationMessageData $data)
|
||||
{
|
||||
return $this->create(
|
||||
$userId,
|
||||
$data->getType(),
|
||||
$data->getTitle(),
|
||||
$data->getMessage(),
|
||||
$data->isPriority(),
|
||||
$data->getOptions(),
|
||||
$data->getTags()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $notificationId
|
||||
* @param array $tags
|
||||
*
|
||||
* @return bool Returns true on success
|
||||
*/
|
||||
public function addTags($notificationId, array $tags)
|
||||
{
|
||||
try {
|
||||
$tagsArray = [];
|
||||
|
||||
// Fetch existing tags
|
||||
$tagsExisting = $this->db->fetchValue(
|
||||
'SELECT n.tags FROM notification_message AS n WHERE n.id = :id',
|
||||
['id' => (int)$notificationId]
|
||||
);
|
||||
if (!empty($tagsExisting)) {
|
||||
$tagsArray = $this->transformTagsStringToArray($tagsExisting);
|
||||
}
|
||||
|
||||
// Update notification
|
||||
$tagsMerged = array_merge($tagsArray, $tags);
|
||||
$tagsString = $this->transformTagsArrayToString($tagsMerged);
|
||||
$this->db->perform(
|
||||
'UPDATE notification_message SET tags = :tags WHERE id = :id',
|
||||
['id' => (int)$notificationId, 'tags' => $tagsString]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $notificationId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($notificationId)
|
||||
{
|
||||
$numRows = (int)$this->db->fetchAffected(
|
||||
'DELETE FROM notification_message WHERE id = :id LIMIT 1',
|
||||
['id' => (int)$notificationId]
|
||||
);
|
||||
|
||||
return $numRows === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete notification messages by UserID
|
||||
*
|
||||
* @param int $userId
|
||||
* @param bool $keepPriorityMessages If true, high priority messages will not be deleted
|
||||
*
|
||||
* @return int Number of deleted messages
|
||||
*/
|
||||
public function deleteByUser($userId, $keepPriorityMessages = true)
|
||||
{
|
||||
$delete = $this->db->delete()
|
||||
->from('notification_message')
|
||||
->where('user_id = ?', (int)$userId);
|
||||
|
||||
if ((bool)$keepPriorityMessages === true) {
|
||||
$delete->where('priority <> ?', 1);
|
||||
}
|
||||
|
||||
$numRows = (int)$this->db->fetchAffected(
|
||||
$delete->getStatement(),
|
||||
$delete->getBindValues()
|
||||
);
|
||||
|
||||
return $numRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete notification messages by tags
|
||||
*
|
||||
* If multiple tags submitted, all tags must occur in the same message.
|
||||
*
|
||||
* @example deleteByTags(['callcenter','incomingcall'])
|
||||
*
|
||||
* @param array $tags
|
||||
* @param int $userId
|
||||
* @param bool $keepPriorityMessages If true, high priority messages will not be deleted
|
||||
*
|
||||
* @return int Number of deleted messages
|
||||
*/
|
||||
public function deleteByTags(array $tags, $userId = null, $keepPriorityMessages = true)
|
||||
{
|
||||
$delete = $this->db->delete()->from('notification_message');
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$tag = $this->normalizeTag($tag);
|
||||
$delete->where('tags LIKE ?', "%|{$tag}|%");
|
||||
}
|
||||
if ($userId !== null) {
|
||||
$delete->where('user_id = ?', (int)$userId);
|
||||
}
|
||||
if ((bool)$keepPriorityMessages === true) {
|
||||
$delete->where('priority <> ?', 1);
|
||||
}
|
||||
|
||||
$numRows = (int)$this->db->fetchAffected(
|
||||
$delete->getStatement(),
|
||||
$delete->getBindValues()
|
||||
);
|
||||
|
||||
return $numRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getValidTypes()
|
||||
{
|
||||
return self::$validMessageTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isValidUser($userId)
|
||||
{
|
||||
// @todo @refactor Move to UserGateway
|
||||
$userCheck = (int)$this->db->fetchValue(
|
||||
'SELECT u.id FROM `user` AS u WHERE u.id = :user_id AND u.activ = 1',
|
||||
['user_id' => (int)$userId]
|
||||
);
|
||||
|
||||
return $userCheck === (int)$userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tags
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function transformTagsArrayToString(array $tags)
|
||||
{
|
||||
if (empty($tags)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
sort($tags);
|
||||
$tags = array_unique($tags);
|
||||
|
||||
$string = '|';
|
||||
foreach ($tags as $tag) {
|
||||
$tag = $this->normalizeTag($tag);
|
||||
$string .= $tag . '|';
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function transformTagsStringToArray($string)
|
||||
{
|
||||
$tags = [];
|
||||
$parts = explode('|', $string);
|
||||
foreach ($parts as $tag) {
|
||||
$tag = $this->normalizeTag($tag);
|
||||
if (!empty($tag)) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
}
|
||||
|
||||
sort($tags);
|
||||
$tags = array_unique($tags);
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function normalizeTag($tag)
|
||||
{
|
||||
$tag = strtolower(trim($tag));
|
||||
$tag = preg_replace('/[^a-z0-9\-]/', '', $tag); // Remove invalid chars
|
||||
$tag = preg_replace('/[-]+/', '-', $tag); // Replace multiple dashes
|
||||
|
||||
return (string)$tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $message
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function truncateMessage($message = null)
|
||||
{
|
||||
if ($message !== null && mb_strlen($message) > 1024) {
|
||||
$message = mb_substr($message, 0, 1020) . ' ...';
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $title
|
||||
* @param null|string $message
|
||||
* @param bool $priority
|
||||
* @param array $options
|
||||
* @param array $tags
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function createPushNotificationForConnectedUsers(
|
||||
$type,
|
||||
$title,
|
||||
$message = null,
|
||||
$priority = false,
|
||||
$options = [],
|
||||
$tags = []
|
||||
) {
|
||||
if (!in_array($type, self::$validMessageTypes, true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'"%s" is not a valid message type. Valid types are: %s', $type, implode(', ', self::$validMessageTypes)
|
||||
));
|
||||
}
|
||||
|
||||
$sql = "INSERT INTO notification_message (user_id, type, title, message, tags, options_json, priority, created_at)
|
||||
SELECT u.id, :type, :title, :msg,:tags,'',:priority,NOW()
|
||||
FROM `user` AS u
|
||||
INNER JOIN useronline uo on u.id = uo.user_id AND uo.login = 1";
|
||||
|
||||
return (int)$this->db->fetchAffected($sql, [
|
||||
'title' => strip_tags($title),
|
||||
'msg' => strip_tags($message),
|
||||
'type' => $type,
|
||||
'priority' => (int)$priority,
|
||||
'options_json' => !empty($options) ? json_encode($options) : null,
|
||||
'tags' => !empty($tags) ? $this->transformTagsArrayToString($tags) : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user