diff options
author | Joas Schilling <nickvergessen@gmx.de> | 2016-05-12 09:42:40 +0200 |
---|---|---|
committer | Thomas Müller <DeepDiver1975@users.noreply.github.com> | 2016-05-12 09:42:40 +0200 |
commit | dd9ee10bc0699e5dcc17c3ef2181dcda01d9a69b (patch) | |
tree | 2d464fcc20ea330481e56487287aeae462ce5917 /apps/dav/lib/carddav | |
parent | 4a3311f430ec6e45c62b2ebde2cae71e943f3c81 (diff) | |
download | nextcloud-server-dd9ee10bc0699e5dcc17c3ef2181dcda01d9a69b.tar.gz nextcloud-server-dd9ee10bc0699e5dcc17c3ef2181dcda01d9a69b.zip |
Move dav app to PSR-4 (#24527)
* Move Application to correct namespace and PSR-4 it
* Move dav app to PSR-4
Diffstat (limited to 'apps/dav/lib/carddav')
-rw-r--r-- | apps/dav/lib/carddav/addressbook.php | 182 | ||||
-rw-r--r-- | apps/dav/lib/carddav/addressbookimpl.php | 224 | ||||
-rw-r--r-- | apps/dav/lib/carddav/addressbookroot.php | 54 | ||||
-rw-r--r-- | apps/dav/lib/carddav/carddavbackend.php | 987 | ||||
-rw-r--r-- | apps/dav/lib/carddav/contactsmanager.php | 65 | ||||
-rw-r--r-- | apps/dav/lib/carddav/converter.php | 171 | ||||
-rw-r--r-- | apps/dav/lib/carddav/plugin.php | 79 | ||||
-rw-r--r-- | apps/dav/lib/carddav/syncjob.php | 40 | ||||
-rw-r--r-- | apps/dav/lib/carddav/syncservice.php | 284 | ||||
-rw-r--r-- | apps/dav/lib/carddav/useraddressbooks.php | 67 | ||||
-rw-r--r-- | apps/dav/lib/carddav/xml/groups.php | 45 |
11 files changed, 0 insertions, 2198 deletions
diff --git a/apps/dav/lib/carddav/addressbook.php b/apps/dav/lib/carddav/addressbook.php deleted file mode 100644 index 8b1b600ec3d..00000000000 --- a/apps/dav/lib/carddav/addressbook.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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 OCA\DAV\DAV\Sharing\IShareable; -use Sabre\CardDAV\Card; -use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\PropPatch; - -class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable { - - /** - * Updates the list of shares. - * - * The first array is a list of people that are to be added to the - * addressbook. - * - * Every element in the add array has the following properties: - * * href - A url. Usually a mailto: address - * * commonName - Usually a first and last name, or false - * * summary - A description of the share, can also be false - * * readOnly - A boolean value - * - * Every element in the remove array is just the address string. - * - * @param array $add - * @param array $remove - * @return void - */ - function updateShares(array $add, array $remove) { - /** @var CardDavBackend $carddavBackend */ - $carddavBackend = $this->carddavBackend; - $carddavBackend->updateShares($this, $add, $remove); - } - - /** - * Returns the list of people whom this addressbook is shared with. - * - * Every element in this array should have the following properties: - * * href - Often a mailto: address - * * commonName - Optional, for example a first + last name - * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. - * * readOnly - boolean - * * summary - Optional, a description for the share - * - * @return array - */ - function getShares() { - /** @var CardDavBackend $carddavBackend */ - $carddavBackend = $this->carddavBackend; - return $carddavBackend->getShares($this->getResourceId()); - } - - function getACL() { - $acl = [ - [ - 'privilege' => '{DAV:}read', - 'principal' => $this->getOwner(), - 'protected' => true, - ]]; - $acl[] = [ - 'privilege' => '{DAV:}write', - 'principal' => $this->getOwner(), - 'protected' => true, - ]; - if ($this->getOwner() !== parent::getOwner()) { - $acl[] = [ - 'privilege' => '{DAV:}read', - 'principal' => parent::getOwner(), - 'protected' => true, - ]; - if ($this->canWrite()) { - $acl[] = [ - 'privilege' => '{DAV:}write', - 'principal' => parent::getOwner(), - 'protected' => true, - ]; - } - } - if ($this->getOwner() === 'principals/system/system') { - $acl[] = [ - 'privilege' => '{DAV:}read', - 'principal' => '{DAV:}authenticated', - 'protected' => true, - ]; - } - - /** @var CardDavBackend $carddavBackend */ - $carddavBackend = $this->carddavBackend; - return $carddavBackend->applyShareAcl($this->getResourceId(), $acl); - } - - function getChildACL() { - return $this->getACL(); - } - - function getChild($name) { - - $obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name); - if (!$obj) { - throw new NotFound('Card not found'); - } - $obj['acl'] = $this->getChildACL(); - return new Card($this->carddavBackend, $this->addressBookInfo, $obj); - - } - - /** - * @return int - */ - public function getResourceId() { - return $this->addressBookInfo['id']; - } - - function getOwner() { - if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) { - return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal']; - } - return parent::getOwner(); - } - - function delete() { - if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) { - $principal = 'principal:' . parent::getOwner(); - $shares = $this->getShares(); - $shares = array_filter($shares, function($share) use ($principal){ - return $share['href'] === $principal; - }); - if (empty($shares)) { - throw new Forbidden(); - } - - /** @var CardDavBackend $cardDavBackend */ - $cardDavBackend = $this->carddavBackend; - $cardDavBackend->updateShares($this, [], [ - 'href' => $principal - ]); - return; - } - parent::delete(); - } - - function propPatch(PropPatch $propPatch) { - if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) { - throw new Forbidden(); - } - parent::propPatch($propPatch); - } - - public function getContactsGroups() { - /** @var CardDavBackend $cardDavBackend */ - $cardDavBackend = $this->carddavBackend; - - return $cardDavBackend->collectCardProperties($this->getResourceId(), 'CATEGORIES'); - } - - private function canWrite() { - if (isset($this->addressBookInfo['{http://owncloud.org/ns}read-only'])) { - return !$this->addressBookInfo['{http://owncloud.org/ns}read-only']; - } - return true; - } -} diff --git a/apps/dav/lib/carddav/addressbookimpl.php b/apps/dav/lib/carddav/addressbookimpl.php deleted file mode 100644 index 8b29d6d5c0c..00000000000 --- a/apps/dav/lib/carddav/addressbookimpl.php +++ /dev/null @@ -1,224 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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(); - $contact = $this->backend->getContact($this->getKey(), $uid . '.vcf'); - } while (!empty($contact)); - - 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(); - } - if ($this->addressBookInfo['principaluri'] === 'principals/system/system' && - $this->addressBookInfo['uri'] === 'system') { - $result['isLocalSystemBook'] = true; - } - return $result; - } -} diff --git a/apps/dav/lib/carddav/addressbookroot.php b/apps/dav/lib/carddav/addressbookroot.php deleted file mode 100644 index 99c36c2e767..00000000000 --- a/apps/dav/lib/carddav/addressbookroot.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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; - -class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot { - - /** - * This method returns a node for a principal. - * - * The passed array contains principal information, and is guaranteed to - * at least contain a uri item. Other properties may or may not be - * supplied by the authentication backend. - * - * @param array $principal - * @return \Sabre\DAV\INode - */ - function getChildForPrincipal(array $principal) { - - return new UserAddressBooks($this->carddavBackend, $principal['uri']); - - } - - function getName() { - - if ($this->principalPrefix === 'principals') { - return parent::getName(); - } - // Grabbing all the components of the principal path. - $parts = explode('/', $this->principalPrefix); - - // We are only interested in the second part. - return $parts[1]; - - } - -} diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php deleted file mode 100644 index 28d5ed1ae99..00000000000 --- a/apps/dav/lib/carddav/carddavbackend.php +++ /dev/null @@ -1,987 +0,0 @@ -<?php -/** - * @author Arthur Schiwon <blizzz@owncloud.com> - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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 OCA\DAV\Connector\Sabre\Principal; -use OCP\DB\QueryBuilder\IQueryBuilder; -use OCA\DAV\DAV\Sharing\Backend; -use OCA\DAV\DAV\Sharing\IShareable; -use OCP\IDBConnection; -use PDO; -use Sabre\CardDAV\Backend\BackendInterface; -use Sabre\CardDAV\Backend\SyncSupport; -use Sabre\CardDAV\Plugin; -use Sabre\DAV\Exception\BadRequest; -use Sabre\HTTP\URLUtil; -use Sabre\VObject\Component\VCard; -use Sabre\VObject\Reader; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\EventDispatcher\GenericEvent; - -class CardDavBackend implements BackendInterface, SyncSupport { - - /** @var Principal */ - private $principalBackend; - - /** @var string */ - private $dbCardsTable = 'cards'; - - /** @var string */ - private $dbCardsPropertiesTable = 'cards_properties'; - - /** @var IDBConnection */ - private $db; - - /** @var Backend */ - private $sharingBackend; - - /** @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'); - - /** @var EventDispatcherInterface */ - private $dispatcher; - - /** - * CardDavBackend constructor. - * - * @param IDBConnection $db - * @param Principal $principalBackend - * @param EventDispatcherInterface $dispatcher - */ - public function __construct(IDBConnection $db, - Principal $principalBackend, - EventDispatcherInterface $dispatcher = null) { - $this->db = $db; - $this->principalBackend = $principalBackend; - $this->dispatcher = $dispatcher; - $this->sharingBackend = new Backend($this->db, $principalBackend, 'addressbook'); - } - - /** - * Returns the list of address books for a specific user. - * - * Every addressbook should have the following properties: - * id - an arbitrary unique id - * uri - the 'basename' part of the url - * principaluri - Same as the passed parameter - * - * Any additional clark-notation property may be passed besides this. Some - * common ones are : - * {DAV:}displayname - * {urn:ietf:params:xml:ns:carddav}addressbook-description - * {http://calendarserver.org/ns/}getctag - * - * @param string $principalUri - * @return array - */ - 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']?$row['synctoken']:'0', - ]; - } - $result->closeCursor(); - - // query for shared calendars - $principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true); - $principals[]= $principalUri; - - $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(); - - while($row = $result->fetch()) { - list(, $name) = URLUtil::splitPath($row['principaluri']); - $uri = $row['uri'] . '_shared_by_' . $name; - $displayName = $row['displayname'] . "($name)"; - if (!isset($addressBooks[$row['id']])) { - $addressBooks[$row['id']] = [ - 'id' => $row['id'], - 'uri' => $uri, - 'principaluri' => $principalUri, - '{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']?$row['synctoken']:'0', - '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'], - '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only' => (int)$row['access'] === Backend::ACCESS_READ, - ]; - } - } - $result->closeCursor(); - - return array_values($addressBooks); - } - - /** - * @param int $addressBookId - */ - public function getAddressBookById($addressBookId) { - $query = $this->db->getQueryBuilder(); - $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken']) - ->from('addressbooks') - ->where($query->expr()->eq('id', $query->createNamedParameter($addressBookId))) - ->execute(); - - $row = $result->fetch(); - $result->closeCursor(); - if ($row === false) { - return null; - } - - return [ - 'id' => $row['id'], - 'uri' => $row['uri'], - 'principaluri' => $row['principaluri'], - '{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']?$row['synctoken']:'0', - ]; - } - - /** - * @param $addressBookUri - * @return array|null - */ - public function getAddressBooksByUri($principal, $addressBookUri) { - $query = $this->db->getQueryBuilder(); - $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken']) - ->from('addressbooks') - ->where($query->expr()->eq('uri', $query->createNamedParameter($addressBookUri))) - ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal))) - ->setMaxResults(1) - ->execute(); - - $row = $result->fetch(); - $result->closeCursor(); - if ($row === false) { - return null; - } - - return [ - 'id' => $row['id'], - 'uri' => $row['uri'], - 'principaluri' => $row['principaluri'], - '{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']?$row['synctoken']:'0', - ]; - } - - /** - * Updates properties for an address book. - * - * The list of mutations is stored in a Sabre\DAV\PropPatch object. - * To do the actual updates, you must tell this object which properties - * you're going to process with the handle() method. - * - * Calling the handle method is like telling the PropPatch object "I - * promise I can handle updating this property". - * - * Read the PropPatch documentation for more info and examples. - * - * @param string $addressBookId - * @param \Sabre\DAV\PropPatch $propPatch - * @return void - */ - function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $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; - } - } - $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))) - ->execute(); - - $this->addChange($addressBookId, "", 2); - - return true; - - }); - } - - /** - * Creates a new address book - * - * @param string $principalUri - * @param string $url Just the 'basename' of the url. - * @param array $properties - * @return int - * @throws BadRequest - */ - function createAddressBook($principalUri, $url, array $properties) { - $values = [ - 'displayname' => null, - 'description' => null, - 'principaluri' => $principalUri, - 'uri' => $url, - 'synctoken' => 1 - ]; - - foreach($properties as $property=>$newValue) { - - switch($property) { - case '{DAV:}displayname' : - $values['displayname'] = $newValue; - break; - case '{' . Plugin::NS_CARDDAV . '}addressbook-description' : - $values['description'] = $newValue; - break; - default : - throw new BadRequest('Unknown property: ' . $property); - } - - } - - // Fallback to make sure the displayname is set. Some clients may refuse - // to work with addressbooks not having a displayname. - if(is_null($values['displayname'])) { - $values['displayname'] = $url; - } - - $query = $this->db->getQueryBuilder(); - $query->insert('addressbooks') - ->values([ - 'uri' => $query->createParameter('uri'), - 'displayname' => $query->createParameter('displayname'), - 'description' => $query->createParameter('description'), - 'principaluri' => $query->createParameter('principaluri'), - 'synctoken' => $query->createParameter('synctoken'), - ]) - ->setParameters($values) - ->execute(); - - return $query->getLastInsertId(); - } - - /** - * Deletes an entire addressbook and all its contents - * - * @param mixed $addressBookId - * @return void - */ - function deleteAddressBook($addressBookId) { - $query = $this->db->getQueryBuilder(); - $query->delete('cards') - ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid'))) - ->setParameter('addressbookid', $addressBookId) - ->execute(); - - $query->delete('addressbookchanges') - ->where($query->expr()->eq('addressbookid', $query->createParameter('addressbookid'))) - ->setParameter('addressbookid', $addressBookId) - ->execute(); - - $query->delete('addressbooks') - ->where($query->expr()->eq('id', $query->createParameter('id'))) - ->setParameter('id', $addressBookId) - ->execute(); - - $this->sharingBackend->deleteAllShares($addressBookId); - - $query->delete($this->dbCardsPropertiesTable) - ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))) - ->execute(); - - } - - /** - * Returns all cards for a specific addressbook id. - * - * This method should return the following properties for each card: - * * carddata - raw vcard data - * * uri - Some unique url - * * lastmodified - A unix timestamp - * - * It's recommended to also return the following properties: - * * etag - A unique etag. This must change every time the card changes. - * * size - The size of the card in bytes. - * - * If these last two properties are provided, less time will be spent - * calculating them. If they are specified, you can also ommit carddata. - * This may speed up certain requests, especially with large cards. - * - * @param mixed $addressBookId - * @return array - */ - function getCards($addressBookId) { - $query = $this->db->getQueryBuilder(); - $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata']) - ->from('cards') - ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))); - - $cards = []; - - $result = $query->execute(); - while($row = $result->fetch()) { - $row['etag'] = '"' . $row['etag'] . '"'; - $row['carddata'] = $this->readBlob($row['carddata']); - $cards[] = $row; - } - $result->closeCursor(); - - return $cards; - } - - /** - * Returns a specific card. - * - * The same set of properties must be returned as with getCards. The only - * exception is that 'carddata' is absolutely required. - * - * If the card does not exist, you must return false. - * - * @param mixed $addressBookId - * @param string $cardUri - * @return array - */ - function getCard($addressBookId, $cardUri) { - $query = $this->db->getQueryBuilder(); - $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata']) - ->from('cards') - ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))) - ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri))) - ->setMaxResults(1); - - $result = $query->execute(); - $row = $result->fetch(); - if (!$row) { - return false; - } - $row['etag'] = '"' . $row['etag'] . '"'; - $row['carddata'] = $this->readBlob($row['carddata']); - - return $row; - } - - /** - * Returns a list of cards. - * - * This method should work identical to getCard, but instead return all the - * cards in the list as an array. - * - * If the backend supports this, it may allow for some speed-ups. - * - * @param mixed $addressBookId - * @param string[] $uris - * @return array - */ - function getMultipleCards($addressBookId, array $uris) { - $query = $this->db->getQueryBuilder(); - $query->select(['id', 'uri', 'lastmodified', 'etag', 'size', 'carddata']) - ->from('cards') - ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))) - ->andWhere($query->expr()->in('uri', $query->createParameter('uri'))) - ->setParameter('uri', $uris, IQueryBuilder::PARAM_STR_ARRAY); - - $cards = []; - - $result = $query->execute(); - while($row = $result->fetch()) { - $row['etag'] = '"' . $row['etag'] . '"'; - $row['carddata'] = $this->readBlob($row['carddata']); - $cards[] = $row; - } - $result->closeCursor(); - - return $cards; - } - - /** - * Creates a new card. - * - * The addressbook id will be passed as the first argument. This is the - * same id as it is returned from the getAddressBooksForUser method. - * - * The cardUri is a base uri, and doesn't include the full path. The - * cardData argument is the vcard body, and is passed as a string. - * - * It is possible to return an ETag from this method. This ETag is for the - * newly created resource, and must be enclosed with double quotes (that - * is, the string itself must contain the double quotes). - * - * You should only return the ETag if you store the carddata as-is. If a - * subsequent GET request on the same card does not have the same body, - * byte-by-byte and you did return an ETag here, clients tend to get - * confused. - * - * If you don't return an ETag, you can just return null. - * - * @param mixed $addressBookId - * @param string $cardUri - * @param string $cardData - * @return string - */ - function createCard($addressBookId, $cardUri, $cardData) { - $etag = md5($cardData); - - $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), - ]) - ->execute(); - - $this->addChange($addressBookId, $cardUri, 1); - $this->updateProperties($addressBookId, $cardUri, $cardData); - - if (!is_null($this->dispatcher)) { - $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::createCard', - new GenericEvent(null, [ - 'addressBookId' => $addressBookId, - 'cardUri' => $cardUri, - 'cardData' => $cardData])); - } - - return '"' . $etag . '"'; - } - - /** - * Updates a card. - * - * The addressbook id will be passed as the first argument. This is the - * same id as it is returned from the getAddressBooksForUser method. - * - * The cardUri is a base uri, and doesn't include the full path. The - * cardData argument is the vcard body, and is passed as a string. - * - * It is possible to return an ETag from this method. This ETag should - * match that of the updated resource, and must be enclosed with double - * quotes (that is: the string itself must contain the actual quotes). - * - * You should only return the ETag if you store the carddata as-is. If a - * subsequent GET request on the same card does not have the same body, - * byte-by-byte and you did return an ETag here, clients tend to get - * confused. - * - * If you don't return an ETag, you can just return null. - * - * @param mixed $addressBookId - * @param string $cardUri - * @param string $cardData - * @return string - */ - function updateCard($addressBookId, $cardUri, $cardData) { - - $etag = md5($cardData); - $query = $this->db->getQueryBuilder(); - $query->update('cards') - ->set('carddata', $query->createNamedParameter($cardData, IQueryBuilder::PARAM_LOB)) - ->set('lastmodified', $query->createNamedParameter(time())) - ->set('size', $query->createNamedParameter(strlen($cardData))) - ->set('etag', $query->createNamedParameter($etag)) - ->where($query->expr()->eq('uri', $query->createNamedParameter($cardUri))) - ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))) - ->execute(); - - $this->addChange($addressBookId, $cardUri, 2); - $this->updateProperties($addressBookId, $cardUri, $cardData); - - if (!is_null($this->dispatcher)) { - $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::updateCard', - new GenericEvent(null, [ - 'addressBookId' => $addressBookId, - 'cardUri' => $cardUri, - 'cardData' => $cardData])); - } - - return '"' . $etag . '"'; - } - - /** - * Deletes a card - * - * @param mixed $addressBookId - * @param string $cardUri - * @return bool - */ - function deleteCard($addressBookId, $cardUri) { - try { - $cardId = $this->getCardId($addressBookId, $cardUri); - } catch (\InvalidArgumentException $e) { - $cardId = null; - } - $query = $this->db->getQueryBuilder(); - $ret = $query->delete('cards') - ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))) - ->andWhere($query->expr()->eq('uri', $query->createNamedParameter($cardUri))) - ->execute(); - - $this->addChange($addressBookId, $cardUri, 3); - - if (!is_null($this->dispatcher)) { - $this->dispatcher->dispatch('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', - new GenericEvent(null, [ - 'addressBookId' => $addressBookId, - 'cardUri' => $cardUri])); - } - - if ($ret === 1) { - if ($cardId !== null) { - $this->purgeProperties($addressBookId, $cardId); - } - return true; - } - - return false; - } - - /** - * The getChanges method returns all the changes that have happened, since - * the specified syncToken in the specified address book. - * - * This function should return an array, such as the following: - * - * [ - * 'syncToken' => 'The current synctoken', - * 'added' => [ - * 'new.txt', - * ], - * 'modified' => [ - * 'modified.txt', - * ], - * 'deleted' => [ - * 'foo.php.bak', - * 'old.txt' - * ] - * ]; - * - * The returned syncToken property should reflect the *current* syncToken - * of the calendar, as reported in the {http://sabredav.org/ns}sync-token - * property. This is needed here too, to ensure the operation is atomic. - * - * If the $syncToken argument is specified as null, this is an initial - * sync, and all members should be reported. - * - * The modified property is an array of nodenames that have changed since - * the last token. - * - * The deleted property is an array with nodenames, that have been deleted - * from collection. - * - * The $syncLevel argument is basically the 'depth' of the report. If it's - * 1, you only have to report changes that happened only directly in - * immediate descendants. If it's 2, it should also include changes from - * the nodes below the child collections. (grandchildren) - * - * The $limit argument allows a client to specify how many results should - * be returned at most. If the limit is not specified, it should be treated - * as infinite. - * - * If the limit (infinite or not) is higher than you're willing to return, - * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception. - * - * If the syncToken is expired (due to data cleanup) or unknown, you must - * return null. - * - * The limit is 'suggestive'. You are free to ignore it. - * - * @param string $addressBookId - * @param string $syncToken - * @param int $syncLevel - * @param int $limit - * @return array - */ - function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) { - // Current synctoken - $stmt = $this->db->prepare('SELECT `synctoken` FROM `*PREFIX*addressbooks` WHERE `id` = ?'); - $stmt->execute([ $addressBookId ]); - $currentToken = $stmt->fetchColumn(0); - - if (is_null($currentToken)) return null; - - $result = [ - 'syncToken' => $currentToken, - 'added' => [], - 'modified' => [], - 'deleted' => [], - ]; - - if ($syncToken) { - - $query = "SELECT `uri`, `operation` FROM `*PREFIX*addressbookchanges` WHERE `synctoken` >= ? AND `synctoken` < ? AND `addressbookid` = ? ORDER BY `synctoken`"; - if ($limit>0) { - $query .= " `LIMIT` " . (int)$limit; - } - - // Fetching all changes - $stmt = $this->db->prepare($query); - $stmt->execute([$syncToken, $currentToken, $addressBookId]); - - $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']; - - } - - 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 { - // No synctoken supplied, this is the initial sync. - $query = "SELECT `uri` FROM `*PREFIX*cards` WHERE `addressbookid` = ?"; - $stmt = $this->db->prepare($query); - $stmt->execute([$addressBookId]); - - $result['added'] = $stmt->fetchAll(\PDO::FETCH_COLUMN); - } - return $result; - } - - /** - * Adds a change record to the addressbookchanges table. - * - * @param mixed $addressBookId - * @param string $objectUri - * @param int $operation 1 = add, 2 = modify, 3 = delete - * @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 - ]); - } - - private function readBlob($cardData) { - if (is_resource($cardData)) { - return stream_get_contents($cardData); - } - - return $cardData; - } - - /** - * @param IShareable $shareable - * @param string[] $add - * @param string[] $remove - */ - public function updateShares(IShareable $shareable, $add, $remove) { - $this->sharingBackend->updateShares($shareable, $add, $remove); - } - - /** - * 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()->ilike('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); - - } - - /** - * @param int $bookId - * @param string $name - * @return array - */ - public function collectCardProperties($bookId, $name) { - $query = $this->db->getQueryBuilder(); - $result = $query->selectDistinct('value') - ->from($this->dbCardsPropertiesTable) - ->where($query->expr()->eq('name', $query->createNamedParameter($name))) - ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($bookId))) - ->execute(); - - $all = $result->fetchAll(PDO::FETCH_COLUMN); - $result->closeCursor(); - - return $all; - } - - /** - * 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 int $addressBookId - * @param string $uri - * @returns array - */ - public function getContact($addressBookId, $uri) { - $result = []; - $query = $this->db->getQueryBuilder(); - $query->select('*')->from($this->dbCardsTable) - ->where($query->expr()->eq('uri', $query->createNamedParameter($uri))) - ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))); - $queryResult = $query->execute(); - $contact = $queryResult->fetch(); - $queryResult->closeCursor(); - - if (is_array($contact)) { - $result = $contact; - } - - return $result; - } - - /** - * Returns the list of people whom this address book is shared with. - * - * Every element in this array should have the following properties: - * * href - Often a mailto: address - * * commonName - Optional, for example a first + last name - * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. - * * readOnly - boolean - * * summary - Optional, a description for the share - * - * @return array - */ - public function getShares($addressBookId) { - return $this->sharingBackend->getShares($addressBookId); - } - - /** - * update properties table - * - * @param int $addressBookId - * @param string $cardUri - * @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') - ] - ); - - 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 int $addressBookId - * @param string $uri - * @return int - */ - protected function getCardId($addressBookId, $uri) { - $query = $this->db->getQueryBuilder(); - $query->select('id')->from($this->dbCardsTable) - ->where($query->expr()->eq('uri', $query->createNamedParameter($uri))) - ->andWhere($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))); - - $result = $query->execute(); - $cardIds = $result->fetch(); - $result->closeCursor(); - - if (!isset($cardIds['id'])) { - throw new \InvalidArgumentException('Card does not exists: ' . $uri); - } - - return (int)$cardIds['id']; - } - - /** - * For shared address books the sharee is set in the ACL of the address book - * @param $addressBookId - * @param $acl - * @return array - */ - public function applyShareAcl($addressBookId, $acl) { - return $this->sharingBackend->applyShareAcl($addressBookId, $acl); - } - - private function convertPrincipal($principalUri, $toV2) { - if ($this->principalBackend->getPrincipalPrefix() === 'principals') { - list(, $name) = URLUtil::splitPath($principalUri); - if ($toV2 === true) { - return "principals/users/$name"; - } - return "principals/$name"; - } - return $principalUri; - } -} diff --git a/apps/dav/lib/carddav/contactsmanager.php b/apps/dav/lib/carddav/contactsmanager.php deleted file mode 100644 index 7900c6ccae0..00000000000 --- a/apps/dav/lib/carddav/contactsmanager.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\Contacts\IManager; - -class ContactsManager { - - /** - * ContactsManager constructor. - * - * @param CardDavBackend $backend - */ - public function __construct(CardDavBackend $backend) { - $this->backend = $backend; - } - - /** - * @param IManager $cm - * @param string $userId - */ - public function setupContactsProvider(IManager $cm, $userId) { - $addressBooks = $this->backend->getAddressBooksForUser("principals/users/$userId"); - $this->register($cm, $addressBooks); - $addressBooks = $this->backend->getAddressBooksForUser("principals/system/system"); - $this->register($cm, $addressBooks); - } - - /** - * @param IManager $cm - * @param $addressBooks - */ - private function register(IManager $cm, $addressBooks) { - foreach ($addressBooks as $addressBookInfo) { - $addressBook = new \OCA\DAV\CardDAV\AddressBook($this->backend, $addressBookInfo); - $cm->registerAddressBook( - new AddressBookImpl( - $addressBook, - $addressBookInfo, - $this->backend - ) - ); - } - } - -} diff --git a/apps/dav/lib/carddav/converter.php b/apps/dav/lib/carddav/converter.php deleted file mode 100644 index c8d9b94c267..00000000000 --- a/apps/dav/lib/carddav/converter.php +++ /dev/null @@ -1,171 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\IImage; -use OCP\IUser; -use Sabre\VObject\Component\VCard; -use Sabre\VObject\Property\Text; - -class Converter { - - /** - * @param IUser $user - * @return VCard - */ - public function createCardFromUser(IUser $user) { - - $uid = $user->getUID(); - $displayName = $user->getDisplayName(); - $displayName = empty($displayName ) ? $uid : $displayName; - $emailAddress = $user->getEMailAddress(); - $cloudId = $user->getCloudId(); - $image = $this->getAvatarImage($user); - - $vCard = new VCard(); - $vCard->add(new Text($vCard, 'UID', $uid)); - if (!empty($displayName)) { - $vCard->add(new Text($vCard, 'FN', $displayName)); - $vCard->add(new Text($vCard, 'N', $this->splitFullName($displayName))); - } - if (!empty($emailAddress)) { - $vCard->add(new Text($vCard, 'EMAIL', $emailAddress, ['TYPE' => 'OTHER'])); - } - if (!empty($cloudId)) { - $vCard->add(new Text($vCard, 'CLOUD', $cloudId)); - } - if ($image) { - $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]); - } - $vCard->validate(); - - return $vCard; - } - - /** - * @param VCard $vCard - * @param IUser $user - * @return bool - */ - public function updateCard(VCard $vCard, IUser $user) { - $uid = $user->getUID(); - $displayName = $user->getDisplayName(); - $displayName = empty($displayName ) ? $uid : $displayName; - $emailAddress = $user->getEMailAddress(); - $cloudId = $user->getCloudId(); - $image = $this->getAvatarImage($user); - - $updated = false; - if($this->propertyNeedsUpdate($vCard, 'FN', $displayName)) { - $vCard->FN = new Text($vCard, 'FN', $displayName); - unset($vCard->N); - $vCard->add(new Text($vCard, 'N', $this->splitFullName($displayName))); - $updated = true; - } - if($this->propertyNeedsUpdate($vCard, 'EMAIL', $emailAddress)) { - $vCard->EMAIL = new Text($vCard, 'EMAIL', $emailAddress); - $updated = true; - } - if($this->propertyNeedsUpdate($vCard, 'CLOUD', $cloudId)) { - $vCard->CLOUD = new Text($vCard, 'CLOUD', $cloudId); - $updated = true; - } - - if($this->propertyNeedsUpdate($vCard, 'PHOTO', $image)) { - $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]); - $updated = true; - } - - if (empty($emailAddress) && !is_null($vCard->EMAIL)) { - unset($vCard->EMAIL); - $updated = true; - } - if (empty($cloudId) && !is_null($vCard->CLOUD)) { - unset($vCard->CLOUD); - $updated = true; - } - if (empty($image) && !is_null($vCard->PHOTO)) { - unset($vCard->PHOTO); - $updated = true; - } - - return $updated; - } - - /** - * @param VCard $vCard - * @param string $name - * @param string|IImage $newValue - * @return bool - */ - private function propertyNeedsUpdate(VCard $vCard, $name, $newValue) { - if (is_null($newValue)) { - return false; - } - $value = $vCard->__get($name); - if (!is_null($value)) { - $value = $value->getValue(); - $newValue = $newValue instanceof IImage ? $newValue->data() : $newValue; - - return $value !== $newValue; - } - return true; - } - - /** - * @param string $fullName - * @return string[] - */ - public function splitFullName($fullName) { - // Very basic western style parsing. I'm not gonna implement - // https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;) - - $elements = explode(' ', $fullName); - $result = ['', '', '', '', '']; - if (count($elements) > 2) { - $result[0] = implode(' ', array_slice($elements, count($elements)-1)); - $result[1] = $elements[0]; - $result[2] = implode(' ', array_slice($elements, 1, count($elements)-2)); - } elseif (count($elements) === 2) { - $result[0] = $elements[1]; - $result[1] = $elements[0]; - } else { - $result[0] = $elements[0]; - } - - return $result; - } - - /** - * @param IUser $user - * @return null|IImage - */ - private function getAvatarImage(IUser $user) { - try { - $image = $user->getAvatarImage(-1); - return $image; - } catch (\Exception $ex) { - return null; - } - } - -} diff --git a/apps/dav/lib/carddav/plugin.php b/apps/dav/lib/carddav/plugin.php deleted file mode 100644 index e02cc5686b8..00000000000 --- a/apps/dav/lib/carddav/plugin.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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 OCA\DAV\CardDAV\Xml\Groups; -use Sabre\DAV\INode; -use Sabre\DAV\PropFind; -use Sabre\DAV\Server; -use Sabre\HTTP\URLUtil; - -class Plugin extends \Sabre\CardDAV\Plugin { - - function initialize(Server $server) { - $server->on('propFind', [$this, 'propFind']); - parent::initialize($server); - } - - /** - * Returns the addressbook home for a given principal - * - * @param string $principal - * @return string - */ - protected function getAddressbookHomeForPrincipal($principal) { - - if (strrpos($principal, 'principals/users', -strlen($principal)) !== false) { - list(, $principalId) = URLUtil::splitPath($principal); - return self::ADDRESSBOOK_ROOT . '/users/' . $principalId; - } - if (strrpos($principal, 'principals/groups', -strlen($principal)) !== false) { - list(, $principalId) = URLUtil::splitPath($principal); - return self::ADDRESSBOOK_ROOT . '/groups/' . $principalId; - } - if (strrpos($principal, 'principals/system', -strlen($principal)) !== false) { - list(, $principalId) = URLUtil::splitPath($principal); - return self::ADDRESSBOOK_ROOT . '/system/' . $principalId; - } - - throw new \LogicException('This is not supposed to happen'); - } - - /** - * Adds all CardDAV-specific properties - * - * @param PropFind $propFind - * @param INode $node - * @return void - */ - function propFind(PropFind $propFind, INode $node) { - - $ns = '{http://owncloud.org/ns}'; - - if ($node instanceof AddressBook) { - - $propFind->handle($ns . 'groups', function () use ($node) { - return new Groups($node->getContactsGroups()); - }); - } - } -} diff --git a/apps/dav/lib/carddav/syncjob.php b/apps/dav/lib/carddav/syncjob.php deleted file mode 100644 index 0554af6fbf1..00000000000 --- a/apps/dav/lib/carddav/syncjob.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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 OC\BackgroundJob\TimedJob; -use OCA\Dav\AppInfo\Application; - -class SyncJob extends TimedJob { - - public function __construct() { - // Run once a day - $this->setInterval(24 * 60 * 60); - } - - protected function run($argument) { - $app = new Application(); - /** @var SyncService $ss */ - $ss = $app->getSyncService(); - $ss->syncInstance(); - } -} diff --git a/apps/dav/lib/carddav/syncservice.php b/apps/dav/lib/carddav/syncservice.php deleted file mode 100644 index c4741a01772..00000000000 --- a/apps/dav/lib/carddav/syncservice.php +++ /dev/null @@ -1,284 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\AppFramework\Http; -use OCP\ILogger; -use OCP\IUser; -use OCP\IUserManager; -use Sabre\DAV\Client; -use Sabre\DAV\Xml\Response\MultiStatus; -use Sabre\DAV\Xml\Service; -use Sabre\HTTP\ClientHttpException; -use Sabre\VObject\Reader; - -class SyncService { - - /** @var CardDavBackend */ - private $backend; - - /** @var IUserManager */ - private $userManager; - - /** @var ILogger */ - private $logger; - - /** @var array */ - private $localSystemAddressBook; - - public function __construct(CardDavBackend $backend, IUserManager $userManager, ILogger $logger) { - $this->backend = $backend; - $this->userManager = $userManager; - $this->logger = $logger; - } - - /** - * @param string $url - * @param string $userName - * @param string $sharedSecret - * @param string $syncToken - * @param int $targetBookId - * @param string $targetPrincipal - * @param array $targetProperties - * @return string - * @throws \Exception - */ - public function syncRemoteAddressBook($url, $userName, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetProperties) { - // 1. create addressbook - $book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookId, $targetProperties); - $addressBookId = $book['id']; - - // 2. query changes - try { - $response = $this->requestSyncReport($url, $userName, $sharedSecret, $syncToken); - } catch (ClientHttpException $ex) { - if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) { - // remote server revoked access to the address book, remove it - $this->backend->deleteAddressBook($addressBookId); - $this->logger->info('Authorization failed, remove address book: ' . $url, ['app' => 'dav']); - throw $ex; - } - } - - // 3. apply changes - // TODO: use multi-get for download - foreach ($response['response'] as $resource => $status) { - $cardUri = basename($resource); - if (isset($status[200])) { - $vCard = $this->download($url, $sharedSecret, $resource); - $existingCard = $this->backend->getCard($addressBookId, $cardUri); - if ($existingCard === false) { - $this->backend->createCard($addressBookId, $cardUri, $vCard['body']); - } else { - $this->backend->updateCard($addressBookId, $cardUri, $vCard['body']); - } - } else { - $this->backend->deleteCard($addressBookId, $cardUri); - } - } - - return $response['token']; - } - - /** - * @param string $principal - * @param string $id - * @param array $properties - * @return array|null - * @throws \Sabre\DAV\Exception\BadRequest - */ - public function ensureSystemAddressBookExists($principal, $id, $properties) { - $book = $this->backend->getAddressBooksByUri($principal, $id); - if (!is_null($book)) { - return $book; - } - $this->backend->createAddressBook($principal, $id, $properties); - - return $this->backend->getAddressBooksByUri($principal, $id); - } - - /** - * @param string $url - * @param string $userName - * @param string $sharedSecret - * @param string $syncToken - * @return array - */ - protected function requestSyncReport($url, $userName, $sharedSecret, $syncToken) { - $settings = [ - 'baseUri' => $url . '/', - 'userName' => $userName, - 'password' => $sharedSecret, - ]; - $client = new Client($settings); - $client->setThrowExceptions(true); - - $addressBookUrl = "remote.php/dav/addressbooks/system/system/system"; - $body = $this->buildSyncCollectionRequestBody($syncToken); - - $response = $client->request('REPORT', $addressBookUrl, $body, [ - 'Content-Type' => 'application/xml' - ]); - - $result = $this->parseMultiStatus($response['body']); - - return $result; - } - - /** - * @param string $url - * @param string $sharedSecret - * @param string $resourcePath - * @return array - */ - protected function download($url, $sharedSecret, $resourcePath) { - $settings = [ - 'baseUri' => $url, - 'userName' => 'system', - 'password' => $sharedSecret, - ]; - $client = new Client($settings); - $client->setThrowExceptions(true); - - $response = $client->request('GET', $resourcePath); - return $response; - } - - /** - * @param string|null $syncToken - * @return string - */ - private function buildSyncCollectionRequestBody($syncToken) { - - $dom = new \DOMDocument('1.0', 'UTF-8'); - $dom->formatOutput = true; - $root = $dom->createElementNS('DAV:', 'd:sync-collection'); - $sync = $dom->createElement('d:sync-token', $syncToken); - $prop = $dom->createElement('d:prop'); - $cont = $dom->createElement('d:getcontenttype'); - $etag = $dom->createElement('d:getetag'); - - $prop->appendChild($cont); - $prop->appendChild($etag); - $root->appendChild($sync); - $root->appendChild($prop); - $dom->appendChild($root); - $body = $dom->saveXML(); - - return $body; - } - - /** - * @param string $body - * @return array - * @throws \Sabre\Xml\ParseException - */ - private function parseMultiStatus($body) { - $xml = new Service(); - - /** @var MultiStatus $multiStatus */ - $multiStatus = $xml->expect('{DAV:}multistatus', $body); - - $result = []; - foreach ($multiStatus->getResponses() as $response) { - $result[$response->getHref()] = $response->getResponseProperties(); - } - - return ['response' => $result, 'token' => $multiStatus->getSyncToken()]; - } - - /** - * @param IUser $user - */ - public function updateUser($user) { - $systemAddressBook = $this->getLocalSystemAddressBook(); - $addressBookId = $systemAddressBook['id']; - $converter = new Converter(); - $name = $user->getBackendClassName(); - $userId = $user->getUID(); - - $cardId = "$name:$userId.vcf"; - $card = $this->backend->getCard($addressBookId, $cardId); - if ($card === false) { - $vCard = $converter->createCardFromUser($user); - $this->backend->createCard($addressBookId, $cardId, $vCard->serialize()); - } else { - $vCard = Reader::read($card['carddata']); - if ($converter->updateCard($vCard, $user)) { - $this->backend->updateCard($addressBookId, $cardId, $vCard->serialize()); - } - } - } - - /** - * @param IUser|string $userOrCardId - */ - public function deleteUser($userOrCardId) { - $systemAddressBook = $this->getLocalSystemAddressBook(); - if ($userOrCardId instanceof IUser){ - $name = $userOrCardId->getBackendClassName(); - $userId = $userOrCardId->getUID(); - - $userOrCardId = "$name:$userId.vcf"; - } - $this->backend->deleteCard($systemAddressBook['id'], $userOrCardId); - } - - /** - * @return array|null - */ - public function getLocalSystemAddressBook() { - if (is_null($this->localSystemAddressBook)) { - $systemPrincipal = "principals/system/system"; - $this->localSystemAddressBook = $this->ensureSystemAddressBookExists($systemPrincipal, 'system', [ - '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance' - ]); - } - - return $this->localSystemAddressBook; - } - - public function syncInstance(\Closure $progressCallback = null) { - $systemAddressBook = $this->getLocalSystemAddressBook(); - $this->userManager->callForAllUsers(function($user) use ($systemAddressBook, $progressCallback) { - $this->updateUser($user); - if (!is_null($progressCallback)) { - $progressCallback(); - } - }); - - // remove no longer existing - $allCards = $this->backend->getCards($systemAddressBook['id']); - foreach($allCards as $card) { - $vCard = Reader::read($card['carddata']); - $uid = $vCard->UID->getValue(); - // load backend and see if user exists - if (!$this->userManager->userExists($uid)) { - $this->deleteUser($card['uri']); - } - } - } - - -} diff --git a/apps/dav/lib/carddav/useraddressbooks.php b/apps/dav/lib/carddav/useraddressbooks.php deleted file mode 100644 index 734e3829e69..00000000000 --- a/apps/dav/lib/carddav/useraddressbooks.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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; - -class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { - - /** - * Returns a list of addressbooks - * - * @return array - */ - function getChildren() { - - $addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri); - $objects = []; - foreach($addressBooks as $addressBook) { - $objects[] = new AddressBook($this->carddavBackend, $addressBook); - } - return $objects; - - } - - /** - * Returns a list of ACE's for this node. - * - * Each ACE has the following properties: - * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are - * currently the only supported privileges - * * 'principal', a url to the principal who owns the node - * * 'protected' (optional), indicating that this ACE is not allowed to - * be updated. - * - * @return array - */ - function getACL() { - - $acl = parent::getACL(); - if ($this->principalUri === 'principals/system/system') { - $acl[] = [ - 'privilege' => '{DAV:}read', - 'principal' => '{DAV:}authenticated', - 'protected' => true, - ]; - } - - return $acl; - } - -} diff --git a/apps/dav/lib/carddav/xml/groups.php b/apps/dav/lib/carddav/xml/groups.php deleted file mode 100644 index b39615db033..00000000000 --- a/apps/dav/lib/carddav/xml/groups.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\Xml; - -use Sabre\Xml\XmlSerializable; -use Sabre\Xml\Element; -use Sabre\Xml\Writer; - -class Groups implements XmlSerializable { - const NS_OWNCLOUD = 'http://owncloud.org/ns'; - - /** @var string[] of TYPE:CHECKSUM */ - private $groups; - - /** - * @param string $groups - */ - public function __construct($groups) { - $this->groups = $groups; - } - - function xmlSerialize(Writer $writer) { - foreach ($this->groups as $group) { - $writer->writeElement('{' . self::NS_OWNCLOUD . '}group', $group); - } - } -} |