зеркало из https://github.com/nextcloud/server.git
feat(CardDAV): Add Sabre\DAV\IMoveTarget support to OCA\DAV\CardDAV\AddressBook
This allows to just UPDATE the card row instead of deleting it and reinsert it. It's very similar to https://github.com/nextcloud/server/pull/30120 for calendars. As we need the addressbookid exposed, this introduces OCA\DAV\CardDAV\Card that extends Sabre's. I chose specifically NOT to auto-inject LoggerInterface in Addressbook like in #30120 because the chain of DI is huge just for ONE simple call and it would break an existing dirty call (OCA\Contacts calling OCA\DAV) of ContactsManager in Contacts: https://github.com/nextcloud/contacts/pull/1722 (in SocialApiService), but this is debatable. Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Родитель
25dd264965
Коммит
13a3ebd4cc
|
@ -114,6 +114,7 @@ return array(
|
||||||
'OCA\\DAV\\CardDAV\\AddressBook' => $baseDir . '/../lib/CardDAV/AddressBook.php',
|
'OCA\\DAV\\CardDAV\\AddressBook' => $baseDir . '/../lib/CardDAV/AddressBook.php',
|
||||||
'OCA\\DAV\\CardDAV\\AddressBookImpl' => $baseDir . '/../lib/CardDAV/AddressBookImpl.php',
|
'OCA\\DAV\\CardDAV\\AddressBookImpl' => $baseDir . '/../lib/CardDAV/AddressBookImpl.php',
|
||||||
'OCA\\DAV\\CardDAV\\AddressBookRoot' => $baseDir . '/../lib/CardDAV/AddressBookRoot.php',
|
'OCA\\DAV\\CardDAV\\AddressBookRoot' => $baseDir . '/../lib/CardDAV/AddressBookRoot.php',
|
||||||
|
'OCA\\DAV\\CardDAV\\Card' => $baseDir . '/../lib/CardDAV/Card.php',
|
||||||
'OCA\\DAV\\CardDAV\\CardDavBackend' => $baseDir . '/../lib/CardDAV/CardDavBackend.php',
|
'OCA\\DAV\\CardDAV\\CardDavBackend' => $baseDir . '/../lib/CardDAV/CardDavBackend.php',
|
||||||
'OCA\\DAV\\CardDAV\\ContactsManager' => $baseDir . '/../lib/CardDAV/ContactsManager.php',
|
'OCA\\DAV\\CardDAV\\ContactsManager' => $baseDir . '/../lib/CardDAV/ContactsManager.php',
|
||||||
'OCA\\DAV\\CardDAV\\Converter' => $baseDir . '/../lib/CardDAV/Converter.php',
|
'OCA\\DAV\\CardDAV\\Converter' => $baseDir . '/../lib/CardDAV/Converter.php',
|
||||||
|
@ -230,6 +231,7 @@ return array(
|
||||||
'OCA\\DAV\\Events\\CalendarUpdatedEvent' => $baseDir . '/../lib/Events/CalendarUpdatedEvent.php',
|
'OCA\\DAV\\Events\\CalendarUpdatedEvent' => $baseDir . '/../lib/Events/CalendarUpdatedEvent.php',
|
||||||
'OCA\\DAV\\Events\\CardCreatedEvent' => $baseDir . '/../lib/Events/CardCreatedEvent.php',
|
'OCA\\DAV\\Events\\CardCreatedEvent' => $baseDir . '/../lib/Events/CardCreatedEvent.php',
|
||||||
'OCA\\DAV\\Events\\CardDeletedEvent' => $baseDir . '/../lib/Events/CardDeletedEvent.php',
|
'OCA\\DAV\\Events\\CardDeletedEvent' => $baseDir . '/../lib/Events/CardDeletedEvent.php',
|
||||||
|
'OCA\\DAV\\Events\\CardMovedEvent' => $baseDir . '/../lib/Events/CardMovedEvent.php',
|
||||||
'OCA\\DAV\\Events\\CardUpdatedEvent' => $baseDir . '/../lib/Events/CardUpdatedEvent.php',
|
'OCA\\DAV\\Events\\CardUpdatedEvent' => $baseDir . '/../lib/Events/CardUpdatedEvent.php',
|
||||||
'OCA\\DAV\\Events\\SabrePluginAuthInitEvent' => $baseDir . '/../lib/Events/SabrePluginAuthInitEvent.php',
|
'OCA\\DAV\\Events\\SabrePluginAuthInitEvent' => $baseDir . '/../lib/Events/SabrePluginAuthInitEvent.php',
|
||||||
'OCA\\DAV\\Events\\SubscriptionCreatedEvent' => $baseDir . '/../lib/Events/SubscriptionCreatedEvent.php',
|
'OCA\\DAV\\Events\\SubscriptionCreatedEvent' => $baseDir . '/../lib/Events/SubscriptionCreatedEvent.php',
|
||||||
|
|
|
@ -129,6 +129,7 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\CardDAV\\AddressBook' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBook.php',
|
'OCA\\DAV\\CardDAV\\AddressBook' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBook.php',
|
||||||
'OCA\\DAV\\CardDAV\\AddressBookImpl' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBookImpl.php',
|
'OCA\\DAV\\CardDAV\\AddressBookImpl' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBookImpl.php',
|
||||||
'OCA\\DAV\\CardDAV\\AddressBookRoot' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBookRoot.php',
|
'OCA\\DAV\\CardDAV\\AddressBookRoot' => __DIR__ . '/..' . '/../lib/CardDAV/AddressBookRoot.php',
|
||||||
|
'OCA\\DAV\\CardDAV\\Card' => __DIR__ . '/..' . '/../lib/CardDAV/Card.php',
|
||||||
'OCA\\DAV\\CardDAV\\CardDavBackend' => __DIR__ . '/..' . '/../lib/CardDAV/CardDavBackend.php',
|
'OCA\\DAV\\CardDAV\\CardDavBackend' => __DIR__ . '/..' . '/../lib/CardDAV/CardDavBackend.php',
|
||||||
'OCA\\DAV\\CardDAV\\ContactsManager' => __DIR__ . '/..' . '/../lib/CardDAV/ContactsManager.php',
|
'OCA\\DAV\\CardDAV\\ContactsManager' => __DIR__ . '/..' . '/../lib/CardDAV/ContactsManager.php',
|
||||||
'OCA\\DAV\\CardDAV\\Converter' => __DIR__ . '/..' . '/../lib/CardDAV/Converter.php',
|
'OCA\\DAV\\CardDAV\\Converter' => __DIR__ . '/..' . '/../lib/CardDAV/Converter.php',
|
||||||
|
@ -245,6 +246,7 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\Events\\CalendarUpdatedEvent' => __DIR__ . '/..' . '/../lib/Events/CalendarUpdatedEvent.php',
|
'OCA\\DAV\\Events\\CalendarUpdatedEvent' => __DIR__ . '/..' . '/../lib/Events/CalendarUpdatedEvent.php',
|
||||||
'OCA\\DAV\\Events\\CardCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/CardCreatedEvent.php',
|
'OCA\\DAV\\Events\\CardCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/CardCreatedEvent.php',
|
||||||
'OCA\\DAV\\Events\\CardDeletedEvent' => __DIR__ . '/..' . '/../lib/Events/CardDeletedEvent.php',
|
'OCA\\DAV\\Events\\CardDeletedEvent' => __DIR__ . '/..' . '/../lib/Events/CardDeletedEvent.php',
|
||||||
|
'OCA\\DAV\\Events\\CardMovedEvent' => __DIR__ . '/..' . '/../lib/Events/CardMovedEvent.php',
|
||||||
'OCA\\DAV\\Events\\CardUpdatedEvent' => __DIR__ . '/..' . '/../lib/Events/CardUpdatedEvent.php',
|
'OCA\\DAV\\Events\\CardUpdatedEvent' => __DIR__ . '/..' . '/../lib/Events/CardUpdatedEvent.php',
|
||||||
'OCA\\DAV\\Events\\SabrePluginAuthInitEvent' => __DIR__ . '/..' . '/../lib/Events/SabrePluginAuthInitEvent.php',
|
'OCA\\DAV\\Events\\SabrePluginAuthInitEvent' => __DIR__ . '/..' . '/../lib/Events/SabrePluginAuthInitEvent.php',
|
||||||
'OCA\\DAV\\Events\\SubscriptionCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/SubscriptionCreatedEvent.php',
|
'OCA\\DAV\\Events\\SubscriptionCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/SubscriptionCreatedEvent.php',
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||||
* @author Joas Schilling <coding@schilljs.com>
|
* @author Joas Schilling <coding@schilljs.com>
|
||||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||||
|
* @author Thomas Citharel <nextcloud@tcit.fr>
|
||||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||||
*
|
*
|
||||||
* @license AGPL-3.0
|
* @license AGPL-3.0
|
||||||
|
@ -27,11 +28,15 @@ namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
use OCA\DAV\DAV\Sharing\IShareable;
|
use OCA\DAV\DAV\Sharing\IShareable;
|
||||||
use OCA\DAV\Exception\UnsupportedLimitOnInitialSyncException;
|
use OCA\DAV\Exception\UnsupportedLimitOnInitialSyncException;
|
||||||
|
use OCP\DB\Exception;
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
|
use OCP\Server;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Sabre\CardDAV\Backend\BackendInterface;
|
use Sabre\CardDAV\Backend\BackendInterface;
|
||||||
use Sabre\CardDAV\Card;
|
|
||||||
use Sabre\DAV\Exception\Forbidden;
|
use Sabre\DAV\Exception\Forbidden;
|
||||||
use Sabre\DAV\Exception\NotFound;
|
use Sabre\DAV\Exception\NotFound;
|
||||||
|
use Sabre\DAV\IMoveTarget;
|
||||||
|
use Sabre\DAV\INode;
|
||||||
use Sabre\DAV\PropPatch;
|
use Sabre\DAV\PropPatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +45,7 @@ use Sabre\DAV\PropPatch;
|
||||||
* @package OCA\DAV\CardDAV
|
* @package OCA\DAV\CardDAV
|
||||||
* @property CardDavBackend $carddavBackend
|
* @property CardDavBackend $carddavBackend
|
||||||
*/
|
*/
|
||||||
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
|
class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable, IMoveTarget {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AddressBook constructor.
|
* AddressBook constructor.
|
||||||
|
@ -52,6 +57,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
|
||||||
public function __construct(BackendInterface $carddavBackend, array $addressBookInfo, IL10N $l10n) {
|
public function __construct(BackendInterface $carddavBackend, array $addressBookInfo, IL10N $l10n) {
|
||||||
parent::__construct($carddavBackend, $addressBookInfo);
|
parent::__construct($carddavBackend, $addressBookInfo);
|
||||||
|
|
||||||
|
|
||||||
if ($this->addressBookInfo['{DAV:}displayname'] === CardDavBackend::PERSONAL_ADDRESSBOOK_NAME &&
|
if ($this->addressBookInfo['{DAV:}displayname'] === CardDavBackend::PERSONAL_ADDRESSBOOK_NAME &&
|
||||||
$this->getName() === CardDavBackend::PERSONAL_ADDRESSBOOK_URI) {
|
$this->getName() === CardDavBackend::PERSONAL_ADDRESSBOOK_URI) {
|
||||||
$this->addressBookInfo['{DAV:}displayname'] = $l10n->t('Contacts');
|
$this->addressBookInfo['{DAV:}displayname'] = $l10n->t('Contacts');
|
||||||
|
@ -160,6 +166,30 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
|
||||||
return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
|
return new Card($this->carddavBackend, $this->addressBookInfo, $obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
$objs = $this->carddavBackend->getCards($this->addressBookInfo['id']);
|
||||||
|
$children = [];
|
||||||
|
foreach ($objs as $obj) {
|
||||||
|
$obj['acl'] = $this->getChildACL();
|
||||||
|
$children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMultipleChildren(array $paths)
|
||||||
|
{
|
||||||
|
$objs = $this->carddavBackend->getMultipleCards($this->addressBookInfo['id'], $paths);
|
||||||
|
$children = [];
|
||||||
|
foreach ($objs as $obj) {
|
||||||
|
$obj['acl'] = $this->getChildACL();
|
||||||
|
$children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $children;
|
||||||
|
}
|
||||||
|
|
||||||
public function getResourceId(): int {
|
public function getResourceId(): int {
|
||||||
return $this->addressBookInfo['id'];
|
return $this->addressBookInfo['id'];
|
||||||
}
|
}
|
||||||
|
@ -223,4 +253,21 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable {
|
||||||
|
|
||||||
return parent::getChanges($syncToken, $syncLevel, $limit);
|
return parent::getChanges($syncToken, $syncLevel, $limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function moveInto($targetName, $sourcePath, INode $sourceNode) {
|
||||||
|
if (!($sourceNode instanceof Card)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $this->carddavBackend->moveCard($sourceNode->getAddressbookId(), (int)$this->addressBookInfo['id'], $sourceNode->getUri(), $sourceNode->getOwner());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Avoid injecting LoggerInterface everywhere
|
||||||
|
Server::get(LoggerInterface::class)->error('Could not move calendar object: ' . $e->getMessage(), ['exception' => $e]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
|
||||||
|
*
|
||||||
|
* @author Thomas Citharel <nextcloud@tcit.fr>
|
||||||
|
*
|
||||||
|
* @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/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
|
class Card extends \Sabre\CardDAV\Card
|
||||||
|
{
|
||||||
|
public function getId(): int {
|
||||||
|
return (int) $this->cardData['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUri(): string {
|
||||||
|
return $this->cardData['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isShared(): bool {
|
||||||
|
if (!isset($this->cardData['{http://owncloud.org/ns}owner-principal'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->cardData['{http://owncloud.org/ns}owner-principal'] !== $this->cardData['principaluri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddressbookId(): int {
|
||||||
|
return (int)$this->cardData['addressbookid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrincipalUri(): string {
|
||||||
|
return $this->addressBookInfo['principaluri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOwner(): ?string {
|
||||||
|
if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) {
|
||||||
|
return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal'];
|
||||||
|
}
|
||||||
|
return parent::getOwner();
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,8 +44,10 @@ use OCA\DAV\Events\AddressBookShareUpdatedEvent;
|
||||||
use OCA\DAV\Events\AddressBookUpdatedEvent;
|
use OCA\DAV\Events\AddressBookUpdatedEvent;
|
||||||
use OCA\DAV\Events\CardCreatedEvent;
|
use OCA\DAV\Events\CardCreatedEvent;
|
||||||
use OCA\DAV\Events\CardDeletedEvent;
|
use OCA\DAV\Events\CardDeletedEvent;
|
||||||
|
use OCA\DAV\Events\CardMovedEvent;
|
||||||
use OCA\DAV\Events\CardUpdatedEvent;
|
use OCA\DAV\Events\CardUpdatedEvent;
|
||||||
use OCP\AppFramework\Db\TTransactional;
|
use OCP\AppFramework\Db\TTransactional;
|
||||||
|
use OCP\DB\Exception;
|
||||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\EventDispatcher\IEventDispatcher;
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
@ -745,6 +747,49 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
}, $this->db);
|
}, $this->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function moveCard(int $sourceAddressBookId, int $targetAddressBookId, string $cardUri, string $oldPrincipalUri): bool {
|
||||||
|
return $this->atomic(function () use ($sourceAddressBookId, $targetAddressBookId, $cardUri, $oldPrincipalUri) {
|
||||||
|
$card = $this->getCard($sourceAddressBookId, $cardUri);
|
||||||
|
if (empty($card)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->update('cards')
|
||||||
|
->set('addressbookid', $query->createNamedParameter($targetAddressBookId, IQueryBuilder::PARAM_INT))
|
||||||
|
->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri, IQueryBuilder::PARAM_STR), IQueryBuilder::PARAM_STR))
|
||||||
|
->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($sourceAddressBookId, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT))
|
||||||
|
->executeStatement();
|
||||||
|
|
||||||
|
$this->purgeProperties($sourceAddressBookId, (int)$card['id']);
|
||||||
|
$this->updateProperties($sourceAddressBookId, $card['uri'], $card['carddata']);
|
||||||
|
|
||||||
|
$this->addChange($sourceAddressBookId, $card['uri'], 3);
|
||||||
|
$this->addChange($targetAddressBookId, $card['uri'], 1);
|
||||||
|
|
||||||
|
$card = $this->getCard($targetAddressBookId, $cardUri);
|
||||||
|
// Card wasn't found - possibly because it was deleted in the meantime by a different client
|
||||||
|
if (empty($card)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetAddressBookRow = $this->getAddressBookById($targetAddressBookId);
|
||||||
|
// the address book this card is being moved to does not exist any longer
|
||||||
|
if (empty($targetAddressBookRow)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceShares = $this->getShares($sourceAddressBookId);
|
||||||
|
$targetShares = $this->getShares($targetAddressBookId);
|
||||||
|
$sourceAddressBookRow = $this->getAddressBookById($sourceAddressBookId);
|
||||||
|
$this->dispatcher->dispatchTyped(new CardMovedEvent($sourceAddressBookId, $sourceAddressBookRow, $targetAddressBookId, $targetAddressBookRow, $sourceShares, $targetShares, $card));
|
||||||
|
return true;
|
||||||
|
}, $this->db);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a card
|
* Deletes a card
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
|
||||||
|
*
|
||||||
|
* @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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Events;
|
||||||
|
|
||||||
|
use OCP\EventDispatcher\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CardMovedEvent
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\Events
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
class CardMovedEvent extends Event {
|
||||||
|
private int $sourceAddressBookId;
|
||||||
|
private array $sourceAddressBookData;
|
||||||
|
private int $targetAddressBookId;
|
||||||
|
private array $targetAddressBookData;
|
||||||
|
private array $sourceShares;
|
||||||
|
private array $targetShares;
|
||||||
|
private array $objectData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function __construct(int $sourceAddressBookId,
|
||||||
|
array $sourceAddressBookData,
|
||||||
|
int $targetAddressBookId,
|
||||||
|
array $targetAddressBookData,
|
||||||
|
array $sourceShares,
|
||||||
|
array $targetShares,
|
||||||
|
array $objectData) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->sourceAddressBookId = $sourceAddressBookId;
|
||||||
|
$this->sourceAddressBookData = $sourceAddressBookData;
|
||||||
|
$this->targetAddressBookId = $targetAddressBookId;
|
||||||
|
$this->targetAddressBookData = $targetAddressBookData;
|
||||||
|
$this->sourceShares = $sourceShares;
|
||||||
|
$this->targetShares = $targetShares;
|
||||||
|
$this->objectData = $objectData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getSourceAddressBookId(): int {
|
||||||
|
return $this->sourceAddressBookId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getSourceAddressBookData(): array {
|
||||||
|
return $this->sourceAddressBookData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getTargetAddressBookId(): int {
|
||||||
|
return $this->targetAddressBookId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getTargetAddressBookData(): array {
|
||||||
|
return $this->targetAddressBookData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getSourceShares(): array {
|
||||||
|
return $this->sourceShares;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getTargetShares(): array {
|
||||||
|
return $this->targetShares;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @since 27.0.0
|
||||||
|
*/
|
||||||
|
public function getObjectData(): array {
|
||||||
|
return $this->objectData;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
* @author Joas Schilling <coding@schilljs.com>
|
* @author Joas Schilling <coding@schilljs.com>
|
||||||
* @author Morris Jobke <hey@morrisjobke.de>
|
* @author Morris Jobke <hey@morrisjobke.de>
|
||||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||||
|
* @author Thomas Citharel <nextcloud@tcit.fr>
|
||||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||||
*
|
*
|
||||||
* @license AGPL-3.0
|
* @license AGPL-3.0
|
||||||
|
@ -26,94 +27,122 @@
|
||||||
namespace OCA\DAV\Tests\unit\CardDAV;
|
namespace OCA\DAV\Tests\unit\CardDAV;
|
||||||
|
|
||||||
use OCA\DAV\CardDAV\AddressBook;
|
use OCA\DAV\CardDAV\AddressBook;
|
||||||
|
use OCA\DAV\CardDAV\Card;
|
||||||
use OCA\DAV\CardDAV\CardDavBackend;
|
use OCA\DAV\CardDAV\CardDavBackend;
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Sabre\DAV\Exception\Forbidden;
|
||||||
use Sabre\DAV\PropPatch;
|
use Sabre\DAV\PropPatch;
|
||||||
use Test\TestCase;
|
use Test\TestCase;
|
||||||
|
|
||||||
class AddressBookTest extends TestCase {
|
class AddressBookTest extends TestCase {
|
||||||
|
public function testMove(): void {
|
||||||
|
$backend = $this->createMock(CardDavBackend::class);
|
||||||
|
$addressBookInfo = [
|
||||||
|
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
||||||
|
'{DAV:}displayname' => 'Test address book',
|
||||||
|
'principaluri' => 'user2',
|
||||||
|
'id' => 666,
|
||||||
|
'uri' => 'default',
|
||||||
|
];
|
||||||
|
$l10n = $this->createMock(IL10N::class);
|
||||||
|
$logger = $this->createMock(LoggerInterface::class);
|
||||||
|
$addressBook = new AddressBook($backend, $addressBookInfo, $l10n, $logger);
|
||||||
|
|
||||||
|
$card = new Card($backend, $addressBookInfo, ['id' => 5, 'carddata' => 'RANDOM VCF DATA', 'uri' => 'something', 'addressbookid' => 23]);
|
||||||
|
|
||||||
|
$backend->expects($this->once())->method('moveCard')->with(23, 666, 'something', 'user1')->willReturn(true);
|
||||||
|
|
||||||
|
$addressBook->moveInto('new', 'old', $card);
|
||||||
|
}
|
||||||
|
|
||||||
public function testDelete(): void {
|
public function testDelete(): void {
|
||||||
/** @var \PHPUnit\Framework\MockObject\MockObject | CardDavBackend $backend */
|
/** @var MockObject | CardDavBackend $backend */
|
||||||
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
||||||
$backend->expects($this->once())->method('updateShares');
|
$backend->expects($this->once())->method('updateShares');
|
||||||
$backend->expects($this->any())->method('getShares')->willReturn([
|
$backend->expects($this->any())->method('getShares')->willReturn([
|
||||||
['href' => 'principal:user2']
|
['href' => 'principal:user2']
|
||||||
]);
|
]);
|
||||||
$calendarInfo = [
|
$addressBookInfo = [
|
||||||
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
||||||
'{DAV:}displayname' => 'Test address book',
|
'{DAV:}displayname' => 'Test address book',
|
||||||
'principaluri' => 'user2',
|
'principaluri' => 'user2',
|
||||||
'id' => 666,
|
'id' => 666,
|
||||||
'uri' => 'default',
|
'uri' => 'default',
|
||||||
];
|
];
|
||||||
$l = $this->createMock(IL10N::class);
|
$l10n = $this->createMock(IL10N::class);
|
||||||
$c = new AddressBook($backend, $calendarInfo, $l);
|
$logger = $this->createMock(LoggerInterface::class);
|
||||||
$c->delete();
|
$addressBook = new AddressBook($backend, $addressBookInfo, $l10n, $logger);
|
||||||
|
$addressBook->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testDeleteFromGroup(): void {
|
public function testDeleteFromGroup(): void {
|
||||||
$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
|
$this->expectException(Forbidden::class);
|
||||||
|
|
||||||
/** @var \PHPUnit\Framework\MockObject\MockObject | CardDavBackend $backend */
|
/** @var MockObject | CardDavBackend $backend */
|
||||||
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
||||||
$backend->expects($this->never())->method('updateShares');
|
$backend->expects($this->never())->method('updateShares');
|
||||||
$backend->expects($this->any())->method('getShares')->willReturn([
|
$backend->expects($this->any())->method('getShares')->willReturn([
|
||||||
['href' => 'principal:group2']
|
['href' => 'principal:group2']
|
||||||
]);
|
]);
|
||||||
$calendarInfo = [
|
$addressBookInfo = [
|
||||||
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
||||||
'{DAV:}displayname' => 'Test address book',
|
'{DAV:}displayname' => 'Test address book',
|
||||||
'principaluri' => 'user2',
|
'principaluri' => 'user2',
|
||||||
'id' => 666,
|
'id' => 666,
|
||||||
'uri' => 'default',
|
'uri' => 'default',
|
||||||
];
|
];
|
||||||
$l = $this->createMock(IL10N::class);
|
$l10n = $this->createMock(IL10N::class);
|
||||||
$c = new AddressBook($backend, $calendarInfo, $l);
|
$logger = $this->createMock(LoggerInterface::class);
|
||||||
$c->delete();
|
$addressBook = new AddressBook($backend, $addressBookInfo, $l10n, $logger);
|
||||||
|
$addressBook->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testPropPatch(): void {
|
public function testPropPatch(): void {
|
||||||
$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
|
$this->expectException(Forbidden::class);
|
||||||
|
|
||||||
/** @var \PHPUnit\Framework\MockObject\MockObject | CardDavBackend $backend */
|
/** @var MockObject | CardDavBackend $backend */
|
||||||
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
||||||
$calendarInfo = [
|
$addressBookInfo = [
|
||||||
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
'{http://owncloud.org/ns}owner-principal' => 'user1',
|
||||||
'{DAV:}displayname' => 'Test address book',
|
'{DAV:}displayname' => 'Test address book',
|
||||||
'principaluri' => 'user2',
|
'principaluri' => 'user2',
|
||||||
'id' => 666,
|
'id' => 666,
|
||||||
'uri' => 'default',
|
'uri' => 'default',
|
||||||
];
|
];
|
||||||
$l = $this->createMock(IL10N::class);
|
$l10n = $this->createMock(IL10N::class);
|
||||||
$c = new AddressBook($backend, $calendarInfo, $l);
|
$logger = $this->createMock(LoggerInterface::class);
|
||||||
$c->propPatch(new PropPatch([]));
|
$addressBook = new AddressBook($backend, $addressBookInfo, $l10n, $logger);
|
||||||
|
$addressBook->propPatch(new PropPatch([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providesReadOnlyInfo
|
* @dataProvider providesReadOnlyInfo
|
||||||
*/
|
*/
|
||||||
public function testAcl($expectsWrite, $readOnlyValue, $hasOwnerSet): void {
|
public function testAcl($expectsWrite, $readOnlyValue, $hasOwnerSet): void {
|
||||||
/** @var \PHPUnit\Framework\MockObject\MockObject | CardDavBackend $backend */
|
/** @var MockObject | CardDavBackend $backend */
|
||||||
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
|
||||||
$backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1);
|
$backend->expects($this->any())->method('applyShareAcl')->willReturnArgument(1);
|
||||||
$calendarInfo = [
|
$addressBookInfo = [
|
||||||
'{DAV:}displayname' => 'Test address book',
|
'{DAV:}displayname' => 'Test address book',
|
||||||
'principaluri' => 'user2',
|
'principaluri' => 'user2',
|
||||||
'id' => 666,
|
'id' => 666,
|
||||||
'uri' => 'default'
|
'uri' => 'default'
|
||||||
];
|
];
|
||||||
if (!is_null($readOnlyValue)) {
|
if (!is_null($readOnlyValue)) {
|
||||||
$calendarInfo['{http://owncloud.org/ns}read-only'] = $readOnlyValue;
|
$addressBookInfo['{http://owncloud.org/ns}read-only'] = $readOnlyValue;
|
||||||
}
|
}
|
||||||
if ($hasOwnerSet) {
|
if ($hasOwnerSet) {
|
||||||
$calendarInfo['{http://owncloud.org/ns}owner-principal'] = 'user1';
|
$addressBookInfo['{http://owncloud.org/ns}owner-principal'] = 'user1';
|
||||||
}
|
}
|
||||||
$l = $this->createMock(IL10N::class);
|
$l10n = $this->createMock(IL10N::class);
|
||||||
$c = new AddressBook($backend, $calendarInfo, $l);
|
$logger = $this->createMock(LoggerInterface::class);
|
||||||
$acl = $c->getACL();
|
$addressBook = new AddressBook($backend, $addressBookInfo, $l10n, $logger);
|
||||||
$childAcl = $c->getChildACL();
|
$acl = $addressBook->getACL();
|
||||||
|
$childAcl = $addressBook->getChildACL();
|
||||||
|
|
||||||
$expectedAcl = [[
|
$expectedAcl = [[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
|
@ -142,7 +171,7 @@ class AddressBookTest extends TestCase {
|
||||||
$this->assertEquals($expectedAcl, $childAcl);
|
$this->assertEquals($expectedAcl, $childAcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function providesReadOnlyInfo() {
|
public function providesReadOnlyInfo(): array {
|
||||||
return [
|
return [
|
||||||
'read-only property not set' => [true, null, true],
|
'read-only property not set' => [true, null, true],
|
||||||
'read-only property is false' => [true, false, true],
|
'read-only property is false' => [true, false, true],
|
||||||
|
|
|
@ -31,6 +31,11 @@
|
||||||
<code>$data</code>
|
<code>$data</code>
|
||||||
</MoreSpecificImplementedParamType>
|
</MoreSpecificImplementedParamType>
|
||||||
</file>
|
</file>
|
||||||
|
<file src="3rdparty/sabre/dav/lib/CardDAV/Card.php">
|
||||||
|
<MoreSpecificImplementedParamType occurrences="1">
|
||||||
|
<code>$cardData</code>
|
||||||
|
</MoreSpecificImplementedParamType>
|
||||||
|
</file>
|
||||||
<file src="3rdparty/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php">
|
<file src="3rdparty/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php">
|
||||||
<LessSpecificImplementedReturnType>
|
<LessSpecificImplementedReturnType>
|
||||||
<code>array</code>
|
<code>array</code>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче