Merge pull request #51136 from nextcloud/feat/noid/occ-list-delete-calendar-subscription

feat: command to list and delete calendar subscriptions
pull/51398/head
Daniel 2025-03-11 14:30:46 +07:00 committed by GitHub
commit a91cd621b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 202 additions and 3 deletions

@ -56,18 +56,20 @@
<commands>
<command>OCA\DAV\Command\CreateAddressBook</command>
<command>OCA\DAV\Command\ListAddressbooks</command>
<command>OCA\DAV\Command\CreateCalendar</command>
<command>OCA\DAV\Command\CreateSubscription</command>
<command>OCA\DAV\Command\DeleteCalendar</command>
<command>OCA\DAV\Command\DeleteSubscription</command>
<command>OCA\DAV\Command\FixCalendarSyncCommand</command>
<command>OCA\DAV\Command\MoveCalendar</command>
<command>OCA\DAV\Command\ListAddressbooks</command>
<command>OCA\DAV\Command\ListCalendars</command>
<command>OCA\DAV\Command\ListSubscriptions</command>
<command>OCA\DAV\Command\MoveCalendar</command>
<command>OCA\DAV\Command\RemoveInvalidShares</command>
<command>OCA\DAV\Command\RetentionCleanupCommand</command>
<command>OCA\DAV\Command\SendEventReminders</command>
<command>OCA\DAV\Command\SyncBirthdayCalendar</command>
<command>OCA\DAV\Command\SyncSystemAddressBook</command>
<command>OCA\DAV\Command\RemoveInvalidShares</command>
</commands>
<settings>

@ -157,9 +157,11 @@ return array(
'OCA\\DAV\\Command\\CreateCalendar' => $baseDir . '/../lib/Command/CreateCalendar.php',
'OCA\\DAV\\Command\\CreateSubscription' => $baseDir . '/../lib/Command/CreateSubscription.php',
'OCA\\DAV\\Command\\DeleteCalendar' => $baseDir . '/../lib/Command/DeleteCalendar.php',
'OCA\\DAV\\Command\\DeleteSubscription' => $baseDir . '/../lib/Command/DeleteSubscription.php',
'OCA\\DAV\\Command\\FixCalendarSyncCommand' => $baseDir . '/../lib/Command/FixCalendarSyncCommand.php',
'OCA\\DAV\\Command\\ListAddressbooks' => $baseDir . '/../lib/Command/ListAddressbooks.php',
'OCA\\DAV\\Command\\ListCalendars' => $baseDir . '/../lib/Command/ListCalendars.php',
'OCA\\DAV\\Command\\ListSubscriptions' => $baseDir . '/../lib/Command/ListSubscriptions.php',
'OCA\\DAV\\Command\\MoveCalendar' => $baseDir . '/../lib/Command/MoveCalendar.php',
'OCA\\DAV\\Command\\RemoveInvalidShares' => $baseDir . '/../lib/Command/RemoveInvalidShares.php',
'OCA\\DAV\\Command\\RetentionCleanupCommand' => $baseDir . '/../lib/Command/RetentionCleanupCommand.php',

@ -172,9 +172,11 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Command\\CreateCalendar' => __DIR__ . '/..' . '/../lib/Command/CreateCalendar.php',
'OCA\\DAV\\Command\\CreateSubscription' => __DIR__ . '/..' . '/../lib/Command/CreateSubscription.php',
'OCA\\DAV\\Command\\DeleteCalendar' => __DIR__ . '/..' . '/../lib/Command/DeleteCalendar.php',
'OCA\\DAV\\Command\\DeleteSubscription' => __DIR__ . '/..' . '/../lib/Command/DeleteSubscription.php',
'OCA\\DAV\\Command\\FixCalendarSyncCommand' => __DIR__ . '/..' . '/../lib/Command/FixCalendarSyncCommand.php',
'OCA\\DAV\\Command\\ListAddressbooks' => __DIR__ . '/..' . '/../lib/Command/ListAddressbooks.php',
'OCA\\DAV\\Command\\ListCalendars' => __DIR__ . '/..' . '/../lib/Command/ListCalendars.php',
'OCA\\DAV\\Command\\ListSubscriptions' => __DIR__ . '/..' . '/../lib/Command/ListSubscriptions.php',
'OCA\\DAV\\Command\\MoveCalendar' => __DIR__ . '/..' . '/../lib/Command/MoveCalendar.php',
'OCA\\DAV\\Command\\RemoveInvalidShares' => __DIR__ . '/..' . '/../lib/Command/RemoveInvalidShares.php',
'OCA\\DAV\\Command\\RetentionCleanupCommand' => __DIR__ . '/..' . '/../lib/Command/RetentionCleanupCommand.php',

@ -735,6 +735,43 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
return $this->rowToSubscription($row, $subscription);
}
public function getSubscriptionByUri(string $principal, string $uri): ?array {
$fields = array_column($this->subscriptionPropertyMap, 0);
$fields[] = 'id';
$fields[] = 'uri';
$fields[] = 'source';
$fields[] = 'synctoken';
$fields[] = 'principaluri';
$fields[] = 'lastmodified';
$query = $this->db->getQueryBuilder();
$query->select($fields)
->from('calendarsubscriptions')
->where($query->expr()->eq('uri', $query->createNamedParameter($uri)))
->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal)))
->setMaxResults(1);
$stmt = $query->executeQuery();
$row = $stmt->fetch();
$stmt->closeCursor();
if ($row === false) {
return null;
}
$row['principaluri'] = (string)$row['principaluri'];
$subscription = [
'id' => $row['id'],
'uri' => $row['uri'],
'principaluri' => $row['principaluri'],
'source' => $row['source'],
'lastmodified' => $row['lastmodified'],
'{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']),
'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ?: '0',
];
return $this->rowToSubscription($row, $subscription);
}
/**
* Creates a new calendar for a principal.
*

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
use OCA\DAV\CalDAV\CachedSubscription;
use OCA\DAV\CalDAV\CalDavBackend;
use OCP\IUserManager;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(
name: 'dav:delete-subscription',
description: 'Delete a calendar subscription for a user',
hidden: false,
)]
class DeleteSubscription extends Command {
public function __construct(
private CalDavBackend $calDavBackend,
private IUserManager $userManager,
) {
parent::__construct();
}
protected function configure(): void {
$this
->addArgument(
'uid',
InputArgument::REQUIRED,
'User who owns the calendar subscription'
)
->addArgument(
'uri',
InputArgument::REQUIRED,
'URI of the calendar to be deleted'
);
}
protected function execute(InputInterface $input, OutputInterface $output): int {
$user = (string)$input->getArgument('uid');
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User $user is unknown");
}
$uri = (string)$input->getArgument('uri');
if ($uri === '') {
throw new \InvalidArgumentException('Specify the URI of the calendar to be deleted');
}
$subscriptionInfo = $this->calDavBackend->getSubscriptionByUri(
'principals/users/' . $user,
$uri
);
if ($subscriptionInfo === null) {
throw new \InvalidArgumentException("User $user has no calendar subscription with the URI $uri");
}
$subscription = new CachedSubscription(
$this->calDavBackend,
$subscriptionInfo,
);
$subscription->delete();
$output->writeln("Calendar subscription with the URI $uri for user $user deleted");
return self::SUCCESS;
}
}

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
use OCA\DAV\CalDAV\CalDavBackend;
use OCP\IAppConfig;
use OCP\IUserManager;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(
name: 'dav:list-subscriptions',
description: 'List all calendar subscriptions for a user',
hidden: false,
)]
class ListSubscriptions extends Command {
public function __construct(
private IUserManager $userManager,
private IAppConfig $appConfig,
private CalDavBackend $caldav,
) {
parent::__construct();
}
protected function configure(): void {
$this->addArgument(
'uid',
InputArgument::REQUIRED,
'User whose calendar subscriptions will be listed'
);
}
protected function execute(InputInterface $input, OutputInterface $output): int {
$user = (string)$input->getArgument('uid');
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException("User $user is unknown");
}
$defaultRefreshRate = $this->appConfig->getValueString('dav', 'calendarSubscriptionRefreshRate', 'P1D');
$subscriptions = $this->caldav->getSubscriptionsForUser("principals/users/$user");
$rows = [];
foreach ($subscriptions as $subscription) {
$rows[] = [
$subscription['uri'],
$subscription['{DAV:}displayname'],
$subscription['{http://apple.com/ns/ical/}refreshrate'] ?? ($defaultRefreshRate . ' (default)'),
$subscription['source'],
];
}
usort($rows, static fn (array $a, array $b) => $a[0] <=> $b[0]);
if (count($rows) > 0) {
$table = new Table($output);
$table
->setHeaders(['URI', 'Displayname', 'Refresh rate', 'Source'])
->setRows($rows)
->render();
} else {
$output->writeln("User $user has no subscriptions");
}
return self::SUCCESS;
}
}