--- /dev/null
+<?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\Command;
+
+use DateTime;
+use DateTimeInterface;
+use OC\Core\Command\Base;
+use OCA\FilesReminders\Model\RichReminder;
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class ListCommand extends Base {
+ public function __construct(
+ private ReminderService $reminderService,
+ private IUserManager $userManager,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this
+ ->setName('files:reminders')
+ ->setDescription('List file reminders')
+ ->addArgument(
+ 'user',
+ InputArgument::OPTIONAL,
+ 'list reminders for user',
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $io = new SymfonyStyle($input, $output);
+
+ $uid = $input->getArgument('user');
+ if ($uid !== null) {
+ /** @var string $uid */
+ $user = $this->userManager->get($uid);
+ if ($user === null) {
+ $io->error("Unknown user <$uid>");
+ return 1;
+ }
+ }
+
+ $reminders = $this->reminderService->getAll($user ?? null);
+ if (empty($reminders)) {
+ $io->text('No reminders');
+ return 0;
+ }
+
+ $io->table(
+ ['UserId', 'Path', 'RemindAt', 'Notified'],
+ array_map(
+ fn (RichReminder $reminder) => [
+ $reminder->getUserId(),
+ $reminder->getNode()->getPath(),
+ DateTime::createFromFormat('U', (string)$reminder->getRemindAt())->format(DateTimeInterface::ATOM), // ISO 8601
+ $reminder->getNotified() ? 'true' : 'false',
+ ],
+ $reminders,
+ )
+ );
+ return 0;
+ }
+}
* @method bool getNotified()
*/
class Reminder extends Entity {
- protected string $userId;
- protected int $fileId;
- protected int $remindAt;
- protected bool $notified = false;
+ protected $userId;
+ protected $fileId;
+ protected $remindAt;
+ protected $notified = false;
public function __construct() {
$this->addType('userId', 'string');
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\IUser;
/**
* @template-extends QBMapper<Reminder>
return parent::update($reminderUpdate);
}
+ public function find(int $id): Reminder {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('user_id', 'file_id', 'remind_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
+
+ return $this->findEntity($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findAll() {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('user_id', 'file_id', 'remind_at', 'notified')
+ ->from($this->getTableName())
+ ->orderBy('remind_at', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findAllForUser(IUser $user) {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('user_id', 'file_id', 'remind_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)))
+ ->orderBy('remind_at', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+
/**
* @return Reminder[]
*/
public function findToRemind() {
$qb = $this->db->getQueryBuilder();
- $qb->select('user_id', 'file_id', 'remind_at')
+ $qb->select('user_id', 'file_id', 'remind_at', 'notified')
->from($this->getTableName())
->where($qb->expr()->lt('remind_at', $qb->createFunction('NOW()')))
->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
public function findToDelete(?int $limit = null) {
$qb = $this->db->getQueryBuilder();
- $qb->select('user_id', 'file_id', 'remind_at')
+ $qb->select('user_id', 'file_id', 'remind_at', 'notified')
->from($this->getTableName())
->where($qb->expr()->eq('notified', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)))
->orderBy('remind_at', 'ASC')
--- /dev/null
+<?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\Model;
+
+use OCA\FilesReminders\Db\Reminder;
+use OCA\FilesReminders\Exception\NodeNotFoundException;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+
+class RichReminder extends Reminder {
+ public function __construct(
+ private Reminder $reminder,
+ private IRootFolder $root,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @throws NodeNotFoundException
+ */
+ public function getNode(): Node {
+ $userFolder = $this->root->getUserFolder($this->getUserId());
+ $nodes = $userFolder->getById($this->getFileId());
+ if (empty($nodes)) {
+ throw new NodeNotFoundException();
+ }
+ $node = reset($nodes);
+ return $node;
+ }
+
+ protected function getter(string $name): mixed {
+ return $this->reminder->getter($name);
+ }
+
+ public function __call(string $methodName, array $args) {
+ return $this->reminder->__call($methodName, $args);
+ }
+}
use InvalidArgumentException;
use OCA\FilesReminders\AppInfo\Application;
use OCA\FilesReminders\Exception\NodeNotFoundException;
+use OCA\FilesReminders\Service\ReminderService;
use OCP\Files\FileInfo;
-use OCP\Files\IRootFolder;
-use OCP\Files\Node;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Notification\IAction;
public function __construct(
protected IFactory $l10nFactory,
protected IURLGenerator $urlGenerator,
- protected IRootFolder $root,
+ protected ReminderService $reminderService,
) {}
public function getID(): string {
switch ($notification->getSubject()) {
case 'reminder-due':
- $fileId = $notification->getSubjectParameters()['fileId'];
- $node = $this->getNode($fileId);
+ $reminderId = (int)$notification->getObjectId();
+ $node = $this->reminderService->get($reminderId)->getNode();
$path = rtrim($node->getPath(), '/');
if (strpos($path, '/' . $notification->getUser() . '/files/') === 0) {
['fileid' => $node->getId()],
);
- $subject = $l->t('Reminder for {filename}');
+ // TRANSLATORS The name placeholder is for a file or folder name
+ $subject = $l->t('Reminder for {name}');
$notification
->setRichSubject(
$subject,
[
- 'filename' => [
+ 'name' => [
'type' => 'file',
'id' => $node->getId(),
'name' => $node->getName(),
],
)
->setParsedSubject(str_replace(
- ['{filename}'],
+ ['{name}'],
[$node->getName()],
$subject,
))
$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;
- }
}
use OCA\FilesReminders\Db\Reminder;
use OCA\FilesReminders\Db\ReminderMapper;
use OCA\FilesReminders\Exception\UserNotFoundException;
+use OCA\FilesReminders\Model\RichReminder;
use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\Files\IRootFolder;
use OCP\IURLGenerator;
+use OCP\IUser;
use OCP\IUserManager;
use OCP\Notification\IManager as INotificationManager;
use Psr\Log\LoggerInterface;
protected IURLGenerator $urlGenerator,
protected INotificationManager $notificationManager,
protected ReminderMapper $reminderMapper,
+ protected IRootFolder $root,
protected LoggerInterface $logger,
) {}
+ public function get(int $id): RichReminder {
+ $reminder = $this->reminderMapper->find($id);
+ return new RichReminder($reminder, $this->root);
+ }
+
+ /**
+ * @return RichReminder[]
+ */
+ public function getAll(?IUser $user = null) {
+ $reminders = ($user !== null)
+ ? $this->reminderMapper->findAllForUser($user)
+ : $this->reminderMapper->findAll();
+ return array_map(
+ fn (Reminder $reminder) => new RichReminder($reminder, $this->root),
+ $reminders,
+ );
+ }
+
/**
* @throws DoesNotExistException
* @throws UserNotFoundException
->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('files', 'folder.svg')))
->setUser($user->getUID())
->setObject('reminder', (string)$reminder->getId())
- ->setSubject('reminder-due', ['fileId' => $reminder->getFileId()])
+ ->setSubject('reminder-due')
->setDateTime(DateTime::createFromFormat('U', (string)$reminder->getRemindAt()));
try {