feat(files_reminders): add list command

Signed-off-by: Christopher Ng <chrng8@gmail.com>
This commit is contained in:
Christopher Ng 2023-07-31 12:10:50 -07:00
parent ea5e128fef
commit c8a32a70cd
6 changed files with 229 additions and 27 deletions

View file

@ -0,0 +1,92 @@
<?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;
}
}

View file

@ -42,10 +42,10 @@ use OCP\AppFramework\Db\Entity;
* @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');

View file

@ -29,6 +29,7 @@ namespace OCA\FilesReminders\Db;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;
/**
* @template-extends QBMapper<Reminder>
@ -51,13 +52,50 @@ class ReminderMapper extends QBMapper {
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)))
@ -72,7 +110,7 @@ class ReminderMapper extends QBMapper {
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')

View file

@ -0,0 +1,62 @@
<?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);
}
}

View file

@ -29,9 +29,8 @@ namespace OCA\FilesReminders\Notification;
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;
@ -42,7 +41,7 @@ class Notifier implements INotifier {
public function __construct(
protected IFactory $l10nFactory,
protected IURLGenerator $urlGenerator,
protected IRootFolder $root,
protected ReminderService $reminderService,
) {}
public function getID(): string {
@ -66,8 +65,8 @@ class Notifier implements INotifier {
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) {
@ -81,12 +80,13 @@ class Notifier implements INotifier {
['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(),
@ -96,7 +96,7 @@ class Notifier implements INotifier {
],
)
->setParsedSubject(str_replace(
['{filename}'],
['{name}'],
[$node->getName()],
$subject,
))
@ -127,16 +127,4 @@ class Notifier implements INotifier {
$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;
}
}

View file

@ -32,8 +32,11 @@ use OCA\FilesReminders\AppInfo\Application;
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;
@ -44,9 +47,28 @@ class ReminderService {
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
@ -67,7 +89,7 @@ class ReminderService {
->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 {