Merge pull request #20696 from owncloud/add-carddav-backends-to-ocp-contactsmanager
Add carddav backend to OCP\ContactsManager
This commit is contained in:
commit
792b270f22
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||||
|
* @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/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
$cm = \OC::$server->getContactsManager();
|
||||||
|
$cm->register(function() use ($cm) {
|
||||||
|
$db = \OC::$server->getDatabaseConnection();
|
||||||
|
$userId = \OC::$server->getUserSession()->getUser()->getUID();
|
||||||
|
$principal = new \OCA\DAV\Connector\Sabre\Principal(
|
||||||
|
\OC::$server->getConfig(),
|
||||||
|
\OC::$server->getUserManager()
|
||||||
|
);
|
||||||
|
$cardDav = new \OCA\DAV\CardDAV\CardDavBackend($db, $principal, \OC::$server->getLogger());
|
||||||
|
$addressBooks = $cardDav->getAddressBooksForUser("principals/$userId");
|
||||||
|
foreach ($addressBooks as $addressBookInfo) {
|
||||||
|
$addressBook = new \OCA\DAV\CardDAV\AddressBook($cardDav, $addressBookInfo);
|
||||||
|
$cm->registerAddressBook(
|
||||||
|
new OCA\DAV\CardDAV\AddressBookImpl(
|
||||||
|
$addressBook,
|
||||||
|
$addressBookInfo,
|
||||||
|
$cardDav
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
|
@ -571,6 +571,78 @@ CREATE TABLE calendarobjects (
|
||||||
</declaration>
|
</declaration>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*cards_properties</name>
|
||||||
|
<declaration>
|
||||||
|
<field>
|
||||||
|
<name>id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<autoincrement>1</autoincrement>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>11</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>addressbookid</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>11</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>cardid</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<unsigned>true</unsigned>
|
||||||
|
<length>11</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>name</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>false</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>value</name>
|
||||||
|
<type>text</type>
|
||||||
|
<default></default>
|
||||||
|
<notnull>false</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>preferred</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>1</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>4</length>
|
||||||
|
</field>
|
||||||
|
<index>
|
||||||
|
<name>card_contactid_index</name>
|
||||||
|
<field>
|
||||||
|
<name>cardid</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
<index>
|
||||||
|
<name>card_name_index</name>
|
||||||
|
<field>
|
||||||
|
<name>name</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
<index>
|
||||||
|
<name>card_value_index</name>
|
||||||
|
<field>
|
||||||
|
<name>value</name>
|
||||||
|
<sorting>ascending</sorting>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<name>*dbprefix*dav_shares</name>
|
<name>*dbprefix*dav_shares</name>
|
||||||
<declaration>
|
<declaration>
|
||||||
|
|
|
@ -8,8 +8,9 @@ $config = \OC::$server->getConfig();
|
||||||
$dbConnection = \OC::$server->getDatabaseConnection();
|
$dbConnection = \OC::$server->getDatabaseConnection();
|
||||||
$userManager = OC::$server->getUserManager();
|
$userManager = OC::$server->getUserManager();
|
||||||
$config = \OC::$server->getConfig();
|
$config = \OC::$server->getConfig();
|
||||||
|
$logger = \OC::$server->getLogger();
|
||||||
|
|
||||||
/** @var Symfony\Component\Console\Application $application */
|
/** @var Symfony\Component\Console\Application $application */
|
||||||
$application->add(new CreateAddressBook($userManager, $dbConnection, $config));
|
$application->add(new CreateAddressBook($userManager, $dbConnection, $config, $logger));
|
||||||
$application->add(new CreateCalendar($userManager, $dbConnection));
|
$application->add(new CreateCalendar($userManager, $dbConnection));
|
||||||
$application->add(new SyncSystemAddressBook($userManager, $dbConnection, $config));
|
$application->add(new SyncSystemAddressBook($userManager, $dbConnection, $config));
|
||||||
|
|
|
@ -6,6 +6,7 @@ use OCA\DAV\CardDAV\CardDavBackend;
|
||||||
use OCA\DAV\Connector\Sabre\Principal;
|
use OCA\DAV\Connector\Sabre\Principal;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
use OCP\ILogger;
|
||||||
use OCP\IUserManager;
|
use OCP\IUserManager;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
@ -23,15 +24,25 @@ class CreateAddressBook extends Command {
|
||||||
/** @var IConfig */
|
/** @var IConfig */
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
/** @var ILogger */
|
||||||
|
private $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param IUserManager $userManager
|
* @param IUserManager $userManager
|
||||||
* @param IDBConnection $dbConnection
|
* @param IDBConnection $dbConnection
|
||||||
|
* @param IConfig $config
|
||||||
|
* @param ILogger $logger
|
||||||
*/
|
*/
|
||||||
function __construct(IUserManager $userManager, IDBConnection $dbConnection, IConfig $config) {
|
function __construct(IUserManager $userManager,
|
||||||
|
IDBConnection $dbConnection,
|
||||||
|
IConfig $config,
|
||||||
|
ILogger $logger
|
||||||
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->userManager = $userManager;
|
$this->userManager = $userManager;
|
||||||
$this->dbConnection = $dbConnection;
|
$this->dbConnection = $dbConnection;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function configure() {
|
protected function configure() {
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||||
|
* @author Björn Schießle <schiessle@owncloud.com>
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||||
|
* @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;
|
||||||
|
|
||||||
|
use OCP\Constants;
|
||||||
|
use OCP\IAddressBook;
|
||||||
|
use Sabre\VObject\Component\VCard;
|
||||||
|
use Sabre\VObject\Property\Text;
|
||||||
|
use Sabre\VObject\Reader;
|
||||||
|
use Sabre\VObject\UUIDUtil;
|
||||||
|
|
||||||
|
class AddressBookImpl implements IAddressBook {
|
||||||
|
|
||||||
|
/** @var CardDavBackend */
|
||||||
|
private $backend;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $addressBookInfo;
|
||||||
|
|
||||||
|
/** @var AddressBook */
|
||||||
|
private $addressBook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AddressBookImpl constructor.
|
||||||
|
*
|
||||||
|
* @param AddressBook $addressBook
|
||||||
|
* @param array $addressBookInfo
|
||||||
|
* @param CardDavBackend $backend
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
AddressBook $addressBook,
|
||||||
|
array $addressBookInfo,
|
||||||
|
CardDavBackend $backend) {
|
||||||
|
|
||||||
|
$this->addressBook = $addressBook;
|
||||||
|
$this->addressBookInfo = $addressBookInfo;
|
||||||
|
$this->backend = $backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string defining the technical unique key
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public function getKey() {
|
||||||
|
return $this->addressBookInfo['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In comparison to getKey() this function returns a human readable (maybe translated) name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public function getDisplayName() {
|
||||||
|
return $this->addressBookInfo['{DAV:}displayname'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $pattern which should match within the $searchProperties
|
||||||
|
* @param array $searchProperties defines the properties within the query pattern should match
|
||||||
|
* @param array $options - for future use. One should always have options!
|
||||||
|
* @return array an array of contacts which are arrays of key-value-pairs
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public function search($pattern, $searchProperties, $options) {
|
||||||
|
$result = $this->backend->search($this->getKey(), $pattern, $searchProperties);
|
||||||
|
|
||||||
|
$vCards = [];
|
||||||
|
foreach ($result as $cardData) {
|
||||||
|
$vCards[] = $this->vCard2Array($this->readCard($cardData));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $properties this array if key-value-pairs defines a contact
|
||||||
|
* @return array an array representing the contact just created or updated
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public function createOrUpdate($properties) {
|
||||||
|
$update = false;
|
||||||
|
if (!isset($properties['UID'])) { // create a new contact
|
||||||
|
$uid = $this->createUid();
|
||||||
|
$uri = $uid . '.vcf';
|
||||||
|
$vCard = $this->createEmptyVCard($uid);
|
||||||
|
} else { // update existing contact
|
||||||
|
$uid = $properties['UID'];
|
||||||
|
$uri = $uid . '.vcf';
|
||||||
|
$vCardData = $this->backend->getCard($this->getKey(), $uri);
|
||||||
|
$vCard = $this->readCard($vCardData['carddata']);
|
||||||
|
$update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($properties as $key => $value) {
|
||||||
|
$vCard->$key = $vCard->createProperty($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($update) {
|
||||||
|
$this->backend->updateCard($this->getKey(), $uri, $vCard->serialize());
|
||||||
|
} else {
|
||||||
|
$this->backend->createCard($this->getKey(), $uri, $vCard->serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->vCard2Array($vCard);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public function getPermissions() {
|
||||||
|
$permissions = $this->addressBook->getACL();
|
||||||
|
$result = 0;
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
switch($permission['privilege']) {
|
||||||
|
case '{DAV:}read':
|
||||||
|
$result |= Constants::PERMISSION_READ;
|
||||||
|
break;
|
||||||
|
case '{DAV:}write':
|
||||||
|
$result |= Constants::PERMISSION_CREATE;
|
||||||
|
$result |= Constants::PERMISSION_UPDATE;
|
||||||
|
break;
|
||||||
|
case '{DAV:}all':
|
||||||
|
$result |= Constants::PERMISSION_ALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $id the unique identifier to a contact
|
||||||
|
* @return bool successful or not
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
public function delete($id) {
|
||||||
|
$uri = $this->backend->getCardUri($id);
|
||||||
|
return $this->backend->deleteCard($this->addressBookInfo['id'], $uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read vCard data into a vCard object
|
||||||
|
*
|
||||||
|
* @param string $cardData
|
||||||
|
* @return VCard
|
||||||
|
*/
|
||||||
|
protected function readCard($cardData) {
|
||||||
|
return Reader::read($cardData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create UID for contact
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function createUid() {
|
||||||
|
do {
|
||||||
|
$uid = $this->getUid();
|
||||||
|
} while (!empty($this->backend->getContact($uid . '.vcf')));
|
||||||
|
|
||||||
|
return $uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getUid is only there for testing, use createUid instead
|
||||||
|
*/
|
||||||
|
protected function getUid() {
|
||||||
|
return UUIDUtil::getUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create empty vcard
|
||||||
|
*
|
||||||
|
* @param string $uid
|
||||||
|
* @return VCard
|
||||||
|
*/
|
||||||
|
protected function createEmptyVCard($uid) {
|
||||||
|
$vCard = new VCard();
|
||||||
|
$vCard->add(new Text($vCard, 'UID', $uid));
|
||||||
|
return $vCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create array with all vCard properties
|
||||||
|
*
|
||||||
|
* @param VCard $vCard
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function vCard2Array(VCard $vCard) {
|
||||||
|
$result = [];
|
||||||
|
foreach ($vCard->children as $property) {
|
||||||
|
$result[$property->name] = $property->getValue();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,19 +23,48 @@
|
||||||
namespace OCA\DAV\CardDAV;
|
namespace OCA\DAV\CardDAV;
|
||||||
|
|
||||||
use OCA\DAV\Connector\Sabre\Principal;
|
use OCA\DAV\Connector\Sabre\Principal;
|
||||||
|
use OCP\IDBConnection;
|
||||||
|
use OCP\ILogger;
|
||||||
use Sabre\CardDAV\Backend\BackendInterface;
|
use Sabre\CardDAV\Backend\BackendInterface;
|
||||||
use Sabre\CardDAV\Backend\SyncSupport;
|
use Sabre\CardDAV\Backend\SyncSupport;
|
||||||
use Sabre\CardDAV\Plugin;
|
use Sabre\CardDAV\Plugin;
|
||||||
use Sabre\DAV\Exception\BadRequest;
|
use Sabre\DAV\Exception\BadRequest;
|
||||||
|
use Sabre\VObject\Component\VCard;
|
||||||
|
use Sabre\VObject\Reader;
|
||||||
|
|
||||||
class CardDavBackend implements BackendInterface, SyncSupport {
|
class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
/** @var Principal */
|
/** @var Principal */
|
||||||
private $principalBackend;
|
private $principalBackend;
|
||||||
|
|
||||||
public function __construct(\OCP\IDBConnection $db, Principal $principalBackend) {
|
/** @var ILogger */
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $dbCardsTable = 'cards';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $dbCardsPropertiesTable = 'cards_properties';
|
||||||
|
|
||||||
|
/** @var IDBConnection */
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/** @var array properties to index */
|
||||||
|
public static $indexProperties = array(
|
||||||
|
'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME',
|
||||||
|
'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CardDavBackend constructor.
|
||||||
|
*
|
||||||
|
* @param IDBConnection $db
|
||||||
|
* @param Principal $principalBackend
|
||||||
|
* @param ILogger $logger
|
||||||
|
*/
|
||||||
|
public function __construct(IDBConnection $db, Principal $principalBackend, ILogger $logger) {
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
$this->principalBackend = $principalBackend;
|
$this->principalBackend = $principalBackend;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,6 +292,11 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
->where($query->expr()->eq('resourceid', $query->createNamedParameter($addressBookId)))
|
->where($query->expr()->eq('resourceid', $query->createNamedParameter($addressBookId)))
|
||||||
->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook')))
|
->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook')))
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
$query->delete($this->dbCardsPropertiesTable)
|
||||||
|
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||||
|
->execute();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -398,7 +432,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->insert('cards')
|
$query->insert('cards')
|
||||||
->values([
|
->values([
|
||||||
'carddata' => $query->createNamedParameter($cardData),
|
'carddata' => $query->createNamedParameter($cardData, \PDO::PARAM_LOB),
|
||||||
'uri' => $query->createNamedParameter($cardUri),
|
'uri' => $query->createNamedParameter($cardUri),
|
||||||
'lastmodified' => $query->createNamedParameter(time()),
|
'lastmodified' => $query->createNamedParameter(time()),
|
||||||
'addressbookid' => $query->createNamedParameter($addressBookId),
|
'addressbookid' => $query->createNamedParameter($addressBookId),
|
||||||
|
@ -408,6 +442,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$this->addChange($addressBookId, $cardUri, 1);
|
$this->addChange($addressBookId, $cardUri, 1);
|
||||||
|
$this->updateProperties($addressBookId, $cardUri, $cardData);
|
||||||
|
|
||||||
return '"' . $etag . '"';
|
return '"' . $etag . '"';
|
||||||
}
|
}
|
||||||
|
@ -451,6 +486,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$this->addChange($addressBookId, $cardUri, 2);
|
$this->addChange($addressBookId, $cardUri, 2);
|
||||||
|
$this->updateProperties($addressBookId, $cardUri, $cardData);
|
||||||
|
|
||||||
return '"' . $etag . '"';
|
return '"' . $etag . '"';
|
||||||
}
|
}
|
||||||
|
@ -463,6 +499,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function deleteCard($addressBookId, $cardUri) {
|
function deleteCard($addressBookId, $cardUri) {
|
||||||
|
$cardId = $this->getCardId($cardUri);
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$ret = $query->delete('cards')
|
$ret = $query->delete('cards')
|
||||||
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)))
|
||||||
|
@ -471,7 +508,12 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
$this->addChange($addressBookId, $cardUri, 3);
|
$this->addChange($addressBookId, $cardUri, 3);
|
||||||
|
|
||||||
return $ret === 1;
|
if ($ret === 1) {
|
||||||
|
$this->purgeProperties($addressBookId, $cardId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -637,6 +679,87 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* search contact
|
||||||
|
*
|
||||||
|
* @param int $addressBookId
|
||||||
|
* @param string $pattern which should match within the $searchProperties
|
||||||
|
* @param array $searchProperties defines the properties within the query pattern should match
|
||||||
|
* @return array an array of contacts which are arrays of key-value-pairs
|
||||||
|
*/
|
||||||
|
public function search($addressBookId, $pattern, $searchProperties) {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query2 = $this->db->getQueryBuilder();
|
||||||
|
$query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp');
|
||||||
|
foreach ($searchProperties as $property) {
|
||||||
|
$query2->orWhere(
|
||||||
|
$query2->expr()->andX(
|
||||||
|
$query2->expr()->eq('cp.name', $query->createNamedParameter($property)),
|
||||||
|
$query2->expr()->like('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId)));
|
||||||
|
|
||||||
|
$query->select('c.carddata')->from($this->dbCardsTable, 'c')
|
||||||
|
->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL())));
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
$cards = $result->fetchAll();
|
||||||
|
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
return array_map(function($array) {return $this->readBlob($array['carddata']);}, $cards);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get URI from a given contact
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getCardUri($id) {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select('uri')->from($this->dbCardsTable)
|
||||||
|
->where($query->expr()->eq('id', $query->createParameter('id')))
|
||||||
|
->setParameter('id', $id);
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
$uri = $result->fetch();
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
if (!isset($uri['uri'])) {
|
||||||
|
throw new \InvalidArgumentException('Card does not exists: ' . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uri['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return contact with the given URI
|
||||||
|
*
|
||||||
|
* @param string $uri
|
||||||
|
* @returns array
|
||||||
|
*/
|
||||||
|
public function getContact($uri) {
|
||||||
|
$result = [];
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select('*')->from($this->dbCardsTable)
|
||||||
|
->where($query->expr()->eq('uri', $query->createParameter('uri')))
|
||||||
|
->setParameter('uri', $uri);
|
||||||
|
$queryResult = $query->execute();
|
||||||
|
$contact = $queryResult->fetch();
|
||||||
|
$queryResult->closeCursor();
|
||||||
|
|
||||||
|
if (is_array($contact)) {
|
||||||
|
$result = $contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $addressBookUri
|
* @param string $addressBookUri
|
||||||
* @param string $element
|
* @param string $element
|
||||||
|
@ -734,4 +857,93 @@ class CardDavBackend implements BackendInterface, SyncSupport {
|
||||||
|
|
||||||
return $shares;
|
return $shares;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update properties table
|
||||||
|
*
|
||||||
|
* @param int $addressBookId
|
||||||
|
* @param string $cardUri
|
||||||
|
* @param string $vCardSerialized
|
||||||
|
*/
|
||||||
|
protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) {
|
||||||
|
$cardId = $this->getCardId($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')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($vCard->children as $property) {
|
||||||
|
if(!in_array($property->name, self::$indexProperties)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$preferred = 0;
|
||||||
|
foreach($property->parameters as $parameter) {
|
||||||
|
if ($parameter->name == 'TYPE' && strtoupper($parameter->getValue()) == 'PREF') {
|
||||||
|
$preferred = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$query->setParameter('name', $property->name);
|
||||||
|
$query->setParameter('value', substr($property->getValue(), 0, 254));
|
||||||
|
$query->setParameter('preferred', $preferred);
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read vCard data into a vCard object
|
||||||
|
*
|
||||||
|
* @param string $cardData
|
||||||
|
* @return VCard
|
||||||
|
*/
|
||||||
|
protected function readCard($cardData) {
|
||||||
|
return Reader::read($cardData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete all properties from a given card
|
||||||
|
*
|
||||||
|
* @param int $addressBookId
|
||||||
|
* @param int $cardId
|
||||||
|
*/
|
||||||
|
protected function purgeProperties($addressBookId, $cardId) {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->delete($this->dbCardsPropertiesTable)
|
||||||
|
->where($query->expr()->eq('cardid', $query->createNamedParameter($cardId)))
|
||||||
|
->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId)));
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get ID from a given contact
|
||||||
|
*
|
||||||
|
* @param string $uri
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function getCardId($uri) {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select('id')->from($this->dbCardsTable)
|
||||||
|
->where($query->expr()->eq('uri', $query->createNamedParameter($uri)));
|
||||||
|
|
||||||
|
$result = $query->execute();
|
||||||
|
$cardIds = $result->fetch();
|
||||||
|
$result->closeCursor();
|
||||||
|
|
||||||
|
if (!isset($cardIds['id'])) {
|
||||||
|
throw new \InvalidArgumentException('Card does not exists: ' . $uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)$cardIds['id'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,11 @@ class RootCollection extends SimpleCollection {
|
||||||
\OC::$server->getSystemTagObjectMapper()
|
\OC::$server->getSystemTagObjectMapper()
|
||||||
);
|
);
|
||||||
|
|
||||||
$usersCardDavBackend = new CardDavBackend($db, $principalBackend);
|
$usersCardDavBackend = new CardDavBackend($db, $principalBackend, \OC::$server->getLogger());
|
||||||
$usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users');
|
$usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users');
|
||||||
$usersAddressBookRoot->disableListing = $disableListing;
|
$usersAddressBookRoot->disableListing = $disableListing;
|
||||||
|
|
||||||
$systemCardDavBackend = new CardDavBackend($db, $principalBackend);
|
$systemCardDavBackend = new CardDavBackend($db, $principalBackend, \OC::$server->getLogger());
|
||||||
$systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system');
|
$systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system');
|
||||||
$systemAddressBookRoot->disableListing = $disableListing;
|
$systemAddressBookRoot->disableListing = $disableListing;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,287 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Björn Schießle <schiessle@owncloud.com>
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||||
|
* @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\Tests\Unit\CardDAV;
|
||||||
|
|
||||||
|
|
||||||
|
use OCA\DAV\CardDAV\AddressBook;
|
||||||
|
use OCA\DAV\CardDAV\AddressBookImpl;
|
||||||
|
use OCA\DAV\CardDAV\CardDavBackend;
|
||||||
|
use Sabre\VObject\Component\VCard;
|
||||||
|
use Sabre\VObject\Property\Text;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class AddressBookImplTest extends TestCase {
|
||||||
|
|
||||||
|
/** @var AddressBookImpl */
|
||||||
|
private $addressBookImpl;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $addressBookInfo;
|
||||||
|
|
||||||
|
/** @var AddressBook | \PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $addressBook;
|
||||||
|
|
||||||
|
/** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $backend;
|
||||||
|
|
||||||
|
/** @var VCard | \PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $vCard;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->addressBookInfo = [
|
||||||
|
'id' => 42,
|
||||||
|
'{DAV:}displayname' => 'display name'
|
||||||
|
];
|
||||||
|
$this->addressBook = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBook')
|
||||||
|
->disableOriginalConstructor()->getMock();
|
||||||
|
$this->backend = $this->getMockBuilder('\OCA\DAV\CardDAV\CardDavBackend')
|
||||||
|
->disableOriginalConstructor()->getMock();
|
||||||
|
$this->vCard = $this->getMock('Sabre\VObject\Component\VCard');
|
||||||
|
|
||||||
|
$this->addressBookImpl = new AddressBookImpl(
|
||||||
|
$this->addressBook,
|
||||||
|
$this->addressBookInfo,
|
||||||
|
$this->backend
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetKey() {
|
||||||
|
$this->assertSame($this->addressBookInfo['id'],
|
||||||
|
$this->addressBookImpl->getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDisplayName() {
|
||||||
|
$this->assertSame($this->addressBookInfo['{DAV:}displayname'],
|
||||||
|
$this->addressBookImpl->getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSearch() {
|
||||||
|
|
||||||
|
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||||
|
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||||
|
->setConstructorArgs(
|
||||||
|
[
|
||||||
|
$this->addressBook,
|
||||||
|
$this->addressBookInfo,
|
||||||
|
$this->backend
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->setMethods(['vCard2Array', 'readCard'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$pattern = 'pattern';
|
||||||
|
$searchProperties = 'properties';
|
||||||
|
|
||||||
|
$this->backend->expects($this->once())->method('search')
|
||||||
|
->with($this->addressBookInfo['id'], $pattern, $searchProperties)
|
||||||
|
->willReturn(
|
||||||
|
[
|
||||||
|
'cardData1',
|
||||||
|
'cardData2'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$addressBookImpl->expects($this->exactly(2))->method('readCard')
|
||||||
|
->willReturn($this->vCard);
|
||||||
|
$addressBookImpl->expects($this->exactly(2))->method('vCard2Array')
|
||||||
|
->with($this->vCard)->willReturn('vCard');
|
||||||
|
|
||||||
|
$result = $addressBookImpl->search($pattern, $searchProperties, []);
|
||||||
|
$this->assertTrue((is_array($result)));
|
||||||
|
$this->assertSame(2, count($result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataTestCreate
|
||||||
|
*
|
||||||
|
* @param array $properties
|
||||||
|
*/
|
||||||
|
public function testCreate($properties) {
|
||||||
|
|
||||||
|
$uid = 'uid';
|
||||||
|
|
||||||
|
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||||
|
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||||
|
->setConstructorArgs(
|
||||||
|
[
|
||||||
|
$this->addressBook,
|
||||||
|
$this->addressBookInfo,
|
||||||
|
$this->backend
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$addressBookImpl->expects($this->once())->method('createUid')
|
||||||
|
->willReturn($uid);
|
||||||
|
$addressBookImpl->expects($this->once())->method('createEmptyVCard')
|
||||||
|
->with($uid)->willReturn($this->vCard);
|
||||||
|
$this->vCard->expects($this->exactly(count($properties)))
|
||||||
|
->method('createProperty');
|
||||||
|
$this->backend->expects($this->once())->method('createCard');
|
||||||
|
$this->backend->expects($this->never())->method('updateCard');
|
||||||
|
$this->backend->expects($this->never())->method('getCard');
|
||||||
|
$addressBookImpl->expects($this->once())->method('vCard2Array')
|
||||||
|
->with($this->vCard)->willReturn(true);
|
||||||
|
|
||||||
|
$this->assertTrue($addressBookImpl->createOrUpdate($properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataTestCreate() {
|
||||||
|
return [
|
||||||
|
[[]],
|
||||||
|
[['FN' => 'John Doe']]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdate() {
|
||||||
|
|
||||||
|
$uid = 'uid';
|
||||||
|
$properties = ['UID' => $uid, 'FN' => 'John Doe'];
|
||||||
|
|
||||||
|
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||||
|
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||||
|
->setConstructorArgs(
|
||||||
|
[
|
||||||
|
$this->addressBook,
|
||||||
|
$this->addressBookInfo,
|
||||||
|
$this->backend
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$addressBookImpl->expects($this->never())->method('createUid');
|
||||||
|
$addressBookImpl->expects($this->never())->method('createEmptyVCard');
|
||||||
|
$this->backend->expects($this->once())->method('getCard')
|
||||||
|
->with($this->addressBookInfo['id'], $uid . '.vcf')
|
||||||
|
->willReturn(['carddata' => 'data']);
|
||||||
|
$addressBookImpl->expects($this->once())->method('readCard')
|
||||||
|
->with('data')->willReturn($this->vCard);
|
||||||
|
$this->vCard->expects($this->exactly(count($properties)))
|
||||||
|
->method('createProperty');
|
||||||
|
$this->backend->expects($this->never())->method('createCard');
|
||||||
|
$this->backend->expects($this->once())->method('updateCard');
|
||||||
|
$addressBookImpl->expects($this->once())->method('vCard2Array')
|
||||||
|
->with($this->vCard)->willReturn(true);
|
||||||
|
|
||||||
|
$this->assertTrue($addressBookImpl->createOrUpdate($properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataTestGetPermissions
|
||||||
|
*
|
||||||
|
* @param array $permissions
|
||||||
|
* @param int $expected
|
||||||
|
*/
|
||||||
|
public function testGetPermissions($permissions, $expected) {
|
||||||
|
$this->addressBook->expects($this->once())->method('getACL')
|
||||||
|
->willReturn($permissions);
|
||||||
|
|
||||||
|
$this->assertSame($expected,
|
||||||
|
$this->addressBookImpl->getPermissions()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataTestGetPermissions() {
|
||||||
|
return [
|
||||||
|
[[], 0],
|
||||||
|
[[['privilege' => '{DAV:}read']], 1],
|
||||||
|
[[['privilege' => '{DAV:}write']], 6],
|
||||||
|
[[['privilege' => '{DAV:}all']], 31],
|
||||||
|
[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 7],
|
||||||
|
[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}all']], 31],
|
||||||
|
[[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}write']], 31],
|
||||||
|
[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write'],['privilege' => '{DAV:}all']], 31],
|
||||||
|
[[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 31],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDelete() {
|
||||||
|
$cardId = 1;
|
||||||
|
$cardUri = 'cardUri';
|
||||||
|
$this->backend->expects($this->once())->method('getCardUri')
|
||||||
|
->with($cardId)->willReturn($cardUri);
|
||||||
|
$this->backend->expects($this->once())->method('deleteCard')
|
||||||
|
->with($this->addressBookInfo['id'], $cardUri)
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$this->assertTrue($this->addressBookImpl->delete($cardId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReadCard() {
|
||||||
|
$vCard = new VCard();
|
||||||
|
$vCard->add(new Text($vCard, 'UID', 'uid'));
|
||||||
|
$vCardSerialized = $vCard->serialize();
|
||||||
|
|
||||||
|
$result = $this->invokePrivate($this->addressBookImpl, 'readCard', [$vCardSerialized]);
|
||||||
|
$resultSerialized = $result->serialize();
|
||||||
|
|
||||||
|
$this->assertSame($vCardSerialized, $resultSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateUid() {
|
||||||
|
/** @var \PHPUnit_Framework_MockObject_MockObject | AddressBookImpl $addressBookImpl */
|
||||||
|
$addressBookImpl = $this->getMockBuilder('OCA\DAV\CardDAV\AddressBookImpl')
|
||||||
|
->setConstructorArgs(
|
||||||
|
[
|
||||||
|
$this->addressBook,
|
||||||
|
$this->addressBookInfo,
|
||||||
|
$this->backend
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->setMethods(['getUid'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$addressBookImpl->expects($this->at(0))->method('getUid')->willReturn('uid0');
|
||||||
|
$addressBookImpl->expects($this->at(1))->method('getUid')->willReturn('uid1');
|
||||||
|
|
||||||
|
// simulate that 'uid0' already exists, so the second uid will be returned
|
||||||
|
$this->backend->expects($this->exactly(2))->method('getContact')
|
||||||
|
->willReturnCallback(
|
||||||
|
function($uid) {
|
||||||
|
return ($uid === 'uid0.vcf');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame('uid1',
|
||||||
|
$this->invokePrivate($addressBookImpl, 'createUid', [])
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateEmptyVCard() {
|
||||||
|
$uid = 'uid';
|
||||||
|
$expectedVCard = new VCard();
|
||||||
|
$expectedVCard->add(new Text($expectedVCard, 'UID', $uid));
|
||||||
|
$expectedVCardSerialized = $expectedVCard->serialize();
|
||||||
|
|
||||||
|
$result = $this->invokePrivate($this->addressBookImpl, 'createEmptyVCard', [$uid]);
|
||||||
|
$resultSerialized = $result->serialize();
|
||||||
|
|
||||||
|
$this->assertSame($expectedVCardSerialized, $resultSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,8 +20,14 @@
|
||||||
*/
|
*/
|
||||||
namespace OCA\DAV\Tests\Unit\CardDAV;
|
namespace OCA\DAV\Tests\Unit\CardDAV;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
use OCA\DAV\CardDAV\CardDavBackend;
|
use OCA\DAV\CardDAV\CardDavBackend;
|
||||||
|
use OCA\DAV\Connector\Sabre\Principal;
|
||||||
|
use OCP\IDBConnection;
|
||||||
|
use OCP\ILogger;
|
||||||
use Sabre\DAV\PropPatch;
|
use Sabre\DAV\PropPatch;
|
||||||
|
use Sabre\VObject\Component\VCard;
|
||||||
|
use Sabre\VObject\Property\Text;
|
||||||
use Test\TestCase;
|
use Test\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,22 +42,46 @@ class CardDavBackendTest extends TestCase {
|
||||||
/** @var CardDavBackend */
|
/** @var CardDavBackend */
|
||||||
private $backend;
|
private $backend;
|
||||||
|
|
||||||
|
/** @var Principal | \PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $principal;
|
||||||
|
|
||||||
|
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/** @var IDBConnection */
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $dbCardsTable = 'cards';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $dbCardsPropertiesTable = 'cards_properties';
|
||||||
|
|
||||||
const UNIT_TEST_USER = 'carddav-unit-test';
|
const UNIT_TEST_USER = 'carddav-unit-test';
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
$this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
->setMethods(['getPrincipalByPath'])
|
->setMethods(['getPrincipalByPath'])
|
||||||
->getMock();
|
->getMock();
|
||||||
$principal->method('getPrincipalByPath')
|
$this->principal->method('getPrincipalByPath')
|
||||||
->willReturn([
|
->willReturn([
|
||||||
'uri' => 'principals/best-friend'
|
'uri' => 'principals/best-friend'
|
||||||
]);
|
]);
|
||||||
|
$this->logger = $this->getMock('\OCP\ILogger');
|
||||||
|
|
||||||
|
$this->db = \OC::$server->getDatabaseConnection();
|
||||||
|
|
||||||
|
$this->backend = new CardDavBackend($this->db, $this->principal, $this->logger);
|
||||||
|
|
||||||
|
// start every test with a empty cards_properties and cards table
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->delete('cards_properties')->execute();
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->delete('cards')->execute();
|
||||||
|
|
||||||
$db = \OC::$server->getDatabaseConnection();
|
|
||||||
$this->backend = new CardDavBackend($db, $principal);
|
|
||||||
|
|
||||||
$this->tearDown();
|
$this->tearDown();
|
||||||
}
|
}
|
||||||
|
@ -96,23 +126,32 @@ class CardDavBackendTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCardOperations() {
|
public function testCardOperations() {
|
||||||
|
|
||||||
|
/** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */
|
||||||
|
$backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||||
|
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||||
|
->setMethods(['updateProperties', 'purgeProperties'])->getMock();
|
||||||
|
|
||||||
// create a new address book
|
// create a new address book
|
||||||
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
$backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||||
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
$books = $backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||||
$this->assertEquals(1, count($books));
|
$this->assertEquals(1, count($books));
|
||||||
$bookId = $books[0]['id'];
|
$bookId = $books[0]['id'];
|
||||||
|
|
||||||
// create a card
|
|
||||||
$uri = $this->getUniqueID('card');
|
$uri = $this->getUniqueID('card');
|
||||||
$this->backend->createCard($bookId, $uri, '');
|
// updateProperties is expected twice, once for createCard and once for updateCard
|
||||||
|
$backend->expects($this->at(0))->method('updateProperties')->with($bookId, $uri, '');
|
||||||
|
$backend->expects($this->at(1))->method('updateProperties')->with($bookId, $uri, '***');
|
||||||
|
// create a card
|
||||||
|
$backend->createCard($bookId, $uri, '');
|
||||||
|
|
||||||
// get all the cards
|
// get all the cards
|
||||||
$cards = $this->backend->getCards($bookId);
|
$cards = $backend->getCards($bookId);
|
||||||
$this->assertEquals(1, count($cards));
|
$this->assertEquals(1, count($cards));
|
||||||
$this->assertEquals('', $cards[0]['carddata']);
|
$this->assertEquals('', $cards[0]['carddata']);
|
||||||
|
|
||||||
// get the cards
|
// get the cards
|
||||||
$card = $this->backend->getCard($bookId, $uri);
|
$card = $backend->getCard($bookId, $uri);
|
||||||
$this->assertNotNull($card);
|
$this->assertNotNull($card);
|
||||||
$this->assertArrayHasKey('id', $card);
|
$this->assertArrayHasKey('id', $card);
|
||||||
$this->assertArrayHasKey('uri', $card);
|
$this->assertArrayHasKey('uri', $card);
|
||||||
|
@ -122,17 +161,23 @@ class CardDavBackendTest extends TestCase {
|
||||||
$this->assertEquals('', $card['carddata']);
|
$this->assertEquals('', $card['carddata']);
|
||||||
|
|
||||||
// update the card
|
// update the card
|
||||||
$this->backend->updateCard($bookId, $uri, '***');
|
$backend->updateCard($bookId, $uri, '***');
|
||||||
$card = $this->backend->getCard($bookId, $uri);
|
$card = $backend->getCard($bookId, $uri);
|
||||||
$this->assertEquals('***', $card['carddata']);
|
$this->assertEquals('***', $card['carddata']);
|
||||||
|
|
||||||
// delete the card
|
// delete the card
|
||||||
$this->backend->deleteCard($bookId, $uri);
|
$backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
|
||||||
$cards = $this->backend->getCards($bookId);
|
$backend->deleteCard($bookId, $uri);
|
||||||
|
$cards = $backend->getCards($bookId);
|
||||||
$this->assertEquals(0, count($cards));
|
$this->assertEquals(0, count($cards));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMultiCard() {
|
public function testMultiCard() {
|
||||||
|
|
||||||
|
$this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||||
|
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||||
|
->setMethods(['updateProperties'])->getMock();
|
||||||
|
|
||||||
// create a new address book
|
// create a new address book
|
||||||
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||||
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||||
|
@ -175,6 +220,11 @@ class CardDavBackendTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSyncSupport() {
|
public function testSyncSupport() {
|
||||||
|
|
||||||
|
$this->backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||||
|
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||||
|
->setMethods(['updateProperties'])->getMock();
|
||||||
|
|
||||||
// create a new address book
|
// create a new address book
|
||||||
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
|
||||||
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
|
||||||
|
@ -221,4 +271,273 @@ class CardDavBackendTest extends TestCase {
|
||||||
$books = $this->backend->getAddressBooksForUser('principals/best-friend');
|
$books = $this->backend->getAddressBooksForUser('principals/best-friend');
|
||||||
$this->assertEquals(0, count($books));
|
$this->assertEquals(0, count($books));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUpdateProperties() {
|
||||||
|
|
||||||
|
$bookId = 42;
|
||||||
|
$cardUri = 'card-uri';
|
||||||
|
$cardId = 2;
|
||||||
|
|
||||||
|
$backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')
|
||||||
|
->setConstructorArgs([$this->db, $this->principal, $this->logger])
|
||||||
|
->setMethods(['getCardId'])->getMock();
|
||||||
|
|
||||||
|
$backend->expects($this->any())->method('getCardId')->willReturn($cardId);
|
||||||
|
|
||||||
|
// add properties for new vCard
|
||||||
|
$vCard = new VCard();
|
||||||
|
$vCard->add(new Text($vCard, 'UID', $cardUri));
|
||||||
|
$vCard->add(new Text($vCard, 'FN', 'John Doe'));
|
||||||
|
$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
|
||||||
|
|
||||||
|
$this->assertSame(2, count($result));
|
||||||
|
|
||||||
|
$this->assertSame('UID', $result[0]['name']);
|
||||||
|
$this->assertSame($cardUri, $result[0]['value']);
|
||||||
|
$this->assertSame($bookId, (int)$result[0]['addressbookid']);
|
||||||
|
$this->assertSame($cardId, (int)$result[0]['cardid']);
|
||||||
|
|
||||||
|
$this->assertSame('FN', $result[1]['name']);
|
||||||
|
$this->assertSame('John Doe', $result[1]['value']);
|
||||||
|
$this->assertSame($bookId, (int)$result[1]['addressbookid']);
|
||||||
|
$this->assertSame($cardId, (int)$result[1]['cardid']);
|
||||||
|
|
||||||
|
// update properties for existing vCard
|
||||||
|
$vCard = new VCard();
|
||||||
|
$vCard->add(new Text($vCard, 'FN', 'John Doe'));
|
||||||
|
$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
|
||||||
|
|
||||||
|
$this->assertSame(1, count($result));
|
||||||
|
|
||||||
|
$this->assertSame('FN', $result[0]['name']);
|
||||||
|
$this->assertSame('John Doe', $result[0]['value']);
|
||||||
|
$this->assertSame($bookId, (int)$result[0]['addressbookid']);
|
||||||
|
$this->assertSame($cardId, (int)$result[0]['cardid']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPurgeProperties() {
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->insert('cards_properties')
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(1),
|
||||||
|
'cardid' => $query->createNamedParameter(1),
|
||||||
|
'name' => $query->createNamedParameter('name1'),
|
||||||
|
'value' => $query->createNamedParameter('value1'),
|
||||||
|
'preferred' => $query->createNamedParameter(0)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->insert('cards_properties')
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(1),
|
||||||
|
'cardid' => $query->createNamedParameter(2),
|
||||||
|
'name' => $query->createNamedParameter('name2'),
|
||||||
|
'value' => $query->createNamedParameter('value2'),
|
||||||
|
'preferred' => $query->createNamedParameter(0)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
|
||||||
|
$this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$result = $query->select('*')->from('cards_properties')->execute()->fetchAll();
|
||||||
|
$this->assertSame(1, count($result));
|
||||||
|
$this->assertSame(1 ,(int)$result[0]['addressbookid']);
|
||||||
|
$this->assertSame(2 ,(int)$result[0]['cardid']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetCardId() {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
|
||||||
|
$query->insert('cards')
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(1),
|
||||||
|
'carddata' => $query->createNamedParameter(''),
|
||||||
|
'uri' => $query->createNamedParameter('uri'),
|
||||||
|
'lastmodified' => $query->createNamedParameter(4738743),
|
||||||
|
'etag' => $query->createNamedParameter('etag'),
|
||||||
|
'size' => $query->createNamedParameter(120)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
$id = $query->getLastInsertId();
|
||||||
|
|
||||||
|
$this->assertSame($id,
|
||||||
|
$this->invokePrivate($this->backend, 'getCardId', ['uri']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testGetCardIdFailed() {
|
||||||
|
$this->invokePrivate($this->backend, 'getCardId', ['uri']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataTestSearch
|
||||||
|
*
|
||||||
|
* @param string $pattern
|
||||||
|
* @param array $expected
|
||||||
|
*/
|
||||||
|
public function testSearch($pattern, $properties, $expected) {
|
||||||
|
/** @var VCard $vCards */
|
||||||
|
$vCards = [];
|
||||||
|
$vCards[0] = new VCard();
|
||||||
|
$vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
|
||||||
|
$vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
|
||||||
|
$vCards[0]->add(new Text($vCards[0], 'CLOUD', 'john@owncloud.org'));
|
||||||
|
$vCards[1] = new VCard();
|
||||||
|
$vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
|
||||||
|
$vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
|
||||||
|
|
||||||
|
$vCardIds = [];
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
for($i=0; $i<2; $i++) {
|
||||||
|
$query->insert($this->dbCardsTable)
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(0),
|
||||||
|
'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), \PDO::PARAM_LOB),
|
||||||
|
'uri' => $query->createNamedParameter('uri' . $i),
|
||||||
|
'lastmodified' => $query->createNamedParameter(time()),
|
||||||
|
'etag' => $query->createNamedParameter('etag' . $i),
|
||||||
|
'size' => $query->createNamedParameter(120),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
$vCardIds[] = $query->getLastInsertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->insert($this->dbCardsPropertiesTable)
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(0),
|
||||||
|
'cardid' => $query->createNamedParameter($vCardIds[0]),
|
||||||
|
'name' => $query->createNamedParameter('FN'),
|
||||||
|
'value' => $query->createNamedParameter('John Doe'),
|
||||||
|
'preferred' => $query->createNamedParameter(0)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
$query->insert($this->dbCardsPropertiesTable)
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(0),
|
||||||
|
'cardid' => $query->createNamedParameter($vCardIds[0]),
|
||||||
|
'name' => $query->createNamedParameter('CLOUD'),
|
||||||
|
'value' => $query->createNamedParameter('John@owncloud.org'),
|
||||||
|
'preferred' => $query->createNamedParameter(0)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
$query->insert($this->dbCardsPropertiesTable)
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(0),
|
||||||
|
'cardid' => $query->createNamedParameter($vCardIds[1]),
|
||||||
|
'name' => $query->createNamedParameter('FN'),
|
||||||
|
'value' => $query->createNamedParameter('John M. Doe'),
|
||||||
|
'preferred' => $query->createNamedParameter(0)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
|
||||||
|
$result = $this->backend->search(0, $pattern, $properties);
|
||||||
|
|
||||||
|
// check result
|
||||||
|
$this->assertSame(count($expected), count($result));
|
||||||
|
$found = [];
|
||||||
|
foreach ($result as $r) {
|
||||||
|
foreach ($expected as $exp) {
|
||||||
|
if (strpos($r, $exp) > 0) {
|
||||||
|
$found[$exp] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertSame(count($expected), count($found));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataTestSearch() {
|
||||||
|
return [
|
||||||
|
['John', ['FN'], ['John Doe', 'John M. Doe']],
|
||||||
|
['M. Doe', ['FN'], ['John M. Doe']],
|
||||||
|
['Do', ['FN'], ['John Doe', 'John M. Doe']],
|
||||||
|
// check if duplicates are handled correctly
|
||||||
|
['John', ['FN', 'CLOUD'], ['John Doe', 'John M. Doe']],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetCardUri() {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->insert($this->dbCardsTable)
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter(1),
|
||||||
|
'carddata' => $query->createNamedParameter('carddata', \PDO::PARAM_LOB),
|
||||||
|
'uri' => $query->createNamedParameter('uri'),
|
||||||
|
'lastmodified' => $query->createNamedParameter(5489543),
|
||||||
|
'etag' => $query->createNamedParameter('etag'),
|
||||||
|
'size' => $query->createNamedParameter(120),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
|
||||||
|
$id = $query->getLastInsertId();
|
||||||
|
|
||||||
|
$this->assertSame('uri', $this->backend->getCardUri($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testGetCardUriFailed() {
|
||||||
|
$this->backend->getCardUri(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetContact() {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
for($i=0; $i<2; $i++) {
|
||||||
|
$query->insert($this->dbCardsTable)
|
||||||
|
->values(
|
||||||
|
[
|
||||||
|
'addressbookid' => $query->createNamedParameter($i),
|
||||||
|
'carddata' => $query->createNamedParameter('carddata' . $i, \PDO::PARAM_LOB),
|
||||||
|
'uri' => $query->createNamedParameter('uri' . $i),
|
||||||
|
'lastmodified' => $query->createNamedParameter(5489543),
|
||||||
|
'etag' => $query->createNamedParameter('etag' . $i),
|
||||||
|
'size' => $query->createNamedParameter(120),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->backend->getContact('uri0');
|
||||||
|
$this->assertSame(7, count($result));
|
||||||
|
$this->assertSame(0, (int)$result['addressbookid']);
|
||||||
|
$this->assertSame('uri0', $result['uri']);
|
||||||
|
$this->assertSame(5489543, (int)$result['lastmodified']);
|
||||||
|
$this->assertSame('etag0', $result['etag']);
|
||||||
|
$this->assertSame(120, (int)$result['size']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetContactFail() {
|
||||||
|
$this->assertEmpty($this->backend->getContact('uri'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue