SharesPlugin.php 5.5 KB

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