diff --git a/apps/dav/lib/CardDAV/SyncService.php b/apps/dav/lib/CardDAV/SyncService.php index e6da3ed5923..279ef34669b 100644 --- a/apps/dav/lib/CardDAV/SyncService.php +++ b/apps/dav/lib/CardDAV/SyncService.php @@ -66,6 +66,7 @@ class SyncService { throw $ex; } + $received = []; // 3. apply changes // TODO: use multi-get for download foreach ($response['response'] as $resource => $status) { @@ -85,6 +86,15 @@ class SyncService { } } + // when doing a full sync, remove any items in the local address book that aren't in the remote one + if (!$syncToken) { + $existingCards = $this->backend->getCards($addressBookId); + $removedCards = array_filter($existingCards, fn (array $card) => !in_array($card['uri'], $received)); + foreach ($removedCards as $removedCard) { + $this->backend->deleteCard($addressBookId, $removedCard['uri']); + } + } + return [ $response['token'], $response['truncated'], diff --git a/apps/federation/lib/Command/SyncFederationAddressBooks.php b/apps/federation/lib/Command/SyncFederationAddressBooks.php index 36cb99473f7..0a2de8143dd 100644 --- a/apps/federation/lib/Command/SyncFederationAddressBooks.php +++ b/apps/federation/lib/Command/SyncFederationAddressBooks.php @@ -11,6 +11,7 @@ use OCA\Federation\SyncFederationAddressBooks as SyncService; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SyncFederationAddressBooks extends Command { @@ -23,19 +24,21 @@ class SyncFederationAddressBooks extends Command { protected function configure() { $this ->setName('federation:sync-addressbooks') - ->setDescription('Synchronizes addressbooks of all federated clouds'); + ->setDescription('Synchronizes addressbooks of all federated clouds') + ->addOption('full', null, InputOption::VALUE_NONE, 'Perform a full sync instead of a delta sync'); } protected function execute(InputInterface $input, OutputInterface $output): int { $progress = new ProgressBar($output); $progress->start(); + $full = (bool)$input->getOption('full'); $this->syncService->syncThemAll(function ($url, $ex) use ($progress, $output): void { if ($ex instanceof \Exception) { $output->writeln("Error while syncing $url : " . $ex->getMessage()); } else { $progress->advance(); } - }); + }, $full); $progress->finish(); $output->writeln(''); diff --git a/apps/federation/lib/SyncFederationAddressBooks.php b/apps/federation/lib/SyncFederationAddressBooks.php index d11f92b76ef..e78a98835e0 100644 --- a/apps/federation/lib/SyncFederationAddressBooks.php +++ b/apps/federation/lib/SyncFederationAddressBooks.php @@ -28,7 +28,7 @@ class SyncFederationAddressBooks { /** * @param \Closure $callback */ - public function syncThemAll(\Closure $callback) { + public function syncThemAll(\Closure $callback, bool $full = false) { $trustedServers = $this->dbHandler->getAllServer(); foreach ($trustedServers as $trustedServer) { $url = $trustedServer['url']; @@ -59,7 +59,7 @@ class SyncFederationAddressBooks { $cardDavUser, $addressBookUrl, $sharedSecret, - $syncToken, + $full ? null : $syncToken, $targetBookId, $targetPrincipal, $targetBookProperties