You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
5.6 KiB

9 years ago
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Maxence Lange <maxence@nextcloud.com>
  7. * @author Robin Appelman <robin@icewind.nl>
  8. * @author Roeland Jago Douma <roeland@famdouma.nl>
  9. * @author Vincent Petry <pvince81@owncloud.com>
  10. *
  11. * @license AGPL-3.0
  12. *
  13. * This code is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU Affero General Public License, version 3,
  15. * as published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License, version 3,
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>
  24. *
  25. */
  26. namespace OCA\DAV\Connector\Sabre;
  27. use \Sabre\DAV\PropFind;
  28. use OCP\IUserSession;
  29. use OCP\Share\IShare;
  30. /**
  31. * Sabre Plugin to provide share-related properties
  32. */
  33. class SharesPlugin extends \Sabre\DAV\ServerPlugin {
  34. const NS_OWNCLOUD = 'http://owncloud.org/ns';
  35. const SHARETYPES_PROPERTYNAME = '{http://owncloud.org/ns}share-types';
  36. /**
  37. * Reference to main server object
  38. *
  39. * @var \Sabre\DAV\Server
  40. */
  41. private $server;
  42. /**
  43. * @var \OCP\Share\IManager
  44. */
  45. private $shareManager;
  46. /**
  47. * @var \Sabre\DAV\Tree
  48. */
  49. private $tree;
  50. /**
  51. * @var string
  52. */
  53. private $userId;
  54. /**
  55. * @var \OCP\Files\Folder
  56. */
  57. private $userFolder;
  58. /**
  59. * @var IShare[]
  60. */
  61. private $cachedShareTypes;
  62. private $cachedFolders = [];
  63. /**
  64. * @param \Sabre\DAV\Tree $tree tree
  65. * @param IUserSession $userSession user session
  66. * @param \OCP\Files\Folder $userFolder user home folder
  67. * @param \OCP\Share\IManager $shareManager share manager
  68. */
  69. public function __construct(
  70. \Sabre\DAV\Tree $tree,
  71. IUserSession $userSession,
  72. \OCP\Files\Folder $userFolder,
  73. \OCP\Share\IManager $shareManager
  74. ) {
  75. $this->tree = $tree;
  76. $this->shareManager = $shareManager;
  77. $this->userFolder = $userFolder;
  78. $this->userId = $userSession->getUser()->getUID();
  79. $this->cachedShareTypes = [];
  80. }
  81. /**
  82. * This initializes the plugin.
  83. *
  84. * This function is called by \Sabre\DAV\Server, after
  85. * addPlugin is called.
  86. *
  87. * This method should set up the required event subscriptions.
  88. *
  89. * @param \Sabre\DAV\Server $server
  90. */
  91. public function initialize(\Sabre\DAV\Server $server) {
  92. $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc';
  93. $server->xml->elementMap[self::SHARETYPES_PROPERTYNAME] = ShareTypeList::class;
  94. $server->protectedProperties[] = self::SHARETYPES_PROPERTYNAME;
  95. $this->server = $server;
  96. $this->server->on('propFind', array($this, 'handleGetProperties'));
  97. }
  98. /**
  99. * Return a list of share types for outgoing shares
  100. *
  101. * @param \OCP\Files\Node $node file node
  102. *
  103. * @return int[] array of share types
  104. */
  105. private function getShareTypes(\OCP\Files\Node $node) {
  106. $shareTypes = [];
  107. $requestedShareTypes = [
  108. \OCP\Share::SHARE_TYPE_USER,
  109. \OCP\Share::SHARE_TYPE_GROUP,
  110. \OCP\Share::SHARE_TYPE_LINK,
  111. \OCP\Share::SHARE_TYPE_REMOTE,
  112. \OCP\Share::SHARE_TYPE_EMAIL,
  113. ];
  114. foreach ($requestedShareTypes as $requestedShareType) {
  115. // one of each type is enough to find out about the types
  116. $shares = $this->shareManager->getSharesBy(
  117. $this->userId,
  118. $requestedShareType,
  119. $node,
  120. false,
  121. 1
  122. );
  123. if (!empty($shares)) {
  124. $shareTypes[] = $requestedShareType;
  125. }
  126. }
  127. return $shareTypes;
  128. }
  129. private function getSharesTypesInFolder(\OCP\Files\Folder $node) {
  130. $shares = $this->shareManager->getSharesInFolder(
  131. $this->userId,
  132. $node,
  133. true
  134. );
  135. $shareTypesByFileId = [];
  136. foreach($shares as $fileId => $sharesForFile) {
  137. $types = array_map(function(IShare $share) {
  138. return $share->getShareType();
  139. }, $sharesForFile);
  140. $types = array_unique($types);
  141. sort($types);
  142. $shareTypesByFileId[$fileId] = $types;
  143. }
  144. return $shareTypesByFileId;
  145. }
  146. /**
  147. * Adds shares to propfind response
  148. *
  149. * @param PropFind $propFind propfind object
  150. * @param \Sabre\DAV\INode $sabreNode sabre node
  151. */
  152. public function handleGetProperties(
  153. PropFind $propFind,
  154. \Sabre\DAV\INode $sabreNode
  155. ) {
  156. if (!($sabreNode instanceof \OCA\DAV\Connector\Sabre\Node)) {
  157. return;
  158. }
  159. // need prefetch ?
  160. if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory
  161. && $propFind->getDepth() !== 0
  162. && !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME))
  163. ) {
  164. $folderNode = $this->userFolder->get($sabreNode->getPath());
  165. $childShares = $this->getSharesTypesInFolder($folderNode);
  166. $this->cachedFolders[] = $sabreNode->getPath();
  167. $this->cachedShareTypes[$folderNode->getId()] = $this->getShareTypes($folderNode);
  168. foreach ($childShares as $id => $shares) {
  169. $this->cachedShareTypes[$id] = $shares;
  170. }
  171. }
  172. $propFind->handle(self::SHARETYPES_PROPERTYNAME, function () use ($sabreNode) {
  173. if (isset($this->cachedShareTypes[$sabreNode->getId()])) {
  174. $shareTypes = $this->cachedShareTypes[$sabreNode->getId()];
  175. } else {
  176. list($parentPath,) = \Sabre\Uri\split($sabreNode->getPath());
  177. if ($parentPath === '') {
  178. $parentPath = '/';
  179. }
  180. // if we already cached the folder this file is in we know there are no shares for this file
  181. if (array_search($parentPath, $this->cachedFolders) === false) {
  182. $node = $this->userFolder->get($sabreNode->getPath());
  183. $shareTypes = $this->getShareTypes($node);
  184. } else {
  185. return [];
  186. }
  187. }
  188. return new ShareTypeList($shareTypes);
  189. });
  190. }
  191. }