You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

324 lines
9.8 KiB

<?php
/**
* @author Joas Schilling <coding@schilljs.com>
*
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Notifications;
use OCA\Notifications\Exceptions\NotificationNotFoundException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\Notification\IAction;
use OCP\Notification\IManager;
use OCP\Notification\INotification;
class Handler {
/** @var IDBConnection */
protected $connection;
/** @var IManager */
protected $manager;
/**
* @param IDBConnection $connection
* @param IManager $manager
*/
public function __construct(IDBConnection $connection, IManager $manager) {
$this->connection = $connection;
$this->manager = $manager;
}
/**
* Add a new notification to the database
*
* @param INotification $notification
* @return int
*/
public function add(INotification $notification): int {
$sql = $this->connection->getQueryBuilder();
$sql->insert('notifications');
$this->sqlInsert($sql, $notification);
$sql->execute();
return $sql->getLastInsertId();
}
/**
* Count the notifications matching the given Notification
*
* @param INotification $notification
* @return int
*/
public function count(INotification $notification): int {
$sql = $this->connection->getQueryBuilder();
$sql->select($sql->createFunction('COUNT(*)'))
->from('notifications');
$this->sqlWhere($sql, $notification);
$statement = $sql->execute();
$count = (int) $statement->fetchColumn();
$statement->closeCursor();
return $count;
}
/**
* Delete the notifications matching the given Notification
*
* @param INotification $notification
* @return array A Map with all deleted notifications [user => [notifications]]
*/
public function delete(INotification $notification): array {
$sql = $this->connection->getQueryBuilder();
$sql->select('notification_id', 'user')
->from('notifications');
$this->sqlWhere($sql, $notification);
$statement = $sql->execute();
$deleted = [];
while ($row = $statement->fetch()) {
if (!isset($deleted[$row['user']])) {
$deleted[$row['user']] = [];
}
$deleted[$row['user']][] = (int) $row['notification_id'];
}
$statement->closeCursor();
foreach ($deleted as $user => $notifications) {
foreach ($notifications as $notificationId) {
$this->deleteById($notificationId, $user);
}
}
return $deleted;
}
/**
* Delete the notification of a given user
*
* @param string $user
* @return bool
*/
public function deleteByUser(string $user): bool {
$notification = $this->manager->createNotification();
try {
$notification->setUser($user);
} catch (\InvalidArgumentException $e) {
return false;
}
return !empty($this->delete($notification));
}
/**
* Delete the notification matching the given id
*
* @param int $id
* @param string $user
* @return bool
*/
public function deleteById(int $id, string $user): bool {
$sql = $this->connection->getQueryBuilder();
$sql->delete('notifications')
->where($sql->expr()->eq('notification_id', $sql->createNamedParameter($id)))
->andWhere($sql->expr()->eq('user', $sql->createNamedParameter($user)));
return (bool) $sql->execute();
}
/**
* Get the notification matching the given id
*
* @param int $id
* @param string $user
* @return INotification
* @throws NotificationNotFoundException
*/
public function getById(int $id, string $user): INotification {
$sql = $this->connection->getQueryBuilder();
$sql->select('*')
->from('notifications')
->where($sql->expr()->eq('notification_id', $sql->createNamedParameter($id)))
->andWhere($sql->expr()->eq('user', $sql->createNamedParameter($user)));
$statement = $sql->execute();
$row = $statement->fetch();
$statement->closeCursor();
if ($row === false) {
throw new NotificationNotFoundException('No entry returned from database');
}
try {
return $this->notificationFromRow($row);
} catch (\InvalidArgumentException $e) {
throw new NotificationNotFoundException('Could not create notification from database row');
}
}
/**
* Return the notifications matching the given Notification
*
* @param INotification $notification
* @param int $limit
* @return array [notification_id => INotification]
*/
public function get(INotification $notification, $limit = 25): array {
$sql = $this->connection->getQueryBuilder();
$sql->select('*')
->from('notifications')
->orderBy('notification_id', 'DESC')
->setMaxResults($limit);
$this->sqlWhere($sql, $notification);
$statement = $sql->execute();
$notifications = [];
while ($row = $statement->fetch()) {
try {
$notifications[(int)$row['notification_id']] = $this->notificationFromRow($row);
} catch (\InvalidArgumentException $e) {
continue;
}
}
$statement->closeCursor();
return $notifications;
}
/**
* Add where statements to a query builder matching the given notification
*
* @param IQueryBuilder $sql
* @param INotification $notification
*/
protected function sqlWhere(IQueryBuilder $sql, INotification $notification) {
if ($notification->getApp() !== '') {
$sql->andWhere($sql->expr()->eq('app', $sql->createNamedParameter($notification->getApp())));
}
if ($notification->getUser() !== '') {
$sql->andWhere($sql->expr()->eq('user', $sql->createNamedParameter($notification->getUser())));
}
$timestamp = $notification->getDateTime()->getTimestamp();
if ($timestamp !== 0) {
$sql->andWhere($sql->expr()->eq('timestamp', $sql->createNamedParameter($timestamp)));
}
if ($notification->getObjectType() !== '') {
$sql->andWhere($sql->expr()->eq('object_type', $sql->createNamedParameter($notification->getObjectType())));
}
if ($notification->getObjectId() !== '') {
$sql->andWhere($sql->expr()->eq('object_id', $sql->createNamedParameter($notification->getObjectId())));
}
if ($notification->getSubject() !== '') {
$sql->andWhere($sql->expr()->eq('subject', $sql->createNamedParameter($notification->getSubject())));
}
if ($notification->getMessage() !== '') {
$sql->andWhere($sql->expr()->eq('message', $sql->createNamedParameter($notification->getMessage())));
}
if ($notification->getLink() !== '') {
$sql->andWhere($sql->expr()->eq('link', $sql->createNamedParameter($notification->getLink())));
}
if ($notification->getIcon() !== '') {
$sql->andWhere($sql->expr()->eq('icon', $sql->createNamedParameter($notification->getIcon())));
}
}
/**
* Turn a notification into an input statement
*
* @param IQueryBuilder $sql
* @param INotification $notification
*/
protected function sqlInsert(IQueryBuilder $sql, INotification $notification) {
$actions = [];
foreach ($notification->getActions() as $action) {
/** @var IAction $action */
$actions[] = [
'label' => $action->getLabel(),
'link' => $action->getLink(),
'type' => $action->getRequestType(),
'primary' => $action->isPrimary(),
];
}
$sql->setValue('app', $sql->createNamedParameter($notification->getApp()))
->setValue('user', $sql->createNamedParameter($notification->getUser()))
->setValue('timestamp', $sql->createNamedParameter($notification->getDateTime()->getTimestamp()))
->setValue('object_type', $sql->createNamedParameter($notification->getObjectType()))
->setValue('object_id', $sql->createNamedParameter($notification->getObjectId()))
->setValue('subject', $sql->createNamedParameter($notification->getSubject()))
->setValue('subject_parameters', $sql->createNamedParameter(json_encode($notification->getSubjectParameters())))
->setValue('message', $sql->createNamedParameter($notification->getMessage()))
->setValue('message_parameters', $sql->createNamedParameter(json_encode($notification->getMessageParameters())))
->setValue('link', $sql->createNamedParameter($notification->getLink()))
->setValue('icon', $sql->createNamedParameter($notification->getIcon()))
->setValue('actions', $sql->createNamedParameter(json_encode($actions)));
}
/**
* Turn a database row into a INotification
*
* @param array $row
* @return INotification
* @throws \InvalidArgumentException
*/
protected function notificationFromRow(array $row): INotification {
$dateTime = new \DateTime();
$dateTime->setTimestamp((int) $row['timestamp']);
$notification = $this->manager->createNotification();
$notification->setApp($row['app'])
->setUser($row['user'])
->setDateTime($dateTime)
->setObject($row['object_type'], $row['object_id'])
->setSubject($row['subject'], (array) json_decode($row['subject_parameters'], true));
if ($row['message'] !== '') {
$notification->setMessage($row['message'], (array) json_decode($row['message_parameters'], true));
}
if ($row['link'] !== '' && $row['link'] !== null) {
$notification->setLink($row['link']);
}
if ($row['icon'] !== '' && $row['icon'] !== null) {
$notification->setIcon($row['icon']);
}
$actions = (array) json_decode($row['actions'], true);
foreach ($actions as $actionData) {
$action = $notification->createAction();
$action->setLabel($actionData['label'])
->setLink($actionData['link'], $actionData['type']);
if (isset($actionData['primary'])) {
$action->setPrimary($actionData['primary']);
}
$notification->addAction($action);
}
return $notification;
}
}