Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 5 additions & 3 deletions apps/dav/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,11 @@
'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',
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
37 changes: 37 additions & 0 deletions apps/dav/lib/CalDAV/CalDavBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,43 @@ public function getSubscriptionById($subscriptionId) {
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.
*
Expand Down
79 changes: 79 additions & 0 deletions apps/dav/lib/Command/DeleteSubscription.php
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really hate, that we have to do this, but I get it at the moment there is no other way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the issue? I don't see it yet

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That we constantly have to append and remove 'principals/users/'

$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;
}
}
77 changes: 77 additions & 0 deletions apps/dav/lib/Command/ListSubscriptions.php
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading