diff options
37 files changed, 735 insertions, 1411 deletions
diff --git a/apps/files_sharing/api/ocssharewrapper.php b/apps/files_sharing/api/ocssharewrapper.php index 3ce2901dfb4..ca04c656c28 100644 --- a/apps/files_sharing/api/ocssharewrapper.php +++ b/apps/files_sharing/api/ocssharewrapper.php @@ -26,25 +26,23 @@ class OCSShareWrapper { * @return Share20OCS */ private function getShare20OCS() { - return new Share20OCS(new \OC\Share20\Manager( - \OC::$server->getUserSession()->getUser(), - \OC::$server->getUserManager(), - \OC::$server->getGroupManager(), - \OC::$server->getLogger(), - \OC::$server->getAppConfig(), - \OC::$server->getUserFolder(), - new \OC\Share20\DefaultShareProvider( - \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getGroupManager(), - \OC::$server->getUserFolder() - ) - ), - \OC::$server->getGroupManager(), - \OC::$server->getUserManager(), - \OC::$server->getRequest(), - \OC::$server->getUserFolder(), - \OC::$server->getURLGenerator()); + return new Share20OCS( + new \OC\Share20\Manager( + \OC::$server->getLogger(), + \OC::$server->getAppConfig(), + new \OC\Share20\DefaultShareProvider( + \OC::$server->getDatabaseConnection(), + \OC::$server->getUserManager(), + \OC::$server->getGroupManager(), + \OC::$server->getRootFolder() + ) + ), + \OC::$server->getGroupManager(), + \OC::$server->getUserManager(), + \OC::$server->getRequest(), + \OC::$server->getRootFolder(), + \OC::$server->getURLGenerator(), + \OC::$server->getUserSession()->getUser()); } public function getAllShares($params) { diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php index aaf5a3c72b6..6c25b4a4426 100644 --- a/apps/files_sharing/api/share20ocs.php +++ b/apps/files_sharing/api/share20ocs.php @@ -22,35 +22,53 @@ namespace OCA\Files_Sharing\API; use OC\Share20\IShare; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\IRequest; +use OCP\Files\Folder; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Files\IRootFolder; + class Share20OCS { /** @var \OC\Share20\Manager */ private $shareManager; - /** @var \OCP\IGroupManager */ + /** @var IGroupManager */ private $groupManager; - /** @var \OCP\IUserManager */ + /** @var IUserManager */ private $userManager; - /** @var \OCP\IRequest */ + /** @var IRequest */ private $request; - /** @var \OCP\Files\Folder */ - private $userFolder; + /** @var IRootFolder */ + private $rootFolder; + + /** @var IUrlGenerator */ + private $urlGenerator; + + /** @var IUser */ + private $currentUser; - public function __construct(\OC\Share20\Manager $shareManager, - \OCP\IGroupManager $groupManager, - \OCP\IUserManager $userManager, - \OCP\IRequest $request, - \OCP\Files\Folder $userFolder, - \OCP\IURLGenerator $urlGenerator) { + public function __construct( + \OC\Share20\Manager $shareManager, + IGroupManager $groupManager, + IUserManager $userManager, + IRequest $request, + IRootFolder $rootFolder, + IURLGenerator $urlGenerator, + IUser $currentUser + ) { $this->shareManager = $shareManager; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->request = $request; - $this->userFolder = $userFolder; + $this->rootFolder = $rootFolder; $this->urlGenerator = $urlGenerator; + $this->currentUser = $currentUser; } /** @@ -73,7 +91,7 @@ class Share20OCS { ]; $path = $share->getPath(); - $result['path'] = $this->userFolder->getRelativePath($path->getPath()); + $result['path'] = $this->rootFolder->getUserFolder($share->getShareOwner()->getUID())->getRelativePath($path->getPath()); if ($path instanceOf \OCP\Files\Folder) { $result['item_type'] = 'folder'; } else { @@ -131,8 +149,12 @@ class Share20OCS { return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); } - $share = $this->formatShare($share); - return new \OC_OCS_Result($share); + if ($this->canAccessShare($share)) { + $share = $this->formatShare($share); + return new \OC_OCS_Result($share); + } else { + return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); + } } /** @@ -156,6 +178,10 @@ class Share20OCS { \OCA\Files_Sharing\API\Local::deleteShare(['id' => $id]); } + if (!$this->canAccessShare($share)) { + return new \OC_OCS_Result(null, 404, 'could not delete share'); + } + try { $this->shareManager->deleteShare($share); } catch (\OC\Share20\Exception\BackendError $e) { @@ -164,4 +190,30 @@ class Share20OCS { return new \OC_OCS_Result(); } + + /** + * @param IShare $share + * @return bool + */ + protected function canAccessShare(IShare $share) { + // Owner of the file and the sharer of the file can always get share + if ($share->getShareOwner() === $this->currentUser || + $share->getSharedBy() === $this->currentUser + ) { + return true; + } + + // If the share is shared with you (or a group you are a member of) + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && + $share->getSharedWith() === $this->currentUser) { + return true; + } + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && + $share->getSharedWith()->inGroup($this->currentUser)) { + return true; + } + + return false; + } } diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 03e448be0af..5f56340d254 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -42,7 +42,6 @@ $l = \OC::$server->getL10N('files_sharing'); $application = new Application(); $application->registerMountProviders(); -$application->setupPropagation(); \OCP\App::registerAdmin('files_sharing', 'settings-admin'); \OCP\App::registerPersonal('files_sharing', 'settings-personal'); diff --git a/apps/files_sharing/appinfo/application.php b/apps/files_sharing/appinfo/application.php index 545a9425083..ffe3a6a513f 100644 --- a/apps/files_sharing/appinfo/application.php +++ b/apps/files_sharing/appinfo/application.php @@ -27,8 +27,6 @@ namespace OCA\Files_Sharing\AppInfo; use OCA\Files_Sharing\Helper; use OCA\Files_Sharing\MountProvider; -use OCA\Files_Sharing\Propagation\PropagationManager; -use OCA\Files_Sharing\Propagation\GroupPropagationManager; use OCP\AppFramework\App; use OC\AppFramework\Utility\SimpleContainer; use OCA\Files_Sharing\Controllers\ExternalSharesController; @@ -116,8 +114,7 @@ class Application extends App { /** @var \OCP\IServerContainer $server */ $server = $c->query('ServerContainer'); return new MountProvider( - $server->getConfig(), - $c->query('PropagationManager') + $server->getConfig() ); }); @@ -132,25 +129,6 @@ class Application extends App { ); }); - $container->registerService('PropagationManager', function (IContainer $c) { - /** @var \OCP\IServerContainer $server */ - $server = $c->query('ServerContainer'); - return new PropagationManager( - $server->getUserSession(), - $server->getConfig() - ); - }); - - $container->registerService('GroupPropagationManager', function (IContainer $c) { - /** @var \OCP\IServerContainer $server */ - $server = $c->query('ServerContainer'); - return new GroupPropagationManager( - $server->getUserSession(), - $server->getGroupManager(), - $c->query('PropagationManager') - ); - }); - /* * Register capabilities */ @@ -164,11 +142,4 @@ class Application extends App { $mountProviderCollection->registerProvider($this->getContainer()->query('MountProvider')); $mountProviderCollection->registerProvider($this->getContainer()->query('ExternalMountProvider')); } - - public function setupPropagation() { - $propagationManager = $this->getContainer()->query('PropagationManager'); - \OCP\Util::connectHook('OC_Filesystem', 'setup', $propagationManager, 'globalSetup'); - - $this->getContainer()->query('GroupPropagationManager')->globalSetup(); - } } diff --git a/apps/files_sharing/lib/mountprovider.php b/apps/files_sharing/lib/mountprovider.php index 458e7f2619b..74a2a3ff4d6 100644 --- a/apps/files_sharing/lib/mountprovider.php +++ b/apps/files_sharing/lib/mountprovider.php @@ -24,7 +24,6 @@ namespace OCA\Files_Sharing; use OC\Files\Filesystem; use OC\User\NoUserException; -use OCA\Files_Sharing\Propagation\PropagationManager; use OCP\Files\Config\IMountProvider; use OCP\Files\Storage\IStorageFactory; use OCP\IConfig; @@ -37,17 +36,10 @@ class MountProvider implements IMountProvider { protected $config; /** - * @var \OCA\Files_Sharing\Propagation\PropagationManager - */ - protected $propagationManager; - - /** * @param \OCP\IConfig $config - * @param \OCA\Files_Sharing\Propagation\PropagationManager $propagationManager */ - public function __construct(IConfig $config, PropagationManager $propagationManager) { + public function __construct(IConfig $config) { $this->config = $config; - $this->propagationManager = $propagationManager; } @@ -60,21 +52,15 @@ class MountProvider implements IMountProvider { */ public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) { $shares = \OCP\Share::getItemsSharedWithUser('file', $user->getUID()); - $propagator = $this->propagationManager->getSharePropagator($user->getUID()); - $propagator->propagateDirtyMountPoints($shares); $shares = array_filter($shares, function ($share) { return $share['permissions'] > 0; }); $shares = array_map(function ($share) use ($user, $storageFactory) { - // for updating etags for the share owner when we make changes to this share. - $ownerPropagator = $this->propagationManager->getChangePropagator($share['uid_owner']); return new SharedMount( '\OC\Files\Storage\Shared', '/' . $user->getUID() . '/' . $share['file_target'], array( - 'propagationManager' => $this->propagationManager, - 'propagator' => $ownerPropagator, 'share' => $share, 'user' => $user->getUID() ), diff --git a/apps/files_sharing/lib/propagation/changewatcher.php b/apps/files_sharing/lib/propagation/changewatcher.php deleted file mode 100644 index e61c161da19..00000000000 --- a/apps/files_sharing/lib/propagation/changewatcher.php +++ /dev/null @@ -1,110 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2015, 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\Files_Sharing\Propagation; - -use OC\Files\Cache\ChangePropagator; -use OC\Files\Filesystem; -use OC\Files\View; -use OCA\Files_Sharing\SharedMount; - -/** - * Watch for changes made in a shared mount and propagate the changes to the share owner - */ -class ChangeWatcher { - /** - * The user view for the logged in user - * - * @var \OC\Files\View - */ - private $baseView; - - /** - * @var RecipientPropagator - */ - private $recipientPropagator; - - /** - * @param \OC\Files\View $baseView the view for the logged in user - * @param RecipientPropagator $recipientPropagator - */ - public function __construct(View $baseView, RecipientPropagator $recipientPropagator) { - $this->baseView = $baseView; - $this->recipientPropagator = $recipientPropagator; - } - - - public function writeHook($params) { - $path = $params['path']; - $fullPath = $this->baseView->getAbsolutePath($path); - $mount = $this->baseView->getMount($path); - if ($mount instanceof SharedMount) { - $this->propagateForOwner($mount->getShare(), $mount->getInternalPath($fullPath), $mount->getOwnerPropagator()); - } - $info = $this->baseView->getFileInfo($path); - if ($info) { - // trigger propagation if the subject of the write hook is shared. - // if a parent folder of $path is shared the propagation will be triggered from the change propagator hooks - $this->recipientPropagator->propagateById($info->getId()); - } - } - - public function renameHook($params) { - $path1 = $params['oldpath']; - $path2 = $params['newpath']; - $fullPath1 = $this->baseView->getAbsolutePath($path1); - $fullPath2 = $this->baseView->getAbsolutePath($path2); - $mount1 = $this->baseView->getMount($path1); - $mount2 = $this->baseView->getMount($path2); - if ($mount1 instanceof SharedMount and $mount1->getInternalPath($fullPath1) !== '') { - $this->propagateForOwner($mount1->getShare(), $mount1->getInternalPath($fullPath1), $mount1->getOwnerPropagator()); - } - if ($mount1 !== $mount2 and $mount2 instanceof SharedMount and $mount2->getInternalPath($fullPath2) !== '') { - $this->propagateForOwner($mount2->getShare(), $mount2->getInternalPath($fullPath2), $mount2->getOwnerPropagator()); - } - } - - /** - * @param array $share - * @param string $internalPath - * @param \OC\Files\Cache\ChangePropagator $propagator - */ - private function propagateForOwner($share, $internalPath, ChangePropagator $propagator) { - // note that we have already set up the filesystem for the owner when mounting the share - $view = new View('/' . $share['uid_owner'] . '/files'); - - $shareRootPath = $view->getPath($share['item_source']); - if (!is_null($shareRootPath)) { - $path = $shareRootPath . '/' . $internalPath; - $path = Filesystem::normalizePath($path); - $propagator->addChange($path); - $propagator->propagateChanges(); - } - } - - public function permissionsHook($params) { - $share = $params['share']; - - if ($share['item_type'] === 'file' || $share['item_type'] === 'folder') { - $this->recipientPropagator->markDirty($share, microtime(true)); - } - } -} diff --git a/apps/files_sharing/lib/propagation/grouppropagationmanager.php b/apps/files_sharing/lib/propagation/grouppropagationmanager.php deleted file mode 100644 index ba550dccec3..00000000000 --- a/apps/files_sharing/lib/propagation/grouppropagationmanager.php +++ /dev/null @@ -1,133 +0,0 @@ -<?php -/** - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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\Files_Sharing\Propagation; - -use OC\Files\Filesystem; -use OC\Files\View; -use OCP\IConfig; -use OCP\IUserSession; -use OCP\IGroup; -use OCP\IUser; -use OCP\IGroupManager; -use OCA\Files_Sharing\Propagation\PropagationManager; - -/** - * Propagate changes on group changes - */ -class GroupPropagationManager { - /** - * @var \OCP\IUserSession - */ - private $userSession; - - /** - * @var \OCP\IGroupManager - */ - private $groupManager; - - /** - * @var PropagationManager - */ - private $propagationManager; - - /** - * Items shared with a given user. - * Key is user id and value is an array of shares. - * - * @var array - */ - private $userShares = []; - - public function __construct(IUserSession $userSession, IGroupManager $groupManager, PropagationManager $propagationManager) { - $this->userSession = $userSession; - $this->groupManager = $groupManager; - $this->propagationManager = $propagationManager; - } - - public function onPreProcessUser(IGroup $group, IUser $targetUser) { - $this->userShares[$targetUser->getUID()] = $this->getUserShares($targetUser->getUID()); - } - - public function onPostAddUser(IGroup $group, IUser $targetUser) { - $targetUserId = $targetUser->getUID(); - $sharesAfter = $this->getUserShares($targetUserId); - - $this->propagateSharesDiff($targetUserId, $sharesAfter, $this->userShares[$targetUserId]); - unset($this->userShares[$targetUserId]); - } - - public function onPostRemoveUser(IGroup $group, IUser $targetUser) { - $targetUserId = $targetUser->getUID(); - $sharesAfter = $this->getUserShares($targetUserId); - - $this->propagateSharesDiff($targetUserId, $this->userShares[$targetUserId], $sharesAfter); - unset($this->userShares[$targetUserId]); - } - - private function getUserShares($targetUserId) { - return \OCP\Share::getItemsSharedWithUser('file', $targetUserId); - } - - /** - * Propagate etag for the shares that are in $shares1 but not in $shares2. - * - * @param string $targetUserId user id for which to propagate shares - * @param array $shares1 - * @param array $shares2 - */ - private function propagateSharesDiff($targetUserId, $shares1, $shares2) { - $sharesToPropagate = array_udiff( - $shares1, - $shares2, - function($share1, $share2) { - return ($share2['id'] - $share1['id']); - } - ); - - \OC\Files\Filesystem::initMountPoints($targetUserId); - $this->propagationManager->propagateSharesToUser($sharesToPropagate, $targetUserId); - } - - /** - * To be called from setupFS trough a hook - * - * Sets up listening to changes made to shares owned by the current user - */ - public function globalSetup() { - $user = $this->userSession->getUser(); - if (!$user) { - return; - } - - $this->groupManager->listen('\OC\Group', 'preAddUser', [$this, 'onPreProcessUser']); - $this->groupManager->listen('\OC\Group', 'postAddUser', [$this, 'onPostAddUser']); - $this->groupManager->listen('\OC\Group', 'preRemoveUser', [$this, 'onPreProcessUser']); - $this->groupManager->listen('\OC\Group', 'postRemoveUser', [$this, 'onPostRemoveUser']); - } - - public function tearDown() { - $this->groupManager->removeListener('\OC\Group', 'preAddUser', [$this, 'onPreProcessUser']); - $this->groupManager->removeListener('\OC\Group', 'postAddUser', [$this, 'onPostAddUser']); - $this->groupManager->removeListener('\OC\Group', 'preRemoveUser', [$this, 'onPreProcessUser']); - $this->groupManager->removeListener('\OC\Group', 'postRemoveUser', [$this, 'onPostRemoveUser']); - } -} diff --git a/apps/files_sharing/lib/propagation/propagationmanager.php b/apps/files_sharing/lib/propagation/propagationmanager.php deleted file mode 100644 index aac9428240d..00000000000 --- a/apps/files_sharing/lib/propagation/propagationmanager.php +++ /dev/null @@ -1,144 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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\Files_Sharing\Propagation; - -use OC\Files\Filesystem; -use OC\Files\View; -use OCP\IConfig; -use OCP\IUserSession; -use OCP\Util; - - -/** - * Keep track of all change and share propagators by owner - */ -class PropagationManager { - /** - * @var \OCP\IUserSession - */ - private $userSession; - - /** - * @var \OCP\IConfig - */ - private $config; - - /** - * Change propagators for share owner - * - * @var \OC\Files\Cache\ChangePropagator[] - */ - private $changePropagators = []; - - /** - * Recipient propagators - * - * @var \OCA\Files_Sharing\Propagation\RecipientPropagator[] - */ - private $sharePropagators = []; - - public function __construct(IUserSession $userSession, IConfig $config) { - $this->userSession = $userSession; - $this->config = $config; - } - - /** - * @param string $user - * @return \OC\Files\Cache\ChangePropagator - */ - public function getChangePropagator($user) { - $activeUser = $this->userSession->getUser(); - - // for the local user we want to propagator from the active view, not any cached one - if ($activeUser && $activeUser->getUID() === $user && Filesystem::getView() instanceof View) { - // it's important that we take the existing propagator here to make sure we can listen to external changes - $this->changePropagators[$user] = Filesystem::getView()->getUpdater()->getPropagator(); - } - if (isset($this->changePropagators[$user])) { - return $this->changePropagators[$user]; - } - $view = new View('/' . $user . '/files'); - $this->changePropagators[$user] = $view->getUpdater()->getPropagator(); - return $this->changePropagators[$user]; - } - - /** - * Propagates etag changes for the given shares to the given user - * - * @param array array of shares for which to trigger etag change - * @param string $user - */ - public function propagateSharesToUser($shares, $user) { - $changePropagator = $this->getChangePropagator($user); - foreach ($shares as $share) { - $changePropagator->addChange($share['file_target']); - } - $time = microtime(true); - $changePropagator->propagateChanges(floor($time)); - } - - /** - * @param string $user - * @return \OCA\Files_Sharing\Propagation\RecipientPropagator - */ - public function getSharePropagator($user) { - if (isset($this->sharePropagators[$user])) { - return $this->sharePropagators[$user]; - } - $this->sharePropagators[$user] = new RecipientPropagator($user, $this->getChangePropagator($user), $this->config, $this); - return $this->sharePropagators[$user]; - } - - /** - * Attach the recipient propagator for $user to the change propagator of a share owner to mark shares as dirty when the owner makes a change to a share - * - * @param string $shareOwner - * @param string $user - */ - public function listenToOwnerChanges($shareOwner, $user) { - $sharePropagator = $this->getSharePropagator($user); - $ownerPropagator = $this->getChangePropagator($shareOwner); - $sharePropagator->attachToPropagator($ownerPropagator, $shareOwner); - } - - /** - * To be called from setupFS trough a hook - * - * Sets up listening to changes made to shares owned by the current user - */ - public function globalSetup() { - $user = $this->userSession->getUser(); - if (!$user) { - return; - } - $recipientPropagator = $this->getSharePropagator($user->getUID()); - $watcher = new ChangeWatcher(Filesystem::getView(), $recipientPropagator); - - // for marking shares owned by the active user as dirty when a file inside them changes - $this->listenToOwnerChanges($user->getUID(), $user->getUID()); - Util::connectHook('OC_Filesystem', 'post_write', $watcher, 'writeHook'); - Util::connectHook('OC_Filesystem', 'post_delete', $watcher, 'writeHook'); - Util::connectHook('OC_Filesystem', 'post_rename', $watcher, 'renameHook'); - Util::connectHook('OCP\Share', 'post_update_permissions', $watcher, 'permissionsHook'); - } -} diff --git a/apps/files_sharing/lib/propagation/recipientpropagator.php b/apps/files_sharing/lib/propagation/recipientpropagator.php deleted file mode 100644 index 5eacf4c0f6e..00000000000 --- a/apps/files_sharing/lib/propagation/recipientpropagator.php +++ /dev/null @@ -1,164 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2015, 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\Files_Sharing\Propagation; - -use OC\Files\Cache\ChangePropagator; -use OC\Files\View; -use OC\Share\Share; -use OCP\Files\NotFoundException; - -/** - * Propagate etags for share recipients - */ -class RecipientPropagator { - /** - * @var string - */ - protected $userId; - - /** - * @var \OC\Files\Cache\ChangePropagator - */ - protected $changePropagator; - - /** - * @var \OCP\IConfig - */ - protected $config; - - /** - * @var PropagationManager - */ - private $manager; - - /** - * @param string $userId current user, must match the propagator's - * user - * @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator - * initialized with a view for $user - * @param \OCP\IConfig $config - * @param PropagationManager $manager - */ - public function __construct($userId, $changePropagator, $config, PropagationManager $manager) { - $this->userId = $userId; - $this->changePropagator = $changePropagator; - $this->config = $config; - $this->manager = $manager; - } - - /** - * Propagate the etag changes for all shares marked as dirty and mark the shares as clean - * - * @param array $shares the shares for the users - * @param int $time - */ - public function propagateDirtyMountPoints(array $shares, $time = null) { - if ($time === null) { - $time = microtime(true); - } - $dirtyShares = $this->getDirtyShares($shares); - foreach ($dirtyShares as $share) { - $this->changePropagator->addChange($share['file_target']); - } - if (count($dirtyShares)) { - $this->config->setUserValue($this->userId, 'files_sharing', 'last_propagate', $time); - $this->changePropagator->propagateChanges(floor($time)); - } - } - - /** - * Get all shares we need to update the etag for - * - * @param array $shares the shares for the users - * @return string[] - */ - protected function getDirtyShares($shares) { - $dirty = []; - $userTime = $this->config->getUserValue($this->userId, 'files_sharing', 'last_propagate', 0); - foreach ($shares as $share) { - $updateTime = $this->config->getAppValue('files_sharing', $share['id'], 0); - if ($updateTime >= $userTime) { - $dirty[] = $share; - } - } - return $dirty; - } - - /** - * @param array $share - * @param float $time - */ - public function markDirty($share, $time = null) { - if ($time === null) { - $time = microtime(true); - } - $this->config->setAppValue('files_sharing', $share['id'], $time); - } - - /** - * Listen on the propagator for updates made to shares owned by a user - * - * @param \OC\Files\Cache\ChangePropagator $propagator - * @param string $owner - */ - public function attachToPropagator(ChangePropagator $propagator, $owner) { - $propagator->listen('\OC\Files', 'propagate', function ($path, $entry) use ($owner) { - $this->propagateById($entry['fileid']); - }); - } - - protected $propagatingIds = []; - - /** - * @param int $id - */ - public function propagateById($id) { - if (isset($this->propagatingIds[$id])) { - return; - } - $this->propagatingIds[$id] = true; - $shares = Share::getAllSharesForFileId($id); - foreach ($shares as $share) { - // propagate down the share tree - $this->markDirty($share, microtime(true)); - - // propagate up the share tree - if ($share['share_with'] === $this->userId) { - $user = $share['uid_owner']; - $view = new View('/' . $user . '/files'); - - try { - $path = $view->getPath($share['file_source']); - } catch (NotFoundException $e) { - $path = null; - } - - $watcher = new ChangeWatcher($view, $this->manager->getSharePropagator($user)); - $watcher->writeHook(['path' => $path]); - } - } - - unset($this->propagatingIds[$id]); - } -} diff --git a/apps/files_sharing/lib/sharedmount.php b/apps/files_sharing/lib/sharedmount.php index a1387957867..275fea97c7f 100644 --- a/apps/files_sharing/lib/sharedmount.php +++ b/apps/files_sharing/lib/sharedmount.php @@ -39,11 +39,6 @@ class SharedMount extends MountPoint implements MoveableMount { protected $storage = null; /** - * @var \OC\Files\Cache\ChangePropagator - */ - protected $ownerPropagator; - - /** * @var \OC\Files\View */ private $recipientView; @@ -54,8 +49,6 @@ class SharedMount extends MountPoint implements MoveableMount { private $user; public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { - // first update the mount point before creating the parent - $this->ownerPropagator = $arguments['propagator']; $this->user = $arguments['user']; $this->recipientView = new View('/' . $this->user . '/files'); $newMountPoint = $this->verifyMountPoint($arguments['share']); @@ -201,11 +194,4 @@ class SharedMount extends MountPoint implements MoveableMount { public function getShare() { return $this->getStorage()->getShare(); } - - /** - * @return \OC\Files\Cache\ChangePropagator - */ - public function getOwnerPropagator() { - return $this->ownerPropagator; - } } diff --git a/apps/files_sharing/lib/sharedpropagator.php b/apps/files_sharing/lib/sharedpropagator.php new file mode 100644 index 00000000000..fcb4b92dd33 --- /dev/null +++ b/apps/files_sharing/lib/sharedpropagator.php @@ -0,0 +1,43 @@ +<?php +/** + * @author Robin Appelman <icewind@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Files_Sharing; + +use OC\Files\Cache\Propagator; + +class SharedPropagator extends Propagator { + /** + * @var \OC\Files\Storage\Shared + */ + protected $storage; + + /** + * @param string $internalPath + * @param int $time + * @return array[] all propagated entries + */ + public function propagateChange($internalPath, $time) { + $source = $this->storage->getSourcePath($internalPath); + /** @var \OC\Files\Storage\Storage $storage */ + list($storage, $sourceInternalPath) = \OC\Files\Filesystem::resolvePath($source); + return $storage->getPropagator()->propagateChange($sourceInternalPath, $time); + } +} diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php index 18e02844179..4807b5ee738 100644 --- a/apps/files_sharing/lib/sharedstorage.php +++ b/apps/files_sharing/lib/sharedstorage.php @@ -51,11 +51,6 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage { private $ownerView; /** - * @var \OCA\Files_Sharing\Propagation\PropagationManager - */ - private $propagationManager; - - /** * @var string */ private $user; @@ -65,7 +60,6 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage { public function __construct($arguments) { $this->share = $arguments['share']; $this->ownerView = $arguments['ownerView']; - $this->propagationManager = $arguments['propagationManager']; $this->user = $arguments['user']; } @@ -75,9 +69,6 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage { } $this->initialized = true; Filesystem::initMountPoints($this->share['uid_owner']); - - // for updating our etags when changes are made to the share from the owners side (probably indirectly by us trough another share) - $this->propagationManager->listenToOwnerChanges($this->share['uid_owner'], $this->user); } /** @@ -571,6 +562,13 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage { return new \OC\Files\Cache\Shared_Watcher($storage); } + public function getPropagator($storage = null) { + if (!$storage) { + $storage = $this; + } + return new \OCA\Files_Sharing\SharedPropagator($storage); + } + public function getOwner($path) { if ($path == '') { $path = $this->getMountPoint(); diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php index f74585eb47d..b7c56fe17f6 100644 --- a/apps/files_sharing/tests/api/share20ocstest.php +++ b/apps/files_sharing/tests/api/share20ocstest.php @@ -20,29 +20,39 @@ */ namespace OCA\Files_Sharing\Tests\API; +use OC\Share20\IShare; use OCA\Files_Sharing\API\Share20OCS; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Files\IRootFolder; class Share20OCSTest extends \Test\TestCase { - /** @var OC\Share20\Manager */ + /** @var \OC\Share20\Manager */ private $shareManager; - /** @var OCP\IGroupManager */ + /** @var IGroupManager */ private $groupManager; - /** @var OCP\IUserManager */ + /** @var IUserManager */ private $userManager; - /** @var OCP\IRequest */ + /** @var IRequest */ private $request; - /** @var OCP\Files\Folder */ - private $userFolder; + /** @var IRootFolder */ + private $rootFolder; - /** @var OCP\IURLGenerator */ + /** @var IURLGenerator */ private $urlGenerator; - /** @var OCS */ + /** @var IUser */ + private $currentUser; + + /** @var Share20OCS */ private $ocs; protected function setUp() { @@ -52,15 +62,19 @@ class Share20OCSTest extends \Test\TestCase { $this->groupManager = $this->getMock('OCP\IGroupManager'); $this->userManager = $this->getMock('OCP\IUserManager'); $this->request = $this->getMock('OCP\IRequest'); - $this->userFolder = $this->getMock('OCP\Files\Folder'); + $this->rootFolder = $this->getMock('OCP\Files\IRootFolder'); $this->urlGenerator = $this->getMock('OCP\IURLGenerator'); - - $this->ocs = new Share20OCS($this->shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->userFolder, - $this->urlGenerator); + $this->currentUser = $this->getMock('OCP\IUser'); + + $this->ocs = new Share20OCS( + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->request, + $this->rootFolder, + $this->urlGenerator, + $this->currentUser + ); } public function testDeleteShareShareNotFound() { @@ -76,6 +90,7 @@ class Share20OCSTest extends \Test\TestCase { public function testDeleteShareCouldNotDelete() { $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareOwner')->willReturn($this->currentUser); $this->shareManager ->expects($this->once()) ->method('getShareById') @@ -94,6 +109,7 @@ class Share20OCSTest extends \Test\TestCase { public function testDeleteShare() { $share = $this->getMock('OC\Share20\IShare'); + $share->method('getSharedBy')->willReturn($this->currentUser); $this->shareManager ->expects($this->once()) ->method('getShareById') @@ -119,7 +135,7 @@ class Share20OCSTest extends \Test\TestCase { $this->assertEquals($expected, $this->ocs->getShare(42)); } - public function createShare($id, $shareType, $sharedWith, $sharedBy, $path, $permissions, + public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner, $path, $permissions, $shareTime, $expiration, $parent, $target, $mail_send, $token=null, $password=null) { $share = $this->getMock('OC\Share20\IShare'); @@ -127,6 +143,7 @@ class Share20OCSTest extends \Test\TestCase { $share->method('getShareType')->willReturn($shareType); $share->method('getSharedWith')->willReturn($sharedWith); $share->method('getSharedBy')->willReturn($sharedBy); + $share->method('getShareOwner')->willReturn($shareOwner); $share->method('getPath')->willReturn($path); $share->method('getPermissions')->willReturn($permissions); $share->method('getShareTime')->willReturn($shareTime); @@ -173,17 +190,20 @@ class Share20OCSTest extends \Test\TestCase { $folder->method('getParent')->willReturn($parentFolder); // File shared with user - $share = $this->createShare(100, - \OCP\Share::SHARE_TYPE_USER, - $user, - $owner, - $file, - 4, - 5, - null, - 6, - 'target', - 0); + $share = $this->createShare( + 100, + \OCP\Share::SHARE_TYPE_USER, + $user, + $owner, + $owner, + $file, + 4, + 5, + null, + 6, + 'target', + 0 + ); $expected = [ 'id' => 100, 'share_type' => \OCP\Share::SHARE_TYPE_USER, @@ -209,17 +229,20 @@ class Share20OCSTest extends \Test\TestCase { $data[] = [$share, $expected]; // Folder shared with group - $share = $this->createShare(101, - \OCP\Share::SHARE_TYPE_GROUP, - $group, - $owner, - $folder, - 4, - 5, - null, - 6, - 'target', - 0); + $share = $this->createShare( + 101, + \OCP\Share::SHARE_TYPE_GROUP, + $group, + $owner, + $owner, + $folder, + 4, + 5, + null, + 6, + 'target', + 0 + ); $expected = [ 'id' => 101, 'share_type' => \OCP\Share::SHARE_TYPE_GROUP, @@ -244,57 +267,24 @@ class Share20OCSTest extends \Test\TestCase { ]; $data[] = [$share, $expected]; - // Folder shared with remote - $share = $this->createShare(101, - \OCP\Share::SHARE_TYPE_REMOTE, - 'user@remote.com', - $owner, - $folder, - 4, - 5, - null, - 6, - 'target', - 0); - $expected = [ - 'id' => 101, - 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE, - 'share_with' => 'user@remote.com', - 'share_with_displayname' => 'user@remote.com', - 'uid_owner' => 'ownerId', - 'displayname_owner' => 'ownerDisplay', - 'item_type' => 'folder', - 'item_source' => 2, - 'file_source' => 2, - 'file_target' => 'target', - 'file_parent' => 3, - 'token' => null, - 'expiration' => null, - 'permissions' => 4, - 'stime' => 5, - 'parent' => 6, - 'storage_id' => 'STORAGE', - 'path' => 'folder', - 'storage' => null, // HACK around static function - 'mail_send' => 0, - ]; - $data[] = [$share, $expected]; - // File shared by link with Expire $expire = \DateTime::createFromFormat('Y-m-d h:i:s', '2000-01-02 01:02:03'); - $share = $this->createShare(101, - \OCP\Share::SHARE_TYPE_LINK, - null, - $owner, - $folder, - 4, - 5, - $expire, - 6, - 'target', - 0, - 'token', - 'password'); + $share = $this->createShare( + 101, + \OCP\Share::SHARE_TYPE_LINK, + null, + $owner, + $owner, + $folder, + 4, + 5, + $expire, + 6, + 'target', + 0, + 'token', + 'password' + ); $expected = [ 'id' => 101, 'share_type' => \OCP\Share::SHARE_TYPE_LINK, @@ -327,20 +317,78 @@ class Share20OCSTest extends \Test\TestCase { * @dataProvider dataGetShare */ public function testGetShare(\OC\Share20\IShare $share, array $result) { + $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') + ->setConstructorArgs([ + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->request, + $this->rootFolder, + $this->urlGenerator, + $this->currentUser + ])->setMethods(['canAccessShare']) + ->getMock(); + + $ocs->method('canAccessShare')->willReturn(true); + $this->shareManager ->expects($this->once()) ->method('getShareById') ->with($share->getId()) ->willReturn($share); - $this->userFolder + $userFolder = $this->getMock('OCP\Files\Folder'); + $userFolder ->method('getRelativePath') ->will($this->returnArgument(0)); + $this->rootFolder->method('getUserFolder') + ->with($share->getShareOwner()->getUID()) + ->willReturn($userFolder); + $this->urlGenerator ->method('linkToRouteAbsolute') ->willReturn('url'); $expected = new \OC_OCS_Result($result); - $this->assertEquals($expected->getData(), $this->ocs->getShare($share->getId())->getData()); } + $this->assertEquals($expected->getData(), $ocs->getShare($share->getId())->getData()); + } + + public function testCanAccessShare() { + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareOwner')->willReturn($this->currentUser); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getSharedBy')->willReturn($this->currentUser); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER); + $share->method('getSharedWith')->willReturn($this->currentUser); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER); + $share->method('getSharedWith')->willReturn($this->getMock('OCP\IUser')); + $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP); + $group = $this->getMock('OCP\IGroup'); + $group->method('inGroup')->with($this->currentUser)->willReturn(true); + $share->method('getSharedWith')->willReturn($group); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP); + $group = $this->getMock('OCP\IGroup'); + $group->method('inGroup')->with($this->currentUser)->willReturn(false); + $share->method('getSharedWith')->willReturn($group); + $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + + $share = $this->getMock('OC\Share20\IShare'); + $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK); + $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } } diff --git a/apps/files_sharing/tests/etagpropagation.php b/apps/files_sharing/tests/etagpropagation.php index 1abf04df84f..2a33732d63f 100644 --- a/apps/files_sharing/tests/etagpropagation.php +++ b/apps/files_sharing/tests/etagpropagation.php @@ -193,7 +193,8 @@ class EtagPropagation extends TestCase { public function testOwnerWritesToSingleFileShare() { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); - Filesystem::file_put_contents('/foo.txt', 'bar'); + Filesystem::file_put_contents('/foo.txt', 'longer_bar'); + Filesystem::touch('/foo.txt', time() - 1); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4, self::TEST_FILES_SHARING_API_USER3]); $this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2]); diff --git a/apps/files_sharing/tests/grouppropagationmanager.php b/apps/files_sharing/tests/grouppropagationmanager.php deleted file mode 100644 index ea32ca4f7ec..00000000000 --- a/apps/files_sharing/tests/grouppropagationmanager.php +++ /dev/null @@ -1,173 +0,0 @@ -<?php -/** - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, 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\Files_sharing\Tests; - -use OC\Files\View; -use OCP\IGroupManager; -use OCP\IGroup; -use OCP\IUser; -use OCP\Share; -use OCA\Files_Sharing\Propagation\GroupPropagationManager; -use OCA\Files_Sharing\Propagation\PropagationManager; - -class GroupPropagationManagerTest extends TestCase { - - /** - * @var GroupPropagationManager - */ - private $groupPropagationManager; - - /** - * @var IGroupManager - */ - private $groupManager; - - /** - * @var PropagationManager - */ - private $propagationManager; - - /** - * @var IGroup - */ - private $recipientGroup; - - /** - * @var IUser - */ - private $recipientUser; - - /** - * @var array - */ - private $fileInfo; - - protected function setUp() { - parent::setUp(); - - $user = $this->getMockBuilder('\OCP\IUser') - ->disableOriginalConstructor() - ->getMock(); - $user->method('getUID')->willReturn(self::TEST_FILES_SHARING_API_USER1); - $userSession = $this->getMockBuilder('\OCP\IUserSession') - ->disableOriginalConstructor() - ->getMock(); - $userSession->method('getUser')->willReturn(selF::TEST_FILES_SHARING_API_USER1); - - $this->propagationManager = $this->getMockBuilder('OCA\Files_Sharing\Propagation\PropagationManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->groupManager = \OC::$server->getGroupManager(); - $this->groupPropagationManager = new GroupPropagationManager( - $userSession, - $this->groupManager, - $this->propagationManager - ); - $this->groupPropagationManager->globalSetup(); - - // since the sharing code is not mockable, we have to create a real folder - $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); - $view1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); - $view1->mkdir('/folder'); - - $this->fileInfo = $view1->getFileInfo('/folder'); - - $this->recipientGroup = $this->groupManager->get(self::TEST_FILES_SHARING_API_GROUP1); - $this->recipientUser = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER3); - - Share::shareItem( - 'folder', - $this->fileInfo['fileid'], - Share::SHARE_TYPE_GROUP, - $this->recipientGroup->getGID(), - \OCP\Constants::PERMISSION_READ - ); - - $this->loginAsUser($this->recipientUser->getUID()); - } - - protected function tearDown() { - $this->groupPropagationManager->tearDown(); - $this->recipientGroup->removeUser($this->recipientUser); - parent::tearDown(); - } - - public function testPropagateWhenAddedToGroup() { - $this->propagationManager->expects($this->once()) - ->method('propagateSharesToUser') - ->with($this->callback(function($shares) { - if (count($shares) !== 1) { - return false; - } - $share = array_values($shares)[0]; - return $share['file_source'] === $this->fileInfo['fileid'] && - $share['share_with'] === $this->recipientGroup->getGID() && - $share['file_target'] === '/folder'; - }), $this->recipientUser->getUID()); - - $this->recipientGroup->addUser($this->recipientUser); - } - - public function testPropagateWhenRemovedFromGroup() { - $this->recipientGroup->addUser($this->recipientUser); - - $this->propagationManager->expects($this->once()) - ->method('propagateSharesToUser') - ->with($this->callback(function($shares) { - if (count($shares) !== 1) { - return false; - } - $share = array_values($shares)[0]; - return $share['file_source'] === $this->fileInfo['fileid'] && - $share['share_with'] === $this->recipientGroup->getGID() && - $share['file_target'] === '/folder'; - }), $this->recipientUser->getUID()); - - $this->recipientGroup->removeUser($this->recipientUser); - } - - public function testPropagateWhenRemovedFromGroupWithSubdirTarget() { - $this->recipientGroup->addUser($this->recipientUser); - - // relogin to refresh mount points - $this->loginAsUser($this->recipientUser->getUID()); - $recipientView = new View('/' . $this->recipientUser->getUID() . '/files'); - - $this->assertTrue($recipientView->mkdir('sub')); - $this->assertTrue($recipientView->rename('folder', 'sub/folder')); - - $this->propagationManager->expects($this->once()) - ->method('propagateSharesToUser') - ->with($this->callback(function($shares) { - if (count($shares) !== 1) { - return false; - } - $share = array_values($shares)[0]; - return $share['file_source'] === $this->fileInfo['fileid'] && - $share['share_with'] === $this->recipientGroup->getGID() && - $share['file_target'] === '/sub/folder'; - }), $this->recipientUser->getUID()); - - $this->recipientGroup->removeUser($this->recipientUser); - } -} diff --git a/apps/files_sharing/tests/testcase.php b/apps/files_sharing/tests/testcase.php index c91734a5b03..6a72a34149a 100644 --- a/apps/files_sharing/tests/testcase.php +++ b/apps/files_sharing/tests/testcase.php @@ -61,7 +61,6 @@ abstract class TestCase extends \Test\TestCase { $application = new Application(); $application->registerMountProviders(); - $application->setupPropagation(); // reset backend \OC_User::clearBackends(); diff --git a/apps/files_trashbin/tests/trashbin.php b/apps/files_trashbin/tests/trashbin.php index e28b854ca1f..934f831ef74 100644 --- a/apps/files_trashbin/tests/trashbin.php +++ b/apps/files_trashbin/tests/trashbin.php @@ -65,7 +65,6 @@ class Test_Trashbin extends \Test\TestCase { \OC::registerShareHooks(); $application = new \OCA\Files_Sharing\AppInfo\Application(); $application->registerMountProviders(); - $application->setupPropagation(); //disable encryption \OC_App::disable('encryption'); diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php index b9bc0932a84..6ebbf830e70 100644 --- a/apps/files_versions/tests/versions.php +++ b/apps/files_versions/tests/versions.php @@ -51,7 +51,6 @@ class Test_Files_Versioning extends \Test\TestCase { $application = new \OCA\Files_Sharing\AppInfo\Application(); $application->registerMountProviders(); - $application->setupPropagation(); // create test user self::loginHelper(self::TEST_VERSIONS_USER2, true); diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 40477243324..e6110c1925d 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -160,6 +160,7 @@ class Cache { } else { //fix types $data['fileid'] = (int)$data['fileid']; + $data['parent'] = (int)$data['parent']; $data['size'] = 0 + $data['size']; $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; @@ -391,12 +392,17 @@ class Cache { if ($file === '') { return -1; } else { - $parent = dirname($file); - if ($parent === '.') { - $parent = ''; - } - return $this->getId($parent); + $parent = $this->getParentPath($file); + return (int) $this->getId($parent); + } + } + + private function getParentPath($path) { + $parent = dirname($path); + if ($parent === '.') { + $parent = ''; } + return $parent; } /** diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php index 9696a82257e..2a48eb13c59 100644 --- a/lib/private/files/cache/changepropagator.php +++ b/lib/private/files/cache/changepropagator.php @@ -22,6 +22,7 @@ namespace OC\Files\Cache; +use OC\Files\Filesystem; use OC\Hooks\BasicEmitter; /** @@ -61,23 +62,30 @@ class ChangePropagator extends BasicEmitter { * @param int $time (optional) the mtime to set for the folders, if not set the current time is used */ public function propagateChanges($time = null) { - $parents = $this->getAllParents(); - $this->changedFiles = array(); + $changes = $this->getChanges(); + $this->changedFiles = []; if (!$time) { $time = time(); } - foreach ($parents as $parent) { + foreach ($changes as $change) { /** * @var \OC\Files\Storage\Storage $storage * @var string $internalPath */ - list($storage, $internalPath) = $this->view->resolvePath($parent); + $absolutePath = $this->view->getAbsolutePath($change); + $mount = $this->view->getMount($change); + $storage = $mount->getStorage(); + $internalPath = $mount->getInternalPath($absolutePath); if ($storage) { - $cache = $storage->getCache(); - $entry = $cache->get($internalPath); - $cache->update($entry['fileid'], array('mtime' => max($time, $entry['mtime']), 'etag' => $storage->getETag($internalPath))); - $this->emit('\OC\Files', 'propagate', [$parent, $entry]); + $propagator = $storage->getPropagator(); + $propagatedEntries = $propagator->propagateChange($internalPath, $time); + + foreach ($propagatedEntries as $entry) { + $absolutePath = Filesystem::normalizePath($mount->getMountPoint() . '/' . $entry['path']); + $relativePath = $this->view->getRelativePath($absolutePath); + $this->emit('\OC\Files', 'propagate', [$relativePath, $entry]); + } } } } diff --git a/lib/private/files/cache/propagator.php b/lib/private/files/cache/propagator.php new file mode 100644 index 00000000000..bd11cef5990 --- /dev/null +++ b/lib/private/files/cache/propagator.php @@ -0,0 +1,66 @@ +<?php +/** + * @author Robin Appelman <icewind@owncloud.com> + * + * @copyright Copyright (c) 2015, 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 OC\Files\Cache; + +/** + * Propagate etags and mtimes within the storage + */ +class Propagator { + /** + * @var \OC\Files\Storage\Storage + */ + protected $storage; + + /** + * @param \OC\Files\Storage\Storage $storage + */ + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + } + + + /** + * @param string $internalPath + * @param int $time + * @return array[] all propagated entries + */ + public function propagateChange($internalPath, $time) { + $cache = $this->storage->getCache($internalPath); + + $parentId = $cache->getParentId($internalPath); + $propagatedEntries = []; + while ($parentId !== -1) { + $entry = $cache->get($parentId); + $propagatedEntries[] = $entry; + if (!$entry) { + return $propagatedEntries; + } + $mtime = max($time, $entry['mtime']); + + $cache->update($parentId, ['mtime' => $mtime, 'etag' => $this->storage->getETag($entry['path'])]); + + $parentId = $entry['parent']; + } + + return $propagatedEntries; + } +} diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index bb810dd45ed..5b5e8697004 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -62,6 +62,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private $owner; /** + * @var string[] + */ + private $childEtags = []; + + /** * @param string|boolean $path * @param Storage\Storage $storage * @param string $internalPath @@ -93,6 +98,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function offsetGet($offset) { if ($offset === 'type') { return $this->getType(); + } else if ($offset === 'etag') { + return $this->getEtag(); } elseif (isset($this->data[$offset])) { return $this->data[$offset]; } else { @@ -153,7 +160,12 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return string */ public function getEtag() { - return $this->data['etag']; + if (count($this->childEtags) > 0) { + $combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags); + return md5($combinedEtag); + } else { + return $this->data['etag']; + } } /** @@ -285,4 +297,26 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function getOwner() { return $this->owner; } + + /** + * Add a cache entry which is the child of this folder + * + * Sets the size, etag and size to for cross-storage childs + * + * @param array $data cache entry for the child + * @param string $entryPath full path of the child entry + */ + public function addSubEntry($data, $entryPath) { + $this->data['size'] += isset($data['size']) ? $data['size'] : 0; + if (isset($data['mtime'])) { + $this->data['mtime'] = max($this->data['mtime'], $data['mtime']); + } + if (isset($data['etag'])) { + // prefix the etag with the relative path of the subentry to propagate etag on mount moves + $relativeEntryPath = substr($entryPath, strlen($this->getPath())); + // attach the permissions to propagate etag on permision changes of submounts + $permissions = isset($data['permissions']) ? $data['permissions'] : 0; + $this->childEtags[] = $relativeEntryPath . '/' . $data['etag'] . $permissions; + } + } } diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 8e4958a930d..3772b442b59 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -37,6 +37,7 @@ namespace OC\Files\Storage; use OC\Files\Cache\Cache; +use OC\Files\Cache\Propagator; use OC\Files\Cache\Scanner; use OC\Files\Filesystem; use OC\Files\Cache\Watcher; @@ -64,6 +65,7 @@ abstract class Common implements Storage { protected $cache; protected $scanner; protected $watcher; + protected $propagator; protected $storageCache; protected $mountOptions = []; @@ -345,6 +347,22 @@ abstract class Common implements Storage { return $this->watcher; } + /** + * get a propagator instance for the cache + * + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Propagator + */ + public function getPropagator($storage = null) { + if (!$storage) { + $storage = $this; + } + if (!isset($this->propagator)) { + $this->propagator = new Propagator($storage); + } + return $this->propagator; + } + public function getStorageCache($storage = null) { if (!$storage) { $storage = $this; diff --git a/lib/private/files/storage/storage.php b/lib/private/files/storage/storage.php index f46ac544b56..3399c717890 100644 --- a/lib/private/files/storage/storage.php +++ b/lib/private/files/storage/storage.php @@ -68,6 +68,14 @@ interface Storage extends \OCP\Files\Storage { public function getWatcher($path = '', $storage = null); /** + * get a propagator instance for the cache + * + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Propagator + */ + public function getPropagator($storage = null); + + /** * @return \OC\Files\Cache\Storage */ public function getStorageCache(); diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index 048738170db..5327b94211b 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -430,6 +430,13 @@ class Wrapper implements \OC\Files\Storage\Storage { return $this->storage->getWatcher($path, $storage); } + public function getPropagator($storage = null) { + if (!$storage) { + $storage = $this; + } + return $this->storage->getPropagator($storage); + } + /** * @return \OC\Files\Cache\Storage */ diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index 4c328993ef7..585a697c5d1 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -167,7 +167,7 @@ class Encryption extends Wrapper { ) )); - return self::wrapSource($source, $mode, $context, 'ocencryption', $wrapper); + return self::wrapSource($source, $context, 'ocencryption', $wrapper, $mode); } /** @@ -181,7 +181,7 @@ class Encryption extends Wrapper { * @return resource * @throws \BadMethodCallException */ - protected static function wrapSource($source, $mode, $context, $protocol, $class) { + protected static function wrapSource($source, $context, $protocol, $class, $mode = 'r+') { try { stream_wrapper_register($protocol, $class); if (@rewinddir($source) === false) { diff --git a/lib/private/files/view.php b/lib/private/files/view.php index cee4b182425..3ad9d36a384 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -707,10 +707,6 @@ class View { } else if ($result) { if ($internalPath1 !== '') { // dont do a cache update for moved mounts $this->updater->rename($path1, $path2); - } else { // only do etag propagation - $this->getUpdater()->getPropagator()->addChange($path1); - $this->getUpdater()->getPropagator()->addChange($path2); - $this->getUpdater()->getPropagator()->propagateChanges(); } } @@ -1179,6 +1175,48 @@ class View { } /** + * Get file info from cache + * + * If the file is not in cached it will be scanned + * If the file has changed on storage the cache will be updated + * + * @param \OC\Files\Storage\Storage $storage + * @param string $internalPath + * @param string $relativePath + * @return array|bool + */ + private function getCacheEntry($storage, $internalPath, $relativePath) { + $cache = $storage->getCache($internalPath); + $data = $cache->get($internalPath); + $watcher = $storage->getWatcher($internalPath); + + try { + // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data + if (!$data || $data['size'] === -1) { + $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); + if (!$storage->file_exists($internalPath)) { + $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); + return false; + } + $scanner = $storage->getScanner($internalPath); + $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); + $data = $cache->get($internalPath); + $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); + } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) { + $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); + $watcher->update($internalPath, $data); + $this->updater->propagate($relativePath); + $data = $cache->get($internalPath); + $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); + } + } catch (LockedException $e) { + // if the file is locked we just use the old cache info + } + + return $data; + } + + /** * get the filesystem info * * @param string $path @@ -1189,9 +1227,8 @@ class View { */ public function getFileInfo($path, $includeMountPoints = true) { $this->assertPathLength($path); - $data = array(); if (!Filesystem::isValidPath($path)) { - return $data; + return false; } if (Cache\Scanner::isPartialFile($path)) { return $this->getPartFileInfo($path); @@ -1202,48 +1239,27 @@ class View { $mount = Filesystem::getMountManager()->find($path); $storage = $mount->getStorage(); $internalPath = $mount->getInternalPath($path); - $data = null; if ($storage) { - $cache = $storage->getCache($internalPath); + $data = $this->getCacheEntry($storage, $internalPath, $relativePath); - $data = $cache->get($internalPath); - $watcher = $storage->getWatcher($internalPath); + if(!is_array($data)) { + return false; + } - try { - // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data - if (!$data) { - $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); - if (!$storage->file_exists($internalPath)) { - $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); - return false; - } - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - $data = $cache->get($internalPath); - $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); - } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) { - $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); - $watcher->update($internalPath, $data); - $this->updater->propagate($path); - $data = $cache->get($internalPath); - $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); - } - } catch (LockedException $e) { - // if the file is locked we just use the old cache info + if ($mount instanceof MoveableMount && $internalPath === '') { + $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE; } + $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath)); + $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner); + if ($data and isset($data['fileid'])) { - // upgrades from oc6 or lower might not have the permissions set in the file cache - if ($data['permissions'] === 0) { - $data['permissions'] = $storage->getPermissions($data['path']); - $cache->update($data['fileid'], array('permissions' => $data['permissions'])); - } if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') { //add the sizes of other mount points to the folder $extOnly = ($includeMountPoints === 'ext'); - $mountPoints = Filesystem::getMountPoints($path); - foreach ($mountPoints as $mountPoint) { - $subStorage = Filesystem::getStorage($mountPoint); + $mounts = Filesystem::getMountManager()->findIn($path); + foreach ($mounts as $mount) { + $subStorage = $mount->getStorage(); if ($subStorage) { // exclude shared storage ? if ($extOnly && $subStorage instanceof \OC\Files\Storage\Shared) { @@ -1251,22 +1267,16 @@ class View { } $subCache = $subStorage->getCache(''); $rootEntry = $subCache->get(''); - $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0; + $info->addSubEntry($rootEntry, $mount->getMountPoint()); } } } } - } - if (!$data) { - return false; - } - if ($mount instanceof MoveableMount && $internalPath === '') { - $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE; + return $info; } - $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath)); - return new FileInfo($path, $storage, $internalPath, $data, $mount, $owner); + return false; } /** @@ -1278,9 +1288,8 @@ class View { */ public function getDirectoryContent($directory, $mimetype_filter = '') { $this->assertPathLength($directory); - $result = array(); if (!Filesystem::isValidPath($directory)) { - return $result; + return []; } $path = $this->getAbsolutePath($directory); $path = Filesystem::normalizePath($path); @@ -1291,50 +1300,25 @@ class View { $cache = $storage->getCache($internalPath); $user = \OC_User::getUser(); - /** - * @var \OC\Files\FileInfo[] $files - */ - $files = array(); + $data = $this->getCacheEntry($storage, $internalPath, $directory); - $data = $cache->get($internalPath); - $watcher = $storage->getWatcher($internalPath); - try { - if (!$data or $data['size'] === -1) { - $this->lockFile($directory, ILockingProvider::LOCK_SHARED); - if (!$storage->file_exists($internalPath)) { - $this->unlockFile($directory, ILockingProvider::LOCK_SHARED); - return array(); - } - $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); - $data = $cache->get($internalPath); - $this->unlockFile($directory, ILockingProvider::LOCK_SHARED); - } else if ($watcher->needsUpdate($internalPath, $data)) { - $this->lockFile($directory, ILockingProvider::LOCK_SHARED); - $watcher->update($internalPath, $data); - $this->updater->propagate($path); - $data = $cache->get($internalPath); - $this->unlockFile($directory, ILockingProvider::LOCK_SHARED); - } - } catch (LockedException $e) { - // if the file is locked we just use the old cache info + if (!is_array($data) || !isset($data['fileid'])) { + return []; } $folderId = $data['fileid']; $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter - foreach ($contents as $content) { - if ($content['permissions'] === 0) { - $content['permissions'] = $storage->getPermissions($content['path']); - $cache->update($content['fileid'], array('permissions' => $content['permissions'])); - } - // if sharing was disabled for the user we remove the share permissions + /** + * @var \OC\Files\FileInfo[] $files + */ + $files = array_map(function (array $content) use ($path, $storage, $mount) { if (\OCP\Util::isSharingDisabledForUser()) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } $owner = $this->getUserObjectForOwner($storage->getOwner($content['path'])); - $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner); - } + return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner); + }, $contents); //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders $mounts = Filesystem::getMountManager()->findIn($path); @@ -1345,7 +1329,8 @@ class View { if ($subStorage) { $subCache = $subStorage->getCache(''); - if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) { + $rootEntry = $subCache->get(''); + if (!$rootEntry) { $subScanner = $subStorage->getScanner(''); try { $subScanner->scanFile(''); @@ -1363,17 +1348,17 @@ class View { ); continue; } + $rootEntry = $subCache->get(''); } - $rootEntry = $subCache->get(''); if ($rootEntry) { $relativePath = trim(substr($mountPoint, $dirLength), '/'); if ($pos = strpos($relativePath, '/')) { //mountpoint inside subfolder add size to the correct folder $entryName = substr($relativePath, 0, $pos); foreach ($files as &$entry) { - if ($entry['name'] === $entryName) { - $entry['size'] += $rootEntry['size']; + if ($entry->getName() === $entryName) { + $entry->addSubEntry($rootEntry, $mountPoint); } } } else { //mountpoint in this folder, add an entry for it @@ -1410,23 +1395,23 @@ class View { } if ($mimetype_filter) { - foreach ($files as $file) { + $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) { if (strpos($mimetype_filter, '/')) { - if ($file['mimetype'] === $mimetype_filter) { + if ($file->getMimetype() === $mimetype_filter) { $result[] = $file; } } else { - if ($file['mimepart'] === $mimetype_filter) { + if ($file->getMimePart() === $mimetype_filter) { $result[] = $file; } } - } - } else { - $result = $files; + }); } - } - return $result; + return $files; + } else { + return []; + } } /** diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php index 5805e41d411..bc3bc0ce9ed 100644 --- a/lib/private/share20/defaultshareprovider.php +++ b/lib/private/share20/defaultshareprovider.php @@ -23,49 +23,61 @@ namespace OC\Share20; use OC\Share20\Exception\ShareNotFound; use OC\Share20\Exception\BackendError; use OCP\IUser; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\Files\Node; class DefaultShareProvider implements IShareProvider { - /** @var \OCP\IDBConnection */ + /** @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; } /** * Share a path * - * @param Share $share - * @return Share The share object + * @param IShare $share + * @return IShare The share object */ - public function create(Share $share) { - throw new \Exception(); + public function create(IShare $share) { } /** * Update a share * - * @param Share $share - * @return Share The share object + * @param IShare $share + * @return IShare The share object */ - public function update(Share $share) { - throw new \Exception(); + public function update(IShare $share) { } /** @@ -125,7 +137,6 @@ class DefaultShareProvider implements IShareProvider { * @return Share[] */ public function getShares(IUser $user, $shareType, $offset, $limit) { - throw new \Exception(); } /** @@ -163,8 +174,7 @@ class DefaultShareProvider implements IShareProvider { * @param \OCP\Files\Node $path * @return IShare[] */ - public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path) { - throw new \Exception(); + public function getSharesByPath(IUser $user, Node $path) { } /** @@ -175,7 +185,6 @@ class DefaultShareProvider implements IShareProvider { * @param Share */ public function getSharedWithMe(IUser $user, $shareType = null) { - throw new \Exception(); } /** @@ -186,7 +195,6 @@ class DefaultShareProvider implements IShareProvider { * @param Share */ public function getShareByToken($token, $password = null) { - throw new \Exception(); } /** @@ -218,14 +226,14 @@ class DefaultShareProvider implements IShareProvider { $share->setSharedBy($this->userManager->get($data['uid_owner'])); // TODO: getById can return an array. How to handle this properly?? - $path = $this->userFolder->getById((int)$data['file_source']); - $path = $path[0]; - $share->setPath($path); + $folder = $this->rootFolder->getUserFolder($share->getSharedBy()->getUID()); + $path = $folder->getById((int)$data['file_source'])[0]; - $owner = $path->getStorage()->getOwner('.'); - if ($owner !== false) { - $share->setShareOwner($this->userManager->get($owner)); - } + $owner = $path->getOwner(); + $share->setShareOwner($owner); + + $path = $this->rootFolder->getUserFolder($owner->getUID())->getById((int)$data['file_source'])[0]; + $share->setPath($path); if ($data['expiration'] !== null) { $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']); @@ -235,5 +243,4 @@ class DefaultShareProvider implements IShareProvider { return $share; } - -} +}
\ No newline at end of file diff --git a/lib/private/share20/ishare.php b/lib/private/share20/ishare.php index a80abebd71c..2e54da7a029 100644 --- a/lib/private/share20/ishare.php +++ b/lib/private/share20/ishare.php @@ -38,7 +38,7 @@ interface IShare { /** * Set the path of this share * - * @param File|Folder $path + * @param Node $path * @return Share The modified object */ public function setPath(Node $path); diff --git a/lib/private/share20/ishareprovider.php b/lib/private/share20/ishareprovider.php index 833de1b58f6..56a550acf71 100644 --- a/lib/private/share20/ishareprovider.php +++ b/lib/private/share20/ishareprovider.php @@ -29,18 +29,18 @@ interface IShareProvider { /** * Share a path * - * @param Share $share - * @return Share The share object + * @param IShare $share + * @return IShare The share object */ - public function create(Share $share); + public function create(IShare $share); /** * Update a share * - * @param Share $share - * @return Share The share object + * @param IShare $share + * @return IShare The share object */ - public function update(Share $share); + public function update(IShare $share); /** * Delete a share diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php index 57d84967977..882b281c490 100644 --- a/lib/private/share20/manager.php +++ b/lib/private/share20/manager.php @@ -22,11 +22,7 @@ namespace OC\Share20; use OCP\IAppConfig; -use OCP\IUserManager; -use OCP\IGroupManager; -use OCP\IUser; use OCP\ILogger; -use OCP\Files\Folder; use OC\Share20\Exception\ShareNotFound; @@ -40,37 +36,26 @@ class Manager { */ private $defaultProvider; - /** @var IUser */ - private $currentUser; - - /** @var IUserManager */ - private $userManager; - - /** @var IGroupManager */ - private $groupManager; - /** @var ILogger */ private $logger; /** @var IAppConfig */ private $appConfig; - /** @var IFolder */ - private $userFolder; - - public function __construct(IUser $user, - IUserManager $userManager, - IGroupManager $groupManager, - ILogger $logger, - IAppConfig $appConfig, - Folder $userFolder, - IShareProvider $defaultProvider) { - $this->currentUser = $user; - $this->userManager = $userManager; - $this->groupManager = $groupManager; + /** + * Manager constructor. + * + * @param ILogger $logger + * @param IAppConfig $appConfig + * @param IShareProvider $defaultProvider + */ + public function __construct( + ILogger $logger, + IAppConfig $appConfig, + IShareProvider $defaultProvider + ) { $this->logger = $logger; $this->appConfig = $appConfig; - $this->userFolder = $userFolder; // TEMP SOLUTION JUST TO GET STARTED $this->defaultProvider = $defaultProvider; @@ -78,12 +63,11 @@ class Manager { /** * Share a path - * + * * @param Share $share * @return Share The share object */ public function createShare(Share $share) { - throw new \Exception(); } /** @@ -93,7 +77,6 @@ class Manager { * @return Share The share object */ public function updateShare(Share $share) { - throw new \Exception(); } /** @@ -118,7 +101,7 @@ class Manager { /** * Delete a share * - * @param Share $share + * @param IShare $share * @throws ShareNotFound * @throws \OC\Share20\Exception\BackendError */ @@ -126,7 +109,7 @@ class Manager { // Just to make sure we have all the info $share = $this->getShareById($share->getId()); - $formatHookParams = function($share) { + $formatHookParams = function(IShare $share) { // Prepare hook $shareType = $share->getShareType(); $sharedWith = ''; @@ -185,7 +168,6 @@ class Manager { * @return Share[] */ public function getShares($page=0, $perPage=50) { - throw new \Exception(); } /** @@ -203,12 +185,6 @@ class Manager { $share = $this->defaultProvider->getShareById($id); - if ($share->getSharedWith() !== $this->currentUser && - $share->getSharedBy() !== $this->currentUser && - $share->getShareOwner() !== $this->currentUser) { - throw new ShareNotFound(); - } - return $share; } @@ -222,7 +198,6 @@ class Manager { * @return Share[] */ public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) { - throw new \Exception(); } /** @@ -235,7 +210,6 @@ class Manager { * @return Share[] */ public function getSharedWithMe($shareType = null, $page=0, $perPage=50) { - throw new \Exception(); } /** @@ -246,10 +220,9 @@ class Manager { * * @return Share * - * @throws ShareNotFoundException + * @throws ShareNotFound */ public function getShareByToken($token, $password=null) { - throw new \Exception(); } /** @@ -277,6 +250,5 @@ class Manager { * @param \OCP\Files\Node $path */ public function getAccessList(\OCP\Files\Node $path) { - throw new \Exception(); } } diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php index 4200816799e..b7ce38ac61d 100644 --- a/lib/private/share20/share.php +++ b/lib/private/share20/share.php @@ -58,7 +58,7 @@ class Share implements IShare { /** * Set the id of the share * - * @param int id + * @param string $id * @return Share The modified object */ public function setId($id) { @@ -292,7 +292,7 @@ class Share implements IShare { /** * Set the target of this share * - * @param string target + * @param string $target * @return Share The modified object */ public function setTarget($target) { diff --git a/tests/lib/files/cache/changepropagator.php b/tests/lib/files/cache/changepropagator.php index 1b56da5e97c..9108330eb9b 100644 --- a/tests/lib/files/cache/changepropagator.php +++ b/tests/lib/files/cache/changepropagator.php @@ -94,4 +94,37 @@ class ChangePropagator extends \Test\TestCase { $this->assertEquals(100, $time - $cache->get('foo')['mtime']); $this->assertEquals(100, $time - $cache->get('foo/bar')['mtime']); } + + public function testPropagateCrossStorage() { + $storage = new Temporary(); + $this->view->mkdir('/foo'); + Filesystem::mount($storage, [], $this->view->getAbsolutePath('/foo/submount')); + $this->view->mkdir('/foo/submount/bar'); + $this->view->file_put_contents('/foo/submount/bar/sad.txt', 'qwerty'); + + $oldInfo1 = $this->view->getFileInfo('/'); + $oldInfo2 = $this->view->getFileInfo('/foo'); + $oldInfo3 = $this->view->getFileInfo('/foo/submount'); + $oldInfo4 = $this->view->getFileInfo('/foo/submount/bar'); + + $time = time() + 50; + + $this->propagator->addChange('/foo/submount/bar/sad.txt'); + $this->propagator->propagateChanges($time); + + $newInfo1 = $this->view->getFileInfo('/'); + $newInfo2 = $this->view->getFileInfo('/foo'); + $newInfo3 = $this->view->getFileInfo('/foo/submount'); + $newInfo4 = $this->view->getFileInfo('/foo/submount/bar'); + + $this->assertEquals($newInfo1->getMTime(), $time); + $this->assertEquals($newInfo2->getMTime(), $time); + $this->assertEquals($newInfo3->getMTime(), $time); + $this->assertEquals($newInfo4->getMTime(), $time); + + $this->assertNotSame($oldInfo1->getEtag(), $newInfo1->getEtag()); + $this->assertNotSame($oldInfo2->getEtag(), $newInfo2->getEtag()); + $this->assertNotSame($oldInfo3->getEtag(), $newInfo3->getEtag()); + $this->assertNotSame($oldInfo4->getEtag(), $newInfo3->getEtag()); + } } diff --git a/tests/lib/files/cache/updaterlegacy.php b/tests/lib/files/cache/updaterlegacy.php index f4d52e9a390..c1a0d3d8230 100644 --- a/tests/lib/files/cache/updaterlegacy.php +++ b/tests/lib/files/cache/updaterlegacy.php @@ -10,6 +10,7 @@ namespace Test\Files\Cache; use \OC\Files\Filesystem as Filesystem; use OC\Files\Storage\Temporary; +use OC\Files\View; class UpdaterLegacy extends \Test\TestCase { /** @@ -111,7 +112,8 @@ class UpdaterLegacy extends \Test\TestCase { $storage2->getScanner()->scan(''); //initialize etags $cache2 = $storage2->getCache(); Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage'); - $folderCachedData = $this->cache->get('folder'); + $view = new View('/' . self::$user . '/files'); + $folderCachedData = $view->getFileInfo('folder'); $substorageCachedData = $cache2->get(''); Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd'); $this->assertTrue($cache2->inCache('foo.txt')); @@ -124,7 +126,7 @@ class UpdaterLegacy extends \Test\TestCase { $this->assertInternalType('string', $cachedData['etag']); $this->assertNotSame($substorageCachedData['etag'], $cachedData['etag']); - $cachedData = $this->cache->get('folder'); + $cachedData = $view->getFileInfo('folder'); $this->assertInternalType('string', $folderCachedData['etag']); $this->assertInternalType('string', $cachedData['etag']); $this->assertNotSame($folderCachedData['etag'], $cachedData['etag']); @@ -168,8 +170,9 @@ class UpdaterLegacy extends \Test\TestCase { $cache2 = $storage2->getCache(); Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage'); Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd'); + $view = new View('/' . self::$user . '/files'); $this->assertTrue($cache2->inCache('foo.txt')); - $folderCachedData = $this->cache->get('folder'); + $folderCachedData = $view->getFileInfo('folder'); $substorageCachedData = $cache2->get(''); Filesystem::unlink('folder/substorage/foo.txt'); $this->assertFalse($cache2->inCache('foo.txt')); @@ -180,7 +183,7 @@ class UpdaterLegacy extends \Test\TestCase { $this->assertNotSame($substorageCachedData['etag'], $cachedData['etag']); $this->assertGreaterThanOrEqual($substorageCachedData['mtime'], $cachedData['mtime']); - $cachedData = $this->cache->get('folder'); + $cachedData = $view->getFileInfo('folder'); $this->assertInternalType('string', $folderCachedData['etag']); $this->assertInternalType('string', $cachedData['etag']); $this->assertNotSame($folderCachedData['etag'], $cachedData['etag']); @@ -222,8 +225,9 @@ class UpdaterLegacy extends \Test\TestCase { $cache2 = $storage2->getCache(); Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage'); Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd'); + $view = new View('/' . self::$user . '/files'); $this->assertTrue($cache2->inCache('foo.txt')); - $folderCachedData = $this->cache->get('folder'); + $folderCachedData = $view->getFileInfo('folder'); $substorageCachedData = $cache2->get(''); $fooCachedData = $cache2->get('foo.txt'); Filesystem::rename('folder/substorage/foo.txt', 'folder/substorage/bar.txt'); @@ -240,7 +244,7 @@ class UpdaterLegacy extends \Test\TestCase { // rename can cause mtime change - invalid assert // $this->assertEquals($mtime, $cachedData['mtime']); - $cachedData = $this->cache->get('folder'); + $cachedData = $view->getFileInfo('folder'); $this->assertInternalType('string', $folderCachedData['etag']); $this->assertInternalType('string', $cachedData['etag']); $this->assertNotSame($folderCachedData['etag'], $cachedData['etag']); @@ -287,35 +291,4 @@ class UpdaterLegacy extends \Test\TestCase { $this->assertEquals($time, $cachedData['mtime']); } - public function testTouchWithMountPoints() { - $storage2 = new \OC\Files\Storage\Temporary(array()); - $cache2 = $storage2->getCache(); - Filesystem::mount($storage2, array(), '/' . self::$user . '/files/folder/substorage'); - Filesystem::file_put_contents('folder/substorage/foo.txt', 'asd'); - $this->assertTrue($cache2->inCache('foo.txt')); - $folderCachedData = $this->cache->get('folder'); - $substorageCachedData = $cache2->get(''); - $fooCachedData = $cache2->get('foo.txt'); - $cachedData = $cache2->get('foo.txt'); - $time = 1371006070; - $this->cache->put('folder', ['mtime' => $time - 100]); - Filesystem::touch('folder/substorage/foo.txt', $time); - $cachedData = $cache2->get('foo.txt'); - $this->assertInternalType('string', $fooCachedData['etag']); - $this->assertInternalType('string', $cachedData['etag']); - $this->assertNotSame($fooCachedData['etag'], $cachedData['etag']); - $this->assertEquals($time, $cachedData['mtime']); - - $cachedData = $cache2->get(''); - $this->assertInternalType('string', $substorageCachedData['etag']); - $this->assertInternalType('string', $cachedData['etag']); - $this->assertNotSame($substorageCachedData['etag'], $cachedData['etag']); - - $cachedData = $this->cache->get('folder'); - $this->assertInternalType('string', $folderCachedData['etag']); - $this->assertInternalType('string', $cachedData['etag']); - $this->assertNotSame($folderCachedData['etag'], $cachedData['etag']); - $this->assertEquals($time, $cachedData['mtime']); - } - } diff --git a/tests/lib/files/etagtest.php b/tests/lib/files/etagtest.php index 1a11b29cf00..192768d04af 100644 --- a/tests/lib/files/etagtest.php +++ b/tests/lib/files/etagtest.php @@ -27,7 +27,6 @@ class EtagTest extends \Test\TestCase { \OC_Hook::clear('OC_Filesystem', 'setup'); $application = new \OCA\Files_Sharing\AppInfo\Application(); $application->registerMountProviders(); - $application->setupPropagation(); \OCP\Share::registerBackend('file', 'OC_Share_Backend_File'); \OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file'); diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php index 4c0b5523947..dc45bc7c085 100644 --- a/tests/lib/share20/defaultshareprovidertest.php +++ b/tests/lib/share20/defaultshareprovidertest.php @@ -23,7 +23,7 @@ namespace Test\Share20; use OCP\IDBConnection; use OCP\IUserManager; use OCP\IGroupManager; -use OCP\Files\Folder; +use OCP\Files\IRootFolder; use OC\Share20\DefaultShareProvider; class DefaultShareProviderTest extends \Test\TestCase { @@ -37,8 +37,8 @@ class DefaultShareProviderTest extends \Test\TestCase { /** @var IGroupManager */ protected $groupManager; - /** @var Folder */ - protected $userFolder; + /** @var IRootFolder */ + protected $rootFolder; /** @var DefaultShareProvider */ protected $provider; @@ -47,7 +47,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->dbConn = \OC::$server->getDatabaseConnection(); $this->userManager = $this->getMock('OCP\IUserManager'); $this->groupManager = $this->getMock('OCP\IGroupManager'); - $this->userFolder = $this->getMock('OCP\Files\Folder'); + $this->rootFolder = $this->getMock('OCP\Files\IRootFolder'); //Empty share table $this->dbConn->getQueryBuilder()->delete('share')->execute(); @@ -56,7 +56,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->dbConn, $this->userManager, $this->groupManager, - $this->userFolder + $this->rootFolder ); } @@ -65,7 +65,7 @@ class DefaultShareProviderTest extends \Test\TestCase { } /** - * @expectedException OC\Share20\Exception\ShareNotFound + * @expectedException \OC\Share20\Exception\ShareNotFound */ public function testGetShareByIdNotExist() { $this->provider->getShareById(1); @@ -97,25 +97,30 @@ class DefaultShareProviderTest extends \Test\TestCase { $id = $id['id']; $cursor->closeCursor(); - $storage = $this->getMock('OC\Files\Storage\Storage'); - $storage - ->expects($this->once()) - ->method('getOwner') - ->willReturn('shareOwner'); - $path = $this->getMock('OCP\Files\File'); - $path - ->expects($this->once()) - ->method('getStorage') - ->wilLReturn($storage); - $this->userFolder - ->expects($this->once()) - ->method('getById') - ->with(42) - ->willReturn([$path]); - $sharedWith = $this->getMock('OCP\IUser'); $sharedBy = $this->getMock('OCP\IUser'); + $sharedBy->method('getUID')->willReturn('sharedBy'); $shareOwner = $this->getMock('OCP\IUser'); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $sharedByPath = $this->getMock('\OCP\Files\File'); + $ownerPath = $this->getMock('\OCP\Files\File'); + + $sharedByPath->method('getOwner')->willReturn($shareOwner); + + $sharedByFolder = $this->getMock('\OCP\Files\Folder'); + $sharedByFolder->method('getById')->with(42)->willReturn([$sharedByPath]); + + $shareOwnerFolder = $this->getMock('\OCP\Files\Folder'); + $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]); + + $this->rootFolder + ->method('getUserFolder') + ->will($this->returnValueMap([ + ['sharedBy', $sharedByFolder], + ['shareOwner', $shareOwnerFolder], + ])); + $this->userManager ->method('get') ->will($this->returnValueMap([ @@ -131,7 +136,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEquals($sharedWith, $share->getSharedWith()); $this->assertEquals($sharedBy, $share->getSharedBy()); $this->assertEquals($shareOwner, $share->getShareOwner()); - $this->assertEquals($path, $share->getPath()); + $this->assertEquals($ownerPath, $share->getPath()); $this->assertEquals(13, $share->getPermissions()); $this->assertEquals(null, $share->getToken()); $this->assertEquals(null, $share->getExpirationDate()); @@ -164,25 +169,30 @@ class DefaultShareProviderTest extends \Test\TestCase { $id = $id['id']; $cursor->closeCursor(); - $storage = $this->getMock('OC\Files\Storage\Storage'); - $storage - ->expects($this->once()) - ->method('getOwner') - ->willReturn('shareOwner'); - $path = $this->getMock('OCP\Files\Folder'); - $path - ->expects($this->once()) - ->method('getStorage') - ->wilLReturn($storage); - $this->userFolder - ->expects($this->once()) - ->method('getById') - ->with(42) - ->willReturn([$path]); - $sharedWith = $this->getMock('OCP\IGroup'); $sharedBy = $this->getMock('OCP\IUser'); + $sharedBy->method('getUID')->willReturn('sharedBy'); $shareOwner = $this->getMock('OCP\IUser'); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $sharedByPath = $this->getMock('\OCP\Files\Folder'); + $ownerPath = $this->getMock('\OCP\Files\Folder'); + + $sharedByPath->method('getOwner')->willReturn($shareOwner); + + $sharedByFolder = $this->getMock('\OCP\Files\Folder'); + $sharedByFolder->method('getById')->with(42)->willReturn([$sharedByPath]); + + $shareOwnerFolder = $this->getMock('\OCP\Files\Folder'); + $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]); + + $this->rootFolder + ->method('getUserFolder') + ->will($this->returnValueMap([ + ['sharedBy', $sharedByFolder], + ['shareOwner', $shareOwnerFolder], + ])); + $this->userManager ->method('get') ->will($this->returnValueMap([ @@ -202,7 +212,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEquals($sharedWith, $share->getSharedWith()); $this->assertEquals($sharedBy, $share->getSharedBy()); $this->assertEquals($shareOwner, $share->getShareOwner()); - $this->assertEquals($path, $share->getPath()); + $this->assertEquals($ownerPath, $share->getPath()); $this->assertEquals(13, $share->getPermissions()); $this->assertEquals(null, $share->getToken()); $this->assertEquals(null, $share->getExpirationDate()); @@ -237,90 +247,29 @@ class DefaultShareProviderTest extends \Test\TestCase { $id = $id['id']; $cursor->closeCursor(); - $storage = $this->getMock('OC\Files\Storage\Storage'); - $storage - ->expects($this->once()) - ->method('getOwner') - ->willReturn('shareOwner'); - $path = $this->getMock('OCP\Files\Node'); - $path - ->expects($this->once()) - ->method('getStorage') - ->wilLReturn($storage); - $this->userFolder - ->expects($this->once()) - ->method('getById') - ->with(42) - ->willReturn([$path]); - $sharedBy = $this->getMock('OCP\IUser'); + $sharedBy->method('getUID')->willReturn('sharedBy'); $shareOwner = $this->getMock('OCP\IUser'); - $this->userManager - ->method('get') - ->will($this->returnValueMap([ - ['sharedBy', $sharedBy], - ['shareOwner', $shareOwner], - ])); - - $share = $this->provider->getShareById($id); - - $this->assertEquals($id, $share->getId()); - $this->assertEquals(\OCP\Share::SHARE_TYPE_LINK, $share->getShareType()); - $this->assertEquals('sharedWith', $share->getPassword()); - $this->assertEquals($sharedBy, $share->getSharedBy()); - $this->assertEquals($shareOwner, $share->getShareOwner()); - $this->assertEquals($path, $share->getPath()); - $this->assertEquals(13, $share->getPermissions()); - $this->assertEquals('token', $share->getToken()); - $this->assertEquals(\DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-02 00:00:00'), $share->getExpirationDate()); - $this->assertEquals('myTarget', $share->getTarget()); - } + $shareOwner->method('getUID')->willReturn('shareOwner'); - public function testGetShareByIdRemoteShare() { - $qb = $this->dbConn->getQueryBuilder(); + $sharedByPath = $this->getMock('\OCP\Files\Folder'); + $ownerPath = $this->getMock('\OCP\Files\Folder'); - $qb->insert('share') - ->values([ - 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_REMOTE), - 'share_with' => $qb->expr()->literal('sharedWith'), - 'uid_owner' => $qb->expr()->literal('sharedBy'), - 'item_type' => $qb->expr()->literal('file'), - 'file_source' => $qb->expr()->literal(42), - 'file_target' => $qb->expr()->literal('myTarget'), - 'permissions' => $qb->expr()->literal(13), - ]); - $this->assertEquals(1, $qb->execute()); + $sharedByPath->method('getOwner')->willReturn($shareOwner); - // Get the id - $qb = $this->dbConn->getQueryBuilder(); - $cursor = $qb->select('id') - ->from('share') - ->setMaxResults(1) - ->orderBy('id', 'DESC') - ->execute(); - $id = $cursor->fetch(); - $id = $id['id']; - $cursor->closeCursor(); + $sharedByFolder = $this->getMock('\OCP\Files\Folder'); + $sharedByFolder->method('getById')->with(42)->willReturn([$sharedByPath]); + $shareOwnerFolder = $this->getMock('\OCP\Files\Folder'); + $shareOwnerFolder->method('getById')->with(42)->willReturn([$ownerPath]); - $storage = $this->getMock('OC\Files\Storage\Storage'); - $storage - ->expects($this->once()) - ->method('getOwner') - ->willReturn('shareOwner'); - $path = $this->getMock('OCP\Files\Node'); - $path - ->expects($this->once()) - ->method('getStorage') - ->wilLReturn($storage); - $this->userFolder - ->expects($this->once()) - ->method('getById') - ->with(42) - ->willReturn([$path]); + $this->rootFolder + ->method('getUserFolder') + ->will($this->returnValueMap([ + ['sharedBy', $sharedByFolder], + ['shareOwner', $shareOwnerFolder], + ])); - $sharedBy = $this->getMock('OCP\IUser'); - $shareOwner = $this->getMock('OCP\IUser'); $this->userManager ->method('get') ->will($this->returnValueMap([ @@ -331,14 +280,14 @@ class DefaultShareProviderTest extends \Test\TestCase { $share = $this->provider->getShareById($id); $this->assertEquals($id, $share->getId()); - $this->assertEquals(\OCP\Share::SHARE_TYPE_REMOTE, $share->getShareType()); - $this->assertEquals('sharedWith', $share->getSharedWith()); + $this->assertEquals(\OCP\Share::SHARE_TYPE_LINK, $share->getShareType()); + $this->assertEquals('sharedWith', $share->getPassword()); $this->assertEquals($sharedBy, $share->getSharedBy()); $this->assertEquals($shareOwner, $share->getShareOwner()); - $this->assertEquals($path, $share->getPath()); + $this->assertEquals($ownerPath, $share->getPath()); $this->assertEquals(13, $share->getPermissions()); - $this->assertEquals(null, $share->getToken()); - $this->assertEquals(null, $share->getExpirationDate()); + $this->assertEquals('token', $share->getToken()); + $this->assertEquals(\DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-02 00:00:00'), $share->getExpirationDate()); $this->assertEquals('myTarget', $share->getTarget()); } @@ -376,7 +325,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->dbConn, $this->userManager, $this->groupManager, - $this->userFolder, + $this->rootFolder, ] ) ->setMethods(['getShareById']) @@ -437,7 +386,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $db, $this->userManager, $this->groupManager, - $this->userFolder, + $this->rootFolder, ] ) ->setMethods(['getShareById']) @@ -504,30 +453,45 @@ class DefaultShareProviderTest extends \Test\TestCase { ]); $qb->execute(); + $shareOwner = $this->getMock('OCP\IUser'); + $shareOwner->method('getUID')->willReturn('shareOwner'); + $user1 = $this->getMock('OCP\IUser'); + $user2 = $this->getMock('OCP\IUser'); + $user2->method('getUID')->willReturn('user2'); + $user3 = $this->getMock('OCP\IUser'); + $user3->method('getUID')->willReturn('user3'); + + $user2Path = $this->getMock('\OCP\Files\File'); + $user2Path->expects($this->once())->method('getOwner')->willReturn($shareOwner); + $user2Folder = $this->getMock('\OCP\Files\Folder'); + $user2Folder->expects($this->once()) + ->method('getById') + ->with(1) + ->willReturn([$user2Path]); - $storage = $this->getMock('OC\Files\Storage\Storage'); - $storage - ->method('getOwner') - ->willReturn('shareOwner'); - $path1 = $this->getMock('OCP\Files\File'); - $path1->expects($this->once())->method('getStorage')->willReturn($storage); - $path2 = $this->getMock('OCP\Files\Folder'); - $path2->expects($this->once())->method('getStorage')->willReturn($storage); - $this->userFolder + $user3Path = $this->getMock('\OCP\Files\Folder'); + $user3Path->expects($this->once())->method('getOwner')->willReturn($shareOwner); + $user3Folder = $this->getMock('\OCP\Files\Folder'); + $user3Folder->expects($this->once()) ->method('getById') + ->with(3) + ->willReturn([$user3Path]); + + $ownerPath = $this->getMock('\OCP\Files\Folder'); + $ownerFolder = $this->getMock('\OCP\Files\Folder'); + $ownerFolder->method('getById')->willReturn([$ownerPath]); + + $this->rootFolder + ->method('getUserFolder') ->will($this->returnValueMap([ - [1, [$path1]], - [3, [$path2]], + ['shareOwner', $ownerFolder], + ['user2', $user2Folder], + ['user3', $user3Folder], ])); - $shareOwner = $this->getMock('OCP\IUser'); - $user1 = $this->getMock('OCP\IUser'); - $user2 = $this->getMock('OCP\IUser'); - $user3 = $this->getMock('OCP\IUser'); $this->userManager ->method('get') ->will($this->returnValueMap([ - ['shareOwner', $shareOwner], ['user1', $user1], ['user2', $user2], ['user3', $user3], @@ -552,7 +516,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEquals($user1, $children[0]->getSharedWith()); $this->assertEquals($user2, $children[0]->getSharedBy()); $this->assertEquals($shareOwner, $children[0]->getShareOwner()); - $this->assertEquals($path1, $children[0]->getPath()); + $this->assertEquals($ownerPath, $children[0]->getPath()); $this->assertEquals(2, $children[0]->getPermissions()); $this->assertEquals(null, $children[0]->getToken()); $this->assertEquals(null, $children[0]->getExpirationDate()); @@ -563,7 +527,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEquals($group1, $children[1]->getSharedWith()); $this->assertEquals($user3, $children[1]->getSharedBy()); $this->assertEquals($shareOwner, $children[1]->getShareOwner()); - $this->assertEquals($path2, $children[1]->getPath()); + $this->assertEquals($ownerPath, $children[1]->getPath()); $this->assertEquals(4, $children[1]->getPermissions()); $this->assertEquals(null, $children[1]->getToken()); $this->assertEquals(null, $children[1]->getExpirationDate()); diff --git a/tests/lib/share20/managertest.php b/tests/lib/share20/managertest.php index 54be9033567..e4d0bfad584 100644 --- a/tests/lib/share20/managertest.php +++ b/tests/lib/share20/managertest.php @@ -23,64 +23,39 @@ namespace Test\Share20; use OC\Share20\Manager; use OC\Share20\Exception; - -use OCP\IUser; -use OCP\IUserManager; -use OCP\IGroupManager; use OCP\ILogger; use OCP\IAppConfig; -use OCP\Files\Folder; -use OCP\Share20\IShareProvider; +use OC\Share20\IShareProvider; class ManagerTest extends \Test\TestCase { /** @var Manager */ protected $manager; - /** @var IUser */ - protected $user; - - /** @var IUserManager */ - protected $userManager; - - /** @var IGroupManager */ - protected $groupManager; - /** @var ILogger */ protected $logger; /** @var IAppConfig */ protected $appConfig; - /** @var Folder */ - protected $userFolder; - /** @var IShareProvider */ protected $defaultProvider; public function setUp() { - $this->user = $this->getMock('\OCP\IUser'); - $this->userManager = $this->getMock('\OCP\IUserManager'); - $this->groupManager = $this->getMock('\OCP\IGroupManager'); $this->logger = $this->getMock('\OCP\ILogger'); $this->appConfig = $this->getMock('\OCP\IAppConfig'); - $this->userFolder = $this->getMock('\OCP\Files\Folder'); $this->defaultProvider = $this->getMock('\OC\Share20\IShareProvider'); $this->manager = new Manager( - $this->user, - $this->userManager, - $this->groupManager, $this->logger, $this->appConfig, - $this->userFolder, $this->defaultProvider ); } /** - * @expectedException OC\Share20\Exception\ShareNotFound + * @expectedException \OC\Share20\Exception\ShareNotFound */ public function testDeleteNoShareId() { $share = $this->getMock('\OC\Share20\IShare'); @@ -115,12 +90,8 @@ class ManagerTest extends \Test\TestCase { public function testDelete($shareType, $sharedWith, $sharedWith_string) { $manager = $this->getMockBuilder('\OC\Share20\Manager') ->setConstructorArgs([ - $this->user, - $this->userManager, - $this->groupManager, $this->logger, $this->appConfig, - $this->userFolder, $this->defaultProvider ]) ->setMethods(['getShareById', 'deleteChildren']) @@ -205,12 +176,8 @@ class ManagerTest extends \Test\TestCase { public function testDeleteNested() { $manager = $this->getMockBuilder('\OC\Share20\Manager') ->setConstructorArgs([ - $this->user, - $this->userManager, - $this->groupManager, $this->logger, $this->appConfig, - $this->userFolder, $this->defaultProvider ]) ->setMethods(['getShareById']) @@ -349,12 +316,8 @@ class ManagerTest extends \Test\TestCase { public function testDeleteChildren() { $manager = $this->getMockBuilder('\OC\Share20\Manager') ->setConstructorArgs([ - $this->user, - $this->userManager, - $this->groupManager, $this->logger, $this->appConfig, - $this->userFolder, $this->defaultProvider ]) ->setMethods(['deleteShare']) @@ -391,82 +354,8 @@ class ManagerTest extends \Test\TestCase { $this->assertSame($shares, $result); } - /** - * @expectedException OC\Share20\Exception\ShareNotFound - */ - public function testGetShareByIdNotFoundInBackend() { - $this->defaultProvider - ->expects($this->once()) - ->method('getShareById') - ->with(42) - ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound())); - - $this->manager->getShareById(42); - } - - /** - * @expectedException OC\Share20\Exception\ShareNotFound - */ - public function testGetShareByIdNotAuthorized() { - $otherUser1 = $this->getMock('\OCP\IUser'); - $otherUser2 = $this->getMock('\OCP\IUser'); - $otherUser3 = $this->getMock('\OCP\IUser'); - + public function testGetShareById() { $share = $this->getMock('\OC\Share20\IShare'); - $share - ->expects($this->once()) - ->method('getSharedWith') - ->with() - ->willReturn($otherUser1); - $share - ->expects($this->once()) - ->method('getSharedBy') - ->with() - ->willReturn($otherUser2); - $share - ->expects($this->once()) - ->method('getShareOwner') - ->with() - ->willReturn($otherUser3); - - $this->defaultProvider - ->expects($this->once()) - ->method('getShareById') - ->with(42) - ->willReturn($share); - - $this->manager->getShareById(42); - } - - public function dataGetShareById() { - return [ - ['getSharedWith'], - ['getSharedBy'], - ['getShareOwner'], - ]; - } - - /** - * @dataProvider dataGetShareById - */ - public function testGetShareById($currentUserIs) { - $otherUser1 = $this->getMock('\OCP\IUser'); - $otherUser2 = $this->getMock('\OCP\IUser'); - $otherUser3 = $this->getMock('\OCP\IUser'); - - $share = $this->getMock('\OC\Share20\IShare'); - $share - ->method('getSharedWith') - ->with() - ->willReturn($currentUserIs === 'getSharedWith' ? $this->user : $otherUser1); - $share - ->method('getSharedBy') - ->with() - ->willReturn($currentUserIs === 'getSharedBy' ? $this->user : $otherUser2); - $share - ->method('getShareOwner') - ->with() - ->willReturn($currentUserIs === 'getShareOwner' ? $this->user : $otherUser3); $this->defaultProvider ->expects($this->once()) |