DefaultShareProvider.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. <?php
  2. /**
  3. * @author Joas Schilling <nickvergessen@owncloud.com>
  4. * @author Roeland Jago Douma <rullzer@owncloud.com>
  5. *
  6. * @copyright Copyright (c) 2016, ownCloud, Inc.
  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 OC\Share20;
  23. use OCP\Files\File;
  24. use OCP\Share\IShareProvider;
  25. use OC\Share20\Exception\InvalidShare;
  26. use OC\Share20\Exception\ProviderException;
  27. use OCP\Share\Exceptions\ShareNotFound;
  28. use OC\Share20\Exception\BackendError;
  29. use OCP\DB\QueryBuilder\IQueryBuilder;
  30. use OCP\IGroup;
  31. use OCP\IGroupManager;
  32. use OCP\IUserManager;
  33. use OCP\Files\IRootFolder;
  34. use OCP\IDBConnection;
  35. use OCP\Files\Node;
  36. /**
  37. * Class DefaultShareProvider
  38. *
  39. * @package OC\Share20
  40. */
  41. class DefaultShareProvider implements IShareProvider {
  42. // Special share type for user modified group shares
  43. const SHARE_TYPE_USERGROUP = 2;
  44. /** @var IDBConnection */
  45. private $dbConn;
  46. /** @var IUserManager */
  47. private $userManager;
  48. /** @var IGroupManager */
  49. private $groupManager;
  50. /** @var IRootFolder */
  51. private $rootFolder;
  52. /**
  53. * DefaultShareProvider constructor.
  54. *
  55. * @param IDBConnection $connection
  56. * @param IUserManager $userManager
  57. * @param IGroupManager $groupManager
  58. * @param IRootFolder $rootFolder
  59. */
  60. public function __construct(
  61. IDBConnection $connection,
  62. IUserManager $userManager,
  63. IGroupManager $groupManager,
  64. IRootFolder $rootFolder) {
  65. $this->dbConn = $connection;
  66. $this->userManager = $userManager;
  67. $this->groupManager = $groupManager;
  68. $this->rootFolder = $rootFolder;
  69. }
  70. /**
  71. * Return the identifier of this provider.
  72. *
  73. * @return string Containing only [a-zA-Z0-9]
  74. */
  75. public function identifier() {
  76. return 'ocinternal';
  77. }
  78. /**
  79. * Share a path
  80. *
  81. * @param \OCP\Share\IShare $share
  82. * @return \OCP\Share\IShare The share object
  83. * @throws ShareNotFound
  84. * @throws \Exception
  85. */
  86. public function create(\OCP\Share\IShare $share) {
  87. $qb = $this->dbConn->getQueryBuilder();
  88. $qb->insert('share');
  89. $qb->setValue('share_type', $qb->createNamedParameter($share->getShareType()));
  90. if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
  91. //Set the UID of the user we share with
  92. $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
  93. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  94. //Set the GID of the group we share with
  95. $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
  96. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
  97. //Set the token of the share
  98. $qb->setValue('token', $qb->createNamedParameter($share->getToken()));
  99. //If a password is set store it
  100. if ($share->getPassword() !== null) {
  101. $qb->setValue('share_with', $qb->createNamedParameter($share->getPassword()));
  102. }
  103. //If an expiration date is set store it
  104. if ($share->getExpirationDate() !== null) {
  105. $qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
  106. }
  107. if (method_exists($share, 'getParent')) {
  108. $qb->setValue('parent', $qb->createNamedParameter($share->getParent()));
  109. }
  110. } else {
  111. throw new \Exception('invalid share type!');
  112. }
  113. // Set what is shares
  114. $qb->setValue('item_type', $qb->createParameter('itemType'));
  115. if ($share->getNode() instanceof \OCP\Files\File) {
  116. $qb->setParameter('itemType', 'file');
  117. } else {
  118. $qb->setParameter('itemType', 'folder');
  119. }
  120. // Set the file id
  121. $qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId()));
  122. $qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId()));
  123. // set the permissions
  124. $qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions()));
  125. // Set who created this share
  126. $qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
  127. // Set who is the owner of this file/folder (and this the owner of the share)
  128. $qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()));
  129. // Set the file target
  130. $qb->setValue('file_target', $qb->createNamedParameter($share->getTarget()));
  131. // Set the time this share was created
  132. $qb->setValue('stime', $qb->createNamedParameter(time()));
  133. // insert the data and fetch the id of the share
  134. $this->dbConn->beginTransaction();
  135. $qb->execute();
  136. $id = $this->dbConn->lastInsertId('*PREFIX*share');
  137. $this->dbConn->commit();
  138. // Now fetch the inserted share and create a complete share object
  139. $qb = $this->dbConn->getQueryBuilder();
  140. $qb->select('*')
  141. ->from('share')
  142. ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
  143. $cursor = $qb->execute();
  144. $data = $cursor->fetch();
  145. $cursor->closeCursor();
  146. if ($data === false) {
  147. throw new ShareNotFound();
  148. }
  149. $share = $this->createShare($data);
  150. return $share;
  151. }
  152. /**
  153. * Update a share
  154. *
  155. * @param \OCP\Share\IShare $share
  156. * @return \OCP\Share\IShare The share object
  157. */
  158. public function update(\OCP\Share\IShare $share) {
  159. if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
  160. /*
  161. * We allow updating the recipient on user shares.
  162. */
  163. $qb = $this->dbConn->getQueryBuilder();
  164. $qb->update('share')
  165. ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
  166. ->set('share_with', $qb->createNamedParameter($share->getSharedWith()))
  167. ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
  168. ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
  169. ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
  170. ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
  171. ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
  172. ->execute();
  173. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  174. $qb = $this->dbConn->getQueryBuilder();
  175. $qb->update('share')
  176. ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
  177. ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
  178. ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
  179. ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
  180. ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
  181. ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
  182. ->execute();
  183. /*
  184. * Update all user defined group shares
  185. */
  186. $qb = $this->dbConn->getQueryBuilder();
  187. $qb->update('share')
  188. ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
  189. ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
  190. ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
  191. ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
  192. ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
  193. ->execute();
  194. /*
  195. * Now update the permissions for all children that have not set it to 0
  196. */
  197. $qb = $this->dbConn->getQueryBuilder();
  198. $qb->update('share')
  199. ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
  200. ->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0)))
  201. ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
  202. ->execute();
  203. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
  204. $qb = $this->dbConn->getQueryBuilder();
  205. $qb->update('share')
  206. ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
  207. ->set('share_with', $qb->createNamedParameter($share->getPassword()))
  208. ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
  209. ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
  210. ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
  211. ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
  212. ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
  213. ->set('token', $qb->createNamedParameter($share->getToken()))
  214. ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
  215. ->execute();
  216. }
  217. return $share;
  218. }
  219. /**
  220. * Get all children of this share
  221. * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
  222. *
  223. * @param \OCP\Share\IShare $parent
  224. * @return \OCP\Share\IShare[]
  225. */
  226. public function getChildren(\OCP\Share\IShare $parent) {
  227. $children = [];
  228. $qb = $this->dbConn->getQueryBuilder();
  229. $qb->select('*')
  230. ->from('share')
  231. ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
  232. ->andWhere(
  233. $qb->expr()->in(
  234. 'share_type',
  235. $qb->createNamedParameter([
  236. \OCP\Share::SHARE_TYPE_USER,
  237. \OCP\Share::SHARE_TYPE_GROUP,
  238. \OCP\Share::SHARE_TYPE_LINK,
  239. ], IQueryBuilder::PARAM_INT_ARRAY)
  240. )
  241. )
  242. ->andWhere($qb->expr()->orX(
  243. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  244. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  245. ))
  246. ->orderBy('id');
  247. $cursor = $qb->execute();
  248. while($data = $cursor->fetch()) {
  249. $children[] = $this->createShare($data);
  250. }
  251. $cursor->closeCursor();
  252. return $children;
  253. }
  254. /**
  255. * Delete a share
  256. *
  257. * @param \OCP\Share\IShare $share
  258. */
  259. public function delete(\OCP\Share\IShare $share) {
  260. $qb = $this->dbConn->getQueryBuilder();
  261. $qb->delete('share')
  262. ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
  263. /*
  264. * If the share is a group share delete all possible
  265. * user defined groups shares.
  266. */
  267. if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  268. $qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
  269. }
  270. $qb->execute();
  271. }
  272. /**
  273. * Unshare a share from the recipient. If this is a group share
  274. * this means we need a special entry in the share db.
  275. *
  276. * @param \OCP\Share\IShare $share
  277. * @param string $recipient UserId of recipient
  278. * @throws BackendError
  279. * @throws ProviderException
  280. */
  281. public function deleteFromSelf(\OCP\Share\IShare $share, $recipient) {
  282. if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  283. $group = $this->groupManager->get($share->getSharedWith());
  284. $user = $this->userManager->get($recipient);
  285. if (!$group->inGroup($user)) {
  286. throw new ProviderException('Recipient not in receiving group');
  287. }
  288. // Try to fetch user specific share
  289. $qb = $this->dbConn->getQueryBuilder();
  290. $stmt = $qb->select('*')
  291. ->from('share')
  292. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
  293. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
  294. ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
  295. ->andWhere($qb->expr()->orX(
  296. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  297. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  298. ))
  299. ->execute();
  300. $data = $stmt->fetch();
  301. /*
  302. * Check if there already is a user specific group share.
  303. * If there is update it (if required).
  304. */
  305. if ($data === false) {
  306. $qb = $this->dbConn->getQueryBuilder();
  307. $type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder';
  308. //Insert new share
  309. $qb->insert('share')
  310. ->values([
  311. 'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
  312. 'share_with' => $qb->createNamedParameter($recipient),
  313. 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
  314. 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
  315. 'parent' => $qb->createNamedParameter($share->getId()),
  316. 'item_type' => $qb->createNamedParameter($type),
  317. 'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
  318. 'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
  319. 'file_target' => $qb->createNamedParameter($share->getTarget()),
  320. 'permissions' => $qb->createNamedParameter(0),
  321. 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
  322. ])->execute();
  323. } else if ($data['permissions'] !== 0) {
  324. // Update existing usergroup share
  325. $qb = $this->dbConn->getQueryBuilder();
  326. $qb->update('share')
  327. ->set('permissions', $qb->createNamedParameter(0))
  328. ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
  329. ->execute();
  330. }
  331. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
  332. if ($share->getSharedWith() !== $recipient) {
  333. throw new ProviderException('Recipient does not match');
  334. }
  335. // We can just delete user and link shares
  336. $this->delete($share);
  337. } else {
  338. throw new ProviderException('Invalid shareType');
  339. }
  340. }
  341. /**
  342. * @inheritdoc
  343. */
  344. public function move(\OCP\Share\IShare $share, $recipient) {
  345. if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
  346. // Just update the target
  347. $qb = $this->dbConn->getQueryBuilder();
  348. $qb->update('share')
  349. ->set('file_target', $qb->createNamedParameter($share->getTarget()))
  350. ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
  351. ->execute();
  352. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  353. // Check if there is a usergroup share
  354. $qb = $this->dbConn->getQueryBuilder();
  355. $stmt = $qb->select('id')
  356. ->from('share')
  357. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
  358. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
  359. ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
  360. ->andWhere($qb->expr()->orX(
  361. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  362. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  363. ))
  364. ->setMaxResults(1)
  365. ->execute();
  366. $data = $stmt->fetch();
  367. $stmt->closeCursor();
  368. if ($data === false) {
  369. // No usergroup share yet. Create one.
  370. $qb = $this->dbConn->getQueryBuilder();
  371. $qb->insert('share')
  372. ->values([
  373. 'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
  374. 'share_with' => $qb->createNamedParameter($recipient),
  375. 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
  376. 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
  377. 'parent' => $qb->createNamedParameter($share->getId()),
  378. 'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'),
  379. 'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
  380. 'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
  381. 'file_target' => $qb->createNamedParameter($share->getTarget()),
  382. 'permissions' => $qb->createNamedParameter($share->getPermissions()),
  383. 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
  384. ])->execute();
  385. } else {
  386. // Already a usergroup share. Update it.
  387. $qb = $this->dbConn->getQueryBuilder();
  388. $qb->update('share')
  389. ->set('file_target', $qb->createNamedParameter($share->getTarget()))
  390. ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
  391. ->execute();
  392. }
  393. }
  394. return $share;
  395. }
  396. /**
  397. * @inheritdoc
  398. */
  399. public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
  400. $qb = $this->dbConn->getQueryBuilder();
  401. $qb->select('*')
  402. ->from('share')
  403. ->andWhere($qb->expr()->orX(
  404. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  405. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  406. ));
  407. $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
  408. /**
  409. * Reshares for this user are shares where they are the owner.
  410. */
  411. if ($reshares === false) {
  412. $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
  413. } else {
  414. $qb->andWhere(
  415. $qb->expr()->orX(
  416. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
  417. $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
  418. )
  419. );
  420. }
  421. if ($node !== null) {
  422. $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
  423. }
  424. if ($limit !== -1) {
  425. $qb->setMaxResults($limit);
  426. }
  427. $qb->setFirstResult($offset);
  428. $qb->orderBy('id');
  429. $cursor = $qb->execute();
  430. $shares = [];
  431. while($data = $cursor->fetch()) {
  432. $shares[] = $this->createShare($data);
  433. }
  434. $cursor->closeCursor();
  435. return $shares;
  436. }
  437. /**
  438. * @inheritdoc
  439. */
  440. public function getShareById($id, $recipientId = null) {
  441. $qb = $this->dbConn->getQueryBuilder();
  442. $qb->select('*')
  443. ->from('share')
  444. ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
  445. ->andWhere(
  446. $qb->expr()->in(
  447. 'share_type',
  448. $qb->createNamedParameter([
  449. \OCP\Share::SHARE_TYPE_USER,
  450. \OCP\Share::SHARE_TYPE_GROUP,
  451. \OCP\Share::SHARE_TYPE_LINK,
  452. ], IQueryBuilder::PARAM_INT_ARRAY)
  453. )
  454. )
  455. ->andWhere($qb->expr()->orX(
  456. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  457. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  458. ));
  459. $cursor = $qb->execute();
  460. $data = $cursor->fetch();
  461. $cursor->closeCursor();
  462. if ($data === false) {
  463. throw new ShareNotFound();
  464. }
  465. try {
  466. $share = $this->createShare($data);
  467. } catch (InvalidShare $e) {
  468. throw new ShareNotFound();
  469. }
  470. // If the recipient is set for a group share resolve to that user
  471. if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  472. $share = $this->resolveGroupShare($share, $recipientId);
  473. }
  474. return $share;
  475. }
  476. /**
  477. * Get shares for a given path
  478. *
  479. * @param \OCP\Files\Node $path
  480. * @return \OCP\Share\IShare[]
  481. */
  482. public function getSharesByPath(Node $path) {
  483. $qb = $this->dbConn->getQueryBuilder();
  484. $cursor = $qb->select('*')
  485. ->from('share')
  486. ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
  487. ->andWhere(
  488. $qb->expr()->orX(
  489. $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
  490. $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
  491. )
  492. )
  493. ->andWhere($qb->expr()->orX(
  494. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  495. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  496. ))
  497. ->execute();
  498. $shares = [];
  499. while($data = $cursor->fetch()) {
  500. $shares[] = $this->createShare($data);
  501. }
  502. $cursor->closeCursor();
  503. return $shares;
  504. }
  505. /**
  506. * @inheritdoc
  507. */
  508. public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
  509. /** @var Share[] $shares */
  510. $shares = [];
  511. if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
  512. //Get shares directly with this user
  513. $qb = $this->dbConn->getQueryBuilder();
  514. $qb->select('*')
  515. ->from('share');
  516. // Order by id
  517. $qb->orderBy('id');
  518. // Set limit and offset
  519. if ($limit !== -1) {
  520. $qb->setMaxResults($limit);
  521. }
  522. $qb->setFirstResult($offset);
  523. $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)))
  524. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
  525. ->andWhere($qb->expr()->orX(
  526. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  527. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  528. ));
  529. // Filter by node if provided
  530. if ($node !== null) {
  531. $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
  532. }
  533. $cursor = $qb->execute();
  534. while($data = $cursor->fetch()) {
  535. $shares[] = $this->createShare($data);
  536. }
  537. $cursor->closeCursor();
  538. } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
  539. $user = $this->userManager->get($userId);
  540. $allGroups = $this->groupManager->getUserGroups($user);
  541. /** @var Share[] $shares2 */
  542. $shares2 = [];
  543. $start = 0;
  544. while(true) {
  545. $groups = array_slice($allGroups, $start, 100);
  546. $start += 100;
  547. if ($groups === []) {
  548. break;
  549. }
  550. $qb = $this->dbConn->getQueryBuilder();
  551. $qb->select('*')
  552. ->from('share')
  553. ->orderBy('id')
  554. ->setFirstResult(0);
  555. if ($limit !== -1) {
  556. $qb->setMaxResults($limit - count($shares));
  557. }
  558. // Filter by node if provided
  559. if ($node !== null) {
  560. $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
  561. }
  562. $groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
  563. $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
  564. ->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
  565. $groups,
  566. IQueryBuilder::PARAM_STR_ARRAY
  567. )))
  568. ->andWhere($qb->expr()->orX(
  569. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  570. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  571. ));
  572. $cursor = $qb->execute();
  573. while($data = $cursor->fetch()) {
  574. if ($offset > 0) {
  575. $offset--;
  576. continue;
  577. }
  578. $shares2[] = $this->createShare($data);
  579. }
  580. $cursor->closeCursor();
  581. }
  582. /*
  583. * Resolve all group shares to user specific shares
  584. * TODO: Optmize this!
  585. */
  586. foreach($shares2 as $share) {
  587. $shares[] = $this->resolveGroupShare($share, $userId);
  588. }
  589. } else {
  590. throw new BackendError('Invalid backend');
  591. }
  592. return $shares;
  593. }
  594. /**
  595. * Get a share by token
  596. *
  597. * @param string $token
  598. * @return \OCP\Share\IShare
  599. * @throws ShareNotFound
  600. */
  601. public function getShareByToken($token) {
  602. $qb = $this->dbConn->getQueryBuilder();
  603. $cursor = $qb->select('*')
  604. ->from('share')
  605. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)))
  606. ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
  607. ->andWhere($qb->expr()->orX(
  608. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  609. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  610. ))
  611. ->execute();
  612. $data = $cursor->fetch();
  613. if ($data === false) {
  614. throw new ShareNotFound();
  615. }
  616. try {
  617. $share = $this->createShare($data);
  618. } catch (InvalidShare $e) {
  619. throw new ShareNotFound();
  620. }
  621. return $share;
  622. }
  623. /**
  624. * Create a share object from an database row
  625. *
  626. * @param mixed[] $data
  627. * @return \OCP\Share\IShare
  628. * @throws InvalidShare
  629. */
  630. private function createShare($data) {
  631. $share = new Share($this->rootFolder);
  632. $share->setId((int)$data['id'])
  633. ->setShareType((int)$data['share_type'])
  634. ->setPermissions((int)$data['permissions'])
  635. ->setTarget($data['file_target'])
  636. ->setMailSend((bool)$data['mail_send']);
  637. $shareTime = new \DateTime();
  638. $shareTime->setTimestamp((int)$data['stime']);
  639. $share->setShareTime($shareTime);
  640. if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
  641. $share->setSharedWith($data['share_with']);
  642. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
  643. $share->setSharedWith($data['share_with']);
  644. } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
  645. $share->setPassword($data['share_with']);
  646. $share->setToken($data['token']);
  647. }
  648. $share->setSharedBy($data['uid_initiator']);
  649. $share->setShareOwner($data['uid_owner']);
  650. $share->setNodeId((int)$data['file_source']);
  651. $share->setNodeType($data['item_type']);
  652. if ($data['expiration'] !== null) {
  653. $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
  654. $share->setExpirationDate($expiration);
  655. }
  656. $share->setProviderId($this->identifier());
  657. return $share;
  658. }
  659. /**
  660. * Resolve a group share to a user specific share
  661. * Thus if the user moved their group share make sure this is properly reflected here.
  662. *
  663. * @param \OCP\Share\IShare $share
  664. * @param string $userId
  665. * @return Share Returns the updated share if one was found else return the original share.
  666. */
  667. private function resolveGroupShare(\OCP\Share\IShare $share, $userId) {
  668. $qb = $this->dbConn->getQueryBuilder();
  669. $stmt = $qb->select('*')
  670. ->from('share')
  671. ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
  672. ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
  673. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
  674. ->andWhere($qb->expr()->orX(
  675. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  676. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  677. ))
  678. ->setMaxResults(1)
  679. ->execute();
  680. $data = $stmt->fetch();
  681. $stmt->closeCursor();
  682. if ($data !== false) {
  683. $share->setPermissions((int)$data['permissions']);
  684. $share->setTarget($data['file_target']);
  685. }
  686. return $share;
  687. }
  688. /**
  689. * A user is deleted from the system
  690. * So clean up the relevant shares.
  691. *
  692. * @param string $uid
  693. * @param int $shareType
  694. */
  695. public function userDeleted($uid, $shareType) {
  696. $qb = $this->dbConn->getQueryBuilder();
  697. $qb->delete('share');
  698. if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
  699. /*
  700. * Delete all user shares that are owned by this user
  701. * or that are received by this user
  702. */
  703. $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
  704. $qb->andWhere(
  705. $qb->expr()->orX(
  706. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
  707. $qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
  708. )
  709. );
  710. } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
  711. /*
  712. * Delete all group shares that are owned by this user
  713. * Or special user group shares that are received by this user
  714. */
  715. $qb->where(
  716. $qb->expr()->andX(
  717. $qb->expr()->orX(
  718. $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
  719. $qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
  720. ),
  721. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))
  722. )
  723. );
  724. $qb->orWhere(
  725. $qb->expr()->andX(
  726. $qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)),
  727. $qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
  728. )
  729. );
  730. } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
  731. /*
  732. * Delete all link shares owned by this user.
  733. * And all link shares initiated by this user (until #22327 is in)
  734. */
  735. $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)));
  736. $qb->andWhere(
  737. $qb->expr()->orX(
  738. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
  739. $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($uid))
  740. )
  741. );
  742. }
  743. $qb->execute();
  744. }
  745. /**
  746. * Delete all shares received by this group. As well as any custom group
  747. * shares for group members.
  748. *
  749. * @param string $gid
  750. */
  751. public function groupDeleted($gid) {
  752. /*
  753. * First delete all custom group shares for group members
  754. */
  755. $qb = $this->dbConn->getQueryBuilder();
  756. $qb->select('id')
  757. ->from('share')
  758. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
  759. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
  760. $cursor = $qb->execute();
  761. $ids = [];
  762. while($row = $cursor->fetch()) {
  763. $ids[] = (int)$row['id'];
  764. }
  765. $cursor->closeCursor();
  766. if (!empty($ids)) {
  767. $chunks = array_chunk($ids, 100);
  768. foreach ($chunks as $chunk) {
  769. $qb->delete('share')
  770. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
  771. ->andWhere($qb->expr()->in('parent', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY)));
  772. $qb->execute();
  773. }
  774. }
  775. /*
  776. * Now delete all the group shares
  777. */
  778. $qb = $this->dbConn->getQueryBuilder();
  779. $qb->delete('share')
  780. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
  781. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
  782. $qb->execute();
  783. }
  784. /**
  785. * Delete custom group shares to this group for this user
  786. *
  787. * @param string $uid
  788. * @param string $gid
  789. */
  790. public function userDeletedFromGroup($uid, $gid) {
  791. /*
  792. * Get all group shares
  793. */
  794. $qb = $this->dbConn->getQueryBuilder();
  795. $qb->select('id')
  796. ->from('share')
  797. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
  798. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
  799. $cursor = $qb->execute();
  800. $ids = [];
  801. while($row = $cursor->fetch()) {
  802. $ids[] = (int)$row['id'];
  803. }
  804. $cursor->closeCursor();
  805. if (!empty($ids)) {
  806. $chunks = array_chunk($ids, 100);
  807. foreach ($chunks as $chunk) {
  808. /*
  809. * Delete all special shares wit this users for the found group shares
  810. */
  811. $qb->delete('share')
  812. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
  813. ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($uid)))
  814. ->andWhere($qb->expr()->in('parent', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY)));
  815. $qb->execute();
  816. }
  817. }
  818. }
  819. }