mirror of
https://github.com/nextcloud/server.git
synced 2026-04-15 22:11:17 -04:00
feat(files_reminders): add service and notifier
Signed-off-by: Christopher Ng <chrng8@gmail.com>
This commit is contained in:
parent
a3ac1b82da
commit
ea5e128fef
5 changed files with 310 additions and 1 deletions
|
|
@ -60,7 +60,23 @@ class ReminderMapper extends QBMapper {
|
|||
$qb->select('user_id', 'file_id', 'remind_at')
|
||||
->from($this->getTableName())
|
||||
->where($qb->expr()->lt('remind_at', $qb->createFunction('NOW()')))
|
||||
->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)));
|
||||
->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
|
||||
->orderBy('remind_at', 'ASC');
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Reminder[]
|
||||
*/
|
||||
public function findToDelete(?int $limit = null) {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb->select('user_id', 'file_id', 'remind_at')
|
||||
->from($this->getTableName())
|
||||
->where($qb->expr()->eq('notified', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)))
|
||||
->orderBy('remind_at', 'ASC')
|
||||
->setMaxResults($limit);
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
|
|
|||
32
apps/files_reminders/lib/Exception/NodeNotFoundException.php
Normal file
32
apps/files_reminders/lib/Exception/NodeNotFoundException.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2023 Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @author Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\FilesReminders\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NodeNotFoundException extends Exception {
|
||||
}
|
||||
32
apps/files_reminders/lib/Exception/UserNotFoundException.php
Normal file
32
apps/files_reminders/lib/Exception/UserNotFoundException.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2023 Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @author Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\FilesReminders\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class UserNotFoundException extends Exception {
|
||||
}
|
||||
142
apps/files_reminders/lib/Notification/Notifier.php
Normal file
142
apps/files_reminders/lib/Notification/Notifier.php
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2023 Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @author Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\FilesReminders\Notification;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OCA\FilesReminders\AppInfo\Application;
|
||||
use OCA\FilesReminders\Exception\NodeNotFoundException;
|
||||
use OCP\Files\FileInfo;
|
||||
use OCP\Files\IRootFolder;
|
||||
use OCP\Files\Node;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\L10N\IFactory;
|
||||
use OCP\Notification\IAction;
|
||||
use OCP\Notification\INotification;
|
||||
use OCP\Notification\INotifier;
|
||||
|
||||
class Notifier implements INotifier {
|
||||
public function __construct(
|
||||
protected IFactory $l10nFactory,
|
||||
protected IURLGenerator $urlGenerator,
|
||||
protected IRootFolder $root,
|
||||
) {}
|
||||
|
||||
public function getID(): string {
|
||||
return Application::APP_ID;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return $this->l10nFactory->get(Application::APP_ID)->t('File reminders');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
* @throws NodeNotFoundException
|
||||
*/
|
||||
public function prepare(INotification $notification, string $languageCode): INotification {
|
||||
$l = $this->l10nFactory->get(Application::APP_ID, $languageCode);
|
||||
|
||||
if ($notification->getApp() !== Application::APP_ID) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
||||
switch ($notification->getSubject()) {
|
||||
case 'reminder-due':
|
||||
$fileId = $notification->getSubjectParameters()['fileId'];
|
||||
$node = $this->getNode($fileId);
|
||||
|
||||
$path = rtrim($node->getPath(), '/');
|
||||
if (strpos($path, '/' . $notification->getUser() . '/files/') === 0) {
|
||||
// Remove /user/files/...
|
||||
$fullPath = $path;
|
||||
[,,, $path] = explode('/', $fullPath, 4);
|
||||
}
|
||||
|
||||
$link = $this->urlGenerator->linkToRouteAbsolute(
|
||||
'files.viewcontroller.showFile',
|
||||
['fileid' => $node->getId()],
|
||||
);
|
||||
|
||||
$subject = $l->t('Reminder for {filename}');
|
||||
$notification
|
||||
->setRichSubject(
|
||||
$subject,
|
||||
[
|
||||
'filename' => [
|
||||
'type' => 'file',
|
||||
'id' => $node->getId(),
|
||||
'name' => $node->getName(),
|
||||
'path' => $path,
|
||||
'link' => $link,
|
||||
],
|
||||
],
|
||||
)
|
||||
->setParsedSubject(str_replace(
|
||||
['{filename}'],
|
||||
[$node->getName()],
|
||||
$subject,
|
||||
))
|
||||
->setLink($link);
|
||||
|
||||
$label = match ($node->getType()) {
|
||||
FileInfo::TYPE_FILE => $l->t('View file'),
|
||||
FileInfo::TYPE_FOLDER => $l->t('View folder'),
|
||||
};
|
||||
|
||||
$this->addActionButton($notification, $label);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException();
|
||||
break;
|
||||
}
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
||||
protected function addActionButton(INotification $notification, string $label): void {
|
||||
$action = $notification->createAction();
|
||||
|
||||
$action->setLabel($label)
|
||||
->setParsedLabel($label)
|
||||
->setLink($notification->getLink(), IAction::TYPE_WEB)
|
||||
->setPrimary(true);
|
||||
|
||||
$notification->addParsedAction($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NodeNotFoundException
|
||||
*/
|
||||
protected function getNode(int $fileId): Node {
|
||||
$nodes = $this->root->getById($fileId);
|
||||
if (empty($nodes)) {
|
||||
throw new NodeNotFoundException();
|
||||
}
|
||||
$node = reset($nodes);
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
87
apps/files_reminders/lib/Service/ReminderService.php
Normal file
87
apps/files_reminders/lib/Service/ReminderService.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2023 Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @author Christopher Ng <chrng8@gmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\FilesReminders\Service;
|
||||
|
||||
use DateTime;
|
||||
use InvalidArgumentException;
|
||||
use OCA\FilesReminders\AppInfo\Application;
|
||||
use OCA\FilesReminders\Db\Reminder;
|
||||
use OCA\FilesReminders\Db\ReminderMapper;
|
||||
use OCA\FilesReminders\Exception\UserNotFoundException;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Notification\IManager as INotificationManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ReminderService {
|
||||
public function __construct(
|
||||
protected IUserManager $userManager,
|
||||
protected IURLGenerator $urlGenerator,
|
||||
protected INotificationManager $notificationManager,
|
||||
protected ReminderMapper $reminderMapper,
|
||||
protected LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws DoesNotExistException
|
||||
* @throws UserNotFoundException
|
||||
*/
|
||||
public function send(Reminder $reminder): void {
|
||||
if ($reminder->getNotified()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->userManager->get($reminder->getUserId());
|
||||
if ($user === null) {
|
||||
throw new UserNotFoundException();
|
||||
}
|
||||
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
$notification
|
||||
->setApp(Application::APP_ID)
|
||||
->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('files', 'folder.svg')))
|
||||
->setUser($user->getUID())
|
||||
->setObject('reminder', (string)$reminder->getId())
|
||||
->setSubject('reminder-due', ['fileId' => $reminder->getFileId()])
|
||||
->setDateTime(DateTime::createFromFormat('U', (string)$reminder->getRemindAt()));
|
||||
|
||||
try {
|
||||
$this->notificationManager->notify($notification);
|
||||
$this->reminderMapper->markNotified($reminder);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$this->logger->error('Failed to send reminder notification', $e->getTrace());
|
||||
}
|
||||
}
|
||||
|
||||
public function cleanUp(?int $limit = null): void {
|
||||
$reminders = $this->reminderMapper->findToDelete($limit);
|
||||
foreach ($reminders as $reminder) {
|
||||
$this->reminderMapper->delete($reminder);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue