mirror of
https://github.com/nextcloud/server.git
synced 2026-04-25 08:08:33 -04:00
fix(dav): Run system address book create-if-not-exists in transaction
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
This commit is contained in:
parent
5993a4b3e3
commit
2cc672d26b
2 changed files with 49 additions and 30 deletions
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
*
|
||||
|
|
@ -29,7 +30,9 @@
|
|||
namespace OCA\DAV\CardDAV;
|
||||
|
||||
use OC\Accounts\AccountManager;
|
||||
use OCP\AppFramework\Db\TTransactional;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -38,10 +41,15 @@ use Sabre\DAV\Xml\Response\MultiStatus;
|
|||
use Sabre\DAV\Xml\Service;
|
||||
use Sabre\HTTP\ClientHttpException;
|
||||
use Sabre\VObject\Reader;
|
||||
use function is_null;
|
||||
|
||||
class SyncService {
|
||||
|
||||
use TTransactional;
|
||||
|
||||
private CardDavBackend $backend;
|
||||
private IUserManager $userManager;
|
||||
private IDBConnection $dbConnection;
|
||||
private LoggerInterface $logger;
|
||||
private ?array $localSystemAddressBook = null;
|
||||
private Converter $converter;
|
||||
|
|
@ -49,6 +57,7 @@ class SyncService {
|
|||
|
||||
public function __construct(CardDavBackend $backend,
|
||||
IUserManager $userManager,
|
||||
IDBConnection $dbConnection,
|
||||
LoggerInterface $logger,
|
||||
Converter $converter) {
|
||||
$this->backend = $backend;
|
||||
|
|
@ -56,6 +65,7 @@ class SyncService {
|
|||
$this->logger = $logger;
|
||||
$this->converter = $converter;
|
||||
$this->certPath = '';
|
||||
$this->dbConnection = $dbConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,12 +96,14 @@ class SyncService {
|
|||
$cardUri = basename($resource);
|
||||
if (isset($status[200])) {
|
||||
$vCard = $this->download($url, $userName, $sharedSecret, $resource);
|
||||
$existingCard = $this->backend->getCard($addressBookId, $cardUri);
|
||||
if ($existingCard === false) {
|
||||
$this->backend->createCard($addressBookId, $cardUri, $vCard['body']);
|
||||
} else {
|
||||
$this->backend->updateCard($addressBookId, $cardUri, $vCard['body']);
|
||||
}
|
||||
$this->atomic(function() use ($addressBookId, $cardUri, $vCard) {
|
||||
$existingCard = $this->backend->getCard($addressBookId, $cardUri);
|
||||
if ($existingCard === false) {
|
||||
$this->backend->createCard($addressBookId, $cardUri, $vCard['body']);
|
||||
} else {
|
||||
$this->backend->updateCard($addressBookId, $cardUri, $vCard['body']);
|
||||
}
|
||||
}, $this->dbConnection);
|
||||
} else {
|
||||
$this->backend->deleteCard($addressBookId, $cardUri);
|
||||
}
|
||||
|
|
@ -104,14 +116,15 @@ class SyncService {
|
|||
* @throws \Sabre\DAV\Exception\BadRequest
|
||||
*/
|
||||
public function ensureSystemAddressBookExists(string $principal, string $uri, array $properties): ?array {
|
||||
$book = $this->backend->getAddressBooksByUri($principal, $uri);
|
||||
if (!is_null($book)) {
|
||||
return $book;
|
||||
}
|
||||
// FIXME This might break in clustered DB setup
|
||||
$this->backend->createAddressBook($principal, $uri, $properties);
|
||||
return $this->atomic(function() use ($principal, $uri, $properties) {
|
||||
$book = $this->backend->getAddressBooksByUri($principal, $uri);
|
||||
if (!is_null($book)) {
|
||||
return $book;
|
||||
}
|
||||
$this->backend->createAddressBook($principal, $uri, $properties);
|
||||
|
||||
return $this->backend->getAddressBooksByUri($principal, $uri);
|
||||
return $this->backend->getAddressBooksByUri($principal, $uri);
|
||||
}, $this->dbConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -206,7 +219,7 @@ class SyncService {
|
|||
/**
|
||||
* @param IUser $user
|
||||
*/
|
||||
public function updateUser(IUser $user) {
|
||||
public function updateUser(IUser $user): void {
|
||||
$systemAddressBook = $this->getLocalSystemAddressBook();
|
||||
$addressBookId = $systemAddressBook['id'];
|
||||
$name = $user->getBackendClassName();
|
||||
|
|
@ -214,20 +227,22 @@ class SyncService {
|
|||
|
||||
$cardId = "$name:$userId.vcf";
|
||||
if ($user->isEnabled()) {
|
||||
$card = $this->backend->getCard($addressBookId, $cardId);
|
||||
if ($card === false) {
|
||||
$vCard = $this->converter->createCardFromUser($user);
|
||||
if ($vCard !== null) {
|
||||
$this->backend->createCard($addressBookId, $cardId, $vCard->serialize(), false);
|
||||
}
|
||||
} else {
|
||||
$vCard = $this->converter->createCardFromUser($user);
|
||||
if (is_null($vCard)) {
|
||||
$this->backend->deleteCard($addressBookId, $cardId);
|
||||
$this->atomic(function() use ($addressBookId, $cardId, $user) {
|
||||
$card = $this->backend->getCard($addressBookId, $cardId);
|
||||
if ($card === false) {
|
||||
$vCard = $this->converter->createCardFromUser($user);
|
||||
if ($vCard !== null) {
|
||||
$this->backend->createCard($addressBookId, $cardId, $vCard->serialize(), false);
|
||||
}
|
||||
} else {
|
||||
$this->backend->updateCard($addressBookId, $cardId, $vCard->serialize());
|
||||
$vCard = $this->converter->createCardFromUser($user);
|
||||
if (is_null($vCard)) {
|
||||
$this->backend->deleteCard($addressBookId, $cardId);
|
||||
} else {
|
||||
$this->backend->updateCard($addressBookId, $cardId, $vCard->serialize());
|
||||
}
|
||||
}
|
||||
}
|
||||
}, $this->dbConnection);
|
||||
} else {
|
||||
$this->backend->deleteCard($addressBookId, $cardId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace OCA\DAV\Tests\unit\CardDAV;
|
|||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCA\DAV\CardDAV\Converter;
|
||||
use OCA\DAV\CardDAV\SyncService;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -84,10 +85,11 @@ class SyncServiceTest extends TestCase {
|
|||
|
||||
/** @var IUserManager $userManager */
|
||||
$userManager = $this->getMockBuilder(IUserManager::class)->disableOriginalConstructor()->getMock();
|
||||
$dbConnection = $this->createMock(IDBConnection::class);
|
||||
$logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
|
||||
$converter = $this->createMock(Converter::class);
|
||||
|
||||
$ss = new SyncService($backend, $userManager, $logger, $converter);
|
||||
$ss = new SyncService($backend, $userManager, $dbConnection, $logger, $converter);
|
||||
$ss->ensureSystemAddressBookExists('principals/users/adam', 'contacts', []);
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +128,7 @@ class SyncServiceTest extends TestCase {
|
|||
|
||||
/** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject $userManager */
|
||||
$userManager = $this->getMockBuilder(IUserManager::class)->disableOriginalConstructor()->getMock();
|
||||
$dbConnection = $this->createMock(IDBConnection::class);
|
||||
|
||||
/** @var IUser | \PHPUnit\Framework\MockObject\MockObject $user */
|
||||
$user = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
|
||||
|
|
@ -139,7 +142,7 @@ class SyncServiceTest extends TestCase {
|
|||
->method('createCardFromUser')
|
||||
->willReturn($this->createMock(VCard::class));
|
||||
|
||||
$ss = new SyncService($backend, $userManager, $logger, $converter);
|
||||
$ss = new SyncService($backend, $userManager, $dbConnection, $logger, $converter);
|
||||
$ss->updateUser($user);
|
||||
|
||||
$ss->updateUser($user);
|
||||
|
|
@ -151,7 +154,7 @@ class SyncServiceTest extends TestCase {
|
|||
* @param int $createCount
|
||||
* @param int $updateCount
|
||||
* @param int $deleteCount
|
||||
* @return \PHPUnit\Framework\MockObject\MockObject
|
||||
* @return \PHPUnit\Framework\MockObject\MockObject|CardDavBackend
|
||||
*/
|
||||
private function getBackendMock($createCount, $updateCount, $deleteCount) {
|
||||
$backend = $this->getMockBuilder(CardDavBackend::class)
|
||||
|
|
@ -170,12 +173,13 @@ class SyncServiceTest extends TestCase {
|
|||
*/
|
||||
private function getSyncServiceMock($backend, $response) {
|
||||
$userManager = $this->getMockBuilder(IUserManager::class)->disableOriginalConstructor()->getMock();
|
||||
$dbConnection = $this->createMock(IDBConnection::class);
|
||||
$logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
|
||||
$converter = $this->createMock(Converter::class);
|
||||
/** @var SyncService | \PHPUnit\Framework\MockObject\MockObject $ss */
|
||||
$ss = $this->getMockBuilder(SyncService::class)
|
||||
->setMethods(['ensureSystemAddressBookExists', 'requestSyncReport', 'download', 'getCertPath'])
|
||||
->setConstructorArgs([$backend, $userManager, $logger, $converter])
|
||||
->setConstructorArgs([$backend, $userManager, $dbConnection, $logger, $converter])
|
||||
->getMock();
|
||||
$ss->method('requestSyncReport')->withAnyParameters()->willReturn(['response' => $response, 'token' => 'sync-token-1']);
|
||||
$ss->method('ensureSystemAddressBookExists')->willReturn(['id' => 1]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue