diff options
author | Carl Schwan <carl@carlschwan.eu> | 2022-07-15 17:11:54 +0200 |
---|---|---|
committer | Carl Schwan <carl@carlschwan.eu> | 2022-07-31 19:37:59 +0200 |
commit | 7b723813cef60e744ab14ab418c82e5ec67a9f2e (patch) | |
tree | eda4a044c9defc883c35d98e1ba5a9e261a3ecdf /apps | |
parent | ab1a20522b1b2730398869a764f672175a1abcb8 (diff) | |
download | nextcloud-server-7b723813cef60e744ab14ab418c82e5ec67a9f2e.tar.gz nextcloud-server-7b723813cef60e744ab14ab418c82e5ec67a9f2e.zip |
Multiple fixes
- Fix tests
- Use non deprecated event stuff
- Add a bit of type hinting to the new stuff
- More safe handling of instanceOfStorage (share might not be the first
wrapper)
- Fix resharing
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
Diffstat (limited to 'apps')
-rw-r--r-- | apps/dav/lib/Connector/Sabre/Node.php | 10 | ||||
-rw-r--r-- | apps/dav/lib/Controller/DirectController.php | 7 | ||||
-rw-r--r-- | apps/dav/lib/DAV/ViewOnlyPlugin.php | 38 | ||||
-rw-r--r-- | apps/dav/tests/unit/Controller/DirectControllerTest.php | 26 | ||||
-rw-r--r-- | apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php | 11 | ||||
-rw-r--r-- | apps/files_sharing/lib/AppInfo/Application.php | 53 | ||||
-rw-r--r-- | apps/files_sharing/lib/Controller/PublicPreviewController.php | 2 | ||||
-rw-r--r-- | apps/files_sharing/lib/Controller/ShareAPIController.php | 67 | ||||
-rw-r--r-- | apps/files_sharing/lib/MountProvider.php | 5 | ||||
-rw-r--r-- | apps/files_sharing/src/components/SharingEntry.vue | 33 | ||||
-rw-r--r-- | apps/files_sharing/src/components/SharingEntryLink.vue | 9 | ||||
-rw-r--r-- | apps/files_sharing/tests/ApplicationTest.php | 47 | ||||
-rw-r--r-- | apps/files_sharing/tests/Controller/ShareAPIControllerTest.php | 187 |
13 files changed, 326 insertions, 169 deletions
diff --git a/apps/dav/lib/Connector/Sabre/Node.php b/apps/dav/lib/Connector/Sabre/Node.php index a55a799a81f..87f2fea394f 100644 --- a/apps/dav/lib/Connector/Sabre/Node.php +++ b/apps/dav/lib/Connector/Sabre/Node.php @@ -38,6 +38,7 @@ namespace OCA\DAV\Connector\Sabre; use OC\Files\Mount\MoveableMount; use OC\Files\Node\File; use OC\Files\Node\Folder; +use OC\Files\Storage\Wrapper\Wrapper; use OC\Files\View; use OCA\DAV\Connector\Sabre\Exception\InvalidPath; use OCP\Files\FileInfo; @@ -334,9 +335,14 @@ abstract class Node implements \Sabre\DAV\INode { $storage = null; } - if ($storage && $storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { + if ($storage && $storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) { /** @var \OCA\Files_Sharing\SharedStorage $storage */ - $attributes = $storage->getShare()->getAttributes()->toArray(); + $attributes = $storage->getShare()->getAttributes(); + if ($attributes === null) { + return []; + } else { + return $attributes->toArray(); + } } return $attributes; diff --git a/apps/dav/lib/Controller/DirectController.php b/apps/dav/lib/Controller/DirectController.php index 260ef3bae04..f9c83488935 100644 --- a/apps/dav/lib/Controller/DirectController.php +++ b/apps/dav/lib/Controller/DirectController.php @@ -36,6 +36,7 @@ use OCP\AppFramework\OCSController; use OCP\AppFramework\Utility\ITimeFactory; use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Events\BeforeDirectFileDownloadEvent; use OCP\Files\File; use OCP\Files\IRootFolder; use OCP\IRequest; @@ -106,10 +107,10 @@ class DirectController extends OCSController { throw new OCSBadRequestException('Direct download only works for files'); } - $event = new GenericEvent(null, ['path' => $userFolder->getRelativePath($file->getPath())]); - $this->eventDispatcher->dispatch('file.beforeGetDirect', $event); + $event = new BeforeDirectFileDownloadEvent($userFolder->getRelativePath($file->getPath())); + $this->eventDispatcher->dispatchTyped($event); - if ($event->getArgument('run') === false) { + if ($event->isSuccessful() === false) { throw new OCSForbiddenException('Permission denied to download file'); } diff --git a/apps/dav/lib/DAV/ViewOnlyPlugin.php b/apps/dav/lib/DAV/ViewOnlyPlugin.php index 17b0823b7d7..1504969b5b4 100644 --- a/apps/dav/lib/DAV/ViewOnlyPlugin.php +++ b/apps/dav/lib/DAV/ViewOnlyPlugin.php @@ -37,18 +37,11 @@ use Sabre\DAV\Exception\NotFound; */ class ViewOnlyPlugin extends ServerPlugin { - /** @var Server $server */ - private $server; + private ?Server $server = null; + private LoggerInterface $logger; - /** @var LoggerInterface $logger */ - private $logger; - - /** - * @param LoggerInterface $logger - */ public function __construct(LoggerInterface $logger) { $this->logger = $logger; - $this->server = null; } /** @@ -58,11 +51,8 @@ class ViewOnlyPlugin extends ServerPlugin { * addPlugin is called. * * This method should set up the required event subscriptions. - * - * @param Server $server - * @return void */ - public function initialize(Server $server) { + public function initialize(Server $server): void { $this->server = $server; //priority 90 to make sure the plugin is called before //Sabre\DAV\CorePlugin::httpGet @@ -73,17 +63,14 @@ class ViewOnlyPlugin extends ServerPlugin { * Disallow download via DAV Api in case file being received share * and having special permission * - * @param RequestInterface $request request object - * @return boolean * @throws Forbidden * @throws NotFoundException */ - public function checkViewOnly( - RequestInterface $request - ) { + public function checkViewOnly(RequestInterface $request): bool { $path = $request->getPath(); try { + assert($this->server !== null); $davNode = $this->server->tree->getNodeForPath($path); if (!($davNode instanceof DavFile)) { return true; @@ -92,21 +79,28 @@ class ViewOnlyPlugin extends ServerPlugin { $node = $davNode->getNode(); $storage = $node->getStorage(); - // using string as we have no guarantee that "files_sharing" app is loaded - if (!$storage->instanceOfStorage('OCA\Files_Sharing\SharedStorage')) { + + if (!$storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) { return true; } // Extract extra permissions /** @var \OCA\Files_Sharing\SharedStorage $storage */ $share = $storage->getShare(); + $attributes = $share->getAttributes(); + if ($attributes === null) { + return true; + } + // Check if read-only and on whether permission can download is both set and disabled. - $canDownload = $share->getAttributes()->getAttribute('permissions', 'download'); + $canDownload = $attributes->getAttribute('permissions', 'download'); if ($canDownload !== null && !$canDownload) { throw new Forbidden('Access to this resource has been denied because it is in view-only mode.'); } } catch (NotFound $e) { - $this->logger->warning($e->getMessage()); + $this->logger->warning($e->getMessage(), [ + 'exception' => $e, + ]); } return true; diff --git a/apps/dav/tests/unit/Controller/DirectControllerTest.php b/apps/dav/tests/unit/Controller/DirectControllerTest.php index 00771e7f7a6..fe6d4ea8f24 100644 --- a/apps/dav/tests/unit/Controller/DirectControllerTest.php +++ b/apps/dav/tests/unit/Controller/DirectControllerTest.php @@ -34,11 +34,12 @@ use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\IRequest; -use OCP\IURLGenerator; +use OCP\IUrlGenerator; use OCP\Security\ISecureRandom; use Test\TestCase; @@ -56,11 +57,13 @@ class DirectControllerTest extends TestCase { /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ private $timeFactory; - /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUrlGenerator|\PHPUnit\Framework\MockObject\MockObject */ private $urlGenerator; - /** @var DirectController */ - private $controller; + /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ + private $eventDispatcher; + + private DirectController $controller; protected function setUp(): void { parent::setUp(); @@ -69,7 +72,8 @@ class DirectControllerTest extends TestCase { $this->directMapper = $this->createMock(DirectMapper::class); $this->random = $this->createMock(ISecureRandom::class); $this->timeFactory = $this->createMock(ITimeFactory::class); - $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->urlGenerator = $this->createMock(IUrlGenerator::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->controller = new DirectController( 'dav', @@ -79,11 +83,12 @@ class DirectControllerTest extends TestCase { $this->directMapper, $this->random, $this->timeFactory, - $this->urlGenerator + $this->urlGenerator, + $this->eventDispatcher ); } - public function testGetUrlNonExistingFileId() { + public function testGetUrlNonExistingFileId(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with('awesomeUser') @@ -97,7 +102,7 @@ class DirectControllerTest extends TestCase { $this->controller->getUrl(101); } - public function testGetUrlForFolder() { + public function testGetUrlForFolder(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with('awesomeUser') @@ -113,7 +118,7 @@ class DirectControllerTest extends TestCase { $this->controller->getUrl(101); } - public function testGetUrlValid() { + public function testGetUrlValid(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with('awesomeUser') @@ -128,6 +133,9 @@ class DirectControllerTest extends TestCase { ->with(101) ->willReturn([$file]); + $userFolder->method('getRelativePath') + ->willReturn('/path'); + $this->random->method('generate') ->with( 60, diff --git a/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php b/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php index 3bd7a2d6dde..f86a60fb4bf 100644 --- a/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php +++ b/apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php @@ -36,8 +36,7 @@ use OCA\DAV\Connector\Sabre\Exception\Forbidden; class ViewOnlyPluginTest extends TestCase { - /** @var ViewOnlyPlugin */ - private $plugin; + private ViewOnlyPlugin $plugin; /** @var Tree | \PHPUnit\Framework\MockObject\MockObject */ private $tree; /** @var RequestInterface | \PHPUnit\Framework\MockObject\MockObject */ @@ -56,14 +55,14 @@ class ViewOnlyPluginTest extends TestCase { $this->plugin->initialize($server); } - public function testCanGetNonDav() { + public function testCanGetNonDav(): void { $this->request->expects($this->once())->method('getPath')->willReturn('files/test/target'); $this->tree->method('getNodeForPath')->willReturn(null); $this->assertTrue($this->plugin->checkViewOnly($this->request)); } - public function testCanGetNonShared() { + public function testCanGetNonShared(): void { $this->request->expects($this->once())->method('getPath')->willReturn('files/test/target'); $davNode = $this->createMock(DavFile::class); $this->tree->method('getNodeForPath')->willReturn($davNode); @@ -78,7 +77,7 @@ class ViewOnlyPluginTest extends TestCase { $this->assertTrue($this->plugin->checkViewOnly($this->request)); } - public function providesDataForCanGet() { + public function providesDataForCanGet(): array { return [ // has attribute permissions-download enabled - can get file [ $this->createMock(File::class), true, true], @@ -92,7 +91,7 @@ class ViewOnlyPluginTest extends TestCase { /** * @dataProvider providesDataForCanGet */ - public function testCanGet($nodeInfo, $attrEnabled, $expectCanDownloadFile) { + public function testCanGet(File $nodeInfo, ?bool $attrEnabled, bool $expectCanDownloadFile): void { $this->request->expects($this->once())->method('getPath')->willReturn('files/test/target'); $davNode = $this->createMock(DavFile::class); diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index ae039520c5b..63fdced9011 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -50,6 +50,7 @@ use OCA\Files_Sharing\Notification\Listener; use OCA\Files_Sharing\Notification\Notifier; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSidebar; +use OCP\Files\Event\BeforeDirectGetEvent; use OCA\Files_Sharing\ShareBackend\File; use OCA\Files_Sharing\ShareBackend\Folder; use OCA\Files_Sharing\ViewOnly; @@ -62,6 +63,8 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\GenericEvent; use OCP\Federation\ICloudIdManager; use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\Events\BeforeDirectFileDownloadEvent; +use OCP\Files\Events\BeforeZipCreatedEvent; use OCP\Files\IRootFolder; use OCP\Group\Events\UserAddedEvent; use OCP\IDBConnection; @@ -157,59 +160,53 @@ class Application extends App implements IBootstrap { public function registerDownloadEvents( IEventDispatcher $dispatcher, - ?IUserSession $userSession, + IUserSession $userSession, IRootFolder $rootFolder ): void { $dispatcher->addListener( - 'file.beforeGetDirect', - function (GenericEvent $event) use ($userSession, $rootFolder) { - $pathsToCheck = [$event->getArgument('path')]; - $event->setArgument('run', true); - + BeforeDirectFileDownloadEvent::class, + function (BeforeDirectFileDownloadEvent $event) use ($userSession, $rootFolder): void { + $pathsToCheck = [$event->getPath()]; // Check only for user/group shares. Don't restrict e.g. share links - if ($userSession && $userSession->isLoggedIn()) { - $uid = $userSession->getUser()->getUID(); + $user = $userSession->getUser(); + if ($user) { $viewOnlyHandler = new ViewOnly( - $rootFolder->getUserFolder($uid) + $rootFolder->getUserFolder($user->getUID()) ); if (!$viewOnlyHandler->check($pathsToCheck)) { - $event->setArgument('run', false); - $event->setArgument('errorMessage', 'Access to this resource or one of its sub-items has been denied.'); + $event->setSuccessful(false); + $event->setErrorMessage('Access to this resource or one of its sub-items has been denied.'); } } } ); $dispatcher->addListener( - 'file.beforeCreateZip', - function (GenericEvent $event) use ($userSession, $rootFolder) { - $dir = $event->getArgument('dir'); - $files = $event->getArgument('files'); + BeforeZipCreatedEvent::class, + function (BeforeZipCreatedEvent $event) use ($userSession, $rootFolder): void { + $dir = $event->getDirectory(); + $files = $event->getFiles(); $pathsToCheck = []; - if (\is_array($files)) { - foreach ($files as $file) { - $pathsToCheck[] = $dir . '/' . $file; - } - } elseif (\is_string($files)) { - $pathsToCheck[] = $dir . '/' . $files; + foreach ($files as $file) { + $pathsToCheck[] = $dir . '/' . $file; } // Check only for user/group shares. Don't restrict e.g. share links - if ($userSession && $userSession->isLoggedIn()) { - $uid = $userSession->getUser()->getUID(); + $user = $userSession->getUser(); + if ($user) { $viewOnlyHandler = new ViewOnly( - $rootFolder->getUserFolder($uid) + $rootFolder->getUserFolder($user->getUID()) ); if (!$viewOnlyHandler->check($pathsToCheck)) { - $event->setArgument('errorMessage', 'Access to this resource or one of its sub-items has been denied.'); - $event->setArgument('run', false); + $event->setErrorMessage('Access to this resource or one of its sub-items has been denied.'); + $event->setSuccessful(false); } else { - $event->setArgument('run', true); + $event->setSuccessful(true); } } else { - $event->setArgument('run', true); + $event->setSuccessful(true); } } ); diff --git a/apps/files_sharing/lib/Controller/PublicPreviewController.php b/apps/files_sharing/lib/Controller/PublicPreviewController.php index 4a16afa7ac0..98c4d8cafb4 100644 --- a/apps/files_sharing/lib/Controller/PublicPreviewController.php +++ b/apps/files_sharing/lib/Controller/PublicPreviewController.php @@ -136,7 +136,7 @@ class PublicPreviewController extends PublicShareController { * @param $token * @return DataResponse|FileDisplayResponse */ - public function directLink($token) { + public function directLink(string $token) { // No token no image if ($token === '') { return new DataResponse([], Http::STATUS_BAD_REQUEST); diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index c72fd8ba8af..59089390667 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -45,6 +45,7 @@ declare(strict_types=1); namespace OCA\Files_Sharing\Controller; use OC\Files\FileInfo; +use OC\Files\Storage\Wrapper\Wrapper; use OCA\Files_Sharing\Exceptions\SharingRightsException; use OCA\Files_Sharing\External\Storage; use OCA\Files_Sharing\SharedStorage; @@ -524,14 +525,7 @@ class ShareAPIController extends OCSController { $permissions &= ~($permissions & ~$node->getPermissions()); } - if ($share->getNode()->getStorage()->instanceOfStorage(SharedStorage::class)) { - /** @var \OCA\Files_Sharing\SharedStorage $storage */ - $inheritedAttributes = $share->getNode()->getStorage()->getShare()->getAttributes(); - if ($inheritedAttributes !== null && $inheritedAttributes->getAttribute('permissions', 'download') === false) { - $share->setHideDownload(true); - } - } - + $this->checkInheritedAttributes($share); if ($shareType === IShare::TYPE_USER) { // Valid user is required to share @@ -1110,6 +1104,25 @@ class ShareAPIController extends OCSController { $share->setNote($note); } + $userFolder = $this->rootFolder->getUserFolder($this->currentUser); + + // get the node with the point of view of the current user + $nodes = $userFolder->getById($share->getNode()->getId()); + if (count($nodes) > 0) { + $node = $nodes[0]; + $storage = $node->getStorage(); + if ($storage && $storage->instanceOfStorage(SharedStorage::class)) { + /** @var \OCA\Files_Sharing\SharedStorage $storage */ + $inheritedAttributes = $storage->getShare()->getAttributes(); + if ($inheritedAttributes !== null && $inheritedAttributes->getAttribute('permissions', 'download') === false) { + if ($hideDownload === 'false') { + throw new OCSBadRequestException($this->l->t('Cannot increase permissions')); + } + $share->setHideDownload(true); + } + } + } + /** * expirationdate, password and publicUpload only make sense for link shares */ @@ -1135,24 +1148,6 @@ class ShareAPIController extends OCSController { $share->setHideDownload(false); } - $userFolder = $this->rootFolder->getUserFolder($this->currentUser); - // get the node with the point of view of the current user - $nodes = $userFolder->getById($share->getNode()->getId()); - if (count($nodes) > 0) { - $node = $nodes[0]; - $storage = $node->getStorage(); - if ($storage->instanceOfStorage(SharedStorage::class)) { - /** @var \OCA\Files_Sharing\SharedStorage $storage */ - $inheritedAttributes = $storage->getShare()->getAttributes(); - if ($inheritedAttributes !== null && $inheritedAttributes->getAttribute('permissions', 'download') === false) { - if ($hideDownload === 'false') { - throw new OCSBadRequestException($this->l->t('Cannot increate permissions')); - } - $share->setHideDownload(true); - } - } - } - $newPermissions = null; if ($publicUpload === 'true') { $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; @@ -1905,4 +1900,24 @@ class ShareAPIController extends OCSController { return $share; } + + private function checkInheritedAttributes(IShare $share): void { + if ($share->getNode()->getStorage()->instanceOfStorage(SharedStorage::class)) { + $storage = $share->getNode()->getStorage(); + if ($storage instanceof Wrapper) { + $storage = $storage->getInstanceOfStorage(SharedStorage::class); + if ($storage === null) { + throw new \RuntimeException('Should not happen, instanceOfStorage but getInstanceOfStorage return null'); + } + } else { + throw new \RuntimeException('Should not happen, instanceOfStorage but not a wrapper'); + } + /** @var \OCA\Files_Sharing\SharedStorage $storage */ + $inheritedAttributes = $storage->getShare()->getAttributes(); + if ($inheritedAttributes !== null && $inheritedAttributes->getAttribute('permissions', 'download') === false) { + $share->setHideDownload(true); + } + } + + } } diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index 30e398d663b..954c9cf70e6 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -242,8 +242,9 @@ class MountProvider implements IMountProvider { $superPermissions |= $share->getPermissions(); // update share permission attributes - if ($share->getAttributes() !== null) { - foreach ($share->getAttributes()->toArray() as $attribute) { + $attributes = $share->getAttributes(); + if ($attributes !== null) { + foreach ($attributes->toArray() as $attribute) { if ($superAttributes->getAttribute($attribute['scope'], $attribute['key']) === true) { // if super share attribute is already enabled, it is most permissive continue; diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue index 0eb0029cb54..f873ef542ed 100644 --- a/apps/files_sharing/src/components/SharingEntry.vue +++ b/apps/files_sharing/src/components/SharingEntry.vue @@ -80,8 +80,9 @@ <ActionCheckbox ref="canDownload" :checked.sync="canDownload" + v-if="isSetDownloadButtonVisible" :disabled="saving || !canSetDownload"> - {{ t('files_sharing', 'Allow download') }} + {{ allowDownloadText }} </ActionCheckbox> <!-- expiration date --> @@ -407,6 +408,36 @@ export default { return (typeof this.share.status === 'object' && !Array.isArray(this.share.status)) }, + /** + * @return {string} + */ + allowDownloadText() { + if (this.isFolder) { + return t('files_sharing', 'Allow download of office files') + } else { + return t('files_sharing', 'Allow download') + } + }, + + /** + * @return {boolean} + */ + isSetDownloadButtonVisible() { + const allowedMimetypes = [ + // Office documents + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.presentation', + ] + + return this.isFolder || allowedMimetypes.includes(this.fileInfo.mimetype) + }, }, methods: { diff --git a/apps/files_sharing/src/components/SharingEntryLink.vue b/apps/files_sharing/src/components/SharingEntryLink.vue index 0699cf2aea4..328d0108332 100644 --- a/apps/files_sharing/src/components/SharingEntryLink.vue +++ b/apps/files_sharing/src/components/SharingEntryLink.vue @@ -159,7 +159,7 @@ <ActionSeparator /> <ActionCheckbox :checked.sync="share.hideDownload" - :disabled="saving" + :disabled="saving || canChangeHideDownload" @change="queueUpdate('hideDownload')"> {{ t('files_sharing', 'Hide download') }} </ActionCheckbox> @@ -607,6 +607,12 @@ export default { isPasswordPolicyEnabled() { return typeof this.config.passwordPolicy === 'object' }, + + canChangeHideDownload() { + const hasDisabledDownload = (shareAttribute) => shareAttribute.key === 'download' && shareAttribute.scope === 'permissions' && shareAttribute.enabled === false + + return this.fileInfo.shareAttributes.some(hasDisabledDownload) + }, }, methods: { @@ -868,7 +874,6 @@ export default { this.$emit('remove:share', this.share) }, }, - } </script> diff --git a/apps/files_sharing/tests/ApplicationTest.php b/apps/files_sharing/tests/ApplicationTest.php index ee04996ac15..11c8137c398 100644 --- a/apps/files_sharing/tests/ApplicationTest.php +++ b/apps/files_sharing/tests/ApplicationTest.php @@ -22,6 +22,8 @@ */ namespace OCA\Files_Sharing\Tests; +use OCP\Files\Events\BeforeDirectFileDownloadEvent; +use OCP\Files\Events\BeforeZipCreatedEvent; use Psr\Log\LoggerInterface; use OC\Share20\LegacyHooks; use OC\Share20\Manager; @@ -32,6 +34,7 @@ use OCP\Constants; use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\Event\BeforeDirectGetEvent; use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; @@ -45,12 +48,8 @@ use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher; use Test\TestCase; class ApplicationTest extends TestCase { - - /** @var Application */ - private $application; - - /** @var IEventDispatcher */ - private $eventDispatcher; + private Application $application; + private IEventDispatcher $eventDispatcher; /** @var IUserSession */ private $userSession; @@ -81,7 +80,7 @@ class ApplicationTest extends TestCase { ); } - public function providesDataForCanGet() { + public function providesDataForCanGet(): array { // normal file (sender) - can download directly $senderFileStorage = $this->createMock(IStorage::class); $senderFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); @@ -130,7 +129,7 @@ class ApplicationTest extends TestCase { /** * @dataProvider providesDataForCanGet */ - public function testCheckDirectCanBeDownloaded($path, $userFolder, $run) { + public function testCheckDirectCanBeDownloaded(string $path, Folder $userFolder, bool $run): void { $user = $this->createMock(IUser::class); $user->method('getUID')->willReturn('test'); $this->userSession->method('getUser')->willReturn($user); @@ -138,13 +137,13 @@ class ApplicationTest extends TestCase { $this->rootFolder->method('getUserFolder')->willReturn($userFolder); // Simulate direct download of file - $event = new GenericEvent(null, [ 'path' => $path ]); - $this->eventDispatcher->dispatch('file.beforeGetDirect', $event); + $event = new BeforeDirectFileDownloadEvent($path); + $this->eventDispatcher->dispatchTyped($event); - $this->assertEquals($run, !$event->hasArgument('errorMessage')); + $this->assertEquals($run, $event->isSuccessful()); } - public function providesDataForCanZip() { + public function providesDataForCanZip(): array { // Mock: Normal file/folder storage $nonSharedStorage = $this->createMock(IStorage::class); $nonSharedStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); @@ -172,7 +171,7 @@ class ApplicationTest extends TestCase { $sender1UserFolder->method('get')->willReturn($sender1RootFolder); $return[] = [ '/folder', ['bar1.txt', 'bar2.txt'], $sender1UserFolder, true ]; - $return[] = [ '/', 'folder', $sender1UserFolder, true ]; + $return[] = [ '/', ['folder'], $sender1UserFolder, true ]; // 3. cannot download zipped 1 non-shared file and 1 secure-shared inside non-shared folder $receiver1File = $this->createMock(File::class); @@ -199,7 +198,7 @@ class ApplicationTest extends TestCase { $receiver2UserFolder = $this->createMock(Folder::class); $receiver2UserFolder->method('get')->willReturn($receiver2RootFolder); - $return[] = [ '/', 'secured-folder', $receiver2UserFolder, false ]; + $return[] = [ '/', ['secured-folder'], $receiver2UserFolder, false ]; return $return; } @@ -207,7 +206,7 @@ class ApplicationTest extends TestCase { /** * @dataProvider providesDataForCanZip */ - public function testCheckZipCanBeDownloaded($dir, $files, $userFolder, $run) { + public function testCheckZipCanBeDownloaded(string $dir, array $files, Folder $userFolder, bool $run): void { $user = $this->createMock(IUser::class); $user->method('getUID')->willReturn('test'); $this->userSession->method('getUser')->willReturn($user); @@ -216,22 +215,22 @@ class ApplicationTest extends TestCase { $this->rootFolder->method('getUserFolder')->with('test')->willReturn($userFolder); // Simulate zip download of folder folder - $event = new GenericEvent(null, ['dir' => $dir, 'files' => $files, 'run' => true]); - $this->eventDispatcher->dispatch('file.beforeCreateZip', $event); + $event = new BeforeZipCreatedEvent($dir, $files); + $this->eventDispatcher->dispatchTyped($event); - $this->assertEquals($run, $event->getArgument('run')); - $this->assertEquals($run, !$event->hasArgument('errorMessage')); + $this->assertEquals($run, $event->isSuccessful()); + $this->assertEquals($run, $event->getErrorMessage() === null); } - public function testCheckFileUserNotFound() { + public function testCheckFileUserNotFound(): void { $this->userSession->method('isLoggedIn')->willReturn(false); // Simulate zip download of folder folder - $event = new GenericEvent(null, ['dir' => '/test', 'files' => ['test.txt'], 'run' => true]); - $this->eventDispatcher->dispatch('file.beforeCreateZip', $event); + $event = new BeforeZipCreatedEvent('/test', ['test.txt']); + $this->eventDispatcher->dispatchTyped($event); // It should run as this would restrict e.g. share links otherwise - $this->assertTrue($event->getArgument('run')); - $this->assertFalse($event->hasArgument('errorMessage')); + $this->assertTrue($event->isSuccessful()); + $this->assertEquals(null, $event->getErrorMessage()); } } diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index a6a81bd672c..f8f4fb18bc8 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -46,6 +46,7 @@ use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\Storage; +use OCP\Files\Storage\IStorage; use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; @@ -1675,8 +1676,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -1709,8 +1712,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -1761,8 +1766,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -1817,8 +1824,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -1876,8 +1885,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -1930,8 +1941,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -1964,8 +1977,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -1985,8 +2000,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2007,8 +2024,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2028,8 +2047,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2064,8 +2085,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2100,8 +2123,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2143,8 +2168,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $path->method('getPath')->willReturn('valid-path'); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -2179,8 +2206,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2222,8 +2251,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); $this->rootFolder->method('get')->with('valid-path')->willReturn($path); @@ -2270,8 +2301,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -2342,8 +2375,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -2396,8 +2431,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -2480,8 +2517,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $path->method('getPath')->willReturn('valid-path'); $userFolder->expects($this->once()) @@ -2523,8 +2562,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(File::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $userFolder->expects($this->once()) ->method('get') @@ -2604,8 +2645,10 @@ class ShareAPIControllerTest extends TestCase { $path = $this->getMockBuilder(Folder::class)->getMock(); $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(true); + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', true], + ['OCA\Files_Sharing\SharedStorage', false], + ]); $path->method('getStorage')->willReturn($storage); $path->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); $userFolder->expects($this->once()) @@ -2964,8 +3007,17 @@ class ShareAPIControllerTest extends TestCase { $this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD'); $ocs = $this->mockFormatShare(); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $folder = $this->getMockBuilder(Folder::class)->getMock(); + $folder->method('getId') + ->willReturn(42); $share = \OC::$server->getShareManager()->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) @@ -3003,8 +3055,16 @@ class ShareAPIControllerTest extends TestCase { $this->expectExceptionMessage('Public upload disabled by the administrator'); $ocs = $this->mockFormatShare(); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $folder = $this->getMockBuilder(Folder::class)->getMock(); + $folder->method('getId')->willReturn(42); $share = \OC::$server->getShareManager()->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) @@ -3026,6 +3086,15 @@ class ShareAPIControllerTest extends TestCase { $ocs = $this->mockFormatShare(); $file = $this->getMockBuilder(File::class)->getMock(); + $file->method('getId') + ->willReturn(42); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $share = \OC::$server->getShareManager()->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) @@ -3039,13 +3108,21 @@ class ShareAPIControllerTest extends TestCase { $ocs->updateShare(42, null, 'password', null, 'true', ''); } - public function testUpdateLinkSharePasswordDoesNotChangeOther() { + public function testUpdateLinkSharePasswordDoesNotChangeOther(): void { $ocs = $this->mockFormatShare(); $date = new \DateTime('2000-01-01'); $date->setTime(0,0,0); $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $share = $this->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) ->setSharedBy($this->currentUser) @@ -3090,7 +3167,15 @@ class ShareAPIControllerTest extends TestCase { $date = new \DateTime('2000-01-01'); $date->setTime(0,0,0); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); $share = $this->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) ->setSharedBy($this->currentUser) @@ -3141,7 +3226,15 @@ class ShareAPIControllerTest extends TestCase { $date = new \DateTime('2000-01-01'); $date->setTime(0,0,0); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); $share = $this->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) ->setSharedBy($this->currentUser) @@ -3174,7 +3267,15 @@ class ShareAPIControllerTest extends TestCase { $date = new \DateTime('2000-01-01'); $date->setTime(0,0,0); + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42) + ->willReturn([]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); $share = $this->newShare(); $share->setPermissions(\OCP\Constants::PERMISSION_ALL) ->setSharedBy($this->currentUser) |