diff --git a/apps/dav/lib/CardDAV/SyncService.php b/apps/dav/lib/CardDAV/SyncService.php index 0e755778df0..af6f08e253a 100644 --- a/apps/dav/lib/CardDAV/SyncService.php +++ b/apps/dav/lib/CardDAV/SyncService.php @@ -66,11 +66,13 @@ class SyncService extends ASyncService { throw $ex; } + $received = []; // 3. apply changes // TODO: use multi-get for download foreach ($response['response'] as $resource => $status) { $cardUri = basename($resource); if (isset($status[200])) { + $received[] = $cardUri; $absoluteUrl = $this->prepareUri($url, $resource); $vCard = $this->download($absoluteUrl, $userName, $sharedSecret); $this->atomic(function () use ($addressBookId, $cardUri, $vCard): void { @@ -86,6 +88,15 @@ class SyncService extends ASyncService { } } + // 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 0325d875969..72d6a9099ee 100644 --- a/apps/federation/lib/Command/SyncFederationAddressBooks.php +++ b/apps/federation/lib/Command/SyncFederationAddressBooks.php @@ -13,6 +13,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 { @@ -25,19 +26,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 51af00310e8..ac51627a81d 100644 --- a/apps/federation/lib/SyncFederationAddressBooks.php +++ b/apps/federation/lib/SyncFederationAddressBooks.php @@ -24,7 +24,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']; @@ -55,7 +55,7 @@ class SyncFederationAddressBooks { $cardDavUser, $addressBookUrl, $sharedSecret, - $syncToken, + $full ? null : $syncToken, $targetBookId, $targetPrincipal, $targetBookProperties