From c91192fb7324c246d3af95ae83ad9ac1ae0a8ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 24 Nov 2015 23:53:27 +0100 Subject: [PATCH 01/16] Adding system addressbook for users of this instance - a occ command is supplied for synchronizing --- apps/dav/appinfo/register_command.php | 3 + apps/dav/command/syncsystemaddressbook.php | 112 +++++++++++++++++++++ apps/dav/lib/carddav/addressbook.php | 26 +++++ apps/dav/lib/carddav/carddavbackend.php | 4 +- apps/dav/lib/carddav/useraddressbooks.php | 26 +++++ apps/dav/lib/connector/sabre/principal.php | 12 +++ 6 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 apps/dav/command/syncsystemaddressbook.php diff --git a/apps/dav/appinfo/register_command.php b/apps/dav/appinfo/register_command.php index 1f0df05411..af41036cdd 100644 --- a/apps/dav/appinfo/register_command.php +++ b/apps/dav/appinfo/register_command.php @@ -2,7 +2,9 @@ use OCA\DAV\Command\CreateAddressBook; use OCA\DAV\Command\CreateCalendar; +use OCA\DAV\Command\SyncSystemAddressBook; +$config = \OC::$server->getConfig(); $dbConnection = \OC::$server->getDatabaseConnection(); $userManager = OC::$server->getUserManager(); $config = \OC::$server->getConfig(); @@ -10,3 +12,4 @@ $config = \OC::$server->getConfig(); /** @var Symfony\Component\Console\Application $application */ $application->add(new CreateAddressBook($userManager, $dbConnection, $config)); $application->add(new CreateCalendar($userManager, $dbConnection)); +$application->add(new SyncSystemAddressBook($userManager, $dbConnection, $config)); diff --git a/apps/dav/command/syncsystemaddressbook.php b/apps/dav/command/syncsystemaddressbook.php new file mode 100644 index 0000000000..01f4d08940 --- /dev/null +++ b/apps/dav/command/syncsystemaddressbook.php @@ -0,0 +1,112 @@ +userManager = $userManager; + $this->dbConnection = $dbConnection; + $this->config = $config; + } + + protected function configure() { + $this + ->setName('dav:sync-system-addressbook') + ->setDescription('Synchronizes users to the system addressbook'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $principalBackend = new Principal( + $this->config, + $this->userManager + ); + + $this->backend = new CardDavBackend($this->dbConnection, $principalBackend); + + // ensure system addressbook exists + $systemAddressBook = $this->ensureSystemAddressBookExists(); + + $output->writeln('Syncing users ...'); + $progress = new ProgressBar($output); + $progress->start(); + $page = 0; + foreach( $this->userManager->getBackends() as $backend) { + $users = $backend->getUsers('', 50, $page++); + foreach($users as $user) { + $user = $this->userManager->get($user); + $name = $user->getBackendClassName(); + $userId = $user->getUID(); + $displayName = $user->getDisplayName(); + $cardId = "$name:$userId.vcf"; + $card = $this->backend->getCard($systemAddressBook['id'], $cardId); + if ($card === false) { + $vCard = new VCard(); + $vCard->add(new Text($vCard, 'UID', $user->getUID())); + $vCard->add(new Text($vCard, 'FN', $displayName)); +// $vCard->add(new Text($vCard, 'EMAIL', $user->getEMailAddress())); + //$vCard->add(new Binary($vCard, 'PHOTO', $user->getAvatar())); + $vCard->validate(); + $this->backend->createCard($systemAddressBook['id'], $cardId, $vCard->serialize()); + } else { + $updated = false; + $vCard = Reader::read($card['carddata']); + if($vCard->FN !== $user->getDisplayName()) { + $vCard->FN = new Text($vCard, 'FN', $displayName); + $updated = true; + } + if ($updated) { + $this->backend->updateCard($systemAddressBook['id'], $cardId, $vCard->serialize()); + } + } + $progress->advance(); + } + } + $progress->finish(); + } + + protected function ensureSystemAddressBookExists() { + $book = $this->backend->getAddressBooksByUri('system'); + if (!is_null($book)) { + return $book; + } + $systemPrincipal = "principals/system"; + $this->backend->createAddressBook($systemPrincipal, 'system', [ + '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance' + ]); + + return $this->backend->getAddressBooksByUri('system'); + } +} diff --git a/apps/dav/lib/carddav/addressbook.php b/apps/dav/lib/carddav/addressbook.php index eff1ad321e..41227088ec 100644 --- a/apps/dav/lib/carddav/addressbook.php +++ b/apps/dav/lib/carddav/addressbook.php @@ -51,4 +51,30 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddres $carddavBackend = $this->carddavBackend; $carddavBackend->getShares($this->getName()); } + + function getACL() { + $acl = parent::getACL(); + if ($this->getOwner() === 'principals/system') { + $acl[] = [ + 'privilege' => '{DAV:}read', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ]; + } + + return $acl; + } + + function getChildACL() { + $acl = parent::getChildACL(); + if ($this->getOwner() === 'principals/system') { + $acl[] = [ + 'privilege' => '{DAV:}read', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ]; + } + + return $acl; + } } diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php index daa31725fa..752669aae2 100644 --- a/apps/dav/lib/carddav/carddavbackend.php +++ b/apps/dav/lib/carddav/carddavbackend.php @@ -108,7 +108,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { return $addressBooks; } - private function getAddressBooksByUri($addressBookUri) { + public function getAddressBooksByUri($addressBookUri) { $query = $this->db->getQueryBuilder(); $result = $query->select(['id', 'uri', 'displayname', 'principaluri', 'description', 'synctoken']) ->from('addressbooks') @@ -117,7 +117,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { ->execute(); $row = $result->fetch(); - if (is_null($row)) { + if ($row === false) { return null; } $result->closeCursor(); diff --git a/apps/dav/lib/carddav/useraddressbooks.php b/apps/dav/lib/carddav/useraddressbooks.php index 5f618a0ece..2e630942e7 100644 --- a/apps/dav/lib/carddav/useraddressbooks.php +++ b/apps/dav/lib/carddav/useraddressbooks.php @@ -20,4 +20,30 @@ class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { } + /** + * 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') { + $acl[] = [ + 'privilege' => '{DAV:}read', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ]; + } + + return $acl; + } + } diff --git a/apps/dav/lib/connector/sabre/principal.php b/apps/dav/lib/connector/sabre/principal.php index cc9c1c40d5..7852eca61a 100644 --- a/apps/dav/lib/connector/sabre/principal.php +++ b/apps/dav/lib/connector/sabre/principal.php @@ -74,6 +74,11 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface { } } + $principals[] = [ + 'uri' => 'principals/system', + '{DAV:}displayname' => 'system', + ]; + return $principals; } @@ -90,6 +95,13 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface { if ($elements[0] !== 'principals') { return null; } + if ($elements[1] === 'system') { + $principal = [ + 'uri' => 'principals/system', + '{DAV:}displayname' => 'system', + ]; + return $principal; + } if ($elements[1] !== 'users') { return null; } From dad6470baa817a796de7e1b6d27daf6d24519096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 25 Nov 2015 21:44:36 +0100 Subject: [PATCH 02/16] Add IUser::getAvatarImage() for easy access --- apps/dav/command/syncsystemaddressbook.php | 13 ++++++---- lib/private/avatar.php | 4 +++- lib/private/user/user.php | 28 +++++++++++++++++++++- lib/public/iuser.php | 9 +++++++ tests/lib/contacts/localadressbook.php | 4 +++- 5 files changed, 51 insertions(+), 7 deletions(-) diff --git a/apps/dav/command/syncsystemaddressbook.php b/apps/dav/command/syncsystemaddressbook.php index 01f4d08940..3139813fc4 100644 --- a/apps/dav/command/syncsystemaddressbook.php +++ b/apps/dav/command/syncsystemaddressbook.php @@ -70,20 +70,25 @@ class SyncSystemAddressBook extends Command { $name = $user->getBackendClassName(); $userId = $user->getUID(); $displayName = $user->getDisplayName(); + //$emailAddress = $user->getEMailAddress(); + $image = $user->getAvatarImage(-1); + $cardId = "$name:$userId.vcf"; $card = $this->backend->getCard($systemAddressBook['id'], $cardId); if ($card === false) { $vCard = new VCard(); - $vCard->add(new Text($vCard, 'UID', $user->getUID())); + $vCard->add(new Text($vCard, 'UID', $userId)); $vCard->add(new Text($vCard, 'FN', $displayName)); -// $vCard->add(new Text($vCard, 'EMAIL', $user->getEMailAddress())); - //$vCard->add(new Binary($vCard, 'PHOTO', $user->getAvatar())); +// $vCard->add(new Text($vCard, 'EMAIL', $emailAddress)); + if ($image) { + $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]); + } $vCard->validate(); $this->backend->createCard($systemAddressBook['id'], $cardId, $vCard->serialize()); } else { $updated = false; $vCard = Reader::read($card['carddata']); - if($vCard->FN !== $user->getDisplayName()) { + if($vCard->FN !== $displayName) { $vCard->FN = new Text($vCard, 'FN', $displayName); $updated = true; } diff --git a/lib/private/avatar.php b/lib/private/avatar.php index 872da35f94..37a813f3ff 100644 --- a/lib/private/avatar.php +++ b/lib/private/avatar.php @@ -79,7 +79,9 @@ class Avatar implements \OCP\IAvatar { /** @var File $node */ $node = $this->folder->get('avatar.' . $ext); $avatar->loadFromData($node->getContent()); - $avatar->resize($size); + if ($size > 0) { + $avatar->resize($size); + } $this->folder->newFile('avatar.' . $size . '.' . $ext)->putContent($avatar->data()); } return $avatar; diff --git a/lib/private/user/user.php b/lib/private/user/user.php index 2740b25d5d..023fc5f5a3 100644 --- a/lib/private/user/user.php +++ b/lib/private/user/user.php @@ -30,6 +30,8 @@ namespace OC\User; use OC\Hooks\Emitter; +use OCP\IAvatarManager; +use OCP\IImage; use OCP\IUser; use OCP\IConfig; @@ -74,17 +76,21 @@ class User implements IUser { */ private $config; + /** @var IAvatarManager */ + private $avatarManager; + /** * @param string $uid * @param \OC_User_Interface $backend * @param \OC\Hooks\Emitter $emitter * @param \OCP\IConfig $config */ - public function __construct($uid, $backend, $emitter = null, IConfig $config = null) { + public function __construct($uid, $backend, $emitter = null, IConfig $config = null, $avatarManager = null) { $this->uid = $uid; $this->backend = $backend; $this->emitter = $emitter; $this->config = $config; + $this->avatarManager = $avatarManager; if ($this->config) { $enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true'); $this->enabled = ($enabled === 'true'); @@ -93,6 +99,9 @@ class User implements IUser { $this->enabled = true; $this->lastLogin = \OC::$server->getConfig()->getUserValue($uid, 'login', 'lastLogin', 0); } + if (is_null($this->avatarManager)) { + $this->avatarManager = \OC::$server->getAvatarManager(); + } } /** @@ -316,4 +325,21 @@ class User implements IUser { public function getEMailAddress() { return $this->config->getUserValue($this->uid, 'settings', 'email'); } + + /** + * get the avatar image if it exists + * + * @param int $size + * @return IImage|null + * @since 9.0.0 + */ + public function getAvatarImage($size) { + $avatar = $this->avatarManager->getAvatar($this->uid); + $image = $avatar->get(-1); + if ($image) { + return $image; + } + + return null; + } } diff --git a/lib/public/iuser.php b/lib/public/iuser.php index 1e52cd5903..f6caef2ba1 100644 --- a/lib/public/iuser.php +++ b/lib/public/iuser.php @@ -152,4 +152,13 @@ interface IUser { * @since 9.0.0 */ public function getEMailAddress(); + + /** + * get the avatar image if it exists + * + * @param int $size + * @return IImage|null + * @since 9.0.0 + */ + public function getAvatarImage($size); } diff --git a/tests/lib/contacts/localadressbook.php b/tests/lib/contacts/localadressbook.php index 6bfcf3d890..5416832453 100644 --- a/tests/lib/contacts/localadressbook.php +++ b/tests/lib/contacts/localadressbook.php @@ -98,6 +98,8 @@ class SimpleUserForTesting implements IUser { } public function getEMailAddress() { - // TODO: Implement getEMailAddress() method. + } + + public function getAvatarImage($size) { } } From dcfd089a6caed18f040284802cb3fe7e5475c4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 26 Nov 2015 20:46:50 +0100 Subject: [PATCH 03/16] Adding a second principal backend which holds system principals - as of now only one principals/system/system --- apps/dav/lib/connector/sabre/principal.php | 12 -- apps/dav/lib/dav/systemprincipalbackend.php | 183 ++++++++++++++++++++ apps/dav/lib/rootcollection.php | 11 +- 3 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 apps/dav/lib/dav/systemprincipalbackend.php diff --git a/apps/dav/lib/connector/sabre/principal.php b/apps/dav/lib/connector/sabre/principal.php index 7852eca61a..cc9c1c40d5 100644 --- a/apps/dav/lib/connector/sabre/principal.php +++ b/apps/dav/lib/connector/sabre/principal.php @@ -74,11 +74,6 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface { } } - $principals[] = [ - 'uri' => 'principals/system', - '{DAV:}displayname' => 'system', - ]; - return $principals; } @@ -95,13 +90,6 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface { if ($elements[0] !== 'principals') { return null; } - if ($elements[1] === 'system') { - $principal = [ - 'uri' => 'principals/system', - '{DAV:}displayname' => 'system', - ]; - return $principal; - } if ($elements[1] !== 'users') { return null; } diff --git a/apps/dav/lib/dav/systemprincipalbackend.php b/apps/dav/lib/dav/systemprincipalbackend.php new file mode 100644 index 0000000000..2c2049ace6 --- /dev/null +++ b/apps/dav/lib/dav/systemprincipalbackend.php @@ -0,0 +1,183 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\DAV; + +use Sabre\DAVACL\PrincipalBackend\AbstractBackend; +use Sabre\HTTP\URLUtil; + +class SystemPrincipalBackend extends AbstractBackend { + + /** + * Returns a list of principals based on a prefix. + * + * This prefix will often contain something like 'principals'. You are only + * expected to return principals that are in this base path. + * + * You are expected to return at least a 'uri' for every user, you can + * return any additional properties if you wish so. Common properties are: + * {DAV:}displayname + * {http://sabredav.org/ns}email-address - This is a custom SabreDAV + * field that's actually injected in a number of other properties. If + * you have an email address, use this property. + * + * @param string $prefixPath + * @return array + */ + function getPrincipalsByPrefix($prefixPath) { + $principals = []; + + if ($prefixPath === 'principals/system') { + $principals[] = [ + 'uri' => 'principals/system/system', + '{DAV:}displayname' => 'system', + ]; + } + + return $principals; + } + + /** + * Returns a specific principal, specified by it's path. + * The returned structure should be the exact same as from + * getPrincipalsByPrefix. + * + * @param string $path + * @return array + */ + function getPrincipalByPath($path) { + + $elements = explode('/', $path); + if ($elements[0] !== 'principals') { + return null; + } + if ($elements[1] === 'system') { + $principal = [ + 'uri' => 'principals/system/system', + '{DAV:}displayname' => 'system', + ]; + return $principal; + } + + return null; + } + + /** + * Updates one ore more webdav properties on a principal. + * + * 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 $path + * @param \Sabre\DAV\PropPatch $propPatch + * @return void + */ + function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) { + } + + /** + * This method is used to search for principals matching a set of + * properties. + * + * This search is specifically used by RFC3744's principal-property-search + * REPORT. + * + * The actual search should be a unicode-non-case-sensitive search. The + * keys in searchProperties are the WebDAV property names, while the values + * are the property values to search on. + * + * By default, if multiple properties are submitted to this method, the + * various properties should be combined with 'AND'. If $test is set to + * 'anyof', it should be combined using 'OR'. + * + * This method should simply return an array with full principal uri's. + * + * If somebody attempted to search on a property the backend does not + * support, you should simply return 0 results. + * + * You can also just return 0 results if you choose to not support + * searching at all, but keep in mind that this may stop certain features + * from working. + * + * @param string $prefixPath + * @param array $searchProperties + * @param string $test + * @return array + */ + function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { + return []; + } + + /** + * Returns the list of members for a group-principal + * + * @param string $principal + * @return array + */ + function getGroupMemberSet($principal) { + // TODO: for now the group principal has only one member, the user itself + $principal = $this->getPrincipalByPath($principal); + if (!$principal) { + throw new \Sabre\DAV\Exception('Principal not found'); + } + + return [$principal['uri']]; + } + + /** + * Returns the list of groups a principal is a member of + * + * @param string $principal + * @return array + */ + function getGroupMembership($principal) { + list($prefix, $name) = URLUtil::splitPath($principal); + + if ($prefix === 'principals/system') { + $principal = $this->getPrincipalByPath($principal); + if (!$principal) { + throw new \Sabre\DAV\Exception('Principal not found'); + } + + return []; + } + return []; + } + + /** + * Updates the list of group members for a group principal. + * + * The principals should be passed as a list of uri's. + * + * @param string $principal + * @param array $members + * @return void + */ + function setGroupMemberSet($principal, array $members) { + throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet'); + } +} diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index 3e349fa31c..11fdc7c960 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -6,6 +6,7 @@ use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CardDAV\AddressBookRoot; use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\Connector\Sabre\Principal; +use OCA\DAV\DAV\SystemPrincipalBackend; use Sabre\CalDAV\CalendarRoot; use Sabre\CalDAV\Principal\Collection; use Sabre\DAV\SimpleCollection; @@ -23,8 +24,10 @@ class RootCollection extends SimpleCollection { $disableListing = !$config->getSystemValue('debug', false); // setup the first level of the dav tree - $principalCollection = new Collection($principalBackend, 'principals/users'); - $principalCollection->disableListing = $disableListing; + $userPrincipals = new Collection($principalBackend, 'principals/users'); + $userPrincipals->disableListing = $disableListing; + $systemPrincipals = new Collection(new SystemPrincipalBackend(), 'principals/system'); + $systemPrincipals->disableListing = $disableListing; $filesCollection = new Files\RootCollection($principalBackend, 'principals/users'); $filesCollection->disableListing = $disableListing; $caldavBackend = new CalDavBackend($db); @@ -37,7 +40,9 @@ class RootCollection extends SimpleCollection { $addressBookRoot->disableListing = $disableListing; $children = [ - new SimpleCollection('principals', [$principalCollection]), + new SimpleCollection('principals', [ + $userPrincipals, + $systemPrincipals]), $filesCollection, $calendarRoot, $addressBookRoot, From 6a2dde64009fdffc6483b920717721634348a12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 27 Nov 2015 13:14:55 +0100 Subject: [PATCH 04/16] user and system addressbooks are now living in sub folders --- apps/dav/command/syncsystemaddressbook.php | 3 +- apps/dav/lib/carddav/addressbook.php | 4 +- apps/dav/lib/carddav/addressbookroot.php | 12 +++++- apps/dav/lib/carddav/plugin.php | 47 ++++++++++++++++++++++ apps/dav/lib/carddav/useraddressbooks.php | 12 +++--- apps/dav/lib/rootcollection.php | 13 ++++-- apps/dav/lib/server.php | 2 +- 7 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 apps/dav/lib/carddav/plugin.php diff --git a/apps/dav/command/syncsystemaddressbook.php b/apps/dav/command/syncsystemaddressbook.php index 3139813fc4..460d398a8b 100644 --- a/apps/dav/command/syncsystemaddressbook.php +++ b/apps/dav/command/syncsystemaddressbook.php @@ -100,6 +100,7 @@ class SyncSystemAddressBook extends Command { } } $progress->finish(); + $output->writeln(''); } protected function ensureSystemAddressBookExists() { @@ -107,7 +108,7 @@ class SyncSystemAddressBook extends Command { if (!is_null($book)) { return $book; } - $systemPrincipal = "principals/system"; + $systemPrincipal = "principals/system/system"; $this->backend->createAddressBook($systemPrincipal, 'system', [ '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance' ]); diff --git a/apps/dav/lib/carddav/addressbook.php b/apps/dav/lib/carddav/addressbook.php index 41227088ec..1e6ecf622d 100644 --- a/apps/dav/lib/carddav/addressbook.php +++ b/apps/dav/lib/carddav/addressbook.php @@ -54,7 +54,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddres function getACL() { $acl = parent::getACL(); - if ($this->getOwner() === 'principals/system') { + if ($this->getOwner() === 'principals/system/system') { $acl[] = [ 'privilege' => '{DAV:}read', 'principal' => '{DAV:}authenticated', @@ -67,7 +67,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddres function getChildACL() { $acl = parent::getChildACL(); - if ($this->getOwner() === 'principals/system') { + if ($this->getOwner() === 'principals/system/system') { $acl[] = [ 'privilege' => '{DAV:}read', 'principal' => '{DAV:}authenticated', diff --git a/apps/dav/lib/carddav/addressbookroot.php b/apps/dav/lib/carddav/addressbookroot.php index ee99ac8d79..8c78d02455 100644 --- a/apps/dav/lib/carddav/addressbookroot.php +++ b/apps/dav/lib/carddav/addressbookroot.php @@ -20,4 +20,14 @@ class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot { } -} \ No newline at end of file + function 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/plugin.php b/apps/dav/lib/carddav/plugin.php new file mode 100644 index 0000000000..f2b3dcbfda --- /dev/null +++ b/apps/dav/lib/carddav/plugin.php @@ -0,0 +1,47 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\CardDAV; + +use Sabre\HTTP\URLUtil; + +class Plugin extends \Sabre\CardDAV\Plugin { + + /** + * 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/system', -strlen($principal)) !== FALSE) { + list(, $principalId) = URLUtil::splitPath($principal); + return self::ADDRESSBOOK_ROOT . '/system/' . $principalId; + } + + throw new \LogicException('This is not supposed to happen'); + } +} diff --git a/apps/dav/lib/carddav/useraddressbooks.php b/apps/dav/lib/carddav/useraddressbooks.php index 2e630942e7..093cee0e1b 100644 --- a/apps/dav/lib/carddav/useraddressbooks.php +++ b/apps/dav/lib/carddav/useraddressbooks.php @@ -11,12 +11,12 @@ class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { */ function getChildren() { - $addressbooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri); - $objs = []; - foreach($addressbooks as $addressbook) { - $objs[] = new AddressBook($this->carddavBackend, $addressbook); + $addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri); + $objects = []; + foreach($addressBooks as $addressBook) { + $objects[] = new AddressBook($this->carddavBackend, $addressBook); } - return $objs; + return $objects; } @@ -35,7 +35,7 @@ class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { function getACL() { $acl = parent::getACL(); - if ($this->principalUri === 'principals/system') { + if ($this->principalUri === 'principals/system/system') { $acl[] = [ 'privilege' => '{DAV:}read', 'principal' => '{DAV:}authenticated', diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index 11fdc7c960..c1635c9cde 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -34,10 +34,13 @@ class RootCollection extends SimpleCollection { $calendarRoot = new CalendarRoot($principalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; - $cardDavBackend = new CardDavBackend(\OC::$server->getDatabaseConnection(), $principalBackend); + $usersCardDavBackend = new CardDavBackend($db, $principalBackend); + $usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users'); + $usersAddressBookRoot->disableListing = $disableListing; - $addressBookRoot = new AddressBookRoot($principalBackend, $cardDavBackend, 'principals/users'); - $addressBookRoot->disableListing = $disableListing; + $systemCardDavBackend = new CardDavBackend($db, $principalBackend); + $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, 'principals/system'); + $systemAddressBookRoot->disableListing = $disableListing; $children = [ new SimpleCollection('principals', [ @@ -45,7 +48,9 @@ class RootCollection extends SimpleCollection { $systemPrincipals]), $filesCollection, $calendarRoot, - $addressBookRoot, + new SimpleCollection('addressbooks', [ + $usersAddressBookRoot, + $systemAddressBookRoot]), ]; parent::__construct('root', $children); diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index ffdb917085..a031f2c442 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -58,7 +58,7 @@ class Server { $this->server->addPlugin(new CardDAV\Sharing\Plugin($authBackend, \OC::$server->getRequest())); // addressbook plugins - $this->server->addPlugin(new \Sabre\CardDAV\Plugin()); + $this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin()); // Finder on OS X requires Class 2 WebDAV support (locking), since we do // not provide locking we emulate it using a fake locking plugin. From 079ae9b7a97a25497e0692dfc31eae831439f4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 30 Nov 2015 10:41:34 +0100 Subject: [PATCH 05/16] Update addressbook home configuration for CalDAVTester --- apps/dav/tests/travis/caldavtest/config/serverinfo.xml | 2 +- .../travis/caldavtest/tests/CardDAV/sync-report.xml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/dav/tests/travis/caldavtest/config/serverinfo.xml b/apps/dav/tests/travis/caldavtest/config/serverinfo.xml index a474bb7135..c80e47f948 100644 --- a/apps/dav/tests/travis/caldavtest/config/serverinfo.xml +++ b/apps/dav/tests/travis/caldavtest/config/serverinfo.xml @@ -569,7 +569,7 @@ $addressbookhome%d: - $addressbooks:$userid%d: + $addressbooks:users/$userid%d: diff --git a/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml index 0321e61edb..ffa6662981 100644 --- a/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml +++ b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sync-report.xml @@ -181,8 +181,7 @@ - remove new resource @@ -264,14 +263,15 @@ multistatusItems okhrefs - $calendar_sync_extra_items: + + 1.vcf 2.vcf - +