aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/Command
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav/lib/Command')
-rw-r--r--apps/dav/lib/Command/ClearCalendarUnshares.php114
-rw-r--r--apps/dav/lib/Command/ClearContactsPhotoCache.php75
-rw-r--r--apps/dav/lib/Command/CreateAddressBook.php63
-rw-r--r--apps/dav/lib/Command/CreateCalendar.php86
-rw-r--r--apps/dav/lib/Command/CreateSubscription.php78
-rw-r--r--apps/dav/lib/Command/DeleteCalendar.php64
-rw-r--r--apps/dav/lib/Command/DeleteSubscription.php79
-rw-r--r--apps/dav/lib/Command/ExportCalendar.php95
-rw-r--r--apps/dav/lib/Command/FixCalendarSyncCommand.php73
-rw-r--r--apps/dav/lib/Command/GetAbsenceCommand.php62
-rw-r--r--apps/dav/lib/Command/ListAddressbooks.php76
-rw-r--r--apps/dav/lib/Command/ListCalendarShares.php131
-rw-r--r--apps/dav/lib/Command/ListCalendars.php49
-rw-r--r--apps/dav/lib/Command/ListSubscriptions.php77
-rw-r--r--apps/dav/lib/Command/MoveCalendar.php88
-rw-r--r--apps/dav/lib/Command/RemoveInvalidShares.php49
-rw-r--r--apps/dav/lib/Command/RetentionCleanupCommand.php32
-rw-r--r--apps/dav/lib/Command/SendEventReminders.php52
-rw-r--r--apps/dav/lib/Command/SetAbsenceCommand.php95
-rw-r--r--apps/dav/lib/Command/SyncBirthdayCalendar.php66
-rw-r--r--apps/dav/lib/Command/SyncSystemAddressBook.php49
21 files changed, 1100 insertions, 453 deletions
diff --git a/apps/dav/lib/Command/ClearCalendarUnshares.php b/apps/dav/lib/Command/ClearCalendarUnshares.php
new file mode 100644
index 00000000000..bb367a9cd0f
--- /dev/null
+++ b/apps/dav/lib/Command/ClearCalendarUnshares.php
@@ -0,0 +1,114 @@
+<?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 OCA\DAV\CalDAV\Sharing\Backend;
+use OCA\DAV\CalDAV\Sharing\Service;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCA\DAV\DAV\Sharing\Backend as BackendAlias;
+use OCA\DAV\DAV\Sharing\SharingMapper;
+use OCP\IAppConfig;
+use OCP\IUserManager;
+use Symfony\Component\Console\Attribute\AsCommand;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\QuestionHelper;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+#[AsCommand(
+ name: 'dav:clear-calendar-unshares',
+ description: 'Clear calendar unshares for a user',
+ hidden: false,
+)]
+class ClearCalendarUnshares extends Command {
+ public function __construct(
+ private IUserManager $userManager,
+ private IAppConfig $appConfig,
+ private Principal $principal,
+ private CalDavBackend $caldav,
+ private Backend $sharingBackend,
+ private Service $sharingService,
+ private SharingMapper $mapper,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this->addArgument(
+ 'uid',
+ InputArgument::REQUIRED,
+ 'User whose unshares to clear'
+ );
+ }
+
+ 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");
+ }
+
+ $principal = $this->principal->getPrincipalByPath('principals/users/' . $user);
+ if ($principal === null) {
+ throw new \InvalidArgumentException("Unable to fetch principal for user $user ");
+ }
+
+ $shares = $this->mapper->getSharesByPrincipals([$principal['uri']], 'calendar');
+ $unshares = array_filter($shares, static fn ($share) => $share['access'] === BackendAlias::ACCESS_UNSHARED);
+
+ if (count($unshares) === 0) {
+ $output->writeln("User $user has no calendar unshares");
+ return self::SUCCESS;
+ }
+
+ $rows = array_map(fn ($share) => $this->formatCalendarUnshare($share), $shares);
+
+ $table = new Table($output);
+ $table
+ ->setHeaders(['Share Id', 'Calendar Id', 'Calendar URI', 'Calendar Name'])
+ ->setRows($rows)
+ ->render();
+
+ $output->writeln('');
+
+ /** @var QuestionHelper $helper */
+ $helper = $this->getHelper('question');
+ $question = new ConfirmationQuestion('Please confirm to delete the above calendar unshare entries [y/n]', false);
+
+ if ($helper->ask($input, $output, $question)) {
+ $this->mapper->deleteUnsharesByPrincipal($principal['uri'], 'calendar');
+ $output->writeln("Calendar unshares for user $user deleted");
+ }
+
+ return self::SUCCESS;
+ }
+
+ private function formatCalendarUnshare(array $share): array {
+ $calendarInfo = $this->caldav->getCalendarById($share['resourceid']);
+
+ $resourceUri = 'Resource not found';
+ $resourceName = '';
+
+ if ($calendarInfo !== null) {
+ $resourceUri = $calendarInfo['uri'];
+ $resourceName = $calendarInfo['{DAV:}displayname'];
+ }
+
+ return [
+ $share['id'],
+ $share['resourceid'],
+ $resourceUri,
+ $resourceName,
+ ];
+ }
+}
diff --git a/apps/dav/lib/Command/ClearContactsPhotoCache.php b/apps/dav/lib/Command/ClearContactsPhotoCache.php
new file mode 100644
index 00000000000..82e64c3145a
--- /dev/null
+++ b/apps/dav/lib/Command/ClearContactsPhotoCache.php
@@ -0,0 +1,75 @@
+<?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 OCP\Files\AppData\IAppDataFactory;
+use OCP\Files\NotPermittedException;
+use Symfony\Component\Console\Attribute\AsCommand;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Helper\QuestionHelper;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+#[AsCommand(
+ name: 'dav:clear-contacts-photo-cache',
+ description: 'Clear cached contact photos',
+ hidden: false,
+)]
+class ClearContactsPhotoCache extends Command {
+
+ public function __construct(
+ private IAppDataFactory $appDataFactory,
+ ) {
+ parent::__construct();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $photoCacheAppData = $this->appDataFactory->get('dav-photocache');
+
+ $folders = $photoCacheAppData->getDirectoryListing();
+ $countFolders = count($folders);
+
+ if ($countFolders === 0) {
+ $output->writeln('No cached contact photos found.');
+ return self::SUCCESS;
+ }
+
+ $output->writeln('Found ' . count($folders) . ' cached contact photos.');
+
+ /** @var QuestionHelper $helper */
+ $helper = $this->getHelper('question');
+ $question = new ConfirmationQuestion('Please confirm to clear the contacts photo cache [y/n] ', true);
+
+ if ($helper->ask($input, $output, $question) === false) {
+ $output->writeln('Clearing the contacts photo cache aborted.');
+ return self::SUCCESS;
+ }
+
+ $progressBar = new ProgressBar($output, $countFolders);
+ $progressBar->start();
+
+ foreach ($folders as $folder) {
+ try {
+ $folder->delete();
+ } catch (NotPermittedException) {
+ }
+ $progressBar->advance();
+ }
+
+ $progressBar->finish();
+
+ $output->writeln('');
+ $output->writeln('Contacts photo cache cleared.');
+
+ return self::SUCCESS;
+ }
+}
diff --git a/apps/dav/lib/Command/CreateAddressBook.php b/apps/dav/lib/Command/CreateAddressBook.php
index 3d56d95868d..9626edeba26 100644
--- a/apps/dav/lib/Command/CreateAddressBook.php
+++ b/apps/dav/lib/Command/CreateAddressBook.php
@@ -1,26 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\DAV\Command;
@@ -32,35 +15,23 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateAddressBook extends Command {
-
- /** @var IUserManager */
- private $userManager;
-
- /** @var CardDavBackend */
- private $cardDavBackend;
-
- /**
- * @param IUserManager $userManager
- * @param CardDavBackend $cardDavBackend
- */
- public function __construct(IUserManager $userManager,
- CardDavBackend $cardDavBackend
+ public function __construct(
+ private IUserManager $userManager,
+ private CardDavBackend $cardDavBackend,
) {
parent::__construct();
- $this->userManager = $userManager;
- $this->cardDavBackend = $cardDavBackend;
}
- protected function configure() {
+ protected function configure(): void {
$this
- ->setName('dav:create-addressbook')
- ->setDescription('Create a dav addressbook')
- ->addArgument('user',
- InputArgument::REQUIRED,
- 'User for whom the addressbook will be created')
- ->addArgument('name',
- InputArgument::REQUIRED,
- 'Name of the addressbook');
+ ->setName('dav:create-addressbook')
+ ->setDescription('Create a dav addressbook')
+ ->addArgument('user',
+ InputArgument::REQUIRED,
+ 'User for whom the addressbook will be created')
+ ->addArgument('name',
+ InputArgument::REQUIRED,
+ 'Name of the addressbook');
}
protected function execute(InputInterface $input, OutputInterface $output): int {
@@ -71,6 +42,6 @@ class CreateAddressBook extends Command {
$name = $input->getArgument('name');
$this->cardDavBackend->createAddressBook("principals/users/$user", $name, []);
- return 0;
+ return self::SUCCESS;
}
}
diff --git a/apps/dav/lib/Command/CreateCalendar.php b/apps/dav/lib/Command/CreateCalendar.php
index 08f937dff9d..033b5f8d347 100644
--- a/apps/dav/lib/Command/CreateCalendar.php
+++ b/apps/dav/lib/Command/CreateCalendar.php
@@ -1,40 +1,27 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Thomas Citharel <nextcloud@tcit.fr>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\DAV\Command;
use OC\KnownUser\KnownUserService;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
+use OCA\DAV\CalDAV\Sharing\Backend;
use OCA\DAV\Connector\Sabre\Principal;
use OCP\Accounts\IAccountManager;
+use OCP\App\IAppManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IUserManager;
+use OCP\IUserSession;
+use OCP\Security\ISecureRandom;
+use OCP\Server;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -42,29 +29,15 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateCalendar extends Command {
-
- /** @var IUserManager */
- protected $userManager;
-
- /** @var IGroupManager $groupManager */
- private $groupManager;
-
- /** @var \OCP\IDBConnection */
- protected $dbConnection;
-
- /**
- * @param IUserManager $userManager
- * @param IGroupManager $groupManager
- * @param IDBConnection $dbConnection
- */
- public function __construct(IUserManager $userManager, IGroupManager $groupManager, IDBConnection $dbConnection) {
+ public function __construct(
+ protected IUserManager $userManager,
+ private IGroupManager $groupManager,
+ protected IDBConnection $dbConnection,
+ ) {
parent::__construct();
- $this->userManager = $userManager;
- $this->groupManager = $groupManager;
- $this->dbConnection = $dbConnection;
}
- protected function configure() {
+ protected function configure(): void {
$this
->setName('dav:create-calendar')
->setDescription('Create a dav calendar')
@@ -84,32 +57,31 @@ class CreateCalendar extends Command {
$principalBackend = new Principal(
$this->userManager,
$this->groupManager,
- \OC::$server->get(IAccountManager::class),
- \OC::$server->getShareManager(),
- \OC::$server->getUserSession(),
- \OC::$server->getAppManager(),
- \OC::$server->query(ProxyMapper::class),
- \OC::$server->get(KnownUserService::class),
- \OC::$server->getConfig(),
+ Server::get(IAccountManager::class),
+ Server::get(\OCP\Share\IManager::class),
+ Server::get(IUserSession::class),
+ Server::get(IAppManager::class),
+ Server::get(ProxyMapper::class),
+ Server::get(KnownUserService::class),
+ Server::get(IConfig::class),
\OC::$server->getL10NFactory(),
);
- $random = \OC::$server->getSecureRandom();
- $logger = \OC::$server->get(LoggerInterface::class);
- $dispatcher = \OC::$server->get(IEventDispatcher::class);
- $config = \OC::$server->get(IConfig::class);
-
+ $random = Server::get(ISecureRandom::class);
+ $logger = Server::get(LoggerInterface::class);
+ $dispatcher = Server::get(IEventDispatcher::class);
+ $config = Server::get(IConfig::class);
$name = $input->getArgument('name');
$caldav = new CalDavBackend(
$this->dbConnection,
$principalBackend,
$this->userManager,
- $this->groupManager,
$random,
$logger,
$dispatcher,
- $config
+ $config,
+ Server::get(Backend::class),
);
$caldav->createCalendar("principals/users/$user", $name, []);
- return 0;
+ return self::SUCCESS;
}
}
diff --git a/apps/dav/lib/Command/CreateSubscription.php b/apps/dav/lib/Command/CreateSubscription.php
new file mode 100644
index 00000000000..1364070e530
--- /dev/null
+++ b/apps/dav/lib/Command/CreateSubscription.php
@@ -0,0 +1,78 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\DAV\Command;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\Theming\ThemingDefaults;
+use OCP\IUserManager;
+use Sabre\DAV\Xml\Property\Href;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class CreateSubscription extends Command {
+ public function __construct(
+ protected IUserManager $userManager,
+ private CalDavBackend $caldav,
+ private ThemingDefaults $themingDefaults,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this
+ ->setName('dav:create-subscription')
+ ->setDescription('Create a dav subscription')
+ ->addArgument('user',
+ InputArgument::REQUIRED,
+ 'User for whom the subscription will be created')
+ ->addArgument('name',
+ InputArgument::REQUIRED,
+ 'Name of the subscription to create')
+ ->addArgument('url',
+ InputArgument::REQUIRED,
+ 'Source url of the subscription to create')
+ ->addArgument('color',
+ InputArgument::OPTIONAL,
+ 'Hex color code for the calendar color');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $user = $input->getArgument('user');
+ if (!$this->userManager->userExists($user)) {
+ $output->writeln("<error>User <$user> in unknown.</error>");
+ return self::FAILURE;
+ }
+
+ $name = $input->getArgument('name');
+ $url = $input->getArgument('url');
+ $color = $input->getArgument('color') ?? $this->themingDefaults->getColorPrimary();
+ $subscriptions = $this->caldav->getSubscriptionsForUser("principals/users/$user");
+
+ $exists = array_filter($subscriptions, function ($row) use ($url) {
+ return $row['source'] === $url;
+ });
+
+ if (!empty($exists)) {
+ $output->writeln("<error>Subscription for url <$url> already exists for this user.</error>");
+ return self::FAILURE;
+ }
+
+ $urlProperty = new Href($url);
+ $properties = ['{http://owncloud.org/ns}calendar-enabled' => 1,
+ '{DAV:}displayname' => $name,
+ '{http://apple.com/ns/ical/}calendar-color' => $color,
+ '{http://calendarserver.org/ns/}source' => $urlProperty,
+ ];
+ $this->caldav->createSubscription("principals/users/$user", $name, $properties);
+ return self::SUCCESS;
+ }
+
+}
diff --git a/apps/dav/lib/Command/DeleteCalendar.php b/apps/dav/lib/Command/DeleteCalendar.php
index dd5f11c740f..f6dbed856e6 100644
--- a/apps/dav/lib/Command/DeleteCalendar.php
+++ b/apps/dav/lib/Command/DeleteCalendar.php
@@ -2,24 +2,8 @@
declare(strict_types=1);
/**
- *
- * @copyright Copyright (c) 2021, Mattia Narducci (mattianarducci1@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 <https://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
@@ -38,40 +22,14 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class DeleteCalendar extends Command {
- /** @var CalDavBackend */
- private $calDav;
-
- /** @var IConfig */
- private $config;
-
- /** @var IL10N */
- private $l10n;
-
- /** @var IUserManager */
- private $userManager;
-
- /** @var LoggerInterface */
- private $logger;
-
- /**
- * @param CalDavBackend $calDav
- * @param IConfig $config
- * @param IL10N $l10n
- * @param IUserManager $userManager
- */
public function __construct(
- CalDavBackend $calDav,
- IConfig $config,
- IL10N $l10n,
- IUserManager $userManager,
- LoggerInterface $logger
+ private CalDavBackend $calDav,
+ private IConfig $config,
+ private IL10N $l10n,
+ private IUserManager $userManager,
+ private LoggerInterface $logger,
) {
parent::__construct();
- $this->calDav = $calDav;
- $this->config = $config;
- $this->l10n = $l10n;
- $this->userManager = $userManager;
- $this->logger = $logger;
}
protected function configure(): void {
@@ -96,9 +54,9 @@ class DeleteCalendar extends Command {
protected function execute(
InputInterface $input,
- OutputInterface $output
+ OutputInterface $output,
): int {
- /** @var string $user **/
+ /** @var string $user */
$user = $input->getArgument('uid');
if (!$this->userManager->userExists($user)) {
throw new \InvalidArgumentException(
@@ -109,7 +67,7 @@ class DeleteCalendar extends Command {
if ($birthday !== false) {
$name = BirthdayService::BIRTHDAY_CALENDAR_URI;
} else {
- /** @var string $name **/
+ /** @var string $name */
$name = $input->getArgument('name');
if (!$name) {
throw new \InvalidArgumentException(
@@ -140,6 +98,6 @@ class DeleteCalendar extends Command {
$calendar->delete();
- return 0;
+ return self::SUCCESS;
}
}
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/ExportCalendar.php b/apps/dav/lib/Command/ExportCalendar.php
new file mode 100644
index 00000000000..6ed8aa2cfe4
--- /dev/null
+++ b/apps/dav/lib/Command/ExportCalendar.php
@@ -0,0 +1,95 @@
+<?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 InvalidArgumentException;
+use OCA\DAV\CalDAV\Export\ExportService;
+use OCP\Calendar\CalendarExportOptions;
+use OCP\Calendar\ICalendarExport;
+use OCP\Calendar\IManager;
+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\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Calendar Export Command
+ *
+ * Used to export data from supported calendars to disk or stdout
+ */
+#[AsCommand(
+ name: 'calendar:export',
+ description: 'Export calendar data from supported calendars to disk or stdout',
+ hidden: false
+)]
+class ExportCalendar extends Command {
+ public function __construct(
+ private IUserManager $userManager,
+ private IManager $calendarManager,
+ private ExportService $exportService,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this->setName('calendar:export')
+ ->setDescription('Export calendar data from supported calendars to disk or stdout')
+ ->addArgument('uid', InputArgument::REQUIRED, 'Id of system user')
+ ->addArgument('uri', InputArgument::REQUIRED, 'Uri of calendar')
+ ->addOption('format', null, InputOption::VALUE_REQUIRED, 'Format of output (ical, jcal, xcal) defaults to ical', 'ical')
+ ->addOption('location', null, InputOption::VALUE_REQUIRED, 'Location of where to write the output. defaults to stdout');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $userId = $input->getArgument('uid');
+ $calendarId = $input->getArgument('uri');
+ $format = $input->getOption('format');
+ $location = $input->getOption('location');
+
+ if (!$this->userManager->userExists($userId)) {
+ throw new InvalidArgumentException("User <$userId> not found.");
+ }
+ // retrieve calendar and evaluate if export is supported
+ $calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $userId, [$calendarId]);
+ if ($calendars === []) {
+ throw new InvalidArgumentException("Calendar <$calendarId> not found.");
+ }
+ $calendar = $calendars[0];
+ if (!$calendar instanceof ICalendarExport) {
+ throw new InvalidArgumentException("Calendar <$calendarId> does not support exporting");
+ }
+ // construct options object
+ $options = new CalendarExportOptions();
+ // evaluate if provided format is supported
+ if (!in_array($format, ExportService::FORMATS, true)) {
+ throw new InvalidArgumentException("Format <$format> is not valid.");
+ }
+ $options->setFormat($format);
+ // evaluate is a valid location was given and is usable otherwise output to stdout
+ if ($location !== null) {
+ $handle = fopen($location, 'wb');
+ if ($handle === false) {
+ throw new InvalidArgumentException("Location <$location> is not valid. Can not open location for write operation.");
+ }
+
+ foreach ($this->exportService->export($calendar, $options) as $chunk) {
+ fwrite($handle, $chunk);
+ }
+ fclose($handle);
+ } else {
+ foreach ($this->exportService->export($calendar, $options) as $chunk) {
+ $output->writeln($chunk);
+ }
+ }
+
+ return self::SUCCESS;
+ }
+}
diff --git a/apps/dav/lib/Command/FixCalendarSyncCommand.php b/apps/dav/lib/Command/FixCalendarSyncCommand.php
new file mode 100644
index 00000000000..cb31355c10d
--- /dev/null
+++ b/apps/dav/lib/Command/FixCalendarSyncCommand.php
@@ -0,0 +1,73 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\DAV\Command;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCP\IUser;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class FixCalendarSyncCommand extends Command {
+
+ public function __construct(
+ private IUserManager $userManager,
+ private CalDavBackend $calDavBackend,
+ ) {
+ parent::__construct('dav:fix-missing-caldav-changes');
+ }
+
+ protected function configure(): void {
+ $this->setDescription('Insert missing calendarchanges rows for existing events');
+ $this->addArgument(
+ 'user',
+ InputArgument::OPTIONAL,
+ 'User to fix calendar sync tokens for, if omitted all users will be fixed',
+ null,
+ );
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output): int {
+ $userArg = $input->getArgument('user');
+ if ($userArg !== null) {
+ $user = $this->userManager->get($userArg);
+ if ($user === null) {
+ $output->writeln("<error>User $userArg does not exist</error>");
+ return self::FAILURE;
+ }
+
+ $this->fixUserCalendars($user);
+ } else {
+ $progress = new ProgressBar($output);
+ $this->userManager->callForSeenUsers(function (IUser $user) use ($progress): void {
+ $this->fixUserCalendars($user, $progress);
+ });
+ $progress->finish();
+ }
+ $output->writeln('');
+ return self::SUCCESS;
+ }
+
+ private function fixUserCalendars(IUser $user, ?ProgressBar $progress = null): void {
+ $calendars = $this->calDavBackend->getCalendarsForUser('principals/users/' . $user->getUID());
+
+ foreach ($calendars as $calendar) {
+ $this->calDavBackend->restoreChanges($calendar['id']);
+ }
+
+ if ($progress !== null) {
+ $progress->advance();
+ }
+ }
+
+}
diff --git a/apps/dav/lib/Command/GetAbsenceCommand.php b/apps/dav/lib/Command/GetAbsenceCommand.php
new file mode 100644
index 00000000000..50d8df4ab38
--- /dev/null
+++ b/apps/dav/lib/Command/GetAbsenceCommand.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+namespace OCA\DAV\Command;
+
+use OCA\DAV\Service\AbsenceService;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class GetAbsenceCommand extends Command {
+
+ public function __construct(
+ private IUserManager $userManager,
+ private AbsenceService $absenceService,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this->setName('dav:absence:get');
+ $this->addArgument(
+ 'user-id',
+ InputArgument::REQUIRED,
+ 'User ID of the affected account'
+ );
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output): int {
+ $userId = $input->getArgument('user-id');
+
+ $user = $this->userManager->get($userId);
+ if ($user === null) {
+ $output->writeln('<error>User not found</error>');
+ return 1;
+ }
+
+ $absence = $this->absenceService->getAbsence($userId);
+ if ($absence === null) {
+ $output->writeln('<info>No absence set</info>');
+ return 0;
+ }
+
+ $output->writeln('<info>Start day:</info> ' . $absence->getFirstDay());
+ $output->writeln('<info>End day:</info> ' . $absence->getLastDay());
+ $output->writeln('<info>Short message:</info> ' . $absence->getStatus());
+ $output->writeln('<info>Message:</info> ' . $absence->getMessage());
+ $output->writeln('<info>Replacement user:</info> ' . ($absence->getReplacementUserId() ?? 'none'));
+ $output->writeln('<info>Replacement display name:</info> ' . ($absence->getReplacementUserDisplayName() ?? 'none'));
+
+ return 0;
+ }
+
+}
diff --git a/apps/dav/lib/Command/ListAddressbooks.php b/apps/dav/lib/Command/ListAddressbooks.php
new file mode 100644
index 00000000000..c0b6e63ccb8
--- /dev/null
+++ b/apps/dav/lib/Command/ListAddressbooks.php
@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\DAV\Command;
+
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\DAV\CardDAV\SystemAddressbook;
+use OCP\IUserManager;
+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;
+
+class ListAddressbooks extends Command {
+ public function __construct(
+ protected IUserManager $userManager,
+ private CardDavBackend $cardDavBackend,
+ ) {
+ parent::__construct('dav:list-addressbooks');
+ }
+
+ protected function configure(): void {
+ $this
+ ->setDescription('List all addressbooks of a user')
+ ->addArgument('uid',
+ InputArgument::REQUIRED,
+ 'User for whom all addressbooks will be listed');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $user = $input->getArgument('uid');
+ if (!$this->userManager->userExists($user)) {
+ throw new \InvalidArgumentException("User <$user> is unknown.");
+ }
+
+ $addressBooks = $this->cardDavBackend->getAddressBooksForUser("principals/users/$user");
+
+ $addressBookTableData = [];
+ foreach ($addressBooks as $book) {
+ // skip system / contacts integration address book
+ if ($book['uri'] === SystemAddressbook::URI_SHARED) {
+ continue;
+ }
+
+ $readOnly = false;
+ $readOnlyIndex = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only';
+ if (isset($book[$readOnlyIndex])) {
+ $readOnly = $book[$readOnlyIndex];
+ }
+
+ $addressBookTableData[] = [
+ $book['uri'],
+ $book['{DAV:}displayname'],
+ $book['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal'] ?? $book['principaluri'],
+ $book['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}owner-displayname'],
+ $readOnly ? ' x ' : ' ✓ ',
+ ];
+ }
+
+ if (count($addressBookTableData) > 0) {
+ $table = new Table($output);
+ $table->setHeaders(['Database ID', 'URI', 'Displayname', 'Owner principal', 'Owner displayname', 'Writable'])
+ ->setRows($addressBookTableData);
+
+ $table->render();
+ } else {
+ $output->writeln("<info>User <$user> has no addressbooks</info>");
+ }
+ return self::SUCCESS;
+ }
+}
diff --git a/apps/dav/lib/Command/ListCalendarShares.php b/apps/dav/lib/Command/ListCalendarShares.php
new file mode 100644
index 00000000000..2729bc80530
--- /dev/null
+++ b/apps/dav/lib/Command/ListCalendarShares.php
@@ -0,0 +1,131 @@
+<?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 OCA\DAV\CalDAV\Sharing\Backend;
+use OCA\DAV\Connector\Sabre\Principal;
+use OCA\DAV\DAV\Sharing\SharingMapper;
+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\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+#[AsCommand(
+ name: 'dav:list-calendar-shares',
+ description: 'List all calendar shares for a user',
+ hidden: false,
+)]
+class ListCalendarShares extends Command {
+ public function __construct(
+ private IUserManager $userManager,
+ private Principal $principal,
+ private CalDavBackend $caldav,
+ private SharingMapper $mapper,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this->addArgument(
+ 'uid',
+ InputArgument::REQUIRED,
+ 'User whose calendar shares will be listed'
+ );
+ $this->addOption(
+ 'calendar-id',
+ '',
+ InputOption::VALUE_REQUIRED,
+ 'List only shares for the given calendar id id',
+ null,
+ );
+ }
+
+ 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");
+ }
+
+ $principal = $this->principal->getPrincipalByPath('principals/users/' . $user);
+ if ($principal === null) {
+ throw new \InvalidArgumentException("Unable to fetch principal for user $user");
+ }
+
+ $memberships = array_merge(
+ [$principal['uri']],
+ $this->principal->getGroupMembership($principal['uri']),
+ $this->principal->getCircleMembership($principal['uri']),
+ );
+
+ $shares = $this->mapper->getSharesByPrincipals($memberships, 'calendar');
+
+ $calendarId = $input->getOption('calendar-id');
+ if ($calendarId !== null) {
+ $shares = array_filter($shares, fn ($share) => $share['resourceid'] === (int)$calendarId);
+ }
+
+ $rows = array_map(fn ($share) => $this->formatCalendarShare($share), $shares);
+
+ if (count($rows) > 0) {
+ $table = new Table($output);
+ $table
+ ->setHeaders(['Share Id', 'Calendar Id', 'Calendar URI', 'Calendar Name', 'Calendar Owner', 'Access By', 'Permissions'])
+ ->setRows($rows)
+ ->render();
+ } else {
+ $output->writeln("User $user has no calendar shares");
+ }
+
+ return self::SUCCESS;
+ }
+
+ private function formatCalendarShare(array $share): array {
+ $calendarInfo = $this->caldav->getCalendarById($share['resourceid']);
+
+ $calendarUri = 'Resource not found';
+ $calendarName = '';
+ $calendarOwner = '';
+
+ if ($calendarInfo !== null) {
+ $calendarUri = $calendarInfo['uri'];
+ $calendarName = $calendarInfo['{DAV:}displayname'];
+ $calendarOwner = $calendarInfo['{http://nextcloud.com/ns}owner-displayname'] . ' (' . $calendarInfo['principaluri'] . ')';
+ }
+
+ $accessBy = match (true) {
+ str_starts_with($share['principaluri'], 'principals/users/') => 'Individual',
+ str_starts_with($share['principaluri'], 'principals/groups/') => 'Group (' . $share['principaluri'] . ')',
+ str_starts_with($share['principaluri'], 'principals/circles/') => 'Team (' . $share['principaluri'] . ')',
+ default => $share['principaluri'],
+ };
+
+ $permissions = match ($share['access']) {
+ Backend::ACCESS_READ => 'Read',
+ Backend::ACCESS_READ_WRITE => 'Read/Write',
+ Backend::ACCESS_UNSHARED => 'Unshare',
+ default => $share['access'],
+ };
+
+ return [
+ $share['id'],
+ $share['resourceid'],
+ $calendarUri,
+ $calendarName,
+ $calendarOwner,
+ $accessBy,
+ $permissions,
+ ];
+ }
+}
diff --git a/apps/dav/lib/Command/ListCalendars.php b/apps/dav/lib/Command/ListCalendars.php
index 35581c2d4b2..408a7e5247f 100644
--- a/apps/dav/lib/Command/ListCalendars.php
+++ b/apps/dav/lib/Command/ListCalendars.php
@@ -1,27 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2018, Georg Ehrke
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Thomas Citharel <nextcloud@tcit.fr>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
@@ -35,24 +16,14 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ListCalendars extends Command {
-
- /** @var IUserManager */
- protected $userManager;
-
- /** @var CalDavBackend */
- private $caldav;
-
- /**
- * @param IUserManager $userManager
- * @param CalDavBackend $caldav
- */
- public function __construct(IUserManager $userManager, CalDavBackend $caldav) {
+ public function __construct(
+ protected IUserManager $userManager,
+ private CalDavBackend $caldav,
+ ) {
parent::__construct();
- $this->userManager = $userManager;
- $this->caldav = $caldav;
}
- protected function configure() {
+ protected function configure(): void {
$this
->setName('dav:list-calendars')
->setDescription('List all calendars of a user')
@@ -93,13 +64,13 @@ class ListCalendars extends Command {
if (count($calendarTableData) > 0) {
$table = new Table($output);
- $table->setHeaders(['uri', 'displayname', 'owner\'s userid', 'owner\'s displayname', 'writable'])
+ $table->setHeaders(['URI', 'Displayname', 'Owner principal', 'Owner displayname', 'Writable'])
->setRows($calendarTableData);
$table->render();
} else {
$output->writeln("<info>User <$user> has no calendars</info>");
}
- return 0;
+ 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;
+ }
+}
diff --git a/apps/dav/lib/Command/MoveCalendar.php b/apps/dav/lib/Command/MoveCalendar.php
index 9272b20b10d..b8acc191cc3 100644
--- a/apps/dav/lib/Command/MoveCalendar.php
+++ b/apps/dav/lib/Command/MoveCalendar.php
@@ -1,28 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2016 Thomas Citharel <nextcloud@tcit.fr>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Thomas Citharel <nextcloud@tcit.fr>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
@@ -42,37 +22,23 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class MoveCalendar extends Command {
- private IUserManager $userManager;
- private IGroupManager $groupManager;
- private IShareManager $shareManager;
- private IConfig $config;
- private IL10N $l10n;
private ?SymfonyStyle $io = null;
- private CalDavBackend $calDav;
- private LoggerInterface $logger;
public const URI_USERS = 'principals/users/';
public function __construct(
- IUserManager $userManager,
- IGroupManager $groupManager,
- IShareManager $shareManager,
- IConfig $config,
- IL10N $l10n,
- CalDavBackend $calDav,
- LoggerInterface $logger
+ private IUserManager $userManager,
+ private IGroupManager $groupManager,
+ private IShareManager $shareManager,
+ private IConfig $config,
+ private IL10N $l10n,
+ private CalDavBackend $calDav,
+ private LoggerInterface $logger,
) {
parent::__construct();
- $this->userManager = $userManager;
- $this->groupManager = $groupManager;
- $this->shareManager = $shareManager;
- $this->config = $config;
- $this->l10n = $l10n;
- $this->calDav = $calDav;
- $this->logger = $logger;
}
- protected function configure() {
+ protected function configure(): void {
$this
->setName('dav:move-calendar')
->setDescription('Move a calendar from an user to another')
@@ -85,7 +51,7 @@ class MoveCalendar extends Command {
->addArgument('destinationuid',
InputArgument::REQUIRED,
'User who will receive the calendar')
- ->addOption('force', 'f', InputOption::VALUE_NONE, "Force the migration by removing existing shares and renaming calendars in case of conflicts");
+ ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force the migration by removing existing shares and renaming calendars in case of conflicts');
}
protected function execute(InputInterface $input, OutputInterface $output): int {
@@ -107,7 +73,7 @@ class MoveCalendar extends Command {
$calendar = $this->calDav->getCalendarByUri(self::URI_USERS . $userOrigin, $name);
- if (null === $calendar) {
+ if ($calendar === null) {
throw new \InvalidArgumentException("User <$userOrigin> has no calendar named <$name>. You can run occ dav:list-calendars to list calendars URIs for this user.");
}
@@ -132,35 +98,27 @@ class MoveCalendar extends Command {
* Warn that share links have changed if there are shares
*/
$this->io->note([
- "Please note that moving calendar " . $calendar['uri'] . " from user <$userOrigin> to <$userDestination> has caused share links to change.",
- "Sharees will need to change \"example.com/remote.php/dav/calendars/uid/" . $calendar['uri'] . "_shared_by_$userOrigin\" to \"example.com/remote.php/dav/calendars/uid/" . $newName ?: $calendar['uri'] . "_shared_by_$userDestination\""
+ 'Please note that moving calendar ' . $calendar['uri'] . " from user <$userOrigin> to <$userDestination> has caused share links to change.",
+ 'Sharees will need to change "example.com/remote.php/dav/calendars/uid/' . $calendar['uri'] . "_shared_by_$userOrigin\" to \"example.com/remote.php/dav/calendars/uid/" . $newName ?: $calendar['uri'] . "_shared_by_$userDestination\""
]);
}
$this->calDav->moveCalendar($name, self::URI_USERS . $userOrigin, self::URI_USERS . $userDestination, $newName);
$this->io->success("Calendar <$name> was moved from user <$userOrigin> to <$userDestination>" . ($newName ? " as <$newName>" : ''));
- return 0;
+ return self::SUCCESS;
}
/**
* Check if the calendar exists for user
- *
- * @param string $userDestination
- * @param string $name
- * @return bool
*/
protected function calendarExists(string $userDestination, string $name): bool {
- return null !== $this->calDav->getCalendarByUri(self::URI_USERS . $userDestination, $name);
+ return $this->calDav->getCalendarByUri(self::URI_USERS . $userDestination, $name) !== null;
}
/**
* Try to find a suitable new calendar name that
- * doesn't exists for the provided user
- *
- * @param string $userDestination
- * @param string $name
- * @return string
+ * doesn't exist for the provided user
*/
protected function getNewCalendarName(string $userDestination, string $name): string {
$increment = 1;
@@ -182,10 +140,6 @@ class MoveCalendar extends Command {
/**
* Check that moving the calendar won't break shares
*
- * @param array $calendar
- * @param string $userOrigin
- * @param string $userDestination
- * @param bool $force
* @return bool had any shares or not
* @throws \InvalidArgumentException
*/
@@ -198,11 +152,11 @@ class MoveCalendar extends Command {
* Check that user destination is member of the groups which whom the calendar was shared
* If we ask to force the migration, the share with the group is dropped
*/
- if ($this->shareManager->shareWithGroupMembersOnly() === true && 'groups' === $prefix && !$this->groupManager->isInGroup($userDestination, $userOrGroup)) {
+ if ($this->shareManager->shareWithGroupMembersOnly() === true && $prefix === 'groups' && !$this->groupManager->isInGroup($userDestination, $userOrGroup)) {
if ($force) {
$this->calDav->updateShares(new Calendar($this->calDav, $calendar, $this->l10n, $this->config, $this->logger), [], ['principal:principals/groups/' . $userOrGroup]);
} else {
- throw new \InvalidArgumentException("User <$userDestination> is not part of the group <$userOrGroup> with whom the calendar <" . $calendar['uri'] . "> was shared. You may use -f to move the calendar while deleting this share.");
+ throw new \InvalidArgumentException("User <$userDestination> is not part of the group <$userOrGroup> with whom the calendar <" . $calendar['uri'] . '> was shared. You may use -f to move the calendar while deleting this share.');
}
}
@@ -213,7 +167,7 @@ class MoveCalendar extends Command {
if ($force) {
$this->calDav->updateShares(new Calendar($this->calDav, $calendar, $this->l10n, $this->config, $this->logger), [], ['principal:principals/users/' . $userOrGroup]);
} else {
- throw new \InvalidArgumentException("The calendar <" . $calendar['uri'] . "> is already shared to user <$userDestination>.You may use -f to move the calendar while deleting this share.");
+ throw new \InvalidArgumentException('The calendar <' . $calendar['uri'] . "> is already shared to user <$userDestination>.You may use -f to move the calendar while deleting this share.");
}
}
}
diff --git a/apps/dav/lib/Command/RemoveInvalidShares.php b/apps/dav/lib/Command/RemoveInvalidShares.php
index 4f9e4836a72..340e878a912 100644
--- a/apps/dav/lib/Command/RemoveInvalidShares.php
+++ b/apps/dav/lib/Command/RemoveInvalidShares.php
@@ -2,27 +2,11 @@
declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2018, ownCloud GmbH
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2018 ownCloud GmbH
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\DAV\Command;
@@ -37,21 +21,14 @@ use Symfony\Component\Console\Output\OutputInterface;
* have no matching principal. Happened because of a bug in the calendar app.
*/
class RemoveInvalidShares extends Command {
-
- /** @var IDBConnection */
- private $connection;
- /** @var Principal */
- private $principalBackend;
-
- public function __construct(IDBConnection $connection,
- Principal $principalBackend) {
+ public function __construct(
+ private IDBConnection $connection,
+ private Principal $principalBackend,
+ ) {
parent::__construct();
-
- $this->connection = $connection;
- $this->principalBackend = $principalBackend;
}
- protected function configure() {
+ protected function configure(): void {
$this
->setName('dav:remove-invalid-shares')
->setDescription('Remove invalid dav shares');
@@ -61,7 +38,7 @@ class RemoveInvalidShares extends Command {
$query = $this->connection->getQueryBuilder();
$result = $query->selectDistinct('principaluri')
->from('dav_shares')
- ->execute();
+ ->executeQuery();
while ($row = $result->fetch()) {
$principaluri = $row['principaluri'];
@@ -72,16 +49,16 @@ class RemoveInvalidShares extends Command {
}
$result->closeCursor();
- return 0;
+ return self::SUCCESS;
}
/**
* @param string $principaluri
*/
- private function deleteSharesForPrincipal($principaluri) {
+ private function deleteSharesForPrincipal($principaluri): void {
$delete = $this->connection->getQueryBuilder();
$delete->delete('dav_shares')
->where($delete->expr()->eq('principaluri', $delete->createNamedParameter($principaluri)));
- $delete->execute();
+ $delete->executeStatement();
}
}
diff --git a/apps/dav/lib/Command/RetentionCleanupCommand.php b/apps/dav/lib/Command/RetentionCleanupCommand.php
index c9beabc974a..f1c941af20e 100644
--- a/apps/dav/lib/Command/RetentionCleanupCommand.php
+++ b/apps/dav/lib/Command/RetentionCleanupCommand.php
@@ -3,25 +3,8 @@
declare(strict_types=1);
/**
- * @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
@@ -31,18 +14,15 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class RetentionCleanupCommand extends Command {
- /** @var RetentionService */
- private $service;
-
- public function __construct(RetentionService $service) {
+ public function __construct(
+ private RetentionService $service,
+ ) {
parent::__construct('dav:retention:clean-up');
-
- $this->service = $service;
}
protected function execute(InputInterface $input, OutputInterface $output): int {
$this->service->cleanUp();
- return 0;
+ return self::SUCCESS;
}
}
diff --git a/apps/dav/lib/Command/SendEventReminders.php b/apps/dav/lib/Command/SendEventReminders.php
index 697248d71a0..89bb5ce8c20 100644
--- a/apps/dav/lib/Command/SendEventReminders.php
+++ b/apps/dav/lib/Command/SendEventReminders.php
@@ -1,25 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2019, Georg Ehrke
- *
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.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/>.
- *
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Command;
@@ -35,22 +18,11 @@ use Symfony\Component\Console\Output\OutputInterface;
* @package OCA\DAV\Command
*/
class SendEventReminders extends Command {
-
- /** @var ReminderService */
- protected $reminderService;
-
- /** @var IConfig */
- protected $config;
-
- /**
- * @param ReminderService $reminderService
- * @param IConfig $config
- */
- public function __construct(ReminderService $reminderService,
- IConfig $config) {
+ public function __construct(
+ protected ReminderService $reminderService,
+ protected IConfig $config,
+ ) {
parent::__construct();
- $this->reminderService = $reminderService;
- $this->config = $config;
}
/**
@@ -62,24 +34,20 @@ class SendEventReminders extends Command {
->setDescription('Sends event reminders');
}
- /**
- * @param InputInterface $input
- * @param OutputInterface $output
- */
protected function execute(InputInterface $input, OutputInterface $output): int {
if ($this->config->getAppValue('dav', 'sendEventReminders', 'yes') !== 'yes') {
$output->writeln('<error>Sending event reminders disabled!</error>');
$output->writeln('<info>Please run "php occ config:app:set dav sendEventReminders --value yes"');
- return 1;
+ return self::FAILURE;
}
if ($this->config->getAppValue('dav', 'sendEventRemindersMode', 'backgroundjob') !== 'occ') {
$output->writeln('<error>Sending event reminders mode set to background-job!</error>');
$output->writeln('<info>Please run "php occ config:app:set dav sendEventRemindersMode --value occ"');
- return 1;
+ return self::FAILURE;
}
$this->reminderService->processReminders();
- return 0;
+ return self::SUCCESS;
}
}
diff --git a/apps/dav/lib/Command/SetAbsenceCommand.php b/apps/dav/lib/Command/SetAbsenceCommand.php
new file mode 100644
index 00000000000..bf91a163f95
--- /dev/null
+++ b/apps/dav/lib/Command/SetAbsenceCommand.php
@@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+namespace OCA\DAV\Command;
+
+use OCA\DAV\Service\AbsenceService;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SetAbsenceCommand extends Command {
+
+ public function __construct(
+ private IUserManager $userManager,
+ private AbsenceService $absenceService,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this->setName('dav:absence:set');
+ $this->addArgument(
+ 'user-id',
+ InputArgument::REQUIRED,
+ 'User ID of the affected account'
+ );
+ $this->addArgument(
+ 'first-day',
+ InputArgument::REQUIRED,
+ 'Inclusive start day formatted as YYYY-MM-DD'
+ );
+ $this->addArgument(
+ 'last-day',
+ InputArgument::REQUIRED,
+ 'Inclusive end day formatted as YYYY-MM-DD'
+ );
+ $this->addArgument(
+ 'short-message',
+ InputArgument::REQUIRED,
+ 'Short message'
+ );
+ $this->addArgument(
+ 'message',
+ InputArgument::REQUIRED,
+ 'Message'
+ );
+ $this->addArgument(
+ 'replacement-user-id',
+ InputArgument::OPTIONAL,
+ 'Replacement user id'
+ );
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output): int {
+ $userId = $input->getArgument('user-id');
+
+ $user = $this->userManager->get($userId);
+ if ($user === null) {
+ $output->writeln('<error>User not found</error>');
+ return 1;
+ }
+
+ $replacementUserId = $input->getArgument('replacement-user-id');
+ if ($replacementUserId === null) {
+ $replacementUser = null;
+ } else {
+ $replacementUser = $this->userManager->get($replacementUserId);
+ if ($replacementUser === null) {
+ $output->writeln('<error>Replacement user not found</error>');
+ return 2;
+ }
+ }
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ $input->getArgument('first-day'),
+ $input->getArgument('last-day'),
+ $input->getArgument('short-message'),
+ $input->getArgument('message'),
+ $replacementUser?->getUID(),
+ $replacementUser?->getDisplayName(),
+ );
+
+ return 0;
+ }
+
+}
diff --git a/apps/dav/lib/Command/SyncBirthdayCalendar.php b/apps/dav/lib/Command/SyncBirthdayCalendar.php
index 6de5357bfde..db1ebb6ecb5 100644
--- a/apps/dav/lib/Command/SyncBirthdayCalendar.php
+++ b/apps/dav/lib/Command/SyncBirthdayCalendar.php
@@ -1,26 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\DAV\Command;
@@ -35,30 +18,15 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SyncBirthdayCalendar extends Command {
-
- /** @var BirthdayService */
- private $birthdayService;
-
- /** @var IConfig */
- private $config;
-
- /** @var IUserManager */
- private $userManager;
-
- /**
- * @param IUserManager $userManager
- * @param IConfig $config
- * @param BirthdayService $birthdayService
- */
- public function __construct(IUserManager $userManager, IConfig $config,
- BirthdayService $birthdayService) {
+ public function __construct(
+ private IUserManager $userManager,
+ private IConfig $config,
+ private BirthdayService $birthdayService,
+ ) {
parent::__construct();
- $this->birthdayService = $birthdayService;
- $this->config = $config;
- $this->userManager = $userManager;
}
- protected function configure() {
+ protected function configure(): void {
$this
->setName('dav:sync-birthday-calendar')
->setDescription('Synchronizes the birthday calendar')
@@ -67,10 +35,6 @@ class SyncBirthdayCalendar extends Command {
'User for whom the birthday calendar will be synchronized');
}
- /**
- * @param InputInterface $input
- * @param OutputInterface $output
- */
protected function execute(InputInterface $input, OutputInterface $output): int {
$this->verifyEnabled();
@@ -89,12 +53,12 @@ class SyncBirthdayCalendar extends Command {
$output->writeln("Start birthday calendar sync for $user");
$this->birthdayService->syncUser($user);
- return 0;
+ return self::SUCCESS;
}
- $output->writeln("Start birthday calendar sync for all users ...");
+ $output->writeln('Start birthday calendar sync for all users ...');
$p = new ProgressBar($output);
$p->start();
- $this->userManager->callForSeenUsers(function ($user) use ($p) {
+ $this->userManager->callForSeenUsers(function ($user) use ($p): void {
$p->advance();
$userId = $user->getUID();
@@ -109,10 +73,10 @@ class SyncBirthdayCalendar extends Command {
$p->finish();
$output->writeln('');
- return 0;
+ return self::SUCCESS;
}
- protected function verifyEnabled() {
+ protected function verifyEnabled(): void {
$isEnabled = $this->config->getAppValue('dav', 'generateBirthdayCalendar', 'yes');
if ($isEnabled !== 'yes') {
diff --git a/apps/dav/lib/Command/SyncSystemAddressBook.php b/apps/dav/lib/Command/SyncSystemAddressBook.php
index 272cca5a08e..54edba01e05 100644
--- a/apps/dav/lib/Command/SyncSystemAddressBook.php
+++ b/apps/dav/lib/Command/SyncSystemAddressBook.php
@@ -1,67 +1,44 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\DAV\Command;
use OCA\DAV\CardDAV\SyncService;
+use OCP\IConfig;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SyncSystemAddressBook extends Command {
-
- /** @var SyncService */
- private $syncService;
-
- /**
- * @param SyncService $syncService
- */
- public function __construct(SyncService $syncService) {
+ public function __construct(
+ private SyncService $syncService,
+ private IConfig $config,
+ ) {
parent::__construct();
- $this->syncService = $syncService;
}
- protected function configure() {
+ protected function configure(): void {
$this
->setName('dav:sync-system-addressbook')
->setDescription('Synchronizes users to the system addressbook');
}
- /**
- * @param InputInterface $input
- * @param OutputInterface $output
- */
protected function execute(InputInterface $input, OutputInterface $output): int {
$output->writeln('Syncing users ...');
$progress = new ProgressBar($output);
$progress->start();
- $this->syncService->syncInstance(function () use ($progress) {
+ $this->syncService->syncInstance(function () use ($progress): void {
$progress->advance();
});
$progress->finish();
$output->writeln('');
- return 0;
+ $this->config->setAppValue('dav', 'needs_system_address_book_sync', 'no');
+ return self::SUCCESS;
}
}