Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
43ac71a
feat: init files_reminders migration
Pytal Jul 31, 2023
29a78fe
feat(files_reminders): add Application
Pytal Jul 31, 2023
6da4542
feat(files_reminders): add info xml
Pytal Jul 31, 2023
b195fe7
feat(files_reminders): add background jobs
Pytal Jul 31, 2023
782a462
feat(files_reminders): add service and notifier
Pytal Jul 31, 2023
5aca833
feat(files_reminders): add list command
Pytal Jul 31, 2023
cbbd0c6
enh: use datetime
Pytal Jul 31, 2023
5e8668b
enh: add created at
Pytal Jul 31, 2023
f5036b5
enh: implement JsonSerializable
Pytal Jul 31, 2023
143346b
feat(files_reminders): add api controller
Pytal Jul 31, 2023
ca003e2
fix: add composer autoload
Pytal Jul 31, 2023
bb4134a
enh: add to shipped
Pytal Jul 31, 2023
c0f327d
enh: rename to due date
Pytal Jul 31, 2023
3f668f3
fix: catch Throwable
Pytal Jul 31, 2023
e99f1b0
enh: add updated at
Pytal Jul 31, 2023
f4c7759
feat(files_reminders): create or update
Pytal Jul 31, 2023
fb71f8c
fix: update find due query
Pytal Jul 31, 2023
ab357bf
feat(files_reminders): add remove endpoint
Pytal Jul 31, 2023
332fd3d
fix: create only if file exists
Pytal Jul 31, 2023
8a410f1
enh: return created status code
Pytal Jul 31, 2023
b77a375
enh: comment interval
Pytal Jul 31, 2023
8f54e2c
enh: serialize path
Pytal Jul 31, 2023
67abe99
enh: does not exist return null
Pytal Jul 31, 2023
ee7aff3
fix: return ocs data
Pytal Jul 31, 2023
67df581
fix: remove throwable handling
Pytal Jul 31, 2023
1c6114b
fix: construct background jobs
Pytal Jul 31, 2023
e12ae21
enh: handle node deleted
Pytal Aug 1, 2023
6fc3530
fix: exit on reminder not found
Pytal Aug 1, 2023
fa7985d
fix: catch NodeNotFoundException in notifier
Pytal Aug 1, 2023
3b81da9
enh: highlight filename
Pytal Aug 1, 2023
05436ac
fix: remove unnecessary parsed subject
Pytal Aug 1, 2023
cdaee2b
fix: return null if table exists
Pytal Aug 1, 2023
0ffb367
enh: add codeowner
Pytal Aug 1, 2023
a377862
enh: add json output to command
Pytal Aug 1, 2023
33f30f5
fix: ignore non-existing
Pytal Aug 1, 2023
2e8906f
fix(ci): add to enabled apps
Pytal Aug 1, 2023
dfba8f4
fix: set endpoint description
Pytal Aug 2, 2023
d3991ee
enh: handle user deleted
Pytal Aug 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(files_reminders): add list command
Signed-off-by: Christopher Ng <[email protected]>
(cherry picked from commit c8a32a7)
  • Loading branch information
Pytal committed Aug 8, 2023
commit 5aca833f2132747b4f2e7a26b9035396a049077a
92 changes: 92 additions & 0 deletions apps/files_reminders/lib/Command/ListCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

/**
* @copyright 2023 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @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;
}
}
8 changes: 4 additions & 4 deletions apps/files_reminders/lib/Db/Reminder.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@
* @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');
Expand Down
42 changes: 40 additions & 2 deletions apps/files_reminders/lib/Db/ReminderMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;

/**
* @template-extends QBMapper<Reminder>
Expand All @@ -51,13 +52,50 @@ public function markNotified(Reminder $reminder): 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)))
Expand All @@ -72,7 +110,7 @@ public function findToRemind() {
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')
Expand Down
62 changes: 62 additions & 0 deletions apps/files_reminders/lib/Model/RichReminder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/**
* @copyright 2023 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @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);
}
}
28 changes: 8 additions & 20 deletions apps/files_reminders/lib/Notification/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@
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;
Expand All @@ -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 {
Expand All @@ -66,8 +65,8 @@ public function prepare(INotification $notification, string $languageCode): INot

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) {
Expand All @@ -81,12 +80,13 @@ public function prepare(INotification $notification, string $languageCode): INot
['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(),
Expand All @@ -96,7 +96,7 @@ public function prepare(INotification $notification, string $languageCode): INot
],
)
->setParsedSubject(str_replace(
['{filename}'],
['{name}'],
[$node->getName()],
$subject,
))
Expand Down Expand Up @@ -127,16 +127,4 @@ protected function addActionButton(INotification $notification, string $label):

$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;
}
}
24 changes: 23 additions & 1 deletion apps/files_reminders/lib/Service/ReminderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@
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;
Expand All @@ -44,9 +47,28 @@ public function __construct(
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
Expand All @@ -67,7 +89,7 @@ public function send(Reminder $reminder): void {
->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 {
Expand Down