summaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/CardDAV/CardDavBackend.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav/lib/CardDAV/CardDavBackend.php')
-rw-r--r--apps/dav/lib/CardDAV/CardDavBackend.php646
1 files changed, 330 insertions, 316 deletions
diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php
index 666f1e7a85c..524a1ee117a 100644
--- a/apps/dav/lib/CardDAV/CardDavBackend.php
+++ b/apps/dav/lib/CardDAV/CardDavBackend.php
@@ -50,7 +50,6 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
use OCP\IGroupManager;
-use OCP\IUser;
use OCP\IUserManager;
use PDO;
use Sabre\CardDAV\Backend\BackendInterface;
@@ -61,7 +60,6 @@ use Sabre\VObject\Component\VCard;
use Sabre\VObject\Reader;
class CardDavBackend implements BackendInterface, SyncSupport {
-
use TTransactional;
public const PERSONAL_ADDRESSBOOK_URI = 'contacts';
@@ -145,87 +143,89 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return array
*/
public function getAddressBooksForUser($principalUri) {
- $principalUriOriginal = $principalUri;
- $principalUri = $this->convertPrincipal($principalUri, true);
- $query = $this->db->getQueryBuilder();
- $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
- ->from('addressbooks')
- ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
-
- $addressBooks = [];
-
- $result = $query->execute();
- while ($row = $result->fetch()) {
- $addressBooks[$row['id']] = [
- 'id' => $row['id'],
- 'uri' => $row['uri'],
- 'principaluri' => $this->convertPrincipal($row['principaluri'], false),
- '{DAV:}displayname' => $row['displayname'],
- '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
- '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
- '{http://sabredav.org/ns}sync-token' => $row['synctoken'] ?: '0',
- ];
+ return $this->atomic(function () use ($principalUri) {
+ $principalUriOriginal = $principalUri;
+ $principalUri = $this->convertPrincipal($principalUri, true);
+ $query = $this->db->getQueryBuilder();
+ $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken'])
+ ->from('addressbooks')
+ ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principalUri)));
- $this->addOwnerPrincipal($addressBooks[$row['id']]);
- }
- $result->closeCursor();
+ $addressBooks = [];
- // query for shared addressbooks
- $principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
- $principals = array_merge($principals, $this->principalBackend->getCircleMembership($principalUriOriginal));
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $addressBooks[$row['id']] = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $this->convertPrincipal($row['principaluri'], false),
+ '{DAV:}displayname' => $row['displayname'],
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken'] ?: '0',
+ ];
+
+ $this->addOwnerPrincipal($addressBooks[$row['id']]);
+ }
+ $result->closeCursor();
- $principals[] = $principalUri;
+ // query for shared addressbooks
+ $principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
+ $principals = array_merge($principals, $this->principalBackend->getCircleMembership($principalUriOriginal));
- $query = $this->db->getQueryBuilder();
- $result = $query->select(['a.id', 'a.uri', 'a.displayname', 'a.principaluri', 'a.description', 'a.synctoken', 's.access'])
- ->from('dav_shares', 's')
- ->join('s', 'addressbooks', 'a', $query->expr()->eq('s.resourceid', 'a.id'))
- ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri')))
- ->andWhere($query->expr()->eq('s.type', $query->createParameter('type')))
- ->setParameter('type', 'addressbook')
- ->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY)
- ->execute();
+ $principals[] = $principalUri;
- $readOnlyPropertyName = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only';
- while ($row = $result->fetch()) {
- if ($row['principaluri'] === $principalUri) {
- continue;
- }
+ $query = $this->db->getQueryBuilder();
+ $result = $query->select(['a.id', 'a.uri', 'a.displayname', 'a.principaluri', 'a.description', 'a.synctoken', 's.access'])
+ ->from('dav_shares', 's')
+ ->join('s', 'addressbooks', 'a', $query->expr()->eq('s.resourceid', 'a.id'))
+ ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri')))
+ ->andWhere($query->expr()->eq('s.type', $query->createParameter('type')))
+ ->setParameter('type', 'addressbook')
+ ->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY)
+ ->execute();
- $readOnly = (int)$row['access'] === Backend::ACCESS_READ;
- if (isset($addressBooks[$row['id']])) {
- if ($readOnly) {
- // New share can not have more permissions then the old one.
- continue;
- }
- if (isset($addressBooks[$row['id']][$readOnlyPropertyName]) &&
- $addressBooks[$row['id']][$readOnlyPropertyName] === 0) {
- // Old share is already read-write, no more permissions can be gained
+ $readOnlyPropertyName = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only';
+ while ($row = $result->fetch()) {
+ if ($row['principaluri'] === $principalUri) {
continue;
}
- }
-
- [, $name] = \Sabre\Uri\split($row['principaluri']);
- $uri = $row['uri'] . '_shared_by_' . $name;
- $displayName = $row['displayname'] . ' (' . ($this->userManager->getDisplayName($name) ?? $name ?? '') . ')';
- $addressBooks[$row['id']] = [
- 'id' => $row['id'],
- 'uri' => $uri,
- 'principaluri' => $principalUriOriginal,
- '{DAV:}displayname' => $displayName,
- '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
- '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
- '{http://sabredav.org/ns}sync-token' => $row['synctoken'] ?: '0',
- '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
- $readOnlyPropertyName => $readOnly,
- ];
+ $readOnly = (int)$row['access'] === Backend::ACCESS_READ;
+ if (isset($addressBooks[$row['id']])) {
+ if ($readOnly) {
+ // New share can not have more permissions then the old one.
+ continue;
+ }
+ if (isset($addressBooks[$row['id']][$readOnlyPropertyName]) &&
+ $addressBooks[$row['id']][$readOnlyPropertyName] === 0) {
+ // Old share is already read-write, no more permissions can be gained
+ continue;
+ }
+ }
- $this->addOwnerPrincipal($addressBooks[$row['id']]);
- }
- $result->closeCursor();
+ [, $name] = \Sabre\Uri\split($row['principaluri']);
+ $uri = $row['uri'] . '_shared_by_' . $name;
+ $displayName = $row['displayname'] . ' (' . ($this->userManager->getDisplayName($name) ?? $name ?? '') . ')';
+
+ $addressBooks[$row['id']] = [
+ 'id' => $row['id'],
+ 'uri' => $uri,
+ 'principaluri' => $principalUriOriginal,
+ '{DAV:}displayname' => $displayName,
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['synctoken'],
+ '{http://sabredav.org/ns}sync-token' => $row['synctoken'] ?: '0',
+ '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'],
+ $readOnlyPropertyName => $readOnly,
+ ];
+
+ $this->addOwnerPrincipal($addressBooks[$row['id']]);
+ }
+ $result->closeCursor();
- return array_values($addressBooks);
+ return array_values($addressBooks);
+ }, $this->db);
}
public function getUsersOwnAddressBooks($principalUri) {
@@ -333,40 +333,42 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return void
*/
public function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
- $supportedProperties = [
- '{DAV:}displayname',
- '{' . Plugin::NS_CARDDAV . '}addressbook-description',
- ];
+ $this->atomic(function () use ($addressBookId, $propPatch) {
+ $supportedProperties = [
+ '{DAV:}displayname',
+ '{' . Plugin::NS_CARDDAV . '}addressbook-description',
+ ];
- $propPatch->handle($supportedProperties, function ($mutations) use ($addressBookId) {
- $updates = [];
- foreach ($mutations as $property => $newValue) {
- switch ($property) {
- case '{DAV:}displayname':
- $updates['displayname'] = $newValue;
- break;
- case '{' . Plugin::NS_CARDDAV . '}addressbook-description':
- $updates['description'] = $newValue;
- break;
+ $propPatch->handle($supportedProperties, function ($mutations) use ($addressBookId) {
+ $updates = [];
+ foreach ($mutations as $property => $newValue) {
+ switch ($property) {
+ case '{DAV:}displayname':
+ $updates['displayname'] = $newValue;
+ break;
+ case '{' . Plugin::NS_CARDDAV . '}addressbook-description':
+ $updates['description'] = $newValue;
+ break;
+ }
}
- }
- $query = $this->db->getQueryBuilder();
- $query->update('addressbooks');
+ $query = $this->db->getQueryBuilder();
+ $query->update('addressbooks');
- foreach ($updates as $key => $value) {
- $query->set($key, $query->createNamedParameter($value));
- }
- $query->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
- ->executeStatement();
+ foreach ($updates as $key => $value) {
+ $query->set($key, $query->createNamedParameter($value));
+ }
+ $query->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId)))
+ ->executeStatement();
- $this->addChange($addressBookId, "", 2);
+ $this->addChange($addressBookId, "", 2);
- $addressBookRow = $this->getAddressBookById((int)$addressBookId);
- $shares = $this->getShares((int)$addressBookId);
- $this->dispatcher->dispatchTyped(new AddressBookUpdatedEvent((int)$addressBookId, $addressBookRow, $shares, $mutations));
+ $addressBookRow = $this->getAddressBookById((int)$addressBookId);
+ $shares = $this->getShares((int)$addressBookId);
+ $this->dispatcher->dispatchTyped(new AddressBookUpdatedEvent((int)$addressBookId, $addressBookRow, $shares, $mutations));
- return true;
- });
+ return true;
+ });
+ }, $this->db);
}
/**
@@ -410,7 +412,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$values['displayname'] = $url;
}
- [$addressBookId, $addressBookRow] = $this->atomic(function() use ($values) {
+ [$addressBookId, $addressBookRow] = $this->atomic(function () use ($values) {
$query = $this->db->getQueryBuilder();
$query->insert('addressbooks')
->values([
@@ -442,38 +444,40 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return void
*/
public function deleteAddressBook($addressBookId) {
- $addressBookId = (int)$addressBookId;
- $addressBookData = $this->getAddressBookById($addressBookId);
- $shares = $this->getShares($addressBookId);
+ $this->atomic(function () use ($addressBookId) {
+ $addressBookId = (int)$addressBookId;
+ $addressBookData = $this->getAddressBookById($addressBookId);
+ $shares = $this->getShares($addressBookId);
- $query = $this->db->getQueryBuilder();
- $query->delete($this->dbCardsTable)
- ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
- ->setParameter('addressbookid', $addressBookId, IQueryBuilder::PARAM_INT)
- ->executeStatement();
+ $query = $this->db->getQueryBuilder();
+ $query->delete($this->dbCardsTable)
+ ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
+ ->setParameter('addressbookid', $addressBookId, IQueryBuilder::PARAM_INT)
+ ->executeStatement();
- $query = $this->db->getQueryBuilder();
- $query->delete('addressbookchanges')
- ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
- ->setParameter('addressbookid', $addressBookId, IQueryBuilder::PARAM_INT)
- ->executeStatement();
+ $query = $this->db->getQueryBuilder();
+ $query->delete('addressbookchanges')
+ ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid')))
+ ->setParameter('addressbookid', $addressBookId, IQueryBuilder::PARAM_INT)
+ ->executeStatement();
- $query = $this->db->getQueryBuilder();
- $query->delete('addressbooks')
- ->where($query->expr()->eq('id', $query->createParameter('id')))
- ->setParameter('id', $addressBookId, IQueryBuilder::PARAM_INT)
- ->executeStatement();
+ $query = $this->db->getQueryBuilder();
+ $query->delete('addressbooks')
+ ->where($query->expr()->eq('id', $query->createParameter('id')))
+ ->setParameter('id', $addressBookId, IQueryBuilder::PARAM_INT)
+ ->executeStatement();
- $this->sharingBackend->deleteAllShares($addressBookId);
+ $this->sharingBackend->deleteAllShares($addressBookId);
- $query = $this->db->getQueryBuilder();
- $query->delete($this->dbCardsPropertiesTable)
- ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId, IQueryBuilder::PARAM_INT)))
- ->executeStatement();
+ $query = $this->db->getQueryBuilder();
+ $query->delete($this->dbCardsPropertiesTable)
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId, IQueryBuilder::PARAM_INT)))
+ ->executeStatement();
- if ($addressBookData) {
- $this->dispatcher->dispatchTyped(new AddressBookDeletedEvent($addressBookId, $addressBookData, $shares));
- }
+ if ($addressBookData) {
+ $this->dispatcher->dispatchTyped(new AddressBookDeletedEvent($addressBookId, $addressBookData, $shares));
+ }
+ }, $this->db);
}
/**
@@ -631,47 +635,48 @@ class CardDavBackend implements BackendInterface, SyncSupport {
public function createCard($addressBookId, $cardUri, $cardData, bool $checkAlreadyExists = true) {
$etag = md5($cardData);
$uid = $this->getUID($cardData);
-
- if ($checkAlreadyExists) {
- $q = $this->db->getQueryBuilder();
- $q->select('uid')
- ->from($this->dbCardsTable)
- ->where($q->expr()->eq('addressbookid', $q->createNamedParameter($addressBookId)))
- ->andWhere($q->expr()->eq('uid', $q->createNamedParameter($uid)))
- ->setMaxResults(1);
- $result = $q->executeQuery();
- $count = (bool)$result->fetchOne();
- $result->closeCursor();
- if ($count) {
- throw new \Sabre\DAV\Exception\BadRequest('VCard object with uid already exists in this addressbook collection.');
+ return $this->atomic(function () use ($addressBookId, $cardUri, $cardData, $checkAlreadyExists, $etag, $uid) {
+ if ($checkAlreadyExists) {
+ $q = $this->db->getQueryBuilder();
+ $q->select('uid')
+ ->from($this->dbCardsTable)
+ ->where($q->expr()->eq('addressbookid', $q->createNamedParameter($addressBookId)))
+ ->andWhere($q->expr()->eq('uid', $q->createNamedParameter($uid)))
+ ->setMaxResults(1);
+ $result = $q->executeQuery();
+ $count = (bool)$result->fetchOne();
+ $result->closeCursor();
+ if ($count) {
+ throw new \Sabre\DAV\Exception\BadRequest('VCard object with uid already exists in this addressbook collection.');
+ }
}
- }
- $query = $this->db->getQueryBuilder();
- $query->insert('cards')
- ->values([
- 'carddata' => $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB),
- 'uri' => $query->createNamedParameter($cardUri),
- 'lastmodified' => $query->createNamedParameter(time()),
- 'addressbookid' => $query->createNamedParameter($addressBookId),
- 'size' => $query->createNamedParameter(strlen($cardData)),
- 'etag' => $query->createNamedParameter($etag),
- 'uid' => $query->createNamedParameter($uid),
- ])
- ->execute();
+ $query = $this->db->getQueryBuilder();
+ $query->insert('cards')
+ ->values([
+ 'carddata' => $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB),
+ 'uri' => $query->createNamedParameter($cardUri),
+ 'lastmodified' => $query->createNamedParameter(time()),
+ 'addressbookid' => $query->createNamedParameter($addressBookId),
+ 'size' => $query->createNamedParameter(strlen($cardData)),
+ 'etag' => $query->createNamedParameter($etag),
+ 'uid' => $query->createNamedParameter($uid),
+ ])
+ ->execute();
- $etagCacheKey = "$addressBookId#$cardUri";
- $this->etagCache[$etagCacheKey] = $etag;
+ $etagCacheKey = "$addressBookId#$cardUri";
+ $this->etagCache[$etagCacheKey] = $etag;
- $this->addChange($addressBookId, $cardUri, 1);
- $this->updateProperties($addressBookId, $cardUri, $cardData);
+ $this->addChange($addressBookId, $cardUri, 1);
+ $this->updateProperties($addressBookId, $cardUri, $cardData);
- $addressBookData = $this->getAddressBookById($addressBookId);
- $shares = $this->getShares($addressBookId);
- $objectRow = $this->getCard($addressBookId, $cardUri);
- $this->dispatcher->dispatchTyped(new CardCreatedEvent($addressBookId, $addressBookData, $shares, $objectRow));
+ $addressBookData = $this->getAddressBookById($addressBookId);
+ $shares = $this->getShares($addressBookId);
+ $objectRow = $this->getCard($addressBookId, $cardUri);
+ $this->dispatcher->dispatchTyped(new CardCreatedEvent($addressBookId, $addressBookData, $shares, $objectRow));
- return '"' . $etag . '"';
+ return '"' . $etag . '"';
+ }, $this->db);
}
/**
@@ -702,34 +707,37 @@ class CardDavBackend implements BackendInterface, SyncSupport {
public function updateCard($addressBookId, $cardUri, $cardData) {
$uid = $this->getUID($cardData);
$etag = md5($cardData);
- $query = $this->db->getQueryBuilder();
- // check for recently stored etag and stop if it is the same
- $etagCacheKey = "$addressBookId#$cardUri";
- if (isset($this->etagCache[$etagCacheKey]) && $this->etagCache[$etagCacheKey] === $etag) {
- return '"' . $etag . '"';
- }
+ return $this->atomic(function () use ($addressBookId, $cardUri, $cardData, $uid, $etag) {
+ $query = $this->db->getQueryBuilder();
- $query->update($this->dbCardsTable)
- ->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
- ->set('lastmodified', $query->createNamedParameter(time()))
- ->set('size', $query->createNamedParameter(strlen($cardData)))
- ->set('etag', $query->createNamedParameter($etag))
- ->set('uid', $query->createNamedParameter($uid))
- ->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
- ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
- ->execute();
+ // check for recently stored etag and stop if it is the same
+ $etagCacheKey = "$addressBookId#$cardUri";
+ if (isset($this->etagCache[$etagCacheKey]) && $this->etagCache[$etagCacheKey] === $etag) {
+ return '"' . $etag . '"';
+ }
+
+ $query->update($this->dbCardsTable)
+ ->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB))
+ ->set('lastmodified', $query->createNamedParameter(time()))
+ ->set('size', $query->createNamedParameter(strlen($cardData)))
+ ->set('etag', $query->createNamedParameter($etag))
+ ->set('uid', $query->createNamedParameter($uid))
+ ->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
+ ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->execute();
- $this->etagCache[$etagCacheKey] = $etag;
+ $this->etagCache[$etagCacheKey] = $etag;
- $this->addChange($addressBookId, $cardUri, 2);
- $this->updateProperties($addressBookId, $cardUri, $cardData);
+ $this->addChange($addressBookId, $cardUri, 2);
+ $this->updateProperties($addressBookId, $cardUri, $cardData);
- $addressBookData = $this->getAddressBookById($addressBookId);
- $shares = $this->getShares($addressBookId);
- $objectRow = $this->getCard($addressBookId, $cardUri);
- $this->dispatcher->dispatchTyped(new CardUpdatedEvent($addressBookId, $addressBookData, $shares, $objectRow));
- return '"' . $etag . '"';
+ $addressBookData = $this->getAddressBookById($addressBookId);
+ $shares = $this->getShares($addressBookId);
+ $objectRow = $this->getCard($addressBookId, $cardUri);
+ $this->dispatcher->dispatchTyped(new CardUpdatedEvent($addressBookId, $addressBookData, $shares, $objectRow));
+ return '"' . $etag . '"';
+ }, $this->db);
}
/**
@@ -740,32 +748,34 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return bool
*/
public function deleteCard($addressBookId, $cardUri) {
- $addressBookData = $this->getAddressBookById($addressBookId);
- $shares = $this->getShares($addressBookId);
- $objectRow = $this->getCard($addressBookId, $cardUri);
-
- try {
- $cardId = $this->getCardId($addressBookId, $cardUri);
- } catch (\InvalidArgumentException $e) {
- $cardId = null;
- }
- $query = $this->db->getQueryBuilder();
- $ret = $query->delete($this->dbCardsTable)
- ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
- ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
- ->executeStatement();
+ return $this->atomic(function () use ($addressBookId, $cardUri) {
+ $addressBookData = $this->getAddressBookById($addressBookId);
+ $shares = $this->getShares($addressBookId);
+ $objectRow = $this->getCard($addressBookId, $cardUri);
+
+ try {
+ $cardId = $this->getCardId($addressBookId, $cardUri);
+ } catch (\InvalidArgumentException $e) {
+ $cardId = null;
+ }
+ $query = $this->db->getQueryBuilder();
+ $ret = $query->delete($this->dbCardsTable)
+ ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
+ ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri)))
+ ->executeStatement();
- $this->addChange($addressBookId, $cardUri, 3);
+ $this->addChange($addressBookId, $cardUri, 3);
- if ($ret === 1) {
- if ($cardId !== null) {
- $this->dispatcher->dispatchTyped(new CardDeletedEvent($addressBookId, $addressBookData, $shares, $objectRow));
- $this->purgeProperties($addressBookId, $cardId);
+ if ($ret === 1) {
+ if ($cardId !== null) {
+ $this->dispatcher->dispatchTyped(new CardDeletedEvent($addressBookId, $addressBookData, $shares, $objectRow));
+ $this->purgeProperties($addressBookId, $cardId);
+ }
+ return true;
}
- return true;
- }
- return false;
+ return false;
+ }, $this->db);
}
/**
@@ -826,81 +836,83 @@ class CardDavBackend implements BackendInterface, SyncSupport {
*/
public function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) {
// Current synctoken
- $qb = $this->db->getQueryBuilder();
- $qb->select('synctoken')
- ->from('addressbooks')
- ->where(
- $qb->expr()->eq('id', $qb->createNamedParameter($addressBookId))
- );
- $stmt = $qb->executeQuery();
- $currentToken = $stmt->fetchOne();
- $stmt->closeCursor();
-
- if (is_null($currentToken)) {
- return [];
- }
-
- $result = [
- 'syncToken' => $currentToken,
- 'added' => [],
- 'modified' => [],
- 'deleted' => [],
- ];
-
- if ($syncToken) {
+ return $this->atomic(function () use ($addressBookId, $syncToken, $syncLevel, $limit) {
$qb = $this->db->getQueryBuilder();
- $qb->select('uri', 'operation')
- ->from('addressbookchanges')
+ $qb->select('synctoken')
+ ->from('addressbooks')
->where(
- $qb->expr()->andX(
- $qb->expr()->gte('synctoken', $qb->createNamedParameter($syncToken)),
- $qb->expr()->lt('synctoken', $qb->createNamedParameter($currentToken)),
- $qb->expr()->eq('addressbookid', $qb->createNamedParameter($addressBookId))
- )
- )->orderBy('synctoken');
+ $qb->expr()->eq('id', $qb->createNamedParameter($addressBookId))
+ );
+ $stmt = $qb->executeQuery();
+ $currentToken = $stmt->fetchOne();
+ $stmt->closeCursor();
- if (is_int($limit) && $limit > 0) {
- $qb->setMaxResults($limit);
+ if (is_null($currentToken)) {
+ return [];
}
- // Fetching all changes
- $stmt = $qb->executeQuery();
+ $result = [
+ 'syncToken' => $currentToken,
+ 'added' => [],
+ 'modified' => [],
+ 'deleted' => [],
+ ];
- $changes = [];
+ if ($syncToken) {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('uri', 'operation')
+ ->from('addressbookchanges')
+ ->where(
+ $qb->expr()->andX(
+ $qb->expr()->gte('synctoken', $qb->createNamedParameter($syncToken)),
+ $qb->expr()->lt('synctoken', $qb->createNamedParameter($currentToken)),
+ $qb->expr()->eq('addressbookid', $qb->createNamedParameter($addressBookId))
+ )
+ )->orderBy('synctoken');
+
+ if (is_int($limit) && $limit > 0) {
+ $qb->setMaxResults($limit);
+ }
- // This loop ensures that any duplicates are overwritten, only the
- // last change on a node is relevant.
- while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- $changes[$row['uri']] = $row['operation'];
- }
- $stmt->closeCursor();
+ // Fetching all changes
+ $stmt = $qb->executeQuery();
- foreach ($changes as $uri => $operation) {
- switch ($operation) {
- case 1:
- $result['added'][] = $uri;
- break;
- case 2:
- $result['modified'][] = $uri;
- break;
- case 3:
- $result['deleted'][] = $uri;
- break;
+ $changes = [];
+
+ // This loop ensures that any duplicates are overwritten, only the
+ // last change on a node is relevant.
+ while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ $changes[$row['uri']] = $row['operation'];
+ }
+ $stmt->closeCursor();
+
+ foreach ($changes as $uri => $operation) {
+ switch ($operation) {
+ case 1:
+ $result['added'][] = $uri;
+ break;
+ case 2:
+ $result['modified'][] = $uri;
+ break;
+ case 3:
+ $result['deleted'][] = $uri;
+ break;
+ }
}
+ } else {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('uri')
+ ->from('cards')
+ ->where(
+ $qb->expr()->eq('addressbookid', $qb->createNamedParameter($addressBookId))
+ );
+ // No synctoken supplied, this is the initial sync.
+ $stmt = $qb->executeQuery();
+ $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN);
+ $stmt->closeCursor();
}
- } else {
- $qb = $this->db->getQueryBuilder();
- $qb->select('uri')
- ->from('cards')
- ->where(
- $qb->expr()->eq('addressbookid', $qb->createNamedParameter($addressBookId))
- );
- // No synctoken supplied, this is the initial sync.
- $stmt = $qb->executeQuery();
- $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN);
- $stmt->closeCursor();
- }
- return $result;
+ return $result;
+ }, $this->db);
}
/**
@@ -912,18 +924,20 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return void
*/
protected function addChange($addressBookId, $objectUri, $operation) {
- $sql = 'INSERT INTO `*PREFIX*addressbookchanges`(`uri`, `synctoken`, `addressbookid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*addressbooks` WHERE `id` = ?';
- $stmt = $this->db->prepare($sql);
- $stmt->execute([
- $objectUri,
- $addressBookId,
- $operation,
- $addressBookId
- ]);
- $stmt = $this->db->prepare('UPDATE `*PREFIX*addressbooks` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?');
- $stmt->execute([
- $addressBookId
- ]);
+ $this->atomic(function () use ($addressBookId, $objectUri, $operation) {
+ $sql = 'INSERT INTO `*PREFIX*addressbookchanges`(`uri`, `synctoken`, `addressbookid`, `operation`) SELECT ?, `synctoken`, ?, ? FROM `*PREFIX*addressbooks` WHERE `id` = ?';
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute([
+ $objectUri,
+ $addressBookId,
+ $operation,
+ $addressBookId
+ ]);
+ $stmt = $this->db->prepare('UPDATE `*PREFIX*addressbooks` SET `synctoken` = `synctoken` + 1 WHERE `id` = ?');
+ $stmt->execute([
+ $addressBookId
+ ]);
+ }, $this->db);
}
/**
@@ -973,13 +987,15 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param list<string> $remove
*/
public function updateShares(IShareable $shareable, array $add, array $remove): void {
- $addressBookId = $shareable->getResourceId();
- $addressBookData = $this->getAddressBookById($addressBookId);
- $oldShares = $this->getShares($addressBookId);
+ $this->atomic(function () use ($shareable, $add, $remove) {
+ $addressBookId = $shareable->getResourceId();
+ $addressBookData = $this->getAddressBookById($addressBookId);
+ $oldShares = $this->getShares($addressBookId);
- $this->sharingBackend->updateShares($shareable, $add, $remove);
+ $this->sharingBackend->updateShares($shareable, $add, $remove);
- $this->dispatcher->dispatchTyped(new AddressBookShareUpdatedEvent($addressBookId, $addressBookData, $oldShares, $add, $remove));
+ $this->dispatcher->dispatchTyped(new AddressBookShareUpdatedEvent($addressBookId, $addressBookData, $oldShares, $add, $remove));
+ }, $this->db);
}
/**
@@ -998,7 +1014,9 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @return array an array of contacts which are arrays of key-value-pairs
*/
public function search($addressBookId, $pattern, $searchProperties, $options = []): array {
- return $this->searchByAddressBookIds([$addressBookId], $pattern, $searchProperties, $options);
+ return $this->atomic(function () use ($addressBookId, $pattern, $searchProperties, $options) {
+ return $this->searchByAddressBookIds([$addressBookId], $pattern, $searchProperties, $options);
+ }, $this->db);
}
/**
@@ -1014,11 +1032,13 @@ class CardDavBackend implements BackendInterface, SyncSupport {
string $pattern,
array $searchProperties,
array $options = []): array {
- $addressBookIds = array_map(static function ($row):int {
- return (int) $row['id'];
- }, $this->getAddressBooksForUser($principalUri));
+ return $this->atomic(function () use ($principalUri, $pattern, $searchProperties, $options) {
+ $addressBookIds = array_map(static function ($row):int {
+ return (int) $row['id'];
+ }, $this->getAddressBooksForUser($principalUri));
- return $this->searchByAddressBookIds($addressBookIds, $pattern, $searchProperties, $options);
+ return $this->searchByAddressBookIds($addressBookIds, $pattern, $searchProperties, $options);
+ }, $this->db);
}
/**
@@ -1219,27 +1239,24 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param string $vCardSerialized
*/
protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) {
- $cardId = $this->getCardId($addressBookId, $cardUri);
- $vCard = $this->readCard($vCardSerialized);
-
- $this->purgeProperties($addressBookId, $cardId);
-
- $query = $this->db->getQueryBuilder();
- $query->insert($this->dbCardsPropertiesTable)
- ->values(
- [
- 'addressbookid' => $query->createNamedParameter($addressBookId),
- 'cardid' => $query->createNamedParameter($cardId),
- 'name' => $query->createParameter('name'),
- 'value' => $query->createParameter('value'),
- 'preferred' => $query->createParameter('preferred')
- ]
- );
+ $this->atomic(function () use ($addressBookId, $cardUri, $vCardSerialized) {
+ $cardId = $this->getCardId($addressBookId, $cardUri);
+ $vCard = $this->readCard($vCardSerialized);
+ $this->purgeProperties($addressBookId, $cardId);
- $this->db->beginTransaction();
+ $query = $this->db->getQueryBuilder();
+ $query->insert($this->dbCardsPropertiesTable)
+ ->values(
+ [
+ 'addressbookid' => $query->createNamedParameter($addressBookId),
+ 'cardid' => $query->createNamedParameter($cardId),
+ 'name' => $query->createParameter('name'),
+ 'value' => $query->createParameter('value'),
+ 'preferred' => $query->createParameter('preferred')
+ ]
+ );
- try {
foreach ($vCard->children() as $property) {
if (!in_array($property->name, self::$indexProperties)) {
continue;
@@ -1256,10 +1273,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
$query->setParameter('preferred', $preferred);
$query->execute();
}
- $this->db->commit();
- } catch (\Exception $e) {
- $this->db->rollBack();
- }
+ }, $this->db);
}
/**