aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorDaniel Kesselberg <mail@danielkesselberg.de>2025-02-28 13:28:07 +0100
committerDaniel <mail@danielkesselberg.de>2025-03-09 16:08:38 +0100
commitc410e08fec9cf771c08c63d0e8e93ab825f40841 (patch)
tree0a41529839879d66d014c55c9f167912fd97036f /apps
parent016519c5b0f8a82a184f9d8bd625ba67ad916473 (diff)
downloadnextcloud-server-c410e08fec9cf771c08c63d0e8e93ab825f40841.tar.gz
nextcloud-server-c410e08fec9cf771c08c63d0e8e93ab825f40841.zip
feat: command to list and delete calendar subscriptionsfeat/noid/occ-list-delete-calendar-subscription
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/appinfo/info.xml8
-rw-r--r--apps/dav/composer/composer/autoload_classmap.php2
-rw-r--r--apps/dav/composer/composer/autoload_static.php2
-rw-r--r--apps/dav/lib/CalDAV/CalDavBackend.php37
-rw-r--r--apps/dav/lib/Command/DeleteSubscription.php79
-rw-r--r--apps/dav/lib/Command/ListSubscriptions.php77
6 files changed, 202 insertions, 3 deletions
diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml
index 6abc8ac9d80..222b5e14b8c 100644
--- a/apps/dav/appinfo/info.xml
+++ b/apps/dav/appinfo/info.xml
@@ -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>
diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php
index 17533c9cf74..13d7c05379b 100644
--- a/apps/dav/composer/composer/autoload_classmap.php
+++ b/apps/dav/composer/composer/autoload_classmap.php
@@ -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',
diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php
index 768fda98443..237ab53558c 100644
--- a/apps/dav/composer/composer/autoload_static.php
+++ b/apps/dav/composer/composer/autoload_static.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',
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php
index 349a4ec3630..81e999cc356 100644
--- a/apps/dav/lib/CalDAV/CalDavBackend.php
+++ b/apps/dav/lib/CalDAV/CalDavBackend.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.
*
diff --git a/apps/dav/lib/Command/DeleteSubscription.php b/apps/dav/lib/Command/DeleteSubscription.php
new file mode 100644
index 00000000000..db0cb6295c9
--- /dev/null
+++ b/apps/dav/lib/Command/DeleteSubscription.php
@@ -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;
+ }
+}
diff --git a/apps/dav/lib/Command/ListSubscriptions.php b/apps/dav/lib/Command/ListSubscriptions.php
new file mode 100644
index 00000000000..67753f25973
--- /dev/null
+++ b/apps/dav/lib/Command/ListSubscriptions.php
@@ -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;
+ }
+}