diff options
Diffstat (limited to 'lib/private/share20/defaultshareprovider.php')
-rw-r--r-- | lib/private/share20/defaultshareprovider.php | 768 |
1 files changed, 654 insertions, 114 deletions
diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php index 7f21d3aadf5..0ab0dc81fa7 100644 --- a/lib/private/share20/defaultshareprovider.php +++ b/lib/private/share20/defaultshareprovider.php @@ -2,7 +2,7 @@ /** * @author Roeland Jago Douma <rullzer@owncloud.com> * - * @copyright Copyright (c) 2015, ownCloud, Inc. + * @copyright Copyright (c) 2016, ownCloud, Inc. * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify @@ -20,68 +20,256 @@ */ namespace OC\Share20; -use OC\Share20\Exception\ShareNotFound; +use OCP\Files\File; +use OCP\Share\IShareProvider; +use OC\Share20\Exception\InvalidShare; +use OC\Share20\Exception\ProviderException; +use OCP\Share\Exceptions\ShareNotFound; use OC\Share20\Exception\BackendError; -use OCP\IUser; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\NotFoundException; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\Files\Node; +/** + * Class DefaultShareProvider + * + * @package OC\Share20 + */ class DefaultShareProvider implements IShareProvider { - /** @var \OCP\IDBConnection */ + // Special share type for user modified group shares + const SHARE_TYPE_USERGROUP = 2; + + /** @var IDBConnection */ private $dbConn; - /** @var \OCP\IUserManager */ + /** @var IUserManager */ private $userManager; - /** @var \OCP\IGroupManager */ + /** @var IGroupManager */ private $groupManager; - /** @var \OCP\Files\Folder */ - private $userFolder; + /** @var IRootFolder */ + private $rootFolder; - public function __construct(\OCP\IDBConnection $connection, - \OCP\IUserManager $userManager, - \OCP\IGroupManager $groupManager, - \OCP\Files\Folder $userFolder) { + /** + * DefaultShareProvider constructor. + * + * @param IDBConnection $connection + * @param IUserManager $userManager + * @param IGroupManager $groupManager + * @param IRootFolder $rootFolder + */ + public function __construct( + IDBConnection $connection, + IUserManager $userManager, + IGroupManager $groupManager, + IRootFolder $rootFolder) { $this->dbConn = $connection; $this->userManager = $userManager; $this->groupManager = $groupManager; - $this->userFolder = $userFolder; + $this->rootFolder = $rootFolder; + } + + /** + * Return the identifier of this provider. + * + * @return string Containing only [a-zA-Z0-9] + */ + public function identifier() { + return 'ocinternal'; } /** * Share a path - * - * @param Share $share - * @return Share The share object + * + * @param \OCP\Share\IShare $share + * @return \OCP\Share\IShare The share object + * @throws ShareNotFound + * @throws \Exception */ - public function create(Share $share) { - throw new \Exception(); + public function create(\OCP\Share\IShare $share) { + $qb = $this->dbConn->getQueryBuilder(); + + $qb->insert('share'); + $qb->setValue('share_type', $qb->createNamedParameter($share->getShareType())); + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + //Set the UID of the user we share with + $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith())); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + //Set the GID of the group we share with + $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith())); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { + //Set the token of the share + $qb->setValue('token', $qb->createNamedParameter($share->getToken())); + + //If a password is set store it + if ($share->getPassword() !== null) { + $qb->setValue('share_with', $qb->createNamedParameter($share->getPassword())); + } + + //If an expiration date is set store it + if ($share->getExpirationDate() !== null) { + $qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime')); + } + } else { + throw new \Exception('invalid share type!'); + } + + // Set what is shares + $qb->setValue('item_type', $qb->createParameter('itemType')); + if ($share->getNode() instanceof \OCP\Files\File) { + $qb->setParameter('itemType', 'file'); + } else { + $qb->setParameter('itemType', 'folder'); + } + + // Set the file id + $qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId())); + $qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId())); + + // set the permissions + $qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions())); + + // Set who created this share + $qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy())); + + // Set who is the owner of this file/folder (and this the owner of the share) + $qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner())); + + // Set the file target + $qb->setValue('file_target', $qb->createNamedParameter($share->getTarget())); + + // Set the time this share was created + $qb->setValue('stime', $qb->createNamedParameter(time())); + + // insert the data and fetch the id of the share + $this->dbConn->beginTransaction(); + $qb->execute(); + $id = $this->dbConn->lastInsertId('*PREFIX*share'); + $this->dbConn->commit(); + + // Now fetch the inserted share and create a complete share object + $qb = $this->dbConn->getQueryBuilder(); + $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); + + $cursor = $qb->execute(); + $data = $cursor->fetch(); + $cursor->closeCursor(); + + if ($data === false) { + throw new ShareNotFound(); + } + + $share = $this->createShare($data); + return $share; } /** * Update a share * - * @param Share $share - * @return Share The share object + * @param \OCP\Share\IShare $share + * @return \OCP\Share\IShare The share object */ - public function update(Share $share) { - throw new \Exception(); + public function update(\OCP\Share\IShare $share) { + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + /* + * We allow updating the recipient on user shares. + */ + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->set('share_with', $qb->createNamedParameter($share->getSharedWith())) + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) + ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) + ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) + ->execute(); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) + ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) + ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) + ->execute(); + + /* + * Update all user defined group shares + */ + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) + ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) + ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) + ->execute(); + + /* + * Now update the permissions for all children that have not set it to 0 + */ + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) + ->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0))) + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) + ->execute(); + + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->set('share_with', $qb->createNamedParameter($share->getPassword())) + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) + ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) + ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) + ->set('token', $qb->createNamedParameter($share->getToken())) + ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) + ->execute(); + } + + return $share; } /** - * Get all childre of this share + * Get all children of this share + * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in * - * @param IShare $share - * @return IShare[] + * @param \OCP\Share\IShare $parent + * @return \OCP\Share\IShare[] */ - private function getChildren(IShare $share) { + public function getChildren(\OCP\Share\IShare $parent) { $children = []; $qb = $this->dbConn->getQueryBuilder(); $qb->select('*') ->from('share') - ->where($qb->expr()->eq('parent', $qb->createParameter('parent'))) - ->setParameter(':parent', $share->getId()); + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) + ->andWhere( + $qb->expr()->in( + 'share_type', + $qb->createNamedParameter([ + \OCP\Share::SHARE_TYPE_USER, + \OCP\Share::SHARE_TYPE_GROUP, + \OCP\Share::SHARE_TYPE_LINK, + ], IQueryBuilder::PARAM_INT_ARRAY) + ) + ) + ->orderBy('id'); $cursor = $qb->execute(); while($data = $cursor->fetch()) { @@ -93,91 +281,244 @@ class DefaultShareProvider implements IShareProvider { } /** - * Delete all the children of this share + * Delete a share * - * @param IShare $share + * @param \OCP\Share\IShare $share */ - protected function deleteChildren(IShare $share) { - foreach($this->getChildren($share) as $child) { - $this->delete($child); + public function delete(\OCP\Share\IShare $share) { + $qb = $this->dbConn->getQueryBuilder(); + $qb->delete('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))); + + /* + * If the share is a group share delete all possible + * user defined groups shares. + */ + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + $qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))); } + + $qb->execute(); } /** - * Delete a share + * Unshare a share from the recipient. If this is a group share + * this means we need a special entry in the share db. * - * @param Share $share + * @param \OCP\Share\IShare $share + * @param string $recipient UserId of recipient * @throws BackendError + * @throws ProviderException */ - public function delete(IShare $share) { - $this->deleteChildren($share); - - // Fetch share to make sure it exists - $share = $this->getShareById($share->getId()); - - $shareType = $share->getShareType(); - $sharedWith = ''; - if ($shareType === \OCP\Share::SHARE_TYPE_USER) { - $sharedWith = $share->getSharedWith()->getUID(); - } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) { - $sharedWith = $share->getSharedWith()->getGID(); + public function deleteFromSelf(\OCP\Share\IShare $share, $recipient) { + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + + $group = $this->groupManager->get($share->getSharedWith()); + $user = $this->userManager->get($recipient); + + if (!$group->inGroup($user)) { + throw new ProviderException('Recipient not in receiving group'); + } + + // Try to fetch user specific share + $qb = $this->dbConn->getQueryBuilder(); + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))) + ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))) + ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) + ->execute(); + + $data = $stmt->fetch(); + + /* + * Check if there already is a user specific group share. + * If there is update it (if required). + */ + if ($data === false) { + $qb = $this->dbConn->getQueryBuilder(); + + $type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder'; + + //Insert new share + $qb->insert('share') + ->values([ + 'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP), + 'share_with' => $qb->createNamedParameter($recipient), + 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()), + 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()), + 'parent' => $qb->createNamedParameter($share->getId()), + 'item_type' => $qb->createNamedParameter($type), + 'item_source' => $qb->createNamedParameter($share->getNode()->getId()), + 'file_source' => $qb->createNamedParameter($share->getNode()->getId()), + 'file_target' => $qb->createNamedParameter($share->getTarget()), + 'permissions' => $qb->createNamedParameter(0), + 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()), + ])->execute(); + + } else if ($data['permissions'] !== 0) { + + // Update existing usergroup share + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->set('permissions', $qb->createNamedParameter(0)) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id']))) + ->execute(); + } + + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + + if ($share->getSharedWith() !== $recipient) { + throw new ProviderException('Recipient does not match'); + } + + // We can just delete user and link shares + $this->delete($share); + } else { + throw new ProviderException('Invalid shareType'); } + } - $hookParams = [ - 'id' => $share->getId(), - 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder', - 'itemSource' => $share->getPath()->getId(), - 'shareType' => $shareType, - 'shareWith' => $sharedWith, - 'itemparent' => $share->getParent(), - 'uidOwner' => $share->getSharedBy()->getUID(), - 'fileSource' => $share->getPath()->getId(), - 'fileTarget' => $share->getTarget() - ]; + /** + * @inheritdoc + */ + public function move(\OCP\Share\IShare $share, $recipient) { + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + // Just update the target + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->set('file_target', $qb->createNamedParameter($share->getTarget())) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->execute(); - \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { - $qb = $this->dbConn->getQueryBuilder(); - $qb->delete('share') - ->where($qb->expr()->eq('id', $qb->createParameter('id'))) - ->setParameter(':id', $share->getId()); - - try { - $qb->execute(); - } catch (\Exception $e) { - throw new BackendError(); + // Check if there is a usergroup share + $qb = $this->dbConn->getQueryBuilder(); + $stmt = $qb->select('id') + ->from('share') + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))) + ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))) + ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) + ->setMaxResults(1) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + if ($data === false) { + // No usergroup share yet. Create one. + $qb = $this->dbConn->getQueryBuilder(); + $qb->insert('share') + ->values([ + 'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP), + 'share_with' => $qb->createNamedParameter($recipient), + 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()), + 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()), + 'parent' => $qb->createNamedParameter($share->getId()), + 'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'), + 'item_source' => $qb->createNamedParameter($share->getNode()->getId()), + 'file_source' => $qb->createNamedParameter($share->getNode()->getId()), + 'file_target' => $qb->createNamedParameter($share->getTarget()), + 'permissions' => $qb->createNamedParameter($share->getPermissions()), + 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()), + ])->execute(); + } else { + // Already a usergroup share. Update it. + $qb = $this->dbConn->getQueryBuilder(); + $qb->update('share') + ->set('file_target', $qb->createNamedParameter($share->getTarget())) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id']))) + ->execute(); + } } - \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams); + return $share; } /** - * Get all shares by the given user + * Get all shares by the given user. Sharetype and path can be used to filter. * - * @param IUser $user + * @param string $userId * @param int $shareType + * @param \OCP\Files\File|\OCP\Files\Folder $node + * @param bool $reshares Also get the shares where $user is the owner instead of just the shares where $user is the initiator + * @param int $limit The maximum number of shares to be returned, -1 for all shares * @param int $offset - * @param int $limit * @return Share[] */ - public function getShares(IUser $user, $shareType, $offset, $limit) { - throw new \Exception(); + public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { + $qb = $this->dbConn->getQueryBuilder(); + $qb->select('*') + ->from('share'); + + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); + + /** + * Reshares for this user are shares where they are the owner. + */ + if ($reshares === false) { + //Special case for old shares created via the web UI + $or1 = $qb->expr()->andX( + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), + $qb->expr()->isNull('uid_initiator') + ); + + $qb->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), + $or1 + ) + ); + } else { + $qb->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) + ) + ); + } + + if ($node !== null) { + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); + } + + if ($limit !== -1) { + $qb->setMaxResults($limit); + } + + $qb->setFirstResult($offset); + $qb->orderBy('id'); + + $cursor = $qb->execute(); + $shares = []; + while($data = $cursor->fetch()) { + $shares[] = $this->createShare($data); + } + $cursor->closeCursor(); + + return $shares; } /** - * Get share by id - * - * @param int $id - * @return IShare - * @throws ShareNotFound + * @inheritdoc */ - public function getShareById($id) { + public function getShareById($id, $recipientId = null) { $qb = $this->dbConn->getQueryBuilder(); $qb->select('*') ->from('share') - ->where($qb->expr()->eq('id', $qb->createParameter('id'))) - ->setParameter(':id', $id); + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) + ->andWhere( + $qb->expr()->in( + 'share_type', + $qb->createNamedParameter([ + \OCP\Share::SHARE_TYPE_USER, + \OCP\Share::SHARE_TYPE_GROUP, + \OCP\Share::SHARE_TYPE_LINK, + ], IQueryBuilder::PARAM_INT_ARRAY) + ) + ); $cursor = $qb->execute(); $data = $cursor->fetch(); @@ -187,7 +528,16 @@ class DefaultShareProvider implements IShareProvider { throw new ShareNotFound(); } - $share = $this->createShare($data); + try { + $share = $this->createShare($data); + } catch (InvalidShare $e) { + throw new ShareNotFound(); + } + + // If the recipient is set for a group share resolve to that user + if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + $share = $this->resolveGroupShare($share, $recipientId); + } return $share; } @@ -196,79 +546,269 @@ class DefaultShareProvider implements IShareProvider { * Get shares for a given path * * @param \OCP\Files\Node $path - * @param Share[] + * @return \OCP\Share\IShare[] */ - public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path) { - throw new \Exception(); + public function getSharesByPath(Node $path) { + $qb = $this->dbConn->getQueryBuilder(); + + $cursor = $qb->select('*') + ->from('share') + ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) + ->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)), + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)) + ) + )->execute(); + + $shares = []; + while($data = $cursor->fetch()) { + $shares[] = $this->createShare($data); + } + $cursor->closeCursor(); + + return $shares; } /** - * Get shared with the given user - * - * @param IUser $user - * @param int $shareType - * @param Share + * @inheritdoc */ - public function getSharedWithMe(IUser $user, $shareType = null) { - throw new \Exception(); + public function getSharedWith($userId, $shareType, $node, $limit, $offset) { + /** @var Share[] $shares */ + $shares = []; + + if ($shareType === \OCP\Share::SHARE_TYPE_USER) { + //Get shares directly with this user + $qb = $this->dbConn->getQueryBuilder(); + $qb->select('*') + ->from('share'); + + // Order by id + $qb->orderBy('id'); + + // Set limit and offset + if ($limit !== -1) { + $qb->setMaxResults($limit); + } + $qb->setFirstResult($offset); + + $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER))); + $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); + + // Filter by node if provided + if ($node !== null) { + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); + } + + $cursor = $qb->execute(); + + while($data = $cursor->fetch()) { + $shares[] = $this->createShare($data); + } + $cursor->closeCursor(); + + } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) { + $user = $this->userManager->get($userId); + $allGroups = $this->groupManager->getUserGroups($user); + + /** @var Share[] $shares2 */ + $shares2 = []; + + $start = 0; + while(true) { + $groups = array_slice($allGroups, $start, 100); + $start += 100; + + if ($groups === []) { + break; + } + + $qb = $this->dbConn->getQueryBuilder(); + $qb->select('*') + ->from('share') + ->orderBy('id') + ->setFirstResult(0); + + if ($limit !== -1) { + $qb->setMaxResults($limit - count($shares)); + } + + // Filter by node if provided + if ($node !== null) { + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); + } + + $groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups); + + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))); + $qb->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter( + $groups, + IQueryBuilder::PARAM_STR_ARRAY + ))); + + $cursor = $qb->execute(); + while($data = $cursor->fetch()) { + if ($offset > 0) { + $offset--; + continue; + } + $shares2[] = $this->createShare($data); + } + $cursor->closeCursor(); + } + + /* + * Resolve all group shares to user specific shares + * TODO: Optmize this! + */ + foreach($shares2 as $share) { + $shares[] = $this->resolveGroupShare($share, $userId); + } + } else { + throw new BackendError('Invalid backend'); + } + + + return $shares; } /** - * Get a share by token and if present verify the password + * Get a share by token * * @param string $token - * @param string $password - * @param Share + * @return \OCP\Share\IShare + * @throws ShareNotFound */ - public function getShareByToken($token, $password = null) { - throw new \Exception(); + public function getShareByToken($token) { + $qb = $this->dbConn->getQueryBuilder(); + + $cursor = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK))) + ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) + ->execute(); + + $data = $cursor->fetch(); + + if ($data === false) { + throw new ShareNotFound(); + } + + try { + $share = $this->createShare($data); + } catch (InvalidShare $e) { + throw new ShareNotFound(); + } + + return $share; } /** * Create a share object from an database row * * @param mixed[] $data - * @return Share + * @return \OCP\Share\IShare + * @throws InvalidShare */ private function createShare($data) { - $share = new Share(); + $share = new Share($this->rootFolder); $share->setId((int)$data['id']) ->setShareType((int)$data['share_type']) ->setPermissions((int)$data['permissions']) ->setTarget($data['file_target']) - ->setShareTime((int)$data['stime']) ->setMailSend((bool)$data['mail_send']); + $shareTime = new \DateTime(); + $shareTime->setTimestamp((int)$data['stime']); + $share->setShareTime($shareTime); + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { - $share->setSharedWith($this->userManager->get($data['share_with'])); + $share->setSharedWith($data['share_with']); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { - $share->setSharedWith($this->groupManager->get($data['share_with'])); + $share->setSharedWith($data['share_with']); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { $share->setPassword($data['share_with']); $share->setToken($data['token']); - } else { - $share->setSharedWith($data['share_with']); } - $share->setSharedBy($this->userManager->get($data['uid_owner'])); + if ($data['uid_initiator'] === null) { + //OLD SHARE + $share->setSharedBy($data['uid_owner']); + $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); - // TODO: getById can return an array. How to handle this properly?? - $path = $this->userFolder->getById($data['file_source']); - $path = $path[0]; - $share->setPath($path); - - $owner = $path->getStorage()->getOwner('.'); - if ($owner !== false) { - $share->setShareOwner($this->userManager->get($owner)); + $owner = $path->getOwner(); + $share->setShareOwner($owner->getUID()); + } else { + //New share! + $share->setSharedBy($data['uid_initiator']); + $share->setShareOwner($data['uid_owner']); } + $share->setNodeId((int)$data['file_source']); + $share->setNodeType($data['item_type']); + if ($data['expiration'] !== null) { $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']); $share->setExpirationDate($expiration); } + $share->setProviderId($this->identifier()); + return $share; } + /** + * Get the node with file $id for $user + * + * @param string $user The userId + * @param int $id + * @return \OCP\Files\File|\OCP\Files\Folder + * @throws InvalidShare + */ + private function getNode($user, $id) { + try { + $userFolder = $this->rootFolder->getUserFolder($user); + } catch (NotFoundException $e) { + throw new InvalidShare(); + } + + $nodes = $userFolder->getById($id); + + if (empty($nodes)) { + throw new InvalidShare(); + } + + return $nodes[0]; + } + + /** + * Resolve a group share to a user specific share + * Thus if the user moved their group share make sure this is properly reflected here. + * + * @param \OCP\Share\IShare $share + * @param string $userId + * @return Share Returns the updated share if one was found else return the original share. + */ + private function resolveGroupShare(\OCP\Share\IShare $share, $userId) { + $qb = $this->dbConn->getQueryBuilder(); + + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))) + ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))) + ->setMaxResults(1) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + if ($data !== false) { + $share->setPermissions((int)$data['permissions']); + $share->setTarget($data['file_target']); + } + + return $share; + } } |