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/DAV | |
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/DAV')
-rw-r--r-- | apps/dav/lib/DAV/GroupPrincipalBackend.php | 200 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Backend.php | 206 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/IShareable.php | 74 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Plugin.php | 200 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Xml/Invite.php | 168 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Xml/ShareRequest.php | 84 | ||||
-rw-r--r-- | apps/dav/lib/DAV/SystemPrincipalBackend.php | 179 |
7 files changed, 1111 insertions, 0 deletions
diff --git a/apps/dav/lib/DAV/GroupPrincipalBackend.php b/apps/dav/lib/DAV/GroupPrincipalBackend.php new file mode 100644 index 00000000000..e0568639784 --- /dev/null +++ b/apps/dav/lib/DAV/GroupPrincipalBackend.php @@ -0,0 +1,200 @@ +<?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\DAV; + +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IUser; +use Sabre\DAV\Exception; +use \Sabre\DAV\PropPatch; +use Sabre\DAVACL\PrincipalBackend\BackendInterface; + +class GroupPrincipalBackend implements BackendInterface { + + const PRINCIPAL_PREFIX = 'principals/groups'; + + /** @var IGroupManager */ + private $groupManager; + + /** + * @param IGroupManager $IGroupManager + */ + public function __construct(IGroupManager $IGroupManager) { + $this->groupManager = $IGroupManager; + } + + /** + * 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 + * + * @param string $prefixPath + * @return string[] + */ + public function getPrincipalsByPrefix($prefixPath) { + $principals = []; + + if ($prefixPath === self::PRINCIPAL_PREFIX) { + foreach($this->groupManager->search('') as $user) { + $principals[] = $this->groupToPrincipal($user); + } + } + + 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 + */ + public function getPrincipalByPath($path) { + $elements = explode('/', $path); + if ($elements[0] !== 'principals') { + return null; + } + if ($elements[1] !== 'groups') { + return null; + } + $name = $elements[2]; + $group = $this->groupManager->get($name); + + if (!is_null($group)) { + return $this->groupToPrincipal($group); + } + + return null; + } + + /** + * Returns the list of members for a group-principal + * + * @param string $principal + * @return string[] + * @throws Exception + */ + public function getGroupMemberSet($principal) { + $elements = explode('/', $principal); + if ($elements[0] !== 'principals') { + return []; + } + if ($elements[1] !== 'groups') { + return []; + } + $name = $elements[2]; + $group = $this->groupManager->get($name); + + if (is_null($group)) { + return []; + } + + return array_map(function($user) { + return $this->userToPrincipal($user); + }, $group->getUsers()); + } + + /** + * Returns the list of groups a principal is a member of + * + * @param string $principal + * @return array + * @throws Exception + */ + public function getGroupMembership($principal) { + 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 string[] $members + * @throws Exception + */ + public function setGroupMemberSet($principal, array $members) { + throw new Exception('Setting members of the group is not supported yet'); + } + + /** + * @param string $path + * @param PropPatch $propPatch + * @return int + */ + function updatePrincipal($path, PropPatch $propPatch) { + return 0; + } + + /** + * @param string $prefixPath + * @param array $searchProperties + * @param string $test + * @return array + */ + function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { + return []; + } + + /** + * @param string $uri + * @param string $principalPrefix + * @return string + */ + function findByUri($uri, $principalPrefix) { + return ''; + } + + /** + * @param IGroup $group + * @return array + */ + protected function groupToPrincipal($group) { + $groupId = $group->getGID(); + $principal = [ + 'uri' => "principals/groups/$groupId", + '{DAV:}displayname' => $groupId, + ]; + + return $principal; + } + + /** + * @param IUser $user + * @return array + */ + protected function userToPrincipal($user) { + $principal = [ + 'uri' => 'principals/users/' . $user->getUID(), + '{DAV:}displayname' => $user->getDisplayName(), + ]; + + return $principal; + } +} diff --git a/apps/dav/lib/DAV/Sharing/Backend.php b/apps/dav/lib/DAV/Sharing/Backend.php new file mode 100644 index 00000000000..225b773713d --- /dev/null +++ b/apps/dav/lib/DAV/Sharing/Backend.php @@ -0,0 +1,206 @@ +<?php +/** + * @author Lukas Reschke <lukas@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\DAV\Sharing; + +use OCA\DAV\Connector\Sabre\Principal; +use OCP\IDBConnection; + +class Backend { + + /** @var IDBConnection */ + private $db; + /** @var Principal */ + private $principalBackend; + /** @var string */ + private $resourceType; + + const ACCESS_OWNER = 1; + const ACCESS_READ_WRITE = 2; + const ACCESS_READ = 3; + + /** + * @param IDBConnection $db + * @param Principal $principalBackend + * @param string $resourceType + */ + public function __construct(IDBConnection $db, Principal $principalBackend, $resourceType) { + $this->db = $db; + $this->principalBackend = $principalBackend; + $this->resourceType = $resourceType; + } + + /** + * @param IShareable $shareable + * @param string[] $add + * @param string[] $remove + */ + public function updateShares($shareable, $add, $remove) { + foreach($add as $element) { + $this->shareWith($shareable, $element); + } + foreach($remove as $element) { + $this->unshare($shareable, $element); + } + } + + /** + * @param IShareable $shareable + * @param string $element + */ + private function shareWith($shareable, $element) { + $user = $element['href']; + $parts = explode(':', $user, 2); + if ($parts[0] !== 'principal') { + return; + } + + // don't share with owner + if ($shareable->getOwner() === $parts[1]) { + return; + } + + // remove the share if it already exists + $this->unshare($shareable, $element['href']); + $access = self::ACCESS_READ; + if (isset($element['readOnly'])) { + $access = $element['readOnly'] ? self::ACCESS_READ : self::ACCESS_READ_WRITE; + } + + $query = $this->db->getQueryBuilder(); + $query->insert('dav_shares') + ->values([ + 'principaluri' => $query->createNamedParameter($parts[1]), + 'type' => $query->createNamedParameter($this->resourceType), + 'access' => $query->createNamedParameter($access), + 'resourceid' => $query->createNamedParameter($shareable->getResourceId()) + ]); + $query->execute(); + } + + /** + * @param $resourceId + */ + public function deleteAllShares($resourceId) { + $query = $this->db->getQueryBuilder(); + $query->delete('dav_shares') + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType))) + ->execute(); + } + + /** + * @param IShareable $shareable + * @param string $element + */ + private function unshare($shareable, $element) { + $parts = explode(':', $element, 2); + if ($parts[0] !== 'principal') { + return; + } + + // don't share with owner + if ($shareable->getOwner() === $parts[1]) { + return; + } + + $query = $this->db->getQueryBuilder(); + $query->delete('dav_shares') + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($shareable->getResourceId()))) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType))) + ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($parts[1]))) + ; + $query->execute(); + } + + /** + * Returns the list of people whom this resource 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 + * + * @param int $resourceId + * @return array + */ + public function getShares($resourceId) { + $query = $this->db->getQueryBuilder(); + $result = $query->select(['principaluri', 'access']) + ->from('dav_shares') + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType))) + ->execute(); + + $shares = []; + while($row = $result->fetch()) { + $p = $this->principalBackend->getPrincipalByPath($row['principaluri']); + $shares[]= [ + 'href' => "principal:${row['principaluri']}", + 'commonName' => isset($p['{DAV:}displayname']) ? $p['{DAV:}displayname'] : '', + 'status' => 1, + 'readOnly' => ($row['access'] == self::ACCESS_READ), + '{http://owncloud.org/ns}principal' => $row['principaluri'], + '{http://owncloud.org/ns}group-share' => is_null($p) + ]; + } + + return $shares; + } + + /** + * For shared resources the sharee is set in the ACL of the resource + * + * @param int $resourceId + * @param array $acl + * @return array + */ + public function applyShareAcl($resourceId, $acl) { + + $shares = $this->getShares($resourceId); + foreach ($shares as $share) { + $acl[] = [ + 'privilege' => '{DAV:}read', + 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], + 'protected' => true, + ]; + if (!$share['readOnly']) { + $acl[] = [ + 'privilege' => '{DAV:}write', + 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], + 'protected' => true, + ]; + } else if ($this->resourceType === 'calendar') { + // Allow changing the properties of read only calendars, + // so users can change the visibility. + $acl[] = [ + 'privilege' => '{DAV:}write-properties', + 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], + 'protected' => true, + ]; + } + } + return $acl; + } +} diff --git a/apps/dav/lib/DAV/Sharing/IShareable.php b/apps/dav/lib/DAV/Sharing/IShareable.php new file mode 100644 index 00000000000..f6b6bfa8862 --- /dev/null +++ b/apps/dav/lib/DAV/Sharing/IShareable.php @@ -0,0 +1,74 @@ +<?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\DAV\Sharing; +use Sabre\DAV\INode; + +/** + * This interface represents a dav resource that can be shared with other users. + * + */ +interface IShareable extends INode { + + /** + * Updates the list of shares. + * + * The first array is a list of people that are to be added to the + * resource. + * + * 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); + + /** + * Returns the list of people whom this resource 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(); + + /** + * @return int + */ + public function getResourceId(); + + /** + * @return string + */ + public function getOwner(); + +}
\ No newline at end of file diff --git a/apps/dav/lib/DAV/Sharing/Plugin.php b/apps/dav/lib/DAV/Sharing/Plugin.php new file mode 100644 index 00000000000..3173d1397ba --- /dev/null +++ b/apps/dav/lib/DAV/Sharing/Plugin.php @@ -0,0 +1,200 @@ +<?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\DAV\Sharing; + +use OCA\DAV\Connector\Sabre\Auth; +use OCA\DAV\DAV\Sharing\Xml\Invite; +use OCP\IRequest; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\INode; +use Sabre\DAV\PropFind; +use Sabre\DAV\Server; +use Sabre\DAV\ServerPlugin; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; + +class Plugin extends ServerPlugin { + + const NS_OWNCLOUD = 'http://owncloud.org/ns'; + + /** @var Auth */ + private $auth; + + /** @var IRequest */ + private $request; + + /** + * Plugin constructor. + * + * @param Auth $authBackEnd + * @param IRequest $request + */ + public function __construct(Auth $authBackEnd, IRequest $request) { + $this->auth = $authBackEnd; + $this->request = $request; + } + + /** + * Reference to SabreDAV server object. + * + * @var \Sabre\DAV\Server + */ + protected $server; + + /** + * This method should return a list of server-features. + * + * This is for example 'versioning' and is added to the DAV: header + * in an OPTIONS response. + * + * @return string[] + */ + function getFeatures() { + return ['oc-resource-sharing']; + } + + /** + * Returns a plugin name. + * + * Using this name other plugins will be able to access other plugins + * using Sabre\DAV\Server::getPlugin + * + * @return string + */ + function getPluginName() { + return 'oc-resource-sharing'; + } + + /** + * This initializes the plugin. + * + * This function is called by Sabre\DAV\Server, after + * addPlugin is called. + * + * This method should set up the required event subscriptions. + * + * @param Server $server + * @return void + */ + function initialize(Server $server) { + $this->server = $server; + $this->server->xml->elementMap['{' . Plugin::NS_OWNCLOUD . '}share'] = 'OCA\\DAV\\DAV\\Sharing\\Xml\\ShareRequest'; + $this->server->xml->elementMap['{' . Plugin::NS_OWNCLOUD . '}invite'] = 'OCA\\DAV\\DAV\\Sharing\\Xml\\Invite'; + + $this->server->on('method:POST', [$this, 'httpPost']); + $this->server->on('propFind', [$this, 'propFind']); + } + + /** + * We intercept this to handle POST requests on a dav resource. + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return null|false + */ + function httpPost(RequestInterface $request, ResponseInterface $response) { + + $path = $request->getPath(); + + // Only handling xml + $contentType = $request->getHeader('Content-Type'); + if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false) + return; + + // Making sure the node exists + try { + $node = $this->server->tree->getNodeForPath($path); + } catch (NotFound $e) { + return; + } + + $requestBody = $request->getBodyAsString(); + + // If this request handler could not deal with this POST request, it + // will return 'null' and other plugins get a chance to handle the + // request. + // + // However, we already requested the full body. This is a problem, + // because a body can only be read once. This is why we preemptively + // re-populated the request body with the existing data. + $request->setBody($requestBody); + + $message = $this->server->xml->parse($requestBody, $request->getUrl(), $documentType); + + switch ($documentType) { + + // Dealing with the 'share' document, which modified invitees on a + // calendar. + case '{' . self::NS_OWNCLOUD . '}share' : + + // We can only deal with IShareableCalendar objects + if (!$node instanceof IShareable) { + return; + } + + $this->server->transactionType = 'post-oc-resource-share'; + + // Getting ACL info + $acl = $this->server->getPlugin('acl'); + + // If there's no ACL support, we allow everything + if ($acl) { + /** @var \Sabre\DAVACL\Plugin $acl */ + $acl->checkPrivileges($path, '{DAV:}write'); + } + + $node->updateShares($message->set, $message->remove); + + $response->setStatus(200); + // Adding this because sending a response body may cause issues, + // and I wanted some type of indicator the response was handled. + $response->setHeader('X-Sabre-Status', 'everything-went-well'); + + // Breaking the event chain + return false; + } + } + + /** + * This event is triggered when properties are requested for a certain + * node. + * + * This allows us to inject any properties early. + * + * @param PropFind $propFind + * @param INode $node + * @return void + */ + function propFind(PropFind $propFind, INode $node) { + if ($node instanceof IShareable) { + + $propFind->handle('{' . Plugin::NS_OWNCLOUD . '}invite', function() use ($node) { + return new Invite( + $node->getShares() + ); + }); + + } + } + +} diff --git a/apps/dav/lib/DAV/Sharing/Xml/Invite.php b/apps/dav/lib/DAV/Sharing/Xml/Invite.php new file mode 100644 index 00000000000..ae40ff06701 --- /dev/null +++ b/apps/dav/lib/DAV/Sharing/Xml/Invite.php @@ -0,0 +1,168 @@ +<?php +/** + * @author Lukas Reschke <lukas@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\DAV\Sharing\Xml; + +use OCA\DAV\DAV\Sharing\Plugin; +use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; + +/** + * Invite property + * + * This property encodes the 'invite' property, as defined by + * the 'caldav-sharing-02' spec, in the http://calendarserver.org/ns/ + * namespace. + * + * @see https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing-02.txt + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Invite implements XmlSerializable { + + /** + * The list of users a calendar has been shared to. + * + * @var array + */ + protected $users; + + /** + * The organizer contains information about the person who shared the + * object. + * + * @var array + */ + protected $organizer; + + /** + * Creates the property. + * + * Users is an array. Each element of the array has the following + * properties: + * + * * href - Often a mailto: address + * * commonName - Optional, for example a first and lastname for a user. + * * status - One of the SharingPlugin::STATUS_* constants. + * * readOnly - true or false + * * summary - Optional, description of the share + * + * The organizer key is optional to specify. It's only useful when a + * 'sharee' requests the sharing information. + * + * The organizer may have the following properties: + * * href - Often a mailto: address. + * * commonName - Optional human-readable name. + * * firstName - Optional first name. + * * lastName - Optional last name. + * + * If you wonder why these two structures are so different, I guess a + * valid answer is that the current spec is still a draft. + * + * @param array $users + */ + function __construct(array $users, array $organizer = null) { + + $this->users = $users; + $this->organizer = $organizer; + + } + + /** + * Returns the list of users, as it was passed to the constructor. + * + * @return array + */ + function getValue() { + + return $this->users; + + } + + /** + * The xmlSerialize metod is called during xml writing. + * + * Use the $writer argument to write its own xml serialization. + * + * An important note: do _not_ create a parent element. Any element + * implementing XmlSerializble should only ever write what's considered + * its 'inner xml'. + * + * The parent of the current element is responsible for writing a + * containing element. + * + * This allows serializers to be re-used for different element names. + * + * If you are opening new elements, you must also close them again. + * + * @param Writer $writer + * @return void + */ + function xmlSerialize(Writer $writer) { + + $cs = '{' . Plugin::NS_OWNCLOUD . '}'; + + if (!is_null($this->organizer)) { + + $writer->startElement($cs . 'organizer'); + $writer->writeElement('{DAV:}href', $this->organizer['href']); + + if (isset($this->organizer['commonName']) && $this->organizer['commonName']) { + $writer->writeElement($cs . 'common-name', $this->organizer['commonName']); + } + if (isset($this->organizer['firstName']) && $this->organizer['firstName']) { + $writer->writeElement($cs . 'first-name', $this->organizer['firstName']); + } + if (isset($this->organizer['lastName']) && $this->organizer['lastName']) { + $writer->writeElement($cs . 'last-name', $this->organizer['lastName']); + } + $writer->endElement(); // organizer + + } + + foreach ($this->users as $user) { + + $writer->startElement($cs . 'user'); + $writer->writeElement('{DAV:}href', $user['href']); + if (isset($user['commonName']) && $user['commonName']) { + $writer->writeElement($cs . 'common-name', $user['commonName']); + } + $writer->writeElement($cs . 'invite-accepted'); + + $writer->startElement($cs . 'access'); + if ($user['readOnly']) { + $writer->writeElement($cs . 'read'); + } else { + $writer->writeElement($cs . 'read-write'); + } + $writer->endElement(); // access + + if (isset($user['summary']) && $user['summary']) { + $writer->writeElement($cs . 'summary', $user['summary']); + } + + $writer->endElement(); //user + + } + + } +} diff --git a/apps/dav/lib/DAV/Sharing/Xml/ShareRequest.php b/apps/dav/lib/DAV/Sharing/Xml/ShareRequest.php new file mode 100644 index 00000000000..776fb446b6c --- /dev/null +++ b/apps/dav/lib/DAV/Sharing/Xml/ShareRequest.php @@ -0,0 +1,84 @@ +<?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\DAV\Sharing\Xml; + +use OCA\DAV\DAV\Sharing\Plugin; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; + +class ShareRequest implements XmlDeserializable { + + public $set = []; + + public $remove = []; + + /** + * Constructor + * + * @param array $set + * @param array $remove + */ + function __construct(array $set, array $remove) { + + $this->set = $set; + $this->remove = $remove; + + } + + static function xmlDeserialize(Reader $reader) { + + $elements = $reader->parseInnerTree([ + '{' . Plugin::NS_OWNCLOUD. '}set' => 'Sabre\\Xml\\Element\\KeyValue', + '{' . Plugin::NS_OWNCLOUD . '}remove' => 'Sabre\\Xml\\Element\\KeyValue', + ]); + + $set = []; + $remove = []; + + foreach ($elements as $elem) { + switch ($elem['name']) { + + case '{' . Plugin::NS_OWNCLOUD . '}set' : + $sharee = $elem['value']; + + $sumElem = '{' . Plugin::NS_OWNCLOUD . '}summary'; + $commonName = '{' . Plugin::NS_OWNCLOUD . '}common-name'; + + $set[] = [ + 'href' => $sharee['{DAV:}href'], + 'commonName' => isset($sharee[$commonName]) ? $sharee[$commonName] : null, + 'summary' => isset($sharee[$sumElem]) ? $sharee[$sumElem] : null, + 'readOnly' => !array_key_exists('{' . Plugin::NS_OWNCLOUD . '}read-write', $sharee), + ]; + break; + + case '{' . Plugin::NS_OWNCLOUD . '}remove' : + $remove[] = $elem['value']['{DAV:}href']; + break; + + } + } + + return new self($set, $remove); + + } + +} diff --git a/apps/dav/lib/DAV/SystemPrincipalBackend.php b/apps/dav/lib/DAV/SystemPrincipalBackend.php new file mode 100644 index 00000000000..8001ec4e6c6 --- /dev/null +++ b/apps/dav/lib/DAV/SystemPrincipalBackend.php @@ -0,0 +1,179 @@ +<?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\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) { + + if ($path === 'principals/system/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'); + } +} |