diff options
Diffstat (limited to 'apps/files_sharing/tests')
71 files changed, 15582 insertions, 12547 deletions
diff --git a/apps/files_sharing/tests/ApiTest.php b/apps/files_sharing/tests/ApiTest.php new file mode 100644 index 00000000000..960f29224bb --- /dev/null +++ b/apps/files_sharing/tests/ApiTest.php @@ -0,0 +1,1501 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Core\AppInfo\ConfigLexicon; +use OC\Files\Cache\Scanner; +use OC\Files\FileInfo; +use OC\Files\Filesystem; +use OC\Files\Storage\Temporary; +use OC\Files\View; +use OCA\Federation\TrustedServers; +use OCA\Files_Sharing\Controller\ShareAPIController; +use OCP\App\IAppManager; +use OCP\AppFramework\OCS\OCSBadRequestException; +use OCP\AppFramework\OCS\OCSException; +use OCP\AppFramework\OCS\OCSForbiddenException; +use OCP\AppFramework\OCS\OCSNotFoundException; +use OCP\Constants; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IDateTimeZone; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\IPreview; +use OCP\IRequest; +use OCP\ITagManager; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\Mail\IMailer; +use OCP\Server; +use OCP\Share\IProviderFactory; +use OCP\Share\IShare; +use OCP\UserStatus\IManager as IUserStatusManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; + +/** + * Class ApiTest + * + * @group DB + * TODO: convert to real integration tests + */ +class ApiTest extends TestCase { + public const TEST_FOLDER_NAME = '/folder_share_api_test'; + public const APP_NAME = 'files_sharing'; + + private static $tempStorage; + + private Folder $userFolder; + private string $subsubfolder; + protected IAppConfig&MockObject $appConfig; + + protected function setUp(): void { + parent::setUp(); + + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no'); + Server::get(IConfig::class)->setAppValue('core', 'shareapi_expire_after_n_days', '7'); + + Filesystem::getLoader()->removeStorageWrapper('sharing_mask'); + + $this->folder = self::TEST_FOLDER_NAME; + $this->subfolder = '/subfolder_share_api_test'; + $this->subsubfolder = '/subsubfolder_share_api_test'; + + $this->filename = '/share-api-test.txt'; + + // save file with content + $this->view->file_put_contents($this->filename, $this->data); + $this->view->mkdir($this->folder); + $this->view->mkdir($this->folder . $this->subfolder); + $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); + $this->view->file_put_contents($this->folder . $this->filename, $this->data); + $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); + $mount = $this->view->getMount($this->filename); + $mount->getStorage()->getScanner()->scan('', Scanner::SCAN_RECURSIVE); + + $this->userFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + + $this->appConfig = $this->createMock(IAppConfig::class); + } + + protected function tearDown(): void { + if ($this->view instanceof View) { + $this->view->unlink($this->filename); + $this->view->deleteAll($this->folder); + } + + self::$tempStorage = null; + + parent::tearDown(); + } + + /** + * @param string $userId The userId of the caller + * @return ShareAPIController + */ + private function createOCS($userId) { + $l = $this->getMockBuilder(IL10N::class)->getMock(); + $l->method('t') + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + $config = $this->createMock(IConfig::class); + $appManager = $this->createMock(IAppManager::class); + $serverContainer = $this->createMock(ContainerInterface::class); + $userStatusManager = $this->createMock(IUserStatusManager::class); + $previewManager = $this->createMock(IPreview::class); + $dateTimeZone = $this->createMock(IDateTimeZone::class); + $logger = $this->createMock(LoggerInterface::class); + $providerFactory = $this->createMock(IProviderFactory::class); + $mailer = $this->createMock(IMailer::class); + $tagManager = $this->createMock(ITagManager::class); + $trustedServers = $this->createMock(TrustedServers::class); + $dateTimeZone->method('getTimeZone')->willReturn(new \DateTimeZone(date_default_timezone_get())); + + return new ShareAPIController( + self::APP_NAME, + $this->getMockBuilder(IRequest::class)->getMock(), + $this->shareManager, + Server::get(IGroupManager::class), + Server::get(IUserManager::class), + Server::get(IRootFolder::class), + Server::get(IURLGenerator::class), + $l, + $config, + $this->appConfig, + $appManager, + $serverContainer, + $userStatusManager, + $previewManager, + $dateTimeZone, + $logger, + $providerFactory, + $mailer, + $tagManager, + $trustedServers, + $userId, + ); + } + + public function testCreateShareUserFile(): void { + $this->setUp(); // for some reasons phpunit refuses to do this for us only for this test + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals(19, $data['permissions']); + $this->assertEmpty($data['expiration']); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + + $ocs->cleanup(); + } + + public function testCreateShareUserFolder(): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals(31, $data['permissions']); + $this->assertEmpty($data['expiration']); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + } + + + public function testCreateShareGroupFile(): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals(19, $data['permissions']); + $this->assertEmpty($data['expiration']); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + } + + public function testCreateShareGroupFolder(): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals(31, $data['permissions']); + $this->assertEmpty($data['expiration']); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + } + + /** + * @group RoutingWeirdness + */ + public function testCreateShareLink(): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals(Constants::PERMISSION_ALL, + $data['permissions']); + $this->assertEmpty($data['expiration']); + $this->assertTrue(is_string($data['token'])); + + // check for correct link + $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']); + $this->assertEquals($url, $data['url']); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + } + + /** + * @group RoutingWeirdness + * @dataProvider dataAllowFederationOnPublicShares + */ + public function testCreateShareLinkPublicUpload(array $appConfig, int $permissions): void { + $this->appConfig->method('getValueBool') + ->willReturnMap([$appConfig]); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true'); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals( + Constants::PERMISSION_READ + | Constants::PERMISSION_CREATE + | Constants::PERMISSION_UPDATE + | Constants::PERMISSION_DELETE + | $permissions, + $data['permissions'] + ); + $this->assertEmpty($data['expiration']); + $this->assertTrue(is_string($data['token'])); + + // check for correct link + $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']); + $this->assertEquals($url, $data['url']); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + } + + public function testEnforceLinkPassword(): void { + $password = md5(time()); + $config = Server::get(IConfig::class); + $config->setAppValue('core', 'shareapi_enforce_links_password', 'yes'); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + try { + $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK); + $this->fail(); + } catch (OCSForbiddenException $e) { + } + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + try { + $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', ''); + $this->fail(); + } catch (OCSForbiddenException $e) { + } + $ocs->cleanup(); + + // share with password should succeed + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', $password); + $ocs->cleanup(); + + $data = $result->getData(); + + // setting new password should succeed + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->updateShare($data['id'], null, $password); + $ocs->cleanup(); + + // removing password should fail + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + try { + $ocs->updateShare($data['id']); + $this->fail(); + } catch (OCSBadRequestException $e) { + } + $ocs->cleanup(); + + // cleanup + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + + $config->setAppValue('core', 'shareapi_enforce_links_password', 'no'); + $this->addToAssertionCount(1); + } + + /** + * @medium + */ + public function testSharePermissions(): void { + // sharing file to a user should work if shareapi_exclude_groups is set + // to no + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no'); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2); + $ocs->cleanup(); + + $data = $result->getData(); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + + // exclude groups, but not the group the user belongs to. Sharing should still work + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'yes'); + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', 'admin,group1,group2'); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2); + $ocs->cleanup(); + + $data = $result->getData(); + + $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($data['id']); + $ocs->cleanup(); + + // now we exclude the group the user belongs to ('group'), sharing should fail now + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', 'admin,group'); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2); + $ocs->cleanup(); + + // cleanup + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups', 'no'); + Server::get(IConfig::class)->setAppValue('core', 'shareapi_exclude_groups_list', ''); + + $this->addToAssertionCount(1); + } + + + /** + * @medium + */ + public function testGetAllShares(): void { + $node = $this->userFolder->get($this->filename); + + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + + $share = $this->shareManager->createShare($share); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + $this->assertTrue(count($result->getData()) === 1); + + $this->shareManager->deleteShare($share); + } + + public function testGetAllSharesWithMe(): void { + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $this->logout(); + + $node1 = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $node2 = $this->userFolder->get($this->folder); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share2 = $this->shareManager->createShare($share2); + $share2->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share2); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $result = $ocs->getShares('true'); + $ocs->cleanup(); + + $this->assertCount(2, $result->getData()); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + /** + * @medium + * @group RoutingWeirdness + */ + public function testPublicLinkUrl(): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK); + $ocs->cleanup(); + + $data = $result->getData(); + + // check if we have a token + $this->assertTrue(is_string($data['token'])); + $id = $data['id']; + + // check for correct link + $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']); + $this->assertEquals($url, $data['url']); + + // check for link in getall shares + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals($url, current($data)['url']); + + // check for path + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals($url, current($data)['url']); + + // check in share id + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShare($id); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertEquals($url, current($data)['url']); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($id); + $ocs->cleanup(); + } + + /** + * @medium + * @depends testCreateShareUserFile + * @depends testCreateShareLink + */ + public function testGetShareFromSource(): void { + $node = $this->userFolder->get($this->filename); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share); + + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share created from testCreateShare() + $this->assertTrue(count($result->getData()) === 2); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + /** + * @medium + * @depends testCreateShareUserFile + * @depends testCreateShareLink + */ + public function testGetShareFromSourceWithReshares(): void { + $node = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share1); + + $share2 = $this->shareManager->newShare(); + $share2->setNode($node) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share2 = $this->shareManager->createShare($share2); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share + $this->assertTrue(count($result->getData()) === 1); + + // now also ask for the reshares + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares('false', 'true', 'false', $this->filename); + $ocs->cleanup(); + + // now we should get two shares, the initial share and the reshare + $this->assertCount(2, $result->getData()); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + /** + * @medium + * @depends testCreateShareUserFile + */ + public function testGetShareFromId(): void { + $node = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share1); + + // call getShare() with share ID + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShare($share1->getId()); + $ocs->cleanup(); + + // test should return one share created from testCreateShare() + $this->assertEquals(1, count($result->getData())); + + $this->shareManager->deleteShare($share1); + } + + /** + * @medium + */ + public function testGetShareFromFolder(): void { + $node1 = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share1); + + $node2 = $this->userFolder->get($this->folder . '/' . $this->filename); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share2); + + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares('false', 'false', 'true', $this->folder); + $ocs->cleanup(); + + // test should return one share within $this->folder + $this->assertTrue(count($result->getData()) === 1); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + public function testGetShareFromFolderWithFile(): void { + $node1 = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share1); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + try { + $ocs->getShares('false', 'false', 'true', $this->filename); + $this->fail(); + } catch (OCSBadRequestException $e) { + $this->assertEquals('Not a directory', $e->getMessage()); + } + $ocs->cleanup(); + + $this->shareManager->deleteShare($share1); + } + + /** + * share a folder, than reshare a file within the shared folder and check if we construct the correct path + * @medium + */ + public function testGetShareFromFolderReshares(): void { + $node1 = $this->userFolder->get($this->folder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $node2 = $this->userFolder->get($this->folder . '/' . $this->filename); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share2); + $share2->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share2); + + $node3 = $this->userFolder->get($this->folder . '/' . $this->subfolder . '/' . $this->filename); + $share3 = $this->shareManager->newShare(); + $share3->setNode($node3) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share3 = $this->shareManager->createShare($share3); + $share3->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share3); + + $testValues = [ + ['query' => $this->folder, + 'expectedResult' => $this->folder . $this->filename], + ['query' => $this->folder . $this->subfolder, + 'expectedResult' => $this->folder . $this->subfolder . $this->filename], + ]; + + foreach ($testValues as $value) { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $result = $ocs->getShares('false', 'false', 'true', $value['query']); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data = $result->getData(); + + $this->assertEquals($value['expectedResult'], $data[0]['path']); + } + + // cleanup + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + $this->shareManager->deleteShare($share3); + } + + /** + * reshare a sub folder and check if we get the correct path + * @medium + */ + public function testGetShareFromSubFolderReShares(): void { + $node1 = $this->userFolder->get($this->folder . $this->subfolder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $node2 = Server::get(IRootFolder::class)->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->get($this->subfolder); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share2); + $share2->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share2); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data = $result->getData(); + + // we should get exactly one result + $this->assertCount(1, $data); + + $this->assertEquals($this->subfolder, $data[0]['path']); + + $this->shareManager->deleteShare($share2); + $this->shareManager->deleteShare($share1); + } + + /** + * test re-re-share of folder if the path gets constructed correctly + * @medium + */ + public function XtestGetShareFromFolderReReShares() { + $node1 = $this->userFolder->get($this->folder . $this->subfolder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share1 = $this->shareManager->createShare($share1); + + $node2 = $this->userFolder->get($this->folder . $this->subfolder . $this->subsubfolder); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share2 = $this->shareManager->createShare($share2); + + $share3 = $this->shareManager->newShare(); + $share3->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER3) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share3 = $this->shareManager->createShare($share3); + + /* + * Test as recipient + */ + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data = $result->getData(); + + // we should get exactly one result + $this->assertCount(1, $data); + $this->assertEquals($this->subsubfolder, $data[0]['path']); + + /* + * Test for first owner/initiator + */ + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data = $result->getData(); + + // we should get exactly one result + $this->assertCount(1, $data); + $this->assertEquals($this->folder . $this->subfolder, $data[0]['path']); + + /* + * Test for second initiator + */ + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data = $result->getData(); + + // we should get exactly one result + $this->assertCount(1, $data); + $this->assertEquals($this->subfolder . $this->subsubfolder, $data[0]['path']); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + $this->shareManager->deleteShare($share3); + } + + /** + * test multiple shared folder if the path gets constructed correctly + * @medium + */ + public function testGetShareMultipleSharedFolder(): void { + $this->setUp(); + $node1 = $this->userFolder->get($this->folder . $this->subfolder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $node2 = $this->userFolder->get($this->folder); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share2 = $this->shareManager->createShare($share2); + $share2->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share2); + + $share3 = $this->shareManager->newShare(); + $share3->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share3 = $this->shareManager->createShare($share3); + $share3->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share3); + + // $request = $this->createRequest(['path' => $this->subfolder]); + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $result1 = $ocs->getShares('false', 'false', 'false', $this->subfolder); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data1 = $result1->getData(); + $this->assertCount(1, $data1); + $s1 = reset($data1); + + //$request = $this->createRequest(['path' => $this->folder.$this->subfolder]); + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $result2 = $ocs->getShares('false', 'false', 'false', $this->folder . $this->subfolder); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data2 = $result2->getData(); + $this->assertCount(1, $data2); + $s2 = reset($data2); + + $this->assertEquals($this->subfolder, $s1['path']); + $this->assertEquals($this->folder . $this->subfolder, $s2['path']); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + $this->shareManager->deleteShare($share3); + } + + /** + * test re-re-share of folder if the path gets constructed correctly + * @medium + */ + public function testGetShareFromFileReReShares(): void { + $node1 = $this->userFolder->get($this->folder . $this->subfolder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $user2Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2); + $node2 = $user2Folder->get($this->subfolder . $this->filename); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share2 = $this->shareManager->createShare($share2); + $share2->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share2); + + $user3Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER3); + $node3 = $user3Folder->get($this->filename); + $share3 = $this->shareManager->newShare(); + $share3->setNode($node3) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER3) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share3 = $this->shareManager->createShare($share3); + $share3->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share3); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3); + $result = $ocs->getShares(); + $ocs->cleanup(); + + // test should return one share within $this->folder + $data = $result->getData(); + + // we should get exactly one result + $this->assertCount(1, $data); + + $this->assertEquals($this->filename, $data[0]['path']); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + $this->shareManager->deleteShare($share3); + } + + /** + * @medium + */ + public function testGetShareFromUnknownId(): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER3); + try { + $ocs->getShare(0); + $this->fail(); + } catch (OCSNotFoundException $e) { + $this->assertEquals('Wrong share ID, share does not exist', $e->getMessage()); + } + $ocs->cleanup(); + } + + /** + * @medium + * @depends testCreateShareUserFile + * @depends testCreateShareLink + */ + public function testUpdateShare(): void { + $password = md5(time()); + + $node1 = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19) + ->setAttributes($this->shareManager->newShare()->newAttributes()); + + $this->assertNotNull($share1->getAttributes()); + $share1 = $this->shareManager->createShare($share1); + $this->assertEquals(19, $share1->getPermissions()); + + $share2 = $this->shareManager->newShare(); + $share2->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share2); + $this->assertEquals(1, $share2->getPermissions()); + + // update permissions + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->updateShare( + $share1->getId(), 1, null, null, null, null, null, null, null, + '[{"scope": "app1", "key": "attr1", "value": true}]' + ); + $ocs->cleanup(); + + $share1 = $this->shareManager->getShareById('ocinternal:' . $share1->getId()); + $this->assertEquals(1, $share1->getPermissions()); + $this->assertEquals(true, $share1->getAttributes()->getAttribute('app1', 'attr1')); + + // update password for link share + $this->assertNull($share2->getPassword()); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->updateShare($share2->getId(), null, $password); + $ocs->cleanup(); + + $share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId()); + $this->assertNotNull($share2->getPassword()); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->updateShare($share2->getId(), null, ''); + $ocs->cleanup(); + + $share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId()); + $this->assertNull($share2->getPassword()); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + /** + * @medium + * @dataProvider dataAllowFederationOnPublicShares + */ + public function testUpdateShareUpload(array $appConfig, int $permissions): void { + $this->appConfig->method('getValueBool')->willReturnMap([ + $appConfig, + ]); + + $node1 = $this->userFolder->get($this->folder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share1 = $this->shareManager->createShare($share1); + + // update public upload + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->updateShare($share1->getId(), null, null, null, 'true'); + $ocs->cleanup(); + + $share1 = $this->shareManager->getShareById($share1->getFullId()); + $this->assertEquals( + Constants::PERMISSION_READ + | Constants::PERMISSION_CREATE + | Constants::PERMISSION_UPDATE + | Constants::PERMISSION_DELETE + | $permissions, + $share1->getPermissions() + ); + + // cleanup + $this->shareManager->deleteShare($share1); + } + + public static function dataAllowFederationOnPublicShares(): array { + return [ + [['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, false], 0], + [['core', ConfigLexicon::SHAREAPI_ALLOW_FEDERATION_ON_PUBLIC_SHARES, false, true], Constants::PERMISSION_SHARE], + ]; + } + + /** + * @medium + */ + public function testUpdateShareExpireDate(): void { + $node1 = $this->userFolder->get($this->folder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $config = Server::get(IConfig::class); + + // enforce expire date, by default 7 days after the file was shared + $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); + + $dateWithinRange = new \DateTime(); + $dateWithinRange->add(new \DateInterval('P6D')); + + $dateOutOfRange = new \DateTime(); + $dateOutOfRange->add(new \DateInterval('P8D')); + + // update expire date to a valid value + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->updateShare($share1->getId(), null, null, null, null, $dateWithinRange->format('Y-m-d')); + $ocs->cleanup(); + + $share1 = $this->shareManager->getShareById($share1->getFullId()); + + // date should be changed + $dateWithinRange->setTime(0, 0, 0); + $dateWithinRange->setTimezone(new \DateTimeZone(date_default_timezone_get())); + $this->assertEquals($dateWithinRange, $share1->getExpirationDate()); + + // update expire date to a value out of range + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + try { + $ocs->updateShare($share1->getId()); + $this->fail(); + } catch (OCSBadRequestException $e) { + } + $ocs->cleanup(); + + $share1 = $this->shareManager->getShareById($share1->getFullId()); + + // date shouldn't be changed + $this->assertEquals($dateWithinRange, $share1->getExpirationDate()); + + // Try to remove expire date + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + try { + $ocs->updateShare($share1->getId()); + $this->fail(); + } catch (OCSBadRequestException $e) { + } + $ocs->cleanup(); + + $share1 = $this->shareManager->getShareById($share1->getFullId()); + + + // date shouldn't be changed + $this->assertEquals($dateWithinRange, $share1->getExpirationDate()); + // cleanup + $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); + $this->shareManager->deleteShare($share1); + } + + /** + * @medium + * @depends testCreateShareUserFile + */ + public function testDeleteShare(): void { + $node1 = $this->userFolder->get($this->filename); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(19); + $share1 = $this->shareManager->createShare($share1); + + $share2 = $this->shareManager->newShare(); + $share2->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share2); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($share1->getId()); + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($share2->getId()); + $ocs->cleanup(); + + $this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_USER)); + $this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_LINK)); + } + + /** + * test unshare of a reshared file + */ + public function testDeleteReshare(): void { + $node1 = $this->userFolder->get($this->folder); + $share1 = $this->shareManager->newShare(); + $share1->setNode($node1) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(31); + $share1 = $this->shareManager->createShare($share1); + $share1->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share1); + + $user2folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2); + $node2 = $user2folder->get($this->folder . '/' . $this->filename); + $share2 = $this->shareManager->newShare(); + $share2->setNode($node2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(1); + $share2 = $this->shareManager->createShare($share2); + $share2->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share2); + + // test if we can unshare the link again + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $ocs->deleteShare($share2->getId()); + $ocs->cleanup(); + + $this->shareManager->deleteShare($share1); + $this->addToAssertionCount(1); + } + + /** + * share a folder which contains a share mount point, should be forbidden + */ + public function testShareFolderWithAMountPoint(): void { + // user 1 shares a folder with user2 + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + // user2 shares a file from the folder as link + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $view->mkdir('localDir'); + + // move mount point to the folder "localDir" + $result = $view->rename($this->folder, 'localDir/' . $this->folder); + $this->assertTrue($result !== false); + + // try to share "localDir" + $fileInfo2 = $view->getFileInfo('localDir'); + + $this->assertTrue($fileInfo2 instanceof FileInfo); + + $pass = true; + try { + $this->share( + IShare::TYPE_USER, + 'localDir', + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER3, + Constants::PERMISSION_ALL + ); + } catch (\Exception $e) { + $pass = false; + } + + $this->assertFalse($pass); + + //cleanup + + $result = $view->rename('localDir/' . $this->folder, $this->folder); + $this->assertTrue($result !== false); + $view->unlink('localDir'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->shareManager->deleteShare($share); + } + + /** + * Post init mount points hook for mounting simulated ext storage + */ + public static function initTestMountPointsHook($data) { + if ($data['user'] === self::TEST_FILES_SHARING_API_USER1) { + Filesystem::mount(self::$tempStorage, [], '/' . self::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME); + } + } + + /** + * Tests mounting a folder that is an external storage mount point. + */ + public function testShareStorageMountPoint(): void { + $tempStorage = new Temporary([]); + $tempStorage->file_put_contents('test.txt', 'abcdef'); + $tempStorage->getScanner()->scan(''); + + $this->registerMount(self::TEST_FILES_SHARING_API_USER1, $tempStorage, self::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME); + + // logging in will auto-mount the temp storage for user1 as well + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + // user 1 shares the mount point folder with user2 + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + // user2: check that mount point name appears correctly + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + $this->assertTrue($view->file_exists($this->folder)); + $this->assertTrue($view->file_exists($this->folder . '/test.txt')); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->shareManager->deleteShare($share); + + \OC_Hook::clear('OC_Filesystem', 'post_initMountPoints'); + \OC_Hook::clear('\OCA\Files_Sharing\Tests\ApiTest', 'initTestMountPointsHook'); + } + + public static function datesProvider() { + $date = new \DateTime(); + $date->setTime(0, 0); + $date->add(new \DateInterval('P5D')); + $date->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + return [ + [$date->format('Y-m-d H:i:s'), true], + ['abc', false], + [$date->format('Y-m-d H:i:s') . 'xyz', false], + ]; + } + + /** + * Make sure only ISO 8601 dates are accepted + * + * @group RoutingWeirdness + */ + #[\PHPUnit\Framework\Attributes\DataProvider('datesProvider')] + public function testPublicLinkExpireDate($date, $valid): void { + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + + try { + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date); + $this->assertTrue($valid); + } catch (OCSNotFoundException $e) { + $this->assertFalse($valid); + $this->assertEquals('Invalid date. Format must be YYYY-MM-DD', $e->getMessage()); + $ocs->cleanup(); + return; + } + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertTrue(is_string($data['token'])); + $this->assertEquals(substr($date, 0, 10), substr($data['expiration'], 0, 10)); + + // check for correct link + $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']); + $this->assertEquals($url, $data['url']); + + $share = $this->shareManager->getShareById('ocinternal:' . $data['id']); + + $this->assertEquals($date, $share->getExpirationDate()->format('Y-m-d H:i:s')); + + $this->shareManager->deleteShare($share); + } + + /** + * @group RoutingWeirdness + */ + public function testCreatePublicLinkExpireDateValid(): void { + $config = Server::get(IConfig::class); + + // enforce expire date, by default 7 days after the file was shared + $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); + + $date = new \DateTime(); + $date->add(new \DateInterval('P5D')); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d')); + $ocs->cleanup(); + + $data = $result->getData(); + $this->assertTrue(is_string($data['token'])); + $this->assertEquals($date->format('Y-m-d 00:00:00'), $data['expiration']); + + // check for correct link + $url = Server::get(IURLGenerator::class)->getAbsoluteURL('/index.php/s/' . $data['token']); + $this->assertEquals($url, $data['url']); + + $share = $this->shareManager->getShareById('ocinternal:' . $data['id']); + $date->setTime(0, 0, 0); + $this->assertEquals($date, $share->getExpirationDate()); + + $this->shareManager->deleteShare($share); + + $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); + } + + public function testCreatePublicLinkExpireDateInvalidFuture(): void { + $config = Server::get(IConfig::class); + + // enforce expire date, by default 7 days after the file was shared + $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); + + $date = new \DateTime(); + $date->add(new \DateInterval('P8D')); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + + try { + $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d')); + $this->fail(); + } catch (OCSException $e) { + $this->assertEquals(404, $e->getCode()); + $this->assertEquals('Cannot set expiration date more than 7 days in the future', $e->getMessage()); + } + $ocs->cleanup(); + + $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); + } + + public function XtestCreatePublicLinkExpireDateInvalidPast() { + $config = Server::get(IConfig::class); + + $date = new \DateTime(); + $date->sub(new \DateInterval('P8D')); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + + try { + $ocs->createShare($this->filename, Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, $date->format('Y-m-d')); + $this->fail(); + } catch (OCSException $e) { + $this->assertEquals(404, $e->getCode()); + $this->assertEquals('Expiration date is in the past', $e->getMessage()); + } + $ocs->cleanup(); + + $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); + } + + /** + * test for no invisible shares + * See: https://github.com/owncloud/core/issues/22295 + */ + public function testInvisibleSharesUser(): void { + // simulate a post request + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_USER, self::TEST_FILES_SHARING_API_USER2); + $ocs->cleanup(); + $data = $result->getData(); + + $topId = $data['id']; + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $ocs->acceptShare($topId); + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK); + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($topId); + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + $this->assertEmpty($result->getData()); + } + + /** + * test for no invisible shares + * See: https://github.com/owncloud/core/issues/22295 + */ + public function testInvisibleSharesGroup(): void { + // simulate a post request + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1); + $ocs->cleanup(); + $data = $result->getData(); + + $topId = $data['id']; + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $ocs->acceptShare($topId); + $ocs->cleanup(); + + \OC_Util::tearDownFS(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2); + $ocs->createShare($this->folder, Constants::PERMISSION_ALL, IShare::TYPE_LINK); + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $ocs->deleteShare($topId); + $ocs->cleanup(); + + $ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1); + $result = $ocs->getShares(); + $ocs->cleanup(); + + $this->assertEmpty($result->getData()); + } +} diff --git a/apps/files_sharing/tests/ApplicationTest.php b/apps/files_sharing/tests/ApplicationTest.php new file mode 100644 index 00000000000..84a3f4b372b --- /dev/null +++ b/apps/files_sharing/tests/ApplicationTest.php @@ -0,0 +1,206 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests; + +use OCA\Files_Sharing\AppInfo\Application; +use OCA\Files_Sharing\Listener\BeforeDirectFileDownloadListener; +use OCA\Files_Sharing\Listener\BeforeZipCreatedListener; +use OCA\Files_Sharing\SharedStorage; +use OCP\Files\Events\BeforeDirectFileDownloadEvent; +use OCP\Files\Events\BeforeZipCreatedEvent; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Storage\IStorage; +use OCP\IUser; +use OCP\IUserSession; +use OCP\Share\IAttributes; +use OCP\Share\IShare; +use Test\TestCase; + +class ApplicationTest extends TestCase { + private Application $application; + + /** @var IUserSession */ + private $userSession; + + /** @var IRootFolder */ + private $rootFolder; + + + protected function setUp(): void { + parent::setUp(); + + $this->application = new Application([]); + + $this->userSession = $this->createMock(IUserSession::class); + $this->rootFolder = $this->createMock(IRootFolder::class); + } + + public function providesDataForCanGet(): array { + // normal file (sender) - can download directly + $senderFileStorage = $this->createMock(IStorage::class); + $senderFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); + $senderFile = $this->createMock(File::class); + $senderFile->method('getStorage')->willReturn($senderFileStorage); + $senderUserFolder = $this->createMock(Folder::class); + $senderUserFolder->method('get')->willReturn($senderFile); + + $result[] = [ '/bar.txt', $senderUserFolder, true ]; + + // shared file (receiver) with attribute secure-view-enabled set false - + // can download directly + $receiverFileShareAttributes = $this->createMock(IAttributes::class); + $receiverFileShareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true); + $receiverFileShare = $this->createMock(IShare::class); + $receiverFileShare->method('getAttributes')->willReturn($receiverFileShareAttributes); + $receiverFileStorage = $this->createMock(SharedStorage::class); + $receiverFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); + $receiverFileStorage->method('getShare')->willReturn($receiverFileShare); + $receiverFile = $this->createMock(File::class); + $receiverFile->method('getStorage')->willReturn($receiverFileStorage); + $receiverUserFolder = $this->createMock(Folder::class); + $receiverUserFolder->method('get')->willReturn($receiverFile); + + $result[] = [ '/share-bar.txt', $receiverUserFolder, true ]; + + // shared file (receiver) with attribute secure-view-enabled set true - + // cannot download directly + $secureReceiverFileShareAttributes = $this->createMock(IAttributes::class); + $secureReceiverFileShareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(false); + $secureReceiverFileShare = $this->createMock(IShare::class); + $secureReceiverFileShare->method('getAttributes')->willReturn($secureReceiverFileShareAttributes); + $secureReceiverFileStorage = $this->createMock(SharedStorage::class); + $secureReceiverFileStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); + $secureReceiverFileStorage->method('getShare')->willReturn($secureReceiverFileShare); + $secureReceiverFile = $this->createMock(File::class); + $secureReceiverFile->method('getStorage')->willReturn($secureReceiverFileStorage); + $secureReceiverUserFolder = $this->createMock(Folder::class); + $secureReceiverUserFolder->method('get')->willReturn($secureReceiverFile); + + $result[] = [ '/secure-share-bar.txt', $secureReceiverUserFolder, false ]; + + return $result; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('providesDataForCanGet')] + 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); + $this->userSession->method('isLoggedIn')->willReturn(true); + $this->rootFolder->method('getUserFolder')->willReturn($userFolder); + + // Simulate direct download of file + $event = new BeforeDirectFileDownloadEvent($path); + $listener = new BeforeDirectFileDownloadListener( + $this->userSession, + $this->rootFolder + ); + $listener->handle($event); + + $this->assertEquals($run, $event->isSuccessful()); + } + + public function providesDataForCanZip(): array { + // Mock: Normal file/folder storage + $nonSharedStorage = $this->createMock(IStorage::class); + $nonSharedStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false); + + // Mock: Secure-view file/folder shared storage + $secureReceiverFileShareAttributes = $this->createMock(IAttributes::class); + $secureReceiverFileShareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(false); + $secureReceiverFileShare = $this->createMock(IShare::class); + $secureReceiverFileShare->method('getAttributes')->willReturn($secureReceiverFileShareAttributes); + $secureSharedStorage = $this->createMock(SharedStorage::class); + $secureSharedStorage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true); + $secureSharedStorage->method('getShare')->willReturn($secureReceiverFileShare); + + // 1. can download zipped 2 non-shared files inside non-shared folder + // 2. can download zipped non-shared folder + $sender1File = $this->createMock(File::class); + $sender1File->method('getStorage')->willReturn($nonSharedStorage); + $sender1Folder = $this->createMock(Folder::class); + $sender1Folder->method('getStorage')->willReturn($nonSharedStorage); + $sender1Folder->method('getDirectoryListing')->willReturn([$sender1File, $sender1File]); + $sender1RootFolder = $this->createMock(Folder::class); + $sender1RootFolder->method('getStorage')->willReturn($nonSharedStorage); + $sender1RootFolder->method('getDirectoryListing')->willReturn([$sender1Folder]); + $sender1UserFolder = $this->createMock(Folder::class); + $sender1UserFolder->method('get')->willReturn($sender1RootFolder); + + $return[] = [ '/folder', ['bar1.txt', 'bar2.txt'], $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); + $receiver1File->method('getStorage')->willReturn($nonSharedStorage); + $receiver1SecureFile = $this->createMock(File::class); + $receiver1SecureFile->method('getStorage')->willReturn($secureSharedStorage); + $receiver1Folder = $this->createMock(Folder::class); + $receiver1Folder->method('getStorage')->willReturn($nonSharedStorage); + $receiver1Folder->method('getDirectoryListing')->willReturn([$receiver1File, $receiver1SecureFile]); + $receiver1RootFolder = $this->createMock(Folder::class); + $receiver1RootFolder->method('getStorage')->willReturn($nonSharedStorage); + $receiver1RootFolder->method('getDirectoryListing')->willReturn([$receiver1Folder]); + $receiver1UserFolder = $this->createMock(Folder::class); + $receiver1UserFolder->method('get')->willReturn($receiver1RootFolder); + + $return[] = [ '/folder', ['secured-bar1.txt', 'bar2.txt'], $receiver1UserFolder, false ]; + + // 4. cannot download zipped secure-shared folder + $receiver2Folder = $this->createMock(Folder::class); + $receiver2Folder->method('getStorage')->willReturn($secureSharedStorage); + $receiver2RootFolder = $this->createMock(Folder::class); + $receiver2RootFolder->method('getStorage')->willReturn($nonSharedStorage); + $receiver2RootFolder->method('getDirectoryListing')->willReturn([$receiver2Folder]); + $receiver2UserFolder = $this->createMock(Folder::class); + $receiver2UserFolder->method('get')->willReturn($receiver2RootFolder); + + $return[] = [ '/', ['secured-folder'], $receiver2UserFolder, false ]; + + return $return; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('providesDataForCanZip')] + 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); + $this->userSession->method('isLoggedIn')->willReturn(true); + + $this->rootFolder->method('getUserFolder')->with('test')->willReturn($userFolder); + + // Simulate zip download of folder folder + $event = new BeforeZipCreatedEvent($dir, $files); + $listener = new BeforeZipCreatedListener( + $this->userSession, + $this->rootFolder + ); + $listener->handle($event); + + + $this->assertEquals($run, $event->isSuccessful()); + $this->assertEquals($run, $event->getErrorMessage() === null); + } + + public function testCheckFileUserNotFound(): void { + $this->userSession->method('isLoggedIn')->willReturn(false); + + // Simulate zip download of folder folder + $event = new BeforeZipCreatedEvent('/test', ['test.txt']); + $listener = new BeforeZipCreatedListener( + $this->userSession, + $this->rootFolder + ); + $listener->handle($event); + + // It should run as this would restrict e.g. share links otherwise + $this->assertTrue($event->isSuccessful()); + $this->assertEquals(null, $event->getErrorMessage()); + } +} diff --git a/apps/files_sharing/tests/CacheTest.php b/apps/files_sharing/tests/CacheTest.php new file mode 100644 index 00000000000..e95d3d4f91a --- /dev/null +++ b/apps/files_sharing/tests/CacheTest.php @@ -0,0 +1,608 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Cache\Cache; +use OC\Files\Filesystem; +use OC\Files\Storage\Storage; +use OC\Files\Storage\Temporary; +use OC\Files\Storage\Wrapper\Jail; +use OC\Files\View; +use OCA\Files_Sharing\SharedStorage; +use OCP\Constants; +use OCP\Files\Cache\IWatcher; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class CacheTest + * + * @group DB + */ +class CacheTest extends TestCase { + + /** + * @var View + */ + public $user2View; + + /** @var Cache */ + protected $ownerCache; + + /** @var Cache */ + protected $sharedCache; + + /** @var Storage */ + protected $ownerStorage; + + /** @var Storage */ + protected $sharedStorage; + + /** @var \OCP\Share\IManager */ + protected $shareManager; + + protected function setUp(): void { + parent::setUp(); + + $this->shareManager = Server::get(\OCP\Share\IManager::class); + + + $userManager = Server::get(IUserManager::class); + $userManager->get(self::TEST_FILES_SHARING_API_USER1)->setDisplayName('User One'); + $userManager->get(self::TEST_FILES_SHARING_API_USER2)->setDisplayName('User Two'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + // prepare user1's dir structure + $this->view->mkdir('container'); + $this->view->mkdir('container/shareddir'); + $this->view->mkdir('container/shareddir/subdir'); + $this->view->mkdir('container/shareddir/emptydir'); + + $textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $this->view->file_put_contents('container/not shared.txt', $textData); + $this->view->file_put_contents('container/shared single file.txt', $textData); + $this->view->file_put_contents('container/shareddir/bar.txt', $textData); + $this->view->file_put_contents('container/shareddir/subdir/another.txt', $textData); + $this->view->file_put_contents('container/shareddir/subdir/another too.txt', $textData); + $this->view->file_put_contents('container/shareddir/subdir/not a text file.xml', '<xml></xml>'); + $this->view->file_put_contents('simplefile.txt', $textData); + + [$this->ownerStorage,] = $this->view->resolvePath(''); + $this->ownerCache = $this->ownerStorage->getCache(); + $this->ownerStorage->getScanner()->scan(''); + + // share "shareddir" with user2 + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + + $node = $rootFolder->get('container/shareddir'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + $node = $rootFolder->get('container/shared single file.txt'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL & ~(Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE)); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + // login as user2 + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // retrieve the shared storage + $secondView = new View('/' . self::TEST_FILES_SHARING_API_USER2); + [$this->sharedStorage,] = $secondView->resolvePath('files/shareddir'); + $this->sharedCache = $this->sharedStorage->getCache(); + } + + protected function tearDown(): void { + if ($this->sharedCache) { + $this->sharedCache->clear(); + } + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $shares = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER); + foreach ($shares as $share) { + $this->shareManager->deleteShare($share); + } + + $this->view->deleteAll('container'); + + $this->ownerCache->clear(); + + parent::tearDown(); + } + + public function searchDataProvider() { + return [ + ['%another%', + [ + ['name' => 'another too.txt', 'path' => 'subdir/another too.txt'], + ['name' => 'another.txt', 'path' => 'subdir/another.txt'], + ] + ], + ['%Another%', + [ + ['name' => 'another too.txt', 'path' => 'subdir/another too.txt'], + ['name' => 'another.txt', 'path' => 'subdir/another.txt'], + ] + ], + ['%dir%', + [ + ['name' => 'emptydir', 'path' => 'emptydir'], + ['name' => 'subdir', 'path' => 'subdir'], + ['name' => 'shareddir', 'path' => ''], + ] + ], + ['%Dir%', + [ + ['name' => 'emptydir', 'path' => 'emptydir'], + ['name' => 'subdir', 'path' => 'subdir'], + ['name' => 'shareddir', 'path' => ''], + ] + ], + ['%txt%', + [ + ['name' => 'bar.txt', 'path' => 'bar.txt'], + ['name' => 'another too.txt', 'path' => 'subdir/another too.txt'], + ['name' => 'another.txt', 'path' => 'subdir/another.txt'], + ] + ], + ['%Txt%', + [ + ['name' => 'bar.txt', 'path' => 'bar.txt'], + ['name' => 'another too.txt', 'path' => 'subdir/another too.txt'], + ['name' => 'another.txt', 'path' => 'subdir/another.txt'], + ] + ], + ['%', + [ + ['name' => 'bar.txt', 'path' => 'bar.txt'], + ['name' => 'emptydir', 'path' => 'emptydir'], + ['name' => 'subdir', 'path' => 'subdir'], + ['name' => 'another too.txt', 'path' => 'subdir/another too.txt'], + ['name' => 'another.txt', 'path' => 'subdir/another.txt'], + ['name' => 'not a text file.xml', 'path' => 'subdir/not a text file.xml'], + ['name' => 'shareddir', 'path' => ''], + ] + ], + ['%nonexistent%', + [ + ] + ], + ]; + } + + /** + * we cannot use a dataProvider because that would cause the stray hook detection to remove the hooks + * that were added in setUpBeforeClass. + */ + public function testSearch(): void { + foreach ($this->searchDataProvider() as $data) { + [$pattern, $expectedFiles] = $data; + + $results = $this->sharedStorage->getCache()->search($pattern); + + $this->verifyFiles($expectedFiles, $results); + } + } + /** + * Test searching by mime type + */ + public function testSearchByMime(): void { + $results = $this->sharedStorage->getCache()->searchByMime('text'); + $check = [ + [ + 'name' => 'bar.txt', + 'path' => 'bar.txt' + ], + [ + 'name' => 'another too.txt', + 'path' => 'subdir/another too.txt' + ], + [ + 'name' => 'another.txt', + 'path' => 'subdir/another.txt' + ], + ]; + $this->verifyFiles($check, $results); + } + + public function testGetFolderContentsInRoot(): void { + $results = $this->user2View->getDirectoryContent('/'); + $results = (array_filter($results, function ($file) { + return $file->getName() !== 'welcome.txt'; + })); + + // we should get the shared items "shareddir" and "shared single file.txt" + // additional root will always contain the example file "welcome.txt", + // so this will be part of the result + $this->verifyFiles( + [ + [ + 'name' => 'shareddir', + 'path' => 'files/shareddir', + 'mimetype' => 'httpd/unix-directory', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + [ + 'name' => 'shared single file.txt', + 'path' => 'files/shared single file.txt', + 'mimetype' => 'text/plain', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + ], + $results + ); + } + + public function testGetFolderContentsInSubdir(): void { + $results = $this->user2View->getDirectoryContent('/shareddir'); + + $this->verifyFiles( + [ + [ + 'name' => 'bar.txt', + 'path' => 'bar.txt', + 'mimetype' => 'text/plain', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + [ + 'name' => 'emptydir', + 'path' => 'emptydir', + 'mimetype' => 'httpd/unix-directory', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + [ + 'name' => 'subdir', + 'path' => 'subdir', + 'mimetype' => 'httpd/unix-directory', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + ], + $results + ); + } + + /** + * This covers a bug where the share owners name was propagated + * to the recipient in the recent files API response where the + * share recipient has a different target set + * + * https://github.com/nextcloud/server/issues/39879 + */ + public function testShareRenameOriginalFileInRecentResults(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('simplefile.txt'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_READ); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $node->move(self::TEST_FILES_SHARING_API_USER1 . '/files/simplefile2.txt'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER3); + $recents = $rootFolder->getRecent(10); + self::assertEquals([ + 'welcome.txt', + 'simplefile.txt' + ], array_map(function ($node) { + return $node->getFileInfo()['name']; + }, $recents)); + } + + public function testGetFolderContentsWhenSubSubdirShared(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('container/shareddir/subdir'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + + $thirdView = new View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files'); + $results = $thirdView->getDirectoryContent('/subdir'); + + $this->verifyFiles( + [ + [ + 'name' => 'another too.txt', + 'path' => 'another too.txt', + 'mimetype' => 'text/plain', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + [ + 'name' => 'another.txt', + 'path' => 'another.txt', + 'mimetype' => 'text/plain', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + [ + 'name' => 'not a text file.xml', + 'path' => 'not a text file.xml', + 'mimetype' => 'application/xml', + 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, + 'displayname_owner' => 'User One', + ], + ], + $results + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->shareManager->deleteShare($share); + } + + /** + * Check if 'results' contains the expected 'examples' only. + * + * @param array $examples array of example files + * @param array $results array of files + */ + private function verifyFiles($examples, $results) { + $this->assertEquals(count($examples), count($results)); + + foreach ($examples as $example) { + foreach ($results as $key => $result) { + if ($result['name'] === $example['name']) { + $this->verifyKeys($example, $result); + unset($results[$key]); + break; + } + } + } + $this->assertEquals([], $results); + } + + /** + * verify if each value from the result matches the expected result + * @param array $example array with the expected results + * @param array $result array with the results + */ + private function verifyKeys($example, $result) { + foreach ($example as $key => $value) { + $this->assertEquals($value, $result[$key]); + } + } + + public function testGetPathByIdDirectShare(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + Filesystem::file_put_contents('test.txt', 'foo'); + $info = Filesystem::getFileInfo('test.txt'); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('test.txt'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(Filesystem::file_exists('/test.txt')); + [$sharedStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/test.txt'); + /** + * @var SharedStorage $sharedStorage + */ + $sharedCache = $sharedStorage->getCache(); + $this->assertEquals('', $sharedCache->getPathById($info->getId())); + } + + public function testGetPathByIdShareSubFolder(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + Filesystem::mkdir('foo'); + Filesystem::mkdir('foo/bar'); + Filesystem::touch('foo/bar/test.txt'); + $folderInfo = Filesystem::getFileInfo('foo'); + $fileInfo = Filesystem::getFileInfo('foo/bar/test.txt'); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('foo'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(Filesystem::file_exists('/foo')); + [$sharedStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/foo'); + /** + * @var SharedStorage $sharedStorage + */ + $sharedCache = $sharedStorage->getCache(); + $this->assertEquals('', $sharedCache->getPathById($folderInfo->getId())); + $this->assertEquals('bar/test.txt', $sharedCache->getPathById($fileInfo->getId())); + } + + public function testNumericStorageId(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + Filesystem::mkdir('foo'); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('foo'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + \OC_Util::tearDownFS(); + + [$sourceStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER1 . '/files/foo'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(Filesystem::file_exists('/foo')); + /** @var SharedStorage $sharedStorage */ + [$sharedStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/foo'); + + $this->assertEquals($sourceStorage->getCache()->getNumericStorageId(), $sharedStorage->getCache()->getNumericStorageId()); + } + + public function testShareJailedStorage(): void { + $sourceStorage = new Temporary(); + $sourceStorage->mkdir('jail'); + $sourceStorage->mkdir('jail/sub'); + $sourceStorage->file_put_contents('jail/sub/foo.txt', 'foo'); + $jailedSource = new Jail([ + 'storage' => $sourceStorage, + 'root' => 'jail' + ]); + $sourceStorage->getScanner()->scan(''); + $this->registerMount(self::TEST_FILES_SHARING_API_USER1, $jailedSource, '/' . self::TEST_FILES_SHARING_API_USER1 . '/files/foo'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('foo/sub'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertEquals('foo', Filesystem::file_get_contents('/sub/foo.txt')); + + Filesystem::file_put_contents('/sub/bar.txt', 'bar'); + /** @var SharedStorage $sharedStorage */ + [$sharedStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/sub'); + + $this->assertTrue($sharedStorage->getCache()->inCache('bar.txt')); + + $this->assertTrue($sourceStorage->getCache()->inCache('jail/sub/bar.txt')); + } + + public function testSearchShareJailedStorage(): void { + $sourceStorage = new Temporary(); + $sourceStorage->mkdir('jail'); + $sourceStorage->mkdir('jail/sub'); + $sourceStorage->file_put_contents('jail/sub/foo.txt', 'foo'); + $jailedSource = new Jail([ + 'storage' => $sourceStorage, + 'root' => 'jail' + ]); + $sourceStorage->getScanner()->scan(''); + $this->registerMount(self::TEST_FILES_SHARING_API_USER1, $jailedSource, '/' . self::TEST_FILES_SHARING_API_USER1 . '/files/foo'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('foo/sub'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + /** @var SharedStorage $sharedStorage */ + [$sharedStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/sub'); + + $results = $sharedStorage->getCache()->search('foo.txt'); + $this->assertCount(1, $results); + } + + public function testWatcherRootChange() { + $sourceStorage = new Temporary(); + $sourceStorage->mkdir('shared'); + $sourceStorage->file_put_contents('shared/foo.txt', 'foo'); + $sourceStorage->getScanner()->scan(''); + $sourceStorage->getWatcher()->setPolicy(IWatcher::CHECK_ALWAYS); + $this->registerMount(self::TEST_FILES_SHARING_API_USER1, $sourceStorage, '/' . self::TEST_FILES_SHARING_API_USER1 . '/files/foo'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('foo/shared'); + $this->assertEquals(3, $node->getSize()); + + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + \OC_Util::tearDownFS(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $view = Filesystem::getView(); + + $sourceStorage->rmdir('shared'); + + $this->assertFalse($view->getFileInfo('shared')); + } +} diff --git a/apps/files_sharing/tests/CapabilitiesTest.php b/apps/files_sharing/tests/CapabilitiesTest.php new file mode 100644 index 00000000000..9a076d7a171 --- /dev/null +++ b/apps/files_sharing/tests/CapabilitiesTest.php @@ -0,0 +1,360 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\KnownUser\KnownUserService; +use OC\Share20\Manager; +use OC\Share20\ShareDisableChecker; +use OCA\Files_Sharing\Capabilities; +use OCP\App\IAppManager; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountManager; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IDateTimeZone; +use OCP\IGroupManager; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\L10N\IFactory; +use OCP\Mail\IMailer; +use OCP\Security\IHasher; +use OCP\Security\ISecureRandom; +use OCP\Share\IProviderFactory; +use Psr\Log\LoggerInterface; + +/** + * Class CapabilitiesTest + * + * @group DB + */ +class CapabilitiesTest extends \Test\TestCase { + + /** + * Test for the general part in each return statement and assert. + * Strip of the general part on the way. + * + * @param string[] $data Capabilities + * @return string[] + */ + private function getFilesSharingPart(array $data) { + $this->assertArrayHasKey('files_sharing', $data); + return $data['files_sharing']; + } + + /** + * Create a mock config object and insert the values in $map to the getAppValue + * function. Then obtain the capabilities and extract the first few + * levels in the array + * + * @param (string[])[] $map Map of arguments to return types for the getAppValue function in the mock + * @return string[] + */ + private function getResults(array $map, array $typedMap = [], bool $federationEnabled = true) { + $config = $this->getMockBuilder(IConfig::class)->disableOriginalConstructor()->getMock(); + $appManager = $this->getMockBuilder(IAppManager::class)->disableOriginalConstructor()->getMock(); + $config->method('getAppValue')->willReturnMap($map); + $appManager->method('isEnabledForAnyone')->with('federation')->willReturn($federationEnabled); + + if (empty($typedMap)) { + $appConfig = $this->createMock(IAppConfig::class); + } else { + // hack to help transition from old IConfig to new IAppConfig + $appConfig = $this->getMockBuilder(IAppConfig::class)->disableOriginalConstructor()->getMock(); + $appConfig->expects($this->any())->method('getValueBool')->willReturnCallback(function (...$args) use ($typedMap): bool { + foreach ($typedMap as $entry) { + if ($entry[0] !== $args[0] || $entry[1] !== $args[1]) { + continue; + } + + return $entry[2]; + } + + return false; + }); + } + + $shareManager = new Manager( + $this->createMock(LoggerInterface::class), + $config, + $this->createMock(ISecureRandom::class), + $this->createMock(IHasher::class), + $this->createMock(IMountManager::class), + $this->createMock(IGroupManager::class), + $this->createMock(IFactory::class), + $this->createMock(IProviderFactory::class), + $this->createMock(IUserManager::class), + $this->createMock(IRootFolder::class), + $this->createMock(IMailer::class), + $this->createMock(IURLGenerator::class), + $this->createMock(\OC_Defaults::class), + $this->createMock(IEventDispatcher::class), + $this->createMock(IUserSession::class), + $this->createMock(KnownUserService::class), + $this->createMock(ShareDisableChecker::class), + $this->createMock(IDateTimeZone::class), + $appConfig, + ); + + $cap = new Capabilities($config, $appConfig, $shareManager, $appManager); + $result = $this->getFilesSharingPart($cap->getCapabilities()); + return $result; + } + + public function testEnabledSharingAPI(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ]; + $result = $this->getResults($map); + $this->assertTrue($result['api_enabled']); + $this->assertArrayHasKey('public', $result); + $this->assertArrayHasKey('user', $result); + $this->assertArrayHasKey('resharing', $result); + } + + public function testDisabledSharingAPI(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'no'], + ]; + $result = $this->getResults($map); + $this->assertFalse($result['api_enabled']); + $this->assertFalse($result['public']['enabled']); + $this->assertFalse($result['user']['send_mail']); + $this->assertFalse($result['resharing']); + } + + public function testNoLinkSharing(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'no'], + ]; + $result = $this->getResults($map); + $this->assertIsArray($result['public']); + $this->assertFalse($result['public']['enabled']); + } + + public function testOnlyLinkSharing(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertIsArray($result['public']); + $this->assertTrue($result['public']['enabled']); + } + + public function testLinkPassword(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $typedMap = [ + ['core', 'shareapi_enforce_links_password', true], + ]; + $result = $this->getResults($map, $typedMap); + $this->assertArrayHasKey('password', $result['public']); + $this->assertArrayHasKey('enforced', $result['public']['password']); + $this->assertTrue($result['public']['password']['enforced']); + } + + public function testLinkNoPassword(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ['core', 'shareapi_enforce_links_password', 'no', 'no'], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('password', $result['public']); + $this->assertArrayHasKey('enforced', $result['public']['password']); + $this->assertFalse($result['public']['password']['enforced']); + } + + public function testLinkNoExpireDate(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_default_expire_date', 'no', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('expire_date', $result['public']); + $this->assertIsArray($result['public']['expire_date']); + $this->assertFalse($result['public']['expire_date']['enabled']); + } + + public function testLinkExpireDate(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '7'], + ['core', 'shareapi_enforce_expire_date', 'no', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('expire_date', $result['public']); + $this->assertIsArray($result['public']['expire_date']); + $this->assertTrue($result['public']['expire_date']['enabled']); + $this->assertArrayHasKey('days', $result['public']['expire_date']); + $this->assertFalse($result['public']['expire_date']['enforced']); + } + + public function testLinkExpireDateEnforced(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('expire_date', $result['public']); + $this->assertIsArray($result['public']['expire_date']); + $this->assertTrue($result['public']['expire_date']['enforced']); + } + + public function testLinkSendMail(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_notification', 'no', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertTrue($result['public']['send_mail']); + } + + public function testLinkNoSendMail(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_notification', 'no', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertFalse($result['public']['send_mail']); + } + + public function testResharing(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_resharing', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertTrue($result['resharing']); + } + + public function testNoResharing(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_resharing', 'yes', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertFalse($result['resharing']); + } + + public function testLinkPublicUpload(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertTrue($result['public']['upload']); + $this->assertTrue($result['public']['upload_files_drop']); + } + + public function testLinkNoPublicUpload(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ]; + $result = $this->getResults($map); + $this->assertFalse($result['public']['upload']); + $this->assertFalse($result['public']['upload_files_drop']); + } + + public function testNoGroupSharing(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_group_sharing', 'yes', 'no'], + ]; + $result = $this->getResults($map); + $this->assertFalse($result['group_sharing']); + } + + public function testGroupSharing(): void { + $map = [ + ['core', 'shareapi_enabled', 'yes', 'yes'], + ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], + ]; + $result = $this->getResults($map); + $this->assertTrue($result['group_sharing']); + } + + public function testFederatedSharingIncoming(): void { + $map = [ + ['files_sharing', 'incoming_server2server_share_enabled', 'yes', 'yes'], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('federation', $result); + $this->assertTrue($result['federation']['incoming']); + } + + public function testFederatedSharingNoIncoming(): void { + $map = [ + ['files_sharing', 'incoming_server2server_share_enabled', 'yes', 'no'], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('federation', $result); + $this->assertFalse($result['federation']['incoming']); + } + + public function testFederatedSharingOutgoing(): void { + $map = [ + ['files_sharing', 'outgoing_server2server_share_enabled', 'yes', 'yes'], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('federation', $result); + $this->assertTrue($result['federation']['outgoing']); + } + + public function testFederatedSharingNoOutgoing(): void { + $map = [ + ['files_sharing', 'outgoing_server2server_share_enabled', 'yes', 'no'], + ]; + $result = $this->getResults($map); + $this->assertArrayHasKey('federation', $result); + $this->assertFalse($result['federation']['outgoing']); + } + + public function testFederatedSharingExpirationDate(): void { + $result = $this->getResults([]); + $this->assertArrayHasKey('federation', $result); + $this->assertEquals(['enabled' => true], $result['federation']['expire_date']); + $this->assertEquals(['enabled' => true], $result['federation']['expire_date_supported']); + } + + public function testFederatedSharingDisabled(): void { + $result = $this->getResults([], federationEnabled: false); + $this->assertArrayHasKey('federation', $result); + $this->assertFalse($result['federation']['incoming']); + $this->assertFalse($result['federation']['outgoing']); + $this->assertEquals(['enabled' => false], $result['federation']['expire_date']); + $this->assertEquals(['enabled' => false], $result['federation']['expire_date_supported']); + } +} diff --git a/apps/files_sharing/tests/Collaboration/ShareRecipientSorterTest.php b/apps/files_sharing/tests/Collaboration/ShareRecipientSorterTest.php new file mode 100644 index 00000000000..572463a9ebc --- /dev/null +++ b/apps/files_sharing/tests/Collaboration/ShareRecipientSorterTest.php @@ -0,0 +1,234 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests\Collaboration; + +use OCA\Files_Sharing\Collaboration\ShareRecipientSorter; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Node; +use OCP\IUser; +use OCP\IUserSession; +use OCP\Share\IManager; +use Test\TestCase; + +class ShareRecipientSorterTest extends TestCase { + /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + protected $shareManager; + /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ + protected $rootFolder; + /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ + protected $userSession; + /** @var ShareRecipientSorter */ + protected $sorter; + + protected function setUp(): void { + parent::setUp(); + + $this->shareManager = $this->createMock(IManager::class); + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->userSession = $this->createMock(IUserSession::class); + + $this->sorter = new ShareRecipientSorter($this->shareManager, $this->rootFolder, $this->userSession); + } + + /** + * @param $data + */ + #[\PHPUnit\Framework\Attributes\DataProvider('sortDataProvider')] + public function testSort($data): void { + $node = $this->createMock(Node::class); + + /** @var Folder|\PHPUnit\Framework\MockObject\MockObject $folder */ + $folder = $this->createMock(Folder::class); + $this->rootFolder->expects($this->any()) + ->method('getUserFolder') + ->willReturn($folder); + + $user = $this->createMock(IUser::class); + $user->expects($this->any()) + ->method('getUID') + ->willReturn('yvonne'); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($user); + + if ($data['context']['itemType'] === 'files') { + $folder->expects($this->once()) + ->method('getFirstNodeById') + ->with($data['context']['itemId']) + ->willReturn($node); + + $this->shareManager->expects($this->once()) + ->method('getAccessList') + ->with($node) + ->willReturn($data['accessList']); + } else { + $folder->expects($this->never()) + ->method('getFirstNodeById'); + $this->shareManager->expects($this->never()) + ->method('getAccessList'); + } + + $workArray = $data['input']; + $this->sorter->sort($workArray, $data['context']); + + $this->assertEquals($data['expected'], $workArray); + } + + public function testSortNoNodes(): void { + /** @var Folder|\PHPUnit\Framework\MockObject\MockObject $folder */ + $folder = $this->createMock(Folder::class); + $this->rootFolder->expects($this->any()) + ->method('getUserFolder') + ->willReturn($folder); + + $folder->expects($this->once()) + ->method('getFirstNodeById') + ->willReturn(null); + + $user = $this->createMock(IUser::class); + $user->expects($this->any()) + ->method('getUID') + ->willReturn('yvonne'); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($user); + + $this->shareManager->expects($this->never()) + ->method('getAccessList'); + + $originalArray = [ + 'users' => [ + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ] + ]; + $workArray = $originalArray; + $this->sorter->sort($workArray, ['itemType' => 'files', 'itemId' => '404']); + + $this->assertEquals($originalArray, $workArray); + } + + public static function sortDataProvider() { + return [[ + [ + #0 – sort properly and otherwise keep existing order + 'context' => ['itemType' => 'files', 'itemId' => '42'], + 'accessList' => ['users' => ['celia', 'darius', 'faruk', 'gail'], 'bots' => ['r2-d2']], + 'input' => [ + 'users' => [ + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ['value' => ['shareWith' => 'celia']], + ['value' => ['shareWith' => 'darius']], + ['value' => ['shareWith' => 'elena']], + ['value' => ['shareWith' => 'faruk']], + ['value' => ['shareWith' => 'gail']], + ], + 'bots' => [ + ['value' => ['shareWith' => 'c-3po']], + ['value' => ['shareWith' => 'r2-d2']], + ] + ], + 'expected' => [ + 'users' => [ + ['value' => ['shareWith' => 'celia']], + ['value' => ['shareWith' => 'darius']], + ['value' => ['shareWith' => 'faruk']], + ['value' => ['shareWith' => 'gail']], + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ['value' => ['shareWith' => 'elena']], + ], + 'bots' => [ + ['value' => ['shareWith' => 'r2-d2']], + ['value' => ['shareWith' => 'c-3po']], + ] + ], + ], + [ + #1 – no recipients + 'context' => ['itemType' => 'files', 'itemId' => '42'], + 'accessList' => ['users' => false], + 'input' => [ + 'users' => [ + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ['value' => ['shareWith' => 'celia']], + ['value' => ['shareWith' => 'darius']], + ['value' => ['shareWith' => 'elena']], + ['value' => ['shareWith' => 'faruk']], + ['value' => ['shareWith' => 'gail']], + ], + 'bots' => [ + ['value' => ['shareWith' => 'c-3po']], + ['value' => ['shareWith' => 'r2-d2']], + ] + ], + 'expected' => [ + 'users' => [ + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ['value' => ['shareWith' => 'celia']], + ['value' => ['shareWith' => 'darius']], + ['value' => ['shareWith' => 'elena']], + ['value' => ['shareWith' => 'faruk']], + ['value' => ['shareWith' => 'gail']], + ], + 'bots' => [ + ['value' => ['shareWith' => 'c-3po']], + ['value' => ['shareWith' => 'r2-d2']], + ] + ], + ], + [ + #2 – unsupported item type + 'context' => ['itemType' => 'announcements', 'itemId' => '42'], + 'accessList' => null, // not needed + 'input' => [ + 'users' => [ + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ['value' => ['shareWith' => 'celia']], + ['value' => ['shareWith' => 'darius']], + ['value' => ['shareWith' => 'elena']], + ['value' => ['shareWith' => 'faruk']], + ['value' => ['shareWith' => 'gail']], + ], + 'bots' => [ + ['value' => ['shareWith' => 'c-3po']], + ['value' => ['shareWith' => 'r2-d2']], + ] + ], + 'expected' => [ + 'users' => [ + ['value' => ['shareWith' => 'alice']], + ['value' => ['shareWith' => 'bob']], + ['value' => ['shareWith' => 'celia']], + ['value' => ['shareWith' => 'darius']], + ['value' => ['shareWith' => 'elena']], + ['value' => ['shareWith' => 'faruk']], + ['value' => ['shareWith' => 'gail']], + ], + 'bots' => [ + ['value' => ['shareWith' => 'c-3po']], + ['value' => ['shareWith' => 'r2-d2']], + ] + ], + ], + [ + #3 – no nothing + 'context' => ['itemType' => 'files', 'itemId' => '42'], + 'accessList' => [], + 'input' => [], + 'expected' => [], + ], + ]]; + } +} diff --git a/apps/files_sharing/tests/Command/CleanupRemoteStoragesTest.php b/apps/files_sharing/tests/Command/CleanupRemoteStoragesTest.php new file mode 100644 index 00000000000..6f0960bf46c --- /dev/null +++ b/apps/files_sharing/tests/Command/CleanupRemoteStoragesTest.php @@ -0,0 +1,205 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud GmbH. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Command; + +use OCA\Files_Sharing\Command\CleanupRemoteStorages; +use OCP\Federation\ICloudId; +use OCP\Federation\ICloudIdManager; +use OCP\IDBConnection; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +/** + * Class CleanupRemoteStoragesTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests\Command + */ +class CleanupRemoteStoragesTest extends TestCase { + + protected IDBConnection $connection; + protected CleanupRemoteStorages $command; + private ICloudIdManager&MockObject $cloudIdManager; + + private $storages = [ + ['id' => 'shared::7b4a322b22f9d0047c38d77d471ce3cf', 'share_token' => 'f2c69dad1dc0649f26976fd210fc62e1', 'remote' => 'https://hostname.tld/owncloud1', 'user' => 'user1'], + ['id' => 'shared::efe3b456112c3780da6155d3a9b9141c', 'share_token' => 'f2c69dad1dc0649f26976fd210fc62e2', 'remote' => 'https://hostname.tld/owncloud2', 'user' => 'user2'], + ['notExistingId' => 'shared::33323d9f4ca416a9e3525b435354bc6f', 'share_token' => 'f2c69dad1dc0649f26976fd210fc62e3', 'remote' => 'https://hostname.tld/owncloud3', 'user' => 'user3'], + ['id' => 'shared::7fe41a07d3f517a923f4b2b599e72cbb', 'files_count' => 2], + ['id' => 'shared::de4aeb2f378d222b6d2c5fd8f4e42f8e', 'share_token' => 'f2c69dad1dc0649f26976fd210fc62e5', 'remote' => 'https://hostname.tld/owncloud5', 'user' => 'user5'], + ['id' => 'shared::af712293ab5eb9e6a1745a13818b99fe', 'files_count' => 3], + ['notExistingId' => 'shared::c34568c143cdac7d2f06e0800b5280f9', 'share_token' => 'f2c69dad1dc0649f26976fd210fc62e7', 'remote' => 'https://hostname.tld/owncloud7', 'user' => 'user7'], + ]; + + protected function setUp(): void { + parent::setUp(); + + $this->connection = Server::get(IDBConnection::class); + + $storageQuery = Server::get(IDBConnection::class)->getQueryBuilder(); + $storageQuery->insert('storages') + ->setValue('id', $storageQuery->createParameter('id')); + + $shareExternalQuery = Server::get(IDBConnection::class)->getQueryBuilder(); + $shareExternalQuery->insert('share_external') + ->setValue('share_token', $shareExternalQuery->createParameter('share_token')) + ->setValue('remote', $shareExternalQuery->createParameter('remote')) + ->setValue('name', $shareExternalQuery->createParameter('name')) + ->setValue('owner', $shareExternalQuery->createParameter('owner')) + ->setValue('user', $shareExternalQuery->createParameter('user')) + ->setValue('mountpoint', $shareExternalQuery->createParameter('mountpoint')) + ->setValue('mountpoint_hash', $shareExternalQuery->createParameter('mountpoint_hash')); + + $filesQuery = Server::get(IDBConnection::class)->getQueryBuilder(); + $filesQuery->insert('filecache') + ->setValue('storage', $filesQuery->createParameter('storage')) + ->setValue('path', $filesQuery->createParameter('path')) + ->setValue('path_hash', $filesQuery->createParameter('path_hash')); + + foreach ($this->storages as &$storage) { + if (isset($storage['id'])) { + $storageQuery->setParameter('id', $storage['id']); + $storageQuery->executeStatement(); + $storage['numeric_id'] = $storageQuery->getLastInsertId(); + } + + if (isset($storage['share_token'])) { + $shareExternalQuery + ->setParameter('share_token', $storage['share_token']) + ->setParameter('remote', $storage['remote']) + ->setParameter('name', 'irrelevant') + ->setParameter('owner', 'irrelevant') + ->setParameter('user', $storage['user']) + ->setParameter('mountpoint', 'irrelevant') + ->setParameter('mountpoint_hash', 'irrelevant'); + $shareExternalQuery->executeStatement(); + } + + if (isset($storage['files_count'])) { + for ($i = 0; $i < $storage['files_count']; $i++) { + $filesQuery->setParameter('storage', $storage['numeric_id']); + $filesQuery->setParameter('path', 'file' . $i); + $filesQuery->setParameter('path_hash', md5('file' . $i)); + $filesQuery->executeStatement(); + } + } + } + + $this->cloudIdManager = $this->createMock(ICloudIdManager::class); + + $this->command = new CleanupRemoteStorages($this->connection, $this->cloudIdManager); + } + + protected function tearDown(): void { + $storageQuery = Server::get(IDBConnection::class)->getQueryBuilder(); + $storageQuery->delete('storages') + ->where($storageQuery->expr()->eq('id', $storageQuery->createParameter('id'))); + + $shareExternalQuery = Server::get(IDBConnection::class)->getQueryBuilder(); + $shareExternalQuery->delete('share_external') + ->where($shareExternalQuery->expr()->eq('share_token', $shareExternalQuery->createParameter('share_token'))) + ->andWhere($shareExternalQuery->expr()->eq('remote', $shareExternalQuery->createParameter('remote'))); + + foreach ($this->storages as $storage) { + if (isset($storage['id'])) { + $storageQuery->setParameter('id', $storage['id']); + $storageQuery->executeStatement(); + } + + if (isset($storage['share_token'])) { + $shareExternalQuery->setParameter('share_token', $storage['share_token']); + $shareExternalQuery->setParameter('remote', $storage['remote']); + $shareExternalQuery->executeStatement(); + } + } + + parent::tearDown(); + } + + private function doesStorageExist($numericId) { + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $qb->select('*') + ->from('storages') + ->where($qb->expr()->eq('numeric_id', $qb->createNamedParameter($numericId))); + + $qResult = $qb->executeQuery(); + $result = $qResult->fetch(); + $qResult->closeCursor(); + if (!empty($result)) { + return true; + } + + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $qb->select('*') + ->from('filecache') + ->where($qb->expr()->eq('storage', $qb->createNamedParameter($numericId))); + + $qResult = $qb->executeQuery(); + $result = $qResult->fetch(); + $qResult->closeCursor(); + if (!empty($result)) { + return true; + } + + return false; + } + + /** + * Test cleanup of orphaned storages + */ + public function testCleanup(): void { + $input = $this->getMockBuilder(InputInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $output = $this->getMockBuilder(OutputInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + // parent folder, `files`, ´test` and `welcome.txt` => 4 elements + $outputCalls = []; + $output + ->expects($this->any()) + ->method('writeln') + ->willReturnCallback(function (string $text) use (&$outputCalls): void { + $outputCalls[] = $text; + }); + + $this->cloudIdManager + ->expects($this->any()) + ->method('getCloudId') + ->willReturnCallback(function (string $user, string $remote) { + $cloudIdMock = $this->createMock(ICloudId::class); + + // The remotes are already sanitized in the original data, so + // they can be directly returned. + $cloudIdMock + ->expects($this->any()) + ->method('getRemote') + ->willReturn($remote); + + return $cloudIdMock; + }); + + $this->command->execute($input, $output); + + $this->assertTrue($this->doesStorageExist($this->storages[0]['numeric_id'])); + $this->assertTrue($this->doesStorageExist($this->storages[1]['numeric_id'])); + $this->assertFalse($this->doesStorageExist($this->storages[3]['numeric_id'])); + $this->assertTrue($this->doesStorageExist($this->storages[4]['numeric_id'])); + $this->assertFalse($this->doesStorageExist($this->storages[5]['numeric_id'])); + + $this->assertEquals([ + '5 remote storage(s) need(s) to be checked', + '5 remote share(s) exist', + ], array_slice($outputCalls, 0, 2)); + } +} diff --git a/apps/files_sharing/tests/Command/FixShareOwnersTest.php b/apps/files_sharing/tests/Command/FixShareOwnersTest.php new file mode 100644 index 00000000000..0fde61895b1 --- /dev/null +++ b/apps/files_sharing/tests/Command/FixShareOwnersTest.php @@ -0,0 +1,117 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Command; + +use OCA\Files_Sharing\Command\FixShareOwners; +use OCA\Files_Sharing\OrphanHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +/** + * Class FixShareOwnersTest + * + * @package OCA\Files_Sharing\Tests\Command + */ +class FixShareOwnersTest extends TestCase { + /** + * @var FixShareOwners + */ + private $command; + + /** + * @var OrphanHelper|\PHPUnit\Framework\MockObject\MockObject + */ + private $orphanHelper; + + protected function setUp(): void { + parent::setUp(); + + $this->orphanHelper = $this->createMock(OrphanHelper::class); + $this->command = new FixShareOwners($this->orphanHelper); + } + + public function testExecuteNoSharesDetected() { + $this->orphanHelper->expects($this->once()) + ->method('getAllShares') + ->willReturn([ + ['id' => 1, 'owner' => 'user1', 'fileid' => 1, 'target' => 'target1'], + ['id' => 2, 'owner' => 'user2', 'fileid' => 2, 'target' => 'target2'], + ]); + $this->orphanHelper->expects($this->exactly(2)) + ->method('isShareValid') + ->willReturn(true); + + $input = $this->createMock(InputInterface::class); + $output = $this->createMock(OutputInterface::class); + + $output->expects($this->once()) + ->method('writeln') + ->with('No broken shares detected'); + $this->command->execute($input, $output); + } + + public function testExecuteSharesDetected() { + $this->orphanHelper->expects($this->once()) + ->method('getAllShares') + ->willReturn([ + ['id' => 1, 'owner' => 'user1', 'fileid' => 1, 'target' => 'target1'], + ['id' => 2, 'owner' => 'user2', 'fileid' => 2, 'target' => 'target2'], + ]); + $this->orphanHelper->expects($this->exactly(2)) + ->method('isShareValid') + ->willReturnOnConsecutiveCalls(true, false); + $this->orphanHelper->expects($this->once()) + ->method('fileExists') + ->willReturn(true); + $this->orphanHelper->expects($this->once()) + ->method('findOwner') + ->willReturn('newOwner'); + $this->orphanHelper->expects($this->once()) + ->method('updateShareOwner'); + + $input = $this->createMock(InputInterface::class); + $output = $this->createMock(OutputInterface::class); + + $output->expects($this->once()) + ->method('writeln') + ->with('Share with id <info>2</info> (target: <info>target2</info>) updated to owner <info>newOwner</info>'); + $this->command->execute($input, $output); + } + + public function testExecuteSharesDetectedDryRun() { + $this->orphanHelper->expects($this->once()) + ->method('getAllShares') + ->willReturn([ + ['id' => 1, 'owner' => 'user1', 'fileid' => 1, 'target' => 'target1'], + ['id' => 2, 'owner' => 'user2', 'fileid' => 2, 'target' => 'target2'], + ]); + $this->orphanHelper->expects($this->exactly(2)) + ->method('isShareValid') + ->willReturnOnConsecutiveCalls(true, false); + $this->orphanHelper->expects($this->once()) + ->method('fileExists') + ->willReturn(true); + $this->orphanHelper->expects($this->once()) + ->method('findOwner') + ->willReturn('newOwner'); + $this->orphanHelper->expects($this->never()) + ->method('updateShareOwner'); + + $input = $this->createMock(InputInterface::class); + $output = $this->createMock(OutputInterface::class); + + $output->expects($this->once()) + ->method('writeln') + ->with('Share with id <info>2</info> (target: <info>target2</info>) can be updated to owner <info>newOwner</info>'); + $input->expects($this->once()) + ->method('getOption') + ->with('dry-run') + ->willReturn(true); + $this->command->execute($input, $output); + } +} diff --git a/apps/files_sharing/tests/Controller/ExternalShareControllerTest.php b/apps/files_sharing/tests/Controller/ExternalShareControllerTest.php new file mode 100644 index 00000000000..7e054d9a6dc --- /dev/null +++ b/apps/files_sharing/tests/Controller/ExternalShareControllerTest.php @@ -0,0 +1,80 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Controllers; + +use OCA\Files_Sharing\Controller\ExternalSharesController; +use OCA\Files_Sharing\External\Manager; +use OCP\AppFramework\Http\JSONResponse; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\IRequest; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * Class ExternalShareControllerTest + * + * @package OCA\Files_Sharing\Controllers + */ +class ExternalShareControllerTest extends \Test\TestCase { + /** @var IRequest */ + private $request; + /** @var \OCA\Files_Sharing\External\Manager */ + private $externalManager; + /** @var IConfig|MockObject */ + private $config; + /** @var IClientService */ + private $clientService; + + protected function setUp(): void { + parent::setUp(); + $this->request = $this->createMock(IRequest::class); + $this->externalManager = $this->createMock(Manager::class); + $this->clientService = $this->createMock(IClientService::class); + $this->config = $this->createMock(IConfig::class); + } + + /** + * @return ExternalSharesController + */ + public function getExternalShareController() { + return new ExternalSharesController( + 'files_sharing', + $this->request, + $this->externalManager, + $this->clientService, + $this->config, + ); + } + + public function testIndex(): void { + $this->externalManager + ->expects($this->once()) + ->method('getOpenShares') + ->willReturn(['MyDummyArray']); + + $this->assertEquals(new JSONResponse(['MyDummyArray']), $this->getExternalShareController()->index()); + } + + public function testCreate(): void { + $this->externalManager + ->expects($this->once()) + ->method('acceptShare') + ->with(4); + + $this->assertEquals(new JSONResponse(), $this->getExternalShareController()->create(4)); + } + + public function testDestroy(): void { + $this->externalManager + ->expects($this->once()) + ->method('declineShare') + ->with(4); + + $this->assertEquals(new JSONResponse(), $this->getExternalShareController()->destroy(4)); + } +} diff --git a/apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php b/apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php new file mode 100644 index 00000000000..f49d839e8d4 --- /dev/null +++ b/apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php @@ -0,0 +1,292 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests\Controller; + +use OCA\Files_Sharing\Controller\PublicPreviewController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Constants; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\NotFoundException; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\IPreview; +use OCP\IRequest; +use OCP\ISession; +use OCP\Preview\IMimeIconProvider; +use OCP\Share\Exceptions\ShareNotFound; +use OCP\Share\IManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class PublicPreviewControllerTest extends TestCase { + + private IPreview&MockObject $previewManager; + private IManager&MockObject $shareManager; + private ITimeFactory&MockObject $timeFactory; + private IRequest&MockObject $request; + + private PublicPreviewController $controller; + + protected function setUp(): void { + parent::setUp(); + + $this->previewManager = $this->createMock(IPreview::class); + $this->shareManager = $this->createMock(IManager::class); + $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->request = $this->createMock(IRequest::class); + + $this->timeFactory->method('getTime') + ->willReturn(1337); + + $this->overwriteService(ITimeFactory::class, $this->timeFactory); + + $this->controller = new PublicPreviewController( + 'files_sharing', + $this->request, + $this->shareManager, + $this->createMock(ISession::class), + $this->previewManager, + $this->createMock(IMimeIconProvider::class), + ); + } + + public function testInvalidToken(): void { + $res = $this->controller->getPreview('', 'file', 10, 10, ''); + $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); + + $this->assertEquals($expected, $res); + } + + public function testInvalidWidth(): void { + $res = $this->controller->getPreview('token', 'file', 0); + $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); + + $this->assertEquals($expected, $res); + } + + public function testInvalidHeight(): void { + $res = $this->controller->getPreview('token', 'file', 10, 0); + $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); + + $this->assertEquals($expected, $res); + } + + public function testInvalidShare(): void { + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willThrowException(new ShareNotFound()); + + $res = $this->controller->getPreview('token', 'file', 10, 10); + $expected = new DataResponse([], Http::STATUS_NOT_FOUND); + + $this->assertEquals($expected, $res); + } + + public function testShareNotAccessable(): void { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(0); + + $res = $this->controller->getPreview('token', 'file', 10, 10); + $expected = new DataResponse([], Http::STATUS_FORBIDDEN); + + $this->assertEquals($expected, $res); + } + + public function testShareNoDownload() { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + + $share->method('canSeeContent') + ->willReturn(false); + + $res = $this->controller->getPreview('token', 'file', 10, 10); + $expected = new DataResponse([], Http::STATUS_FORBIDDEN); + + $this->assertEquals($expected, $res); + } + + public function testShareNoDownloadButPreviewHeader() { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + + $share->method('canSeeContent') + ->willReturn(false); + + $this->request->method('getHeader') + ->with('x-nc-preview') + ->willReturn('true'); + + $file = $this->createMock(File::class); + $share->method('getNode') + ->willReturn($file); + + $preview = $this->createMock(ISimpleFile::class); + $preview->method('getName')->willReturn('name'); + $preview->method('getMTime')->willReturn(42); + $this->previewManager->method('getPreview') + ->with($this->equalTo($file), 10, 10, false) + ->willReturn($preview); + + $preview->method('getMimeType') + ->willReturn('myMime'); + + $res = $this->controller->getPreview('token', 'file', 10, 10, true); + $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'myMime']); + $expected->cacheFor(15 * 60); + $this->assertEquals($expected, $res); + } + + public function testShareWithAttributes() { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + + $share->method('canSeeContent') + ->willReturn(true); + + $this->request->method('getHeader') + ->with('x-nc-preview') + ->willReturn('true'); + + $file = $this->createMock(File::class); + $share->method('getNode') + ->willReturn($file); + + $preview = $this->createMock(ISimpleFile::class); + $preview->method('getName')->willReturn('name'); + $preview->method('getMTime')->willReturn(42); + $this->previewManager->method('getPreview') + ->with($this->equalTo($file), 10, 10, false) + ->willReturn($preview); + + $preview->method('getMimeType') + ->willReturn('myMime'); + + $res = $this->controller->getPreview('token', 'file', 10, 10, true); + $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'myMime']); + $expected->cacheFor(3600 * 24); + $this->assertEquals($expected, $res); + } + + public function testPreviewFile() { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + + $file = $this->createMock(File::class); + $share->method('getNode') + ->willReturn($file); + + $share->method('canSeeContent') + ->willReturn(true); + + $preview = $this->createMock(ISimpleFile::class); + $preview->method('getName')->willReturn('name'); + $preview->method('getMTime')->willReturn(42); + $this->previewManager->method('getPreview') + ->with($this->equalTo($file), 10, 10, false) + ->willReturn($preview); + + $preview->method('getMimeType') + ->willReturn('myMime'); + + $res = $this->controller->getPreview('token', 'file', 10, 10, true); + $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'myMime']); + $expected->cacheFor(3600 * 24); + $this->assertEquals($expected, $res); + } + + public function testPreviewFolderInvalidFile(): void { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + + $folder = $this->createMock(Folder::class); + $share->method('getNode') + ->willReturn($folder); + + $share->method('canSeeContent') + ->willReturn(true); + + $folder->method('get') + ->with($this->equalTo('file')) + ->willThrowException(new NotFoundException()); + + $res = $this->controller->getPreview('token', 'file', 10, 10, true); + $expected = new DataResponse([], Http::STATUS_NOT_FOUND); + $this->assertEquals($expected, $res); + } + + + public function testPreviewFolderValidFile(): void { + $share = $this->createMock(IShare::class); + $this->shareManager->method('getShareByToken') + ->with($this->equalTo('token')) + ->willReturn($share); + + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + + $folder = $this->createMock(Folder::class); + $share->method('getNode') + ->willReturn($folder); + + $share->method('canSeeContent') + ->willReturn(true); + + $file = $this->createMock(File::class); + $folder->method('get') + ->with($this->equalTo('file')) + ->willReturn($file); + + $preview = $this->createMock(ISimpleFile::class); + $preview->method('getName')->willReturn('name'); + $preview->method('getMTime')->willReturn(42); + $this->previewManager->method('getPreview') + ->with($this->equalTo($file), 10, 10, false) + ->willReturn($preview); + + $preview->method('getMimeType') + ->willReturn('myMime'); + + $res = $this->controller->getPreview('token', 'file', 10, 10, true); + $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'myMime']); + $expected->cacheFor(3600 * 24); + $this->assertEquals($expected, $res); + } +} diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php new file mode 100644 index 00000000000..e6be0342c26 --- /dev/null +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -0,0 +1,5380 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Controller; + +use OCA\Federation\TrustedServers; +use OCA\Files_Sharing\Controller\ShareAPIController; +use OCP\App\IAppManager; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCS\OCSBadRequestException; +use OCP\AppFramework\OCS\OCSException; +use OCP\AppFramework\OCS\OCSForbiddenException; +use OCP\AppFramework\OCS\OCSNotFoundException; +use OCP\Constants; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Mount\IShareOwnerlessMount; +use OCP\Files\NotFoundException; +use OCP\Files\Storage\IStorage; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IDateTimeZone; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\IPreview; +use OCP\IRequest; +use OCP\ITagManager; +use OCP\ITags; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Lock\ILockingProvider; +use OCP\Lock\LockedException; +use OCP\Mail\IMailer; +use OCP\Server; +use OCP\Share\Exceptions\GenericShareException; +use OCP\Share\Exceptions\ShareNotFound; +use OCP\Share\IAttributes as IShareAttributes; +use OCP\Share\IManager; +use OCP\Share\IProviderFactory; +use OCP\Share\IShare; +use OCP\UserStatus\IManager as IUserStatusManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Test\TestCase; + +/** + * Class ShareAPIControllerTest + * + * @package OCA\Files_Sharing\Tests\Controller + * @group DB + */ +class ShareAPIControllerTest extends TestCase { + + private string $appName = 'files_sharing'; + private string $currentUser; + + private ShareAPIController $ocs; + + private IManager&MockObject $shareManager; + private IGroupManager&MockObject $groupManager; + private IUserManager&MockObject $userManager; + private IRequest&MockObject $request; + private IRootFolder&MockObject $rootFolder; + private IURLGenerator&MockObject $urlGenerator; + private IL10N&MockObject $l; + private IConfig&MockObject $config; + private IAppConfig&MockObject $appConfig; + private IAppManager&MockObject $appManager; + private ContainerInterface&MockObject $serverContainer; + private IUserStatusManager&MockObject $userStatusManager; + private IPreview&MockObject $previewManager; + private IDateTimeZone&MockObject $dateTimeZone; + private LoggerInterface&MockObject $logger; + private IProviderFactory&MockObject $factory; + private IMailer&MockObject $mailer; + private ITagManager&MockObject $tagManager; + private TrustedServers&MockObject $trustedServers; + + protected function setUp(): void { + $this->shareManager = $this->createMock(IManager::class); + $this->shareManager + ->expects($this->any()) + ->method('shareApiEnabled') + ->willReturn(true); + $this->shareManager + ->expects($this->any()) + ->method('shareProviderExists')->willReturn(true); + $this->groupManager = $this->createMock(IGroupManager::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->request = $this->createMock(IRequest::class); + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->currentUser = 'currentUser'; + + $this->l = $this->createMock(IL10N::class); + $this->l->method('t') + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + $this->config = $this->createMock(IConfig::class); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->serverContainer = $this->createMock(ContainerInterface::class); + $this->userStatusManager = $this->createMock(IUserStatusManager::class); + $this->previewManager = $this->createMock(IPreview::class); + $this->previewManager->method('isAvailable') + ->willReturnCallback(function ($fileInfo) { + return $fileInfo->getMimeType() === 'mimeWithPreview'; + }); + $this->dateTimeZone = $this->createMock(IDateTimeZone::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->factory = $this->createMock(IProviderFactory::class); + $this->mailer = $this->createMock(IMailer::class); + $this->tagManager = $this->createMock(ITagManager::class); + $this->trustedServers = $this->createMock(TrustedServers::class); + + $this->ocs = new ShareAPIController( + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser + ); + + } + + /** + * @return ShareAPIController&MockObject + */ + private function mockFormatShare() { + return $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ])->onlyMethods(['formatShare']) + ->getMock(); + } + + private function newShare() { + return Server::get(IManager::class)->newShare(); + } + + + private function mockShareAttributes() { + $formattedShareAttributes = [ + [ + 'scope' => 'permissions', + 'key' => 'download', + 'value' => true + ] + ]; + + $shareAttributes = $this->createMock(IShareAttributes::class); + $shareAttributes->method('toArray')->willReturn($formattedShareAttributes); + $shareAttributes->method('getAttribute')->with('permissions', 'download')->willReturn(true); + + // send both IShare attributes class and expected json string + return [$shareAttributes, \json_encode($formattedShareAttributes)]; + } + + public function testDeleteShareShareNotFound(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Wrong share ID, share does not exist'); + + $this->shareManager + ->expects($this->exactly(7)) + ->method('getShareById') + ->willReturnCallback(function ($id): void { + if ($id === 'ocinternal:42' || $id === 'ocRoomShare:42' || $id === 'ocFederatedSharing:42' || $id === 'ocCircleShare:42' || $id === 'ocMailShare:42' || $id === 'deck:42' || $id === 'sciencemesh:42') { + throw new ShareNotFound(); + } else { + throw new \Exception(); + } + }); + + $this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true); + + $this->ocs->deleteShare(42); + } + + public function testDeleteShare(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + + $share = $this->newShare(); + $share->setSharedBy($this->currentUser) + ->setNode($node); + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + $this->shareManager + ->expects($this->once()) + ->method('deleteShare') + ->with($share); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $expected = new DataResponse(); + $result = $this->ocs->deleteShare(42); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testDeleteShareLocked(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Could not delete share'); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(1); + + $share = $this->newShare(); + $share->setNode($node); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$node]); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + + $this->shareManager + ->expects($this->never()) + ->method('deleteShare') + ->with($share); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED) + ->willThrowException(new LockedException('mypath')); + + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share])); + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share])); + + $this->ocs->deleteShare(42); + } + + /** + * You can always remove a share that was shared with you + */ + public function testDeleteShareWithMe(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + + $share = $this->newShare(); + $share->setSharedWith($this->currentUser) + ->setShareType(IShare::TYPE_USER) + ->setNode($node); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + + $this->shareManager + ->expects($this->once()) + ->method('deleteShare') + ->with($share); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share])); + $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share])); + + $this->ocs->deleteShare(42); + } + + /** + * You can always delete a share you own + */ + public function testDeleteShareOwner(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + + $share = $this->newShare(); + $share->setSharedBy($this->currentUser) + ->setNode($node); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + + $this->shareManager + ->expects($this->once()) + ->method('deleteShare') + ->with($share); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share])); + $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share])); + + $this->ocs->deleteShare(42); + } + + /** + * You can always delete a share when you own + * the file path it belong to + */ + public function testDeleteShareFileOwner(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(1); + + $share = $this->newShare(); + $share->setShareOwner($this->currentUser) + ->setNode($node); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + + $this->shareManager + ->expects($this->once()) + ->method('deleteShare') + ->with($share); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteFromSelf', [$share])); + $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShare', [$share])); + + $this->ocs->deleteShare(42); + } + + /** + * You can remove (the mountpoint, not the share) + * a share if you're in the group the share is shared with + */ + public function testDeleteSharedWithMyGroup(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(1); + + $share = $this->newShare(); + $share->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('group') + ->setNode($node); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + + // canDeleteShareFromSelf + $user = $this->createMock(IUser::class); + $group = $this->getMockBuilder(IGroup::class)->getMock(); + $this->groupManager + ->method('get') + ->with('group') + ->willReturn($group); + $this->userManager + ->method('get') + ->with($this->currentUser) + ->willReturn($user); + $group->method('inGroup') + ->with($user) + ->willReturn(true); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$share->getNode()]); + + $this->shareManager->expects($this->once()) + ->method('deleteFromSelf') + ->with($share, $this->currentUser); + + $this->shareManager->expects($this->never()) + ->method('deleteShare'); + + $this->assertTrue($this->invokePrivate($this->ocs, 'canDeleteShareFromSelf', [$share])); + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share])); + + $this->ocs->deleteShare(42); + } + + /** + * You cannot remove a share if you're not + * in the group the share is shared with + */ + public function testDeleteSharedWithGroupIDontBelongTo(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Wrong share ID, share does not exist'); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + + $share = $this->newShare(); + $share->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('group') + ->setNode($node); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + + // canDeleteShareFromSelf + $user = $this->createMock(IUser::class); + $group = $this->getMockBuilder(IGroup::class)->getMock(); + $this->groupManager + ->method('get') + ->with('group') + ->willReturn($group); + $this->userManager + ->method('get') + ->with($this->currentUser) + ->willReturn($user); + $group->method('inGroup') + ->with($user) + ->willReturn(false); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$share->getNode()]); + + $this->shareManager->expects($this->never()) + ->method('deleteFromSelf'); + + $this->shareManager->expects($this->never()) + ->method('deleteShare'); + + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShareFromSelf', [$share])); + $this->assertFalse($this->invokePrivate($this->ocs, 'canDeleteShare', [$share])); + + $this->ocs->deleteShare(42); + } + + public function testDeleteShareOwnerless(): void { + $ocs = $this->mockFormatShare(); + + $mount = $this->createMock(IShareOwnerlessMount::class); + + $file = $this->createMock(File::class); + $file + ->expects($this->exactly(2)) + ->method('getPermissions') + ->willReturn(Constants::PERMISSION_SHARE); + $file + ->expects($this->once()) + ->method('getMountPoint') + ->willReturn($mount); + + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(2) + ->willReturn([$file]); + $userFolder->method('getFirstNodeById') + ->with(2) + ->willReturn($file); + + $this->rootFolder + ->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $share = $this->createMock(IShare::class); + $share + ->expects($this->once()) + ->method('getNode') + ->willReturn($file); + $share + ->expects($this->exactly(2)) + ->method('getNodeId') + ->willReturn(2); + $share + ->expects($this->exactly(2)) + ->method('getPermissions') + ->willReturn(Constants::PERMISSION_SHARE); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:1', $this->currentUser) + ->willReturn($share); + + $this->shareManager + ->expects($this->once()) + ->method('deleteShare') + ->with($share); + + $result = $ocs->deleteShare(1); + $this->assertInstanceOf(DataResponse::class, $result); + } + + /* + * FIXME: Enable once we have a federated Share Provider + + public function testGetGetShareNotExists() { + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42', 'currentUser') + ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound())); + + $expected = new \OC\OCS\Result(null, 404, 'wrong share ID, share does not exist.'); + $this->assertEquals($expected, $this->ocs->getShare(42)); + } + */ + + public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner, $path, $permissions, + $shareTime, $expiration, $parent, $target, $mail_send, $note = '', $token = null, + $password = null, $label = '', $attributes = null) { + $share = $this->getMockBuilder(IShare::class)->getMock(); + $share->method('getId')->willReturn($id); + $share->method('getShareType')->willReturn($shareType); + $share->method('getSharedWith')->willReturn($sharedWith); + $share->method('getSharedBy')->willReturn($sharedBy); + $share->method('getShareOwner')->willReturn($shareOwner); + $share->method('getNode')->willReturn($path); + $share->method('getPermissions')->willReturn($permissions); + $share->method('getNote')->willReturn($note); + $share->method('getLabel')->willReturn($label); + $share->method('getAttributes')->willReturn($attributes); + $time = new \DateTime(); + $time->setTimestamp($shareTime); + $share->method('getShareTime')->willReturn($time); + $share->method('getExpirationDate')->willReturn($expiration); + $share->method('getTarget')->willReturn($target); + $share->method('getMailSend')->willReturn($mail_send); + $share->method('getToken')->willReturn($token); + $share->method('getPassword')->willReturn($password); + + if ($shareType === IShare::TYPE_USER + || $shareType === IShare::TYPE_GROUP + || $shareType === IShare::TYPE_LINK) { + $share->method('getFullId')->willReturn('ocinternal:' . $id); + } + + return $share; + } + + public function dataGetShare() { + $data = []; + + $cache = $this->getMockBuilder('OC\Files\Cache\Cache') + ->disableOriginalConstructor() + ->getMock(); + $cache->method('getNumericStorageId')->willReturn(101); + + $storage = $this->getMockBuilder(IStorage::class) + ->disableOriginalConstructor() + ->getMock(); + $storage->method('getId')->willReturn('STORAGE'); + $storage->method('getCache')->willReturn($cache); + + $parentFolder = $this->getMockBuilder(Folder::class)->getMock(); + $parentFolder->method('getId')->willReturn(3); + $mountPoint = $this->createMock(IMountPoint::class); + $mountPoint->method('getMountType')->willReturn(''); + + $file = $this->getMockBuilder('OCP\Files\File')->getMock(); + $file->method('getId')->willReturn(1); + $file->method('getPath')->willReturn('file'); + $file->method('getStorage')->willReturn($storage); + $file->method('getParent')->willReturn($parentFolder); + $file->method('getSize')->willReturn(123465); + $file->method('getMTime')->willReturn(1234567890); + $file->method('getMimeType')->willReturn('myMimeType'); + $file->method('getMountPoint')->willReturn($mountPoint); + + $folder = $this->getMockBuilder(Folder::class)->getMock(); + $folder->method('getId')->willReturn(2); + $folder->method('getPath')->willReturn('folder'); + $folder->method('getStorage')->willReturn($storage); + $folder->method('getParent')->willReturn($parentFolder); + $folder->method('getSize')->willReturn(123465); + $folder->method('getMTime')->willReturn(1234567890); + $folder->method('getMimeType')->willReturn('myFolderMimeType'); + $folder->method('getMountPoint')->willReturn($mountPoint); + + [$shareAttributes, $shareAttributesReturnJson] = $this->mockShareAttributes(); + + // File shared with user + $share = $this->createShare( + 100, + IShare::TYPE_USER, + 'userId', + 'initiatorId', + 'ownerId', + $file, + 4, + 5, + null, + 6, + 'target', + 0, + 'personal note', + $shareAttributes, + ); + $expected = [ + 'id' => 100, + 'share_type' => IShare::TYPE_USER, + 'share_with' => 'userId', + 'share_with_displayname' => 'userDisplay', + 'share_with_displayname_unique' => 'userId@example.com', + 'uid_owner' => 'initiatorId', + 'displayname_owner' => 'initiatorDisplay', + 'item_type' => 'file', + 'item_source' => 1, + 'file_source' => 1, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'attributes' => $shareAttributesReturnJson, + 'stime' => 5, + 'parent' => null, + 'storage_id' => 'STORAGE', + 'path' => 'file', + 'storage' => 101, + 'mail_send' => 0, + 'uid_file_owner' => 'ownerId', + 'note' => 'personal note', + 'label' => '', + 'displayname_file_owner' => 'ownerDisplay', + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123465, + 'item_mtime' => 1234567890, + 'attributes' => null, + 'item_permissions' => 4, + 'is-mount-root' => false, + 'mount-type' => '', + ]; + $data[] = [$share, $expected]; + + // Folder shared with group + $share = $this->createShare( + 101, + IShare::TYPE_GROUP, + 'groupId', + 'initiatorId', + 'ownerId', + $folder, + 4, + 5, + null, + 6, + 'target', + 0, + 'personal note', + $shareAttributes, + ); + $expected = [ + 'id' => 101, + 'share_type' => IShare::TYPE_GROUP, + 'share_with' => 'groupId', + 'share_with_displayname' => 'groupId', + 'uid_owner' => 'initiatorId', + 'displayname_owner' => 'initiatorDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => null, + 'expiration' => null, + 'permissions' => 4, + 'attributes' => $shareAttributesReturnJson, + 'stime' => 5, + 'parent' => null, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => 101, + 'mail_send' => 0, + 'uid_file_owner' => 'ownerId', + 'note' => 'personal note', + 'label' => '', + 'displayname_file_owner' => 'ownerDisplay', + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123465, + 'item_mtime' => 1234567890, + 'attributes' => null, + 'item_permissions' => 4, + 'is-mount-root' => false, + 'mount-type' => '', + ]; + $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, + IShare::TYPE_LINK, + null, + 'initiatorId', + 'ownerId', + $folder, + 4, + 5, + $expire, + 6, + 'target', + 0, + 'personal note', + 'token', + 'password', + 'first link share' + ); + $expected = [ + 'id' => 101, + 'share_type' => IShare::TYPE_LINK, + 'password' => 'password', + 'share_with' => 'password', + 'share_with_displayname' => '(Shared link)', + 'send_password_by_talk' => false, + 'uid_owner' => 'initiatorId', + 'displayname_owner' => 'initiatorDisplay', + 'item_type' => 'folder', + 'item_source' => 2, + 'file_source' => 2, + 'file_target' => 'target', + 'file_parent' => 3, + 'token' => 'token', + 'expiration' => '2000-01-02 00:00:00', + 'permissions' => 4, + 'attributes' => null, + 'stime' => 5, + 'parent' => null, + 'storage_id' => 'STORAGE', + 'path' => 'folder', + 'storage' => 101, + 'mail_send' => 0, + 'url' => 'url', + 'uid_file_owner' => 'ownerId', + 'note' => 'personal note', + 'label' => 'first link share', + 'displayname_file_owner' => 'ownerDisplay', + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123465, + 'item_mtime' => 1234567890, + 'attributes' => null, + 'item_permissions' => 4, + 'is-mount-root' => false, + 'mount-type' => '', + ]; + $data[] = [$share, $expected]; + + return $data; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetShare')] + public function testGetShare(IShare $share, array $result): void { + /** @var ShareAPIController&MockObject $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ]) + ->onlyMethods(['canAccessShare']) + ->getMock(); + + $ocs->expects($this->any()) + ->method('canAccessShare') + ->willReturn(true); + + $this->shareManager + ->expects($this->any()) + ->method('getShareById') + ->with($share->getFullId(), 'currentUser') + ->willReturn($share); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $userFolder + ->method('getRelativePath') + ->willReturnArgument(0); + + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$share->getNode()]); + $userFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($share->getNode()); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $this->urlGenerator + ->method('linkToRouteAbsolute') + ->willReturn('url'); + + $initiator = $this->getMockBuilder(IUser::class)->getMock(); + $initiator->method('getUID')->willReturn('initiatorId'); + $initiator->method('getDisplayName')->willReturn('initiatorDisplay'); + + $owner = $this->getMockBuilder(IUser::class)->getMock(); + $owner->method('getUID')->willReturn('ownerId'); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + + $user = $this->getMockBuilder(IUser::class)->getMock(); + $user->method('getUID')->willReturn('userId'); + $user->method('getDisplayName')->willReturn('userDisplay'); + $user->method('getSystemEMailAddress')->willReturn('userId@example.com'); + + $group = $this->getMockBuilder(IGroup::class)->getMock(); + $group->method('getGID')->willReturn('groupId'); + + $this->userManager->method('get')->willReturnMap([ + ['userId', $user], + ['initiatorId', $initiator], + ['ownerId', $owner], + ]); + $this->groupManager->method('get')->willReturnMap([ + ['group', $group], + ]); + $this->dateTimeZone->method('getTimezone')->willReturn(new \DateTimeZone('UTC')); + + $data = $ocs->getShare($share->getId())->getData()[0]; + $this->assertEquals($result, $data); + } + + + public function testGetShareInvalidNode(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Wrong share ID, share does not exist'); + + $share = Server::get(IManager::class)->newShare(); + $share->setSharedBy('initiator') + ->setSharedWith('recipient') + ->setShareOwner('owner'); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:42', 'currentUser') + ->willReturn($share); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $this->ocs->getShare(42); + } + + public function dataGetShares() { + $folder = $this->getMockBuilder(Folder::class)->getMock(); + $file1 = $this->getMockBuilder(File::class)->getMock(); + $file1->method('getName') + ->willReturn('file1'); + $file2 = $this->getMockBuilder(File::class)->getMock(); + $file2->method('getName') + ->willReturn('file2'); + + $folder->method('getDirectoryListing') + ->willReturn([$file1, $file2]); + + $file1UserShareOwner = Server::get(IManager::class)->newShare(); + $file1UserShareOwner->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(4); + + $file1UserShareOwnerExpected = [ + 'id' => 4, + 'share_type' => IShare::TYPE_USER, + ]; + + $file1UserShareInitiator = Server::get(IManager::class)->newShare(); + $file1UserShareInitiator->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('currentUser') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(8); + + $file1UserShareInitiatorExpected = [ + 'id' => 8, + 'share_type' => IShare::TYPE_USER, + ]; + + $file1UserShareRecipient = Server::get(IManager::class)->newShare(); + $file1UserShareRecipient->setShareType(IShare::TYPE_USER) + ->setSharedWith('currentUser') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(15); + + $file1UserShareRecipientExpected = [ + 'id' => 15, + 'share_type' => IShare::TYPE_USER, + ]; + + $file1UserShareOther = Server::get(IManager::class)->newShare(); + $file1UserShareOther->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(16); + + $file1UserShareOtherExpected = [ + 'id' => 16, + 'share_type' => IShare::TYPE_USER, + ]; + + $file1GroupShareOwner = Server::get(IManager::class)->newShare(); + $file1GroupShareOwner->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(23); + + $file1GroupShareOwnerExpected = [ + 'id' => 23, + 'share_type' => IShare::TYPE_GROUP, + ]; + + $file1GroupShareRecipient = Server::get(IManager::class)->newShare(); + $file1GroupShareRecipient->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('currentUserGroup') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(42); + + $file1GroupShareRecipientExpected = [ + 'id' => 42, + 'share_type' => IShare::TYPE_GROUP, + ]; + + $file1GroupShareOther = Server::get(IManager::class)->newShare(); + $file1GroupShareOther->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(108); + + $file1LinkShareOwner = Server::get(IManager::class)->newShare(); + $file1LinkShareOwner->setShareType(IShare::TYPE_LINK) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(415); + + $file1LinkShareOwnerExpected = [ + 'id' => 415, + 'share_type' => IShare::TYPE_LINK, + ]; + + $file1EmailShareOwner = Server::get(IManager::class)->newShare(); + $file1EmailShareOwner->setShareType(IShare::TYPE_EMAIL) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(416); + + $file1EmailShareOwnerExpected = [ + 'id' => 416, + 'share_type' => IShare::TYPE_EMAIL, + ]; + + $file1CircleShareOwner = Server::get(IManager::class)->newShare(); + $file1CircleShareOwner->setShareType(IShare::TYPE_CIRCLE) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(423); + + $file1CircleShareOwnerExpected = [ + 'id' => 423, + 'share_type' => IShare::TYPE_CIRCLE, + ]; + + $file1RoomShareOwner = Server::get(IManager::class)->newShare(); + $file1RoomShareOwner->setShareType(IShare::TYPE_ROOM) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file1) + ->setId(442); + + $file1RoomShareOwnerExpected = [ + 'id' => 442, + 'share_type' => IShare::TYPE_ROOM, + ]; + + $file1RemoteShareOwner = Server::get(IManager::class)->newShare(); + $file1RemoteShareOwner->setShareType(IShare::TYPE_REMOTE) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setExpirationDate(new \DateTime('2000-01-01T01:02:03')) + ->setNode($file1) + ->setId(815); + + $file1RemoteShareOwnerExpected = [ + 'id' => 815, + 'share_type' => IShare::TYPE_REMOTE, + ]; + + $file1RemoteGroupShareOwner = Server::get(IManager::class)->newShare(); + $file1RemoteGroupShareOwner->setShareType(IShare::TYPE_REMOTE_GROUP) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setExpirationDate(new \DateTime('2000-01-02T01:02:03')) + ->setNode($file1) + ->setId(816); + + $file1RemoteGroupShareOwnerExpected = [ + 'id' => 816, + 'share_type' => IShare::TYPE_REMOTE_GROUP, + ]; + + $file2UserShareOwner = Server::get(IManager::class)->newShare(); + $file2UserShareOwner->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file2) + ->setId(823); + + $file2UserShareOwnerExpected = [ + 'id' => 823, + 'share_type' => IShare::TYPE_USER, + ]; + + $data = [ + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareOwner, $file1UserShareOwner], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected + ] + ], + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + ] + ], + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + $file1UserShareInitiatorExpected, + $file1UserShareOtherExpected, + ] + ], + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther], + ], + ], + [ + ], + [ + $file1UserShareInitiatorExpected, + ] + ], + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + IShare::TYPE_GROUP => [$file1GroupShareRecipient], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + $file1GroupShareRecipientExpected, + ] + ], + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + IShare::TYPE_GROUP => [$file1GroupShareOwner], + IShare::TYPE_LINK => [$file1LinkShareOwner], + IShare::TYPE_EMAIL => [$file1EmailShareOwner], + IShare::TYPE_CIRCLE => [$file1CircleShareOwner], + IShare::TYPE_ROOM => [$file1RoomShareOwner], + IShare::TYPE_REMOTE => [$file1RemoteShareOwner], + IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + $file1GroupShareOwnerExpected, + $file1LinkShareOwnerExpected, + $file1EmailShareOwnerExpected, + $file1CircleShareOwnerExpected, + $file1RoomShareOwnerExpected, + ] + ], + [ + [ + 'path' => $file1, + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + IShare::TYPE_GROUP => [$file1GroupShareOwner], + IShare::TYPE_LINK => [$file1LinkShareOwner], + IShare::TYPE_EMAIL => [$file1EmailShareOwner], + IShare::TYPE_CIRCLE => [$file1CircleShareOwner], + IShare::TYPE_ROOM => [$file1RoomShareOwner], + IShare::TYPE_REMOTE => [$file1RemoteShareOwner], + IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner], + ], + ], + [ + IShare::TYPE_REMOTE => true, + IShare::TYPE_REMOTE_GROUP => true, + ], + [ + $file1UserShareOwnerExpected, + $file1GroupShareOwnerExpected, + $file1LinkShareOwnerExpected, + $file1EmailShareOwnerExpected, + $file1CircleShareOwnerExpected, + $file1RoomShareOwnerExpected, + $file1RemoteShareOwnerExpected, + $file1RemoteGroupShareOwnerExpected, + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + ], + 'file2' => [ + IShare::TYPE_USER => [$file2UserShareOwner], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + $file2UserShareOwnerExpected, + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareOwner, $file1UserShareOwner], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner, $file1UserShareRecipient], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther], + ], + 'file2' => [ + IShare::TYPE_USER => [$file2UserShareOwner], + ], + ], + [ + ], + [ + $file1UserShareInitiatorExpected, + $file1UserShareOtherExpected, + $file2UserShareOwnerExpected, + ] + ], + // This might not happen in a real environment, as the combination + // of shares does not seem to be possible on a folder without + // resharing rights; if the folder has resharing rights then the + // share with others would be included too in the results. + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareRecipient, $file1UserShareInitiator, $file1UserShareOther], + ], + ], + [ + ], + [ + $file1UserShareInitiatorExpected, + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + IShare::TYPE_GROUP => [$file1GroupShareRecipient], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + $file1GroupShareRecipientExpected, + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + IShare::TYPE_GROUP => [$file1GroupShareOwner], + IShare::TYPE_LINK => [$file1LinkShareOwner], + IShare::TYPE_EMAIL => [$file1EmailShareOwner], + IShare::TYPE_CIRCLE => [$file1CircleShareOwner], + IShare::TYPE_ROOM => [$file1RoomShareOwner], + IShare::TYPE_REMOTE => [$file1RemoteShareOwner], + IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner], + ], + ], + [ + ], + [ + $file1UserShareOwnerExpected, + $file1GroupShareOwnerExpected, + $file1LinkShareOwnerExpected, + $file1EmailShareOwnerExpected, + $file1CircleShareOwnerExpected, + $file1RoomShareOwnerExpected, + ] + ], + [ + [ + 'path' => $folder, + 'subfiles' => 'true', + ], + [ + 'file1' => [ + IShare::TYPE_USER => [$file1UserShareOwner], + IShare::TYPE_GROUP => [$file1GroupShareOwner], + IShare::TYPE_LINK => [$file1LinkShareOwner], + IShare::TYPE_EMAIL => [$file1EmailShareOwner], + IShare::TYPE_CIRCLE => [$file1CircleShareOwner], + IShare::TYPE_ROOM => [$file1RoomShareOwner], + IShare::TYPE_REMOTE => [$file1RemoteShareOwner], + IShare::TYPE_REMOTE_GROUP => [$file1RemoteGroupShareOwner], + ], + ], + [ + IShare::TYPE_REMOTE => true, + IShare::TYPE_REMOTE_GROUP => true, + ], + [ + $file1UserShareOwnerExpected, + $file1GroupShareOwnerExpected, + $file1LinkShareOwnerExpected, + $file1EmailShareOwnerExpected, + $file1CircleShareOwnerExpected, + $file1RoomShareOwnerExpected, + $file1RemoteShareOwnerExpected, + $file1RemoteGroupShareOwnerExpected, + ] + ], + ]; + + return $data; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetShares')] + public function testGetShares(array $getSharesParameters, array $shares, array $extraShareTypes, array $expected): void { + /** @var ShareAPIController&MockObject $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ]) + ->onlyMethods(['formatShare']) + ->getMock(); + + $ocs->method('formatShare') + ->willReturnCallback( + function ($share) { + return [ + 'id' => $share->getId(), + 'share_type' => $share->getShareType() + ]; + } + ); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $userFolder->method('get') + ->with('path') + ->willReturn($getSharesParameters['path']); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $this->shareManager + ->method('getSharesBy') + ->willReturnCallback( + function ($user, $shareType, $node) use ($shares) { + if (!isset($shares[$node->getName()]) || !isset($shares[$node->getName()][$shareType])) { + return []; + } + return $shares[$node->getName()][$shareType]; + } + ); + + $this->shareManager + ->method('outgoingServer2ServerSharesAllowed') + ->willReturn($extraShareTypes[ISHARE::TYPE_REMOTE] ?? false); + + $this->shareManager + ->method('outgoingServer2ServerGroupSharesAllowed') + ->willReturn($extraShareTypes[ISHARE::TYPE_REMOTE_GROUP] ?? false); + + $this->groupManager + ->method('isInGroup') + ->willReturnCallback( + function ($user, $group) { + return $group === 'currentUserGroup'; + } + ); + + $result = $ocs->getShares( + $getSharesParameters['sharedWithMe'] ?? 'false', + $getSharesParameters['reshares'] ?? 'false', + $getSharesParameters['subfiles'] ?? 'false', + 'path' + ); + + $this->assertEquals($expected, $result->getData()); + } + + public function testCanAccessShareAsOwner(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareOwner')->willReturn($this->currentUser); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + + public function testCanAccessShareAsSharer(): void { + $share = $this->createMock(IShare::class); + $share->method('getSharedBy')->willReturn($this->currentUser); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + + public function testCanAccessShareAsSharee(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_USER); + $share->method('getSharedWith')->willReturn($this->currentUser); + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + + public function testCannotAccessLinkShare(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_LINK); + $share->method('getNodeId')->willReturn(42); + + $userFolder = $this->createMock(Folder::class); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataCanAccessShareWithPermissions')] + public function testCanAccessShareWithPermissions(int $permissions, bool $expected): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_USER); + $share->method('getSharedWith')->willReturn($this->createMock(IUser::class)); + $share->method('getNodeId')->willReturn(42); + + $file = $this->createMock(File::class); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $userFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($file); + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$file]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $file->method('getPermissions') + ->willReturn($permissions); + + if ($expected) { + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } else { + $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + } + + public static function dataCanAccessShareWithPermissions(): array { + return [ + [Constants::PERMISSION_SHARE, true], + [Constants::PERMISSION_READ, false], + [Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, true], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataCanAccessShareAsGroupMember')] + public function testCanAccessShareAsGroupMember(string $group, bool $expected): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_GROUP); + $share->method('getSharedWith')->willReturn($group); + $share->method('getNodeId')->willReturn(42); + + $file = $this->createMock(File::class); + + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($file); + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$file]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $user = $this->createMock(IUser::class); + $this->userManager->method('get') + ->with($this->currentUser) + ->willReturn($user); + + $group = $this->createMock(IGroup::class); + $group->method('inGroup')->with($user)->willReturn(true); + $group2 = $this->createMock(IGroup::class); + $group2->method('inGroup')->with($user)->willReturn(false); + + $this->groupManager->method('get')->willReturnMap([ + ['group', $group], + ['group2', $group2], + ['group-null', null], + ]); + + if ($expected) { + $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } else { + $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + } + + public static function dataCanAccessShareAsGroupMember(): array { + return [ + ['group', true], + ['group2', false], + ['group-null', false], + ]; + } + + public function dataCanAccessRoomShare() { + $result = []; + + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_ROOM); + $share->method('getSharedWith')->willReturn('recipientRoom'); + + $result[] = [ + false, $share, false, false + ]; + + $result[] = [ + false, $share, false, true + ]; + + $result[] = [ + true, $share, true, true + ]; + + $result[] = [ + false, $share, true, false + ]; + + return $result; + } + + /** + * + * @param bool $expects + * @param IShare $share + * @param bool helperAvailable + * @param bool canAccessShareByHelper + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataCanAccessRoomShare')] + public function testCanAccessRoomShare(bool $expected, IShare $share, bool $helperAvailable, bool $canAccessShareByHelper): void { + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$share->getNode()]); + + if (!$helperAvailable) { + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(false); + } else { + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(true); + + // This is not possible anymore with PHPUnit 10+ + // as `setMethods` was removed and now real reflection is used, thus the class needs to exist. + // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController') + $helper = $this->getMockBuilder(\stdClass::class) + ->addMethods(['canAccessShare']) + ->getMock(); + $helper->method('canAccessShare') + ->with($share, $this->currentUser) + ->willReturn($canAccessShareByHelper); + + $this->serverContainer->method('get') + ->with('\OCA\Talk\Share\Helper\ShareAPIController') + ->willReturn($helper); + } + + $this->assertEquals($expected, $this->invokePrivate($this->ocs, 'canAccessShare', [$share])); + } + + + public function testCreateShareNoPath(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Please specify a file or folder path'); + + $this->ocs->createShare(); + } + + + public function testCreateShareInvalidPath(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Wrong path, file/folder does not exist'); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('invalid-path') + ->willThrowException(new NotFoundException()); + + $this->ocs->createShare('invalid-path'); + } + + public function testCreateShareInvalidShareType(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Unknown share type'); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $file] = $this->getNonSharedUserFile(); + $this->rootFolder->expects($this->atLeastOnce()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->atLeastOnce()) + ->method('get') + ->with('valid-path') + ->willReturn($file); + $userFolder->method('getById') + ->willReturn([]); + + $file->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->ocs->createShare('valid-path', 31); + } + + public function testCreateShareUserNoShareWith(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Please specify a valid account to share with'); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER); + } + + + public function testCreateShareUserNoValidShareWith(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Please specify a valid account to share with'); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + $this->userManager->method('userExists') + ->with('invalidUser') + ->willReturn(false); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'invalidUser'); + } + + public function testCreateShareUser(): void { + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + /** @var ShareAPIController $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ])->onlyMethods(['formatShare']) + ->getMock(); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->expects($this->exactly(2)) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $this->userManager->method('userExists')->with('validUser')->willReturn(true); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('createShare') + ->with($this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getPermissions() === ( + Constants::PERMISSION_ALL + & ~Constants::PERMISSION_DELETE + & ~Constants::PERMISSION_CREATE + ) + && $share->getShareType() === IShare::TYPE_USER + && $share->getSharedWith() === 'validUser' + && $share->getSharedBy() === 'currentUser'; + })) + ->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'validUser'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testCreateShareGroupNoValidShareWith(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Please specify a valid group'); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + $this->shareManager->method('createShare')->willReturnArgument(0); + $this->shareManager->method('allowGroupSharing')->willReturn(true); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'invalidGroup'); + } + + public function testCreateShareGroup(): void { + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + /** @var ShareAPIController&MockObject $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ])->onlyMethods(['formatShare']) + ->getMock(); + + $this->request + ->method('getParam') + ->willReturnMap([ + ['path', null, 'valid-path'], + ['permissions', null, Constants::PERMISSION_ALL], + ['shareType', '-1', IShare::TYPE_GROUP], + ['shareWith', null, 'validGroup'], + ]); + + [$userFolder, $path] = $this->getNonSharedUserFolder(); + $this->rootFolder->expects($this->exactly(2)) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true); + + $this->shareManager->expects($this->once()) + ->method('allowGroupSharing') + ->willReturn(true); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('createShare') + ->with($this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getShareType() === IShare::TYPE_GROUP + && $share->getSharedWith() === 'validGroup' + && $share->getSharedBy() === 'currentUser'; + })) + ->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'validGroup'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testCreateShareGroupNotAllowed(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Group sharing is disabled by the administrator'); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $path] = $this->getNonSharedUserFolder(); + $this->rootFolder->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true); + + $this->shareManager->expects($this->once()) + ->method('allowGroupSharing') + ->willReturn(false); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_GROUP, 'invalidGroup'); + } + + + public function testCreateShareLinkNoLinksAllowed(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Public link sharing is disabled by the administrator'); + + $this->request + ->method('getParam') + ->willReturnMap([ + ['path', null, 'valid-path'], + ['shareType', '-1', IShare::TYPE_LINK], + ]); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + $this->shareManager->method('shareApiAllowLinks')->willReturn(false); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK); + } + + + public function testCreateShareLinkNoPublicUpload(): void { + $this->expectException(OCSForbiddenException::class); + $this->expectExceptionMessage('Public upload disabled by the administrator'); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true'); + } + + + public function testCreateShareLinkPublicUploadFile(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Public upload is only possible for publicly shared folders'); + + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(42); + $file->method('getStorage')->willReturn($storage); + + $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); + $this->rootFolder->method('get')->with('valid-path')->willReturn($file); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true'); + } + + public function testCreateShareLinkPublicUploadFolder(): void { + $ocs = $this->mockFormatShare(); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(1); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('createShare')->with( + $this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getShareType() === IShare::TYPE_LINK + && $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) + && $share->getSharedBy() === 'currentUser' + && $share->getPassword() === null + && $share->getExpirationDate() === null; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true', '', null, ''); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareLinkPassword(): void { + $ocs = $this->mockFormatShare(); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('createShare')->with( + $this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getShareType() === IShare::TYPE_LINK + && $share->getPermissions() === Constants::PERMISSION_READ // publicUpload was set to false + && $share->getSharedBy() === 'currentUser' + && $share->getPassword() === 'password' + && $share->getExpirationDate() === null; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_READ, IShare::TYPE_LINK, null, 'false', 'password', null, ''); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareLinkSendPasswordByTalk(): void { + $ocs = $this->mockFormatShare(); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true); + + $this->shareManager->expects($this->once())->method('createShare')->with( + $this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getShareType() === IShare::TYPE_LINK + && $share->getPermissions() === (Constants::PERMISSION_ALL & ~(Constants::PERMISSION_SHARE)) + && $share->getSharedBy() === 'currentUser' + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() === null; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true', 'password', 'true', ''); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testCreateShareLinkSendPasswordByTalkWithTalkDisabled(): void { + $this->expectException(OCSForbiddenException::class); + $this->expectExceptionMessage('Sharing valid-path sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'); + + $ocs = $this->mockFormatShare(); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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(); + $this->rootFolder->method('get')->with('valid-path')->willReturn($path); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false); + + $this->shareManager->expects($this->never())->method('createShare'); + + $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', 'password', 'true', ''); + } + + public function testCreateShareValidExpireDate(): void { + $ocs = $this->mockFormatShare(); + + $this->request + ->method('getParam') + ->willReturnMap([ + ['path', null, 'valid-path'], + ['shareType', '-1', IShare::TYPE_LINK], + ['publicUpload', null, 'false'], + ['expireDate', '', '2000-01-01'], + ['password', '', ''], + ]); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('createShare')->with( + $this->callback(function (IShare $share) use ($path) { + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + return $share->getNode() === $path + && $share->getShareType() === IShare::TYPE_LINK + && $share->getPermissions() === Constants::PERMISSION_READ | Constants::PERMISSION_SHARE + && $share->getSharedBy() === 'currentUser' + && $share->getPassword() === null + && $share->getExpirationDate() == $date; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', null, IShare::TYPE_LINK, null, 'false', '', null, '2000-01-01'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testCreateShareInvalidExpireDate(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD'); + + $ocs = $this->mockFormatShare(); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->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); + $this->rootFolder->method('getById') + ->willReturn([]); + + $this->shareManager->method('newShare')->willReturn(Server::get(IManager::class)->newShare()); + $this->shareManager->method('shareApiAllowLinks')->willReturn(true); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'false', '', null, 'a1b2d3'); + } + + public function testCreateShareRemote(): void { + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + /** @var ShareAPIController $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ])->onlyMethods(['formatShare']) + ->getMock(); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->expects($this->exactly(2)) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $this->userManager->method('userExists')->with('validUser')->willReturn(true); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('createShare') + ->with($this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getPermissions() === ( + Constants::PERMISSION_ALL + & ~Constants::PERMISSION_DELETE + & ~Constants::PERMISSION_CREATE + ) + && $share->getShareType() === IShare::TYPE_REMOTE + && $share->getSharedWith() === 'user@example.org' + && $share->getSharedBy() === 'currentUser'; + })) + ->willReturnArgument(0); + + $this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_REMOTE, 'user@example.org'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareRemoteGroup(): void { + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + /** @var ShareAPIController $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ])->onlyMethods(['formatShare']) + ->getMock(); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->expects($this->exactly(2)) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $this->userManager->method('userExists')->with('validUser')->willReturn(true); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('createShare') + ->with($this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getPermissions() === ( + Constants::PERMISSION_ALL + & ~Constants::PERMISSION_DELETE + & ~Constants::PERMISSION_CREATE + ) + && $share->getShareType() === IShare::TYPE_REMOTE_GROUP + && $share->getSharedWith() === 'group@example.org' + && $share->getSharedBy() === 'currentUser'; + })) + ->willReturnArgument(0); + + $this->shareManager->method('outgoingServer2ServerGroupSharesAllowed')->willReturn(true); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_REMOTE_GROUP, 'group@example.org'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareRoom(): void { + $ocs = $this->mockFormatShare(); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->expects($this->exactly(2)) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(true); + + // This is not possible anymore with PHPUnit 10+ + // as `setMethods` was removed and now real reflection is used, thus the class needs to exist. + // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController') + $helper = $this->getMockBuilder(\stdClass::class) + ->addMethods(['createShare']) + ->getMock(); + $helper->method('createShare') + ->with( + $share, + 'recipientRoom', + Constants::PERMISSION_ALL + & ~Constants::PERMISSION_DELETE + & ~Constants::PERMISSION_CREATE, + '' + )->willReturnCallback( + function ($share): void { + $share->setSharedWith('recipientRoom'); + $share->setPermissions(Constants::PERMISSION_ALL); + } + ); + + $this->serverContainer->method('get') + ->with('\OCA\Talk\Share\Helper\ShareAPIController') + ->willReturn($helper); + + $this->shareManager->method('createShare') + ->with($this->callback(function (IShare $share) use ($path) { + return $share->getNode() === $path + && $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getShareType() === IShare::TYPE_ROOM + && $share->getSharedWith() === 'recipientRoom' + && $share->getSharedBy() === 'currentUser'; + })) + ->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testCreateShareRoomHelperNotAvailable(): void { + $this->expectException(OCSForbiddenException::class); + $this->expectExceptionMessage('Sharing valid-path failed because the back end does not support room shares'); + + $ocs = $this->mockFormatShare(); + + $share = $this->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $path] = $this->getNonSharedUserFolder(); + $this->rootFolder->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path->method('getPath')->willReturn('valid-path'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(false); + + $this->shareManager->expects($this->never())->method('createShare'); + + $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom'); + } + + + public function testCreateShareRoomHelperThrowException(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Exception thrown by the helper'); + + $ocs = $this->mockFormatShare(); + + $share = $this->newShare(); + $share->setSharedBy('currentUser'); + $this->shareManager->method('newShare')->willReturn($share); + + [$userFolder, $path] = $this->getNonSharedUserFile(); + $this->rootFolder->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $path->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(true); + + // This is not possible anymore with PHPUnit 10+ + // as `setMethods` was removed and now real reflection is used, thus the class needs to exist. + // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController') + $helper = $this->getMockBuilder(\stdClass::class) + ->addMethods(['createShare']) + ->getMock(); + $helper->method('createShare') + ->with( + $share, + 'recipientRoom', + Constants::PERMISSION_ALL & ~(Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE), + '' + )->willReturnCallback( + function ($share): void { + throw new OCSNotFoundException('Exception thrown by the helper'); + } + ); + + $this->serverContainer->method('get') + ->with('\OCA\Talk\Share\Helper\ShareAPIController') + ->willReturn($helper); + + $this->shareManager->expects($this->never())->method('createShare'); + + $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_ROOM, 'recipientRoom'); + } + + /** + * Test for https://github.com/owncloud/core/issues/22587 + * TODO: Remove once proper solution is in place + */ + public function testCreateReshareOfFederatedMountNoDeletePermissions(): void { + $share = Server::get(IManager::class)->newShare(); + $this->shareManager->method('newShare')->willReturn($share); + + /** @var ShareAPIController&MockObject $ocs */ + $ocs = $this->getMockBuilder(ShareAPIController::class) + ->setConstructorArgs([ + $this->appName, + $this->request, + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->rootFolder, + $this->urlGenerator, + $this->l, + $this->config, + $this->appConfig, + $this->appManager, + $this->serverContainer, + $this->userStatusManager, + $this->previewManager, + $this->dateTimeZone, + $this->logger, + $this->factory, + $this->mailer, + $this->tagManager, + $this->trustedServers, + $this->currentUser, + ])->onlyMethods(['formatShare']) + ->getMock(); + + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->expects($this->exactly(2)) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMockBuilder(Folder::class)->getMock(); + $path->method('getId')->willReturn(42); + + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', true], + ['OCA\Files_Sharing\SharedStorage', false], + ]); + $userFolder->method('getStorage')->willReturn($storage); + $path->method('getStorage')->willReturn($storage); + + $path->method('getPermissions')->willReturn(Constants::PERMISSION_READ); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + $userFolder->method('getById') + ->willReturn([]); + + $this->userManager->method('userExists')->with('validUser')->willReturn(true); + + $this->shareManager + ->expects($this->once()) + ->method('createShare') + ->with($this->callback(function (IShare $share) { + return $share->getPermissions() === Constants::PERMISSION_READ; + })) + ->willReturnArgument(0); + + $ocs->createShare('valid-path', Constants::PERMISSION_ALL, IShare::TYPE_USER, 'validUser'); + } + + + public function testUpdateShareCantAccess(): void { + $this->expectException(OCSNotFoundException::class); + $this->expectExceptionMessage('Wrong share ID, share does not exist'); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $share = $this->newShare(); + $share->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with($share->getNodeId()) + ->willReturn([$share->getNode()]); + + $this->ocs->updateShare(42); + } + + + public function testUpdateNoParametersLink(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Wrong or no update parameter given'); + + $node = $this->getMockBuilder(Folder::class)->getMock(); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->ocs->updateShare(42); + } + + + public function testUpdateNoParametersOther(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Wrong or no update parameter given'); + + $node = $this->getMockBuilder(Folder::class)->getMock(); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_GROUP) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->ocs->updateShare(42); + } + + public function testUpdateLinkShareClear(): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $node->method('getId') + ->willReturn(42); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setExpirationDate(new \DateTime()) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) { + return $share->getPermissions() === Constants::PERMISSION_READ + && $share->getPassword() === null + && $share->getExpirationDate() === null + // Once set a note or a label are never back to null, only to an + // empty string. + && $share->getNote() === '' + && $share->getLabel() === '' + && $share->getHideDownload() === false; + }) + )->willReturnArgument(0); + + $this->shareManager->method('getSharedWith') + ->willReturn([]); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + $userFolder->method('getFirstNodeById') + ->with(42) + ->willReturn($node); + + $mountPoint = $this->createMock(IMountPoint::class); + $node->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, '', null, 'false', '', '', '', 'false'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkShareSet(): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) { + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) + && $share->getPassword() === 'password' + && $share->getExpirationDate() == $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $this->shareManager->method('getSharedWith') + ->willReturn([]); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, 'password', null, 'true', '2000-01-01', 'note', 'label', 'true'); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('publicUploadParamsProvider')] + public function testUpdateLinkShareEnablePublicUpload($permissions, $publicUpload, $expireDate, $password): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + $this->shareManager->method('getSharedWith')->willReturn([]); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) { + return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) + && $share->getPassword() === 'password' + && $share->getExpirationDate() === null; + }) + )->willReturnArgument(0); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, $permissions, $password, null, $publicUpload, $expireDate); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public static function publicLinkValidPermissionsProvider() { + return [ + [Constants::PERMISSION_CREATE], + [Constants::PERMISSION_READ], + [Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE], + [Constants::PERMISSION_READ | Constants::PERMISSION_DELETE], + [Constants::PERMISSION_READ | Constants::PERMISSION_CREATE], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('publicLinkValidPermissionsProvider')] + public function testUpdateLinkShareSetCRUDPermissions($permissions): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + $this->shareManager->method('getSharedWith')->willReturn([]); + + $this->shareManager + ->expects($this->any()) + ->method('updateShare') + ->willReturnArgument(0); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, $permissions, 'password', null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public static function publicLinkInvalidPermissionsProvider1() { + return [ + [Constants::PERMISSION_DELETE], + [Constants::PERMISSION_UPDATE], + [Constants::PERMISSION_SHARE], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('publicLinkInvalidPermissionsProvider1')] + public function testUpdateLinkShareSetInvalidCRUDPermissions1($permissions): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Share must at least have READ or CREATE permissions'); + + $this->testUpdateLinkShareSetCRUDPermissions($permissions, null); + } + + public static function publicLinkInvalidPermissionsProvider2() { + return [ + [Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE], + [Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('publicLinkInvalidPermissionsProvider2')] + public function testUpdateLinkShareSetInvalidCRUDPermissions2($permissions): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Share must have READ permission if UPDATE or DELETE permission is set'); + + $this->testUpdateLinkShareSetCRUDPermissions($permissions); + } + + public function testUpdateLinkShareInvalidDate(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Invalid date. Format must be YYYY-MM-DD'); + + $ocs = $this->mockFormatShare(); + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $ocs->updateShare(42, null, 'password', null, 'true', '2000-01-a'); + } + + public static function publicUploadParamsProvider() { + return [ + [null, 'true', null, 'password'], + // legacy had no delete + [ + Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, + 'true', null, 'password' + ], + // correct + [ + Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, + null, null, 'password' + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('publicUploadParamsProvider')] + public function testUpdateLinkSharePublicUploadNotAllowed($permissions, $publicUpload, $expireDate, $password): void { + $this->expectException(OCSForbiddenException::class); + $this->expectExceptionMessage('Public upload disabled by the administrator'); + + $ocs = $this->mockFormatShare(); + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $folder->method('getId')->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(false); + + $ocs->updateShare(42, $permissions, $password, null, $publicUpload, $expireDate); + } + + + public function testUpdateLinkSharePublicUploadOnFile(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Public upload is only possible for publicly shared folders'); + + $ocs = $this->mockFormatShare(); + + $file = $this->getMockBuilder(File::class)->getMock(); + $file->method('getId') + ->willReturn(42); + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setNode($file); + + $this->shareManager + ->method('getShareById') + ->with('ocinternal:42') + ->willReturn($share); + $this->shareManager + ->method('shareApiLinkAllowPublicUpload') + ->willReturn(true); + $this->shareManager + ->method('updateShare') + ->with($share) + ->willThrowException(new \InvalidArgumentException('File shares cannot have create or delete permissions')); + + $ocs->updateShare(42, null, 'password', null, 'true', ''); + } + + public function testUpdateLinkSharePasswordDoesNotChangeOther(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $node->method('getId')->willReturn(42); + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) use ($date) { + return $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getPassword() === 'newpassword' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, 'newpassword', null, null, null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkShareSendPasswordByTalkDoesNotChangeOther(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + $node->method('getId')->willReturn(42); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(false) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) use ($date) { + return $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, null, 'true', null, null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + + public function testUpdateLinkShareSendPasswordByTalkWithTalkDisabledDoesNotChangeOther(): void { + $this->expectException(OCSForbiddenException::class); + $this->expectExceptionMessage('"Sending the password by Nextcloud Talk" for sharing a file or folder failed because Nextcloud Talk is not enabled.'); + + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + $node->method('getId')->willReturn(42); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(false) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false); + + $this->shareManager->expects($this->never())->method('updateShare'); + + $ocs->updateShare(42, null, null, 'true', null, null, null, null, null); + } + + public function testUpdateLinkShareDoNotSendPasswordByTalkDoesNotChangeOther(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + $node->method('getId')->willReturn(42); + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(true); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) use ($date) { + return $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === false + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, null, 'false', null, null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkShareDoNotSendPasswordByTalkWithTalkDisabledDoesNotChangeOther(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + $date->setTime(0, 0, 0); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $node->method('getId') + ->willReturn(42); + + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->appManager->method('isEnabledForUser')->with('spreed')->willReturn(false); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) use ($date) { + return $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === false + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + + $mountPoint = $this->createMock(IMountPoint::class); + $node->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $mountPoint = $this->createMock(IMountPoint::class); + $node->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, null, 'false', null, null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkShareExpireDateDoesNotChangeOther(): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $node] = $this->getNonSharedUserFolder(); + $node->method('getId') + ->willReturn(42); + + $share = $this->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate(new \DateTime()) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($node); + + $node->expects($this->once()) + ->method('lock') + ->with(ILockingProvider::LOCK_SHARED); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) { + $date = new \DateTime('2010-12-23'); + $date->setTime(0, 0, 0); + + return $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() == $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$node]); + + $mountPoint = $this->createMock(IMountPoint::class); + $node->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, null, null, null, '2010-12-23', null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkSharePublicUploadDoesNotChangeOther(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) use ($date) { + return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $this->shareManager->method('getSharedWith') + ->willReturn([]); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, null, null, null, 'true', null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkSharePermissions(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_ALL) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) use ($date): bool { + return $share->getPermissions() === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $this->shareManager->method('getSharedWith')->willReturn([]); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, 7, null, null, 'true', null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateLinkSharePermissionsShare(): void { + $ocs = $this->mockFormatShare(); + + $date = new \DateTime('2000-01-01'); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_LINK) + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($date) + ->setNote('note') + ->setLabel('label') + ->setHideDownload(true) + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once()) + ->method('updateShare') + ->with( + $this->callback(function (IShare $share) use ($date) { + return $share->getPermissions() === Constants::PERMISSION_ALL + && $share->getPassword() === 'password' + && $share->getSendPasswordByTalk() === true + && $share->getExpirationDate() === $date + && $share->getNote() === 'note' + && $share->getLabel() === 'label' + && $share->getHideDownload() === true; + }) + )->willReturnArgument(0); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $this->shareManager->method('getSharedWith')->willReturn([]); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, Constants::PERMISSION_ALL, null, null, null, null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateOtherPermissions(): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $file] = $this->getNonSharedUserFolder(); + $file->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share->setPermissions(Constants::PERMISSION_ALL) + ->setSharedBy($this->currentUser) + ->setShareType(IShare::TYPE_USER) + ->setNode($file); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); + + $this->shareManager->expects($this->once())->method('updateShare')->with( + $this->callback(function (IShare $share) { + return $share->getPermissions() === Constants::PERMISSION_ALL; + }) + )->willReturnArgument(0); + + $this->shareManager->method('getSharedWith')->willReturn([]); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$file]); + + $mountPoint = $this->createMock(IMountPoint::class); + $file->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $expected = new DataResponse([]); + $result = $ocs->updateShare(42, 31, null, null, null, null); + + $this->assertInstanceOf(get_class($expected), $result); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testUpdateShareCannotIncreasePermissions(): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share + ->setId(42) + ->setSharedBy($this->currentUser) + ->setShareOwner('anotheruser') + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('group1') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder); + + // note: updateShare will modify the received instance but getSharedWith will reread from the database, + // so their values will be different + $incomingShare = Server::get(IManager::class)->newShare(); + $incomingShare + ->setId(42) + ->setSharedBy($this->currentUser) + ->setShareOwner('anotheruser') + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('group1') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder); + + $this->request + ->method('getParam') + ->willReturnMap([ + ['permissions', null, '31'], + ]); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->shareManager->expects($this->any()) + ->method('getSharedWith') + ->willReturnMap([ + ['currentUser', IShare::TYPE_USER, $share->getNode(), -1, 0, []], + ['currentUser', IShare::TYPE_GROUP, $share->getNode(), -1, 0, [$incomingShare]], + ['currentUser', IShare::TYPE_ROOM, $share->getNode(), -1, 0, []] + ]); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + $userFolder->method('getFirstNodeById') + ->with(42) + ->willReturn($folder); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $this->shareManager->expects($this->once()) + ->method('updateShare') + ->with($share) + ->willThrowException(new GenericShareException('Cannot increase permissions of path/file', 'Cannot increase permissions of path/file', 404)); + + try { + $ocs->updateShare(42, 31); + $this->fail(); + } catch (OCSException $e) { + $this->assertEquals('Cannot increase permissions of path/file', $e->getMessage()); + } + } + + public function testUpdateShareCanIncreasePermissionsIfOwner(): void { + $ocs = $this->mockFormatShare(); + + [$userFolder, $folder] = $this->getNonSharedUserFolder(); + $folder->method('getId') + ->willReturn(42); + + $share = Server::get(IManager::class)->newShare(); + $share + ->setId(42) + ->setSharedBy($this->currentUser) + ->setShareOwner($this->currentUser) + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('group1') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder); + + // note: updateShare will modify the received instance but getSharedWith will reread from the database, + // so their values will be different + $incomingShare = Server::get(IManager::class)->newShare(); + $incomingShare + ->setId(42) + ->setSharedBy($this->currentUser) + ->setShareOwner($this->currentUser) + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('group1') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder); + + $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); + + $this->shareManager->expects($this->any()) + ->method('getSharedWith') + ->willReturnMap([ + ['currentUser', IShare::TYPE_USER, $share->getNode(), -1, 0, []], + ['currentUser', IShare::TYPE_GROUP, $share->getNode(), -1, 0, [$incomingShare]] + ]); + + $this->shareManager->expects($this->once()) + ->method('updateShare') + ->with($share) + ->willReturn($share); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $userFolder->method('getById') + ->with(42) + ->willReturn([$folder]); + + $mountPoint = $this->createMock(IMountPoint::class); + $folder->method('getMountPoint') + ->willReturn($mountPoint); + $mountPoint->method('getStorageRootId') + ->willReturn(42); + + $result = $ocs->updateShare(42, 31); + $this->assertInstanceOf(DataResponse::class, $result); + } + + public function testUpdateShareOwnerless(): void { + $ocs = $this->mockFormatShare(); + + $mount = $this->createMock(IShareOwnerlessMount::class); + + $file = $this->createMock(File::class); + $file + ->expects($this->exactly(2)) + ->method('getPermissions') + ->willReturn(Constants::PERMISSION_SHARE); + $file + ->expects($this->once()) + ->method('getMountPoint') + ->willReturn($mount); + + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(2) + ->willReturn([$file]); + $userFolder->method('getFirstNodeById') + ->with(2) + ->willReturn($file); + + $this->rootFolder + ->method('getUserFolder') + ->with($this->currentUser) + ->willReturn($userFolder); + + $share = $this->createMock(IShare::class); + $share + ->expects($this->once()) + ->method('getNode') + ->willReturn($file); + $share + ->expects($this->exactly(2)) + ->method('getNodeId') + ->willReturn(2); + $share + ->expects($this->exactly(2)) + ->method('getPermissions') + ->willReturn(Constants::PERMISSION_SHARE); + + $this->shareManager + ->expects($this->once()) + ->method('getShareById') + ->with('ocinternal:1', $this->currentUser) + ->willReturn($share); + + $this->shareManager + ->expects($this->once()) + ->method('updateShare') + ->with($share) + ->willReturn($share); + + $result = $ocs->updateShare(1, Constants::PERMISSION_ALL); + $this->assertInstanceOf(DataResponse::class, $result); + } + + public function dataFormatShare() { + $file = $this->getMockBuilder(File::class)->getMock(); + $folder = $this->getMockBuilder(Folder::class)->getMock(); + $parent = $this->getMockBuilder(Folder::class)->getMock(); + $fileWithPreview = $this->getMockBuilder(File::class)->getMock(); + + $file->method('getMimeType')->willReturn('myMimeType'); + $folder->method('getMimeType')->willReturn('myFolderMimeType'); + $fileWithPreview->method('getMimeType')->willReturn('mimeWithPreview'); + + $mountPoint = $this->createMock(IMountPoint::class); + $mountPoint->method('getMountType')->willReturn(''); + $file->method('getMountPoint')->willReturn($mountPoint); + $folder->method('getMountPoint')->willReturn($mountPoint); + $fileWithPreview->method('getMountPoint')->willReturn($mountPoint); + + $file->method('getPath')->willReturn('file'); + $folder->method('getPath')->willReturn('folder'); + $fileWithPreview->method('getPath')->willReturn('fileWithPreview'); + + $parent->method('getId')->willReturn(1); + $folder->method('getId')->willReturn(2); + $file->method('getId')->willReturn(3); + $fileWithPreview->method('getId')->willReturn(4); + + $file->method('getParent')->willReturn($parent); + $folder->method('getParent')->willReturn($parent); + $fileWithPreview->method('getParent')->willReturn($parent); + + $file->method('getSize')->willReturn(123456); + $folder->method('getSize')->willReturn(123456); + $fileWithPreview->method('getSize')->willReturn(123456); + $file->method('getMTime')->willReturn(1234567890); + $folder->method('getMTime')->willReturn(1234567890); + $fileWithPreview->method('getMTime')->willReturn(1234567890); + + $cache = $this->getMockBuilder('OCP\Files\Cache\ICache')->getMock(); + $cache->method('getNumericStorageId')->willReturn(100); + $storage = $this->createMock(IStorage::class); + $storage->method('getId')->willReturn('storageId'); + $storage->method('getCache')->willReturn($cache); + + $file->method('getStorage')->willReturn($storage); + $folder->method('getStorage')->willReturn($storage); + $fileWithPreview->method('getStorage')->willReturn($storage); + + + $mountPoint = $this->getMockBuilder(IMountPoint::class)->getMock(); + $mountPoint->method('getMountType')->willReturn(''); + $file->method('getMountPoint')->willReturn($mountPoint); + $folder->method('getMountPoint')->willReturn($mountPoint); + + $owner = $this->getMockBuilder(IUser::class)->getMock(); + $owner->method('getDisplayName')->willReturn('ownerDN'); + $initiator = $this->getMockBuilder(IUser::class)->getMock(); + $initiator->method('getDisplayName')->willReturn('initiatorDN'); + $recipient = $this->getMockBuilder(IUser::class)->getMock(); + $recipient->method('getDisplayName')->willReturn('recipientDN'); + $recipient->method('getSystemEMailAddress')->willReturn('recipient'); + [$shareAttributes, $shareAttributesReturnJson] = $this->mockShareAttributes(); + + $result = []; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setAttributes($shareAttributes) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + // User backend down + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_USER, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'attributes' => $shareAttributesReturnJson, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipient', + 'share_with_displayname' => 'recipient', + 'share_with_displayname_unique' => 'recipient', + 'note' => 'personal note', + 'label' => '', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => '[{"scope":"permissions","key":"download","value":true}]', + 'item_permissions' => 1, + ], $share, [], false + ]; + // User backend up + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_USER, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiatorDN', + 'permissions' => 1, + 'attributes' => $shareAttributesReturnJson, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'ownerDN', + 'note' => 'personal note', + 'label' => '', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipient', + 'share_with_displayname' => 'recipientDN', + 'share_with_displayname_unique' => 'recipient', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => '[{"scope":"permissions","key":"download","value":true}]', + 'item_permissions' => 1, + ], $share, [ + ['owner', $owner], + ['initiator', $initiator], + ['recipient', $recipient], + ], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + // User backend down + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_USER, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'attributes' => null, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => '', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipient', + 'share_with_displayname' => 'recipient', + 'share_with_displayname_unique' => 'recipient', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + // User backend down + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_USER, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'attributes' => null, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'currentUser', + 'displayname_file_owner' => 'currentUser', + 'note' => 'personal note', + 'label' => '', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipient', + 'share_with_displayname' => 'recipient', + 'share_with_displayname_unique' => 'recipient', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => true, + 'can_delete' => true, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 11, + ], $share, [], false + ]; + + // with existing group + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('recipientGroup') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_GROUP, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'attributes' => null, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => '', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipientGroup', + 'share_with_displayname' => 'recipientGroupDisplayName', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + // with unknown group / no group backend + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('recipientGroup2') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_GROUP, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => '', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipientGroup2', + 'share_with_displayname' => 'recipientGroup2', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_LINK) + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setPassword('mypassword') + ->setExpirationDate(new \DateTime('2001-01-02T00:00:00')) + ->setToken('myToken') + ->setNote('personal note') + ->setLabel('new link share') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_LINK, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'attributes' => null, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => '2001-01-02 00:00:00', + 'token' => 'myToken', + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => 'new link share', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'password' => 'mypassword', + 'share_with' => 'mypassword', + 'share_with_displayname' => '(Shared link)', + 'send_password_by_talk' => false, + 'mail_send' => 0, + 'url' => 'myLink', + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_LINK) + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setPassword('mypassword') + ->setSendPasswordByTalk(true) + ->setExpirationDate(new \DateTime('2001-01-02T00:00:00')) + ->setToken('myToken') + ->setNote('personal note') + ->setLabel('new link share') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_LINK, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => '2001-01-02 00:00:00', + 'token' => 'myToken', + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => 'new link share', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'password' => 'mypassword', + 'share_with' => 'mypassword', + 'share_with_displayname' => '(Shared link)', + 'send_password_by_talk' => true, + 'mail_send' => 0, + 'url' => 'myLink', + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_REMOTE) + ->setSharedBy('initiator') + ->setSharedWith('user@server.com') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setExpirationDate(new \DateTime('2001-02-03T04:05:06')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_REMOTE, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => '2001-02-03 00:00:00', + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'user@server.com', + 'share_with_displayname' => 'foobar', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + 'is_trusted_server' => false, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_REMOTE_GROUP) + ->setSharedBy('initiator') + ->setSharedWith('user@server.com') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setExpirationDate(new \DateTime('2001-02-03T04:05:06')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_REMOTE_GROUP, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => '2001-02-03 00:00:00', + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'user@server.com', + 'share_with_displayname' => 'foobar', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + 'is_trusted_server' => false, + ], $share, [], false + ]; + + // Circle with id, display name and avatar set by the Circles app + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_CIRCLE) + ->setSharedBy('initiator') + ->setSharedWith('Circle (Public circle, circleOwner) [4815162342]') + ->setSharedWithDisplayName('The display name') + ->setSharedWithAvatar('path/to/the/avatar') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_CIRCLE, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'attributes' => null, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => '', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => '4815162342', + 'share_with_displayname' => 'The display name', + 'share_with_avatar' => 'path/to/the/avatar', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + // Circle with id set by the Circles app + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_CIRCLE) + ->setSharedBy('initiator') + ->setSharedWith('Circle (Public circle, circleOwner) [4815162342]') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_CIRCLE, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => '', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => '4815162342', + 'share_with_displayname' => 'Circle (Public circle, circleOwner)', + 'share_with_avatar' => '', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + // Circle with id not set by the Circles app + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_CIRCLE) + ->setSharedBy('initiator') + ->setSharedWith('Circle (Public circle, circleOwner)') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_CIRCLE, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => '', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'Circle', + 'share_with_displayname' => 'Circle (Public circle, circleOwner)', + 'share_with_avatar' => '', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_USER) + ->setSharedBy('initiator') + ->setSharedWith('recipient') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [], $share, [], true + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_EMAIL) + ->setSharedBy('initiator') + ->setSharedWith('user@server.com') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setId(42) + ->setPassword('password'); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_EMAIL, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => '', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'user@server.com', + 'share_with_displayname' => 'mail display name', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'password' => 'password', + 'send_password_by_talk' => false, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'password_expiration_time' => null, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_EMAIL) + ->setSharedBy('initiator') + ->setSharedWith('user@server.com') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($folder) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setId(42) + ->setPassword('password') + ->setSendPasswordByTalk(true); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_EMAIL, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => '', + 'label' => '', + 'path' => 'folder', + 'item_type' => 'folder', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 2, + 'file_source' => 2, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'user@server.com', + 'share_with_displayname' => 'mail display name', + 'mail_send' => 0, + 'mimetype' => 'myFolderMimeType', + 'has_preview' => false, + 'password' => 'password', + 'send_password_by_talk' => true, + 'hide_download' => 0, + 'can_edit' => false, + 'can_delete' => false, + 'password_expiration_time' => null, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, [], false + ]; + + // Preview is available + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_USER) + ->setSharedWith('recipient') + ->setSharedBy('initiator') + ->setShareOwner('currentUser') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($fileWithPreview) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_USER, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'currentUser', + 'displayname_file_owner' => 'currentUser', + 'note' => 'personal note', + 'label' => '', + 'path' => 'fileWithPreview', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 4, + 'file_source' => 4, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipient', + 'share_with_displayname' => 'recipient', + 'share_with_displayname_unique' => 'recipient', + 'mail_send' => 0, + 'mimetype' => 'mimeWithPreview', + 'has_preview' => true, + 'hide_download' => 0, + 'can_edit' => true, + 'can_delete' => true, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 11, + ], $share, [], false + ]; + + return $result; + } + + /** + * + * @param array $expects + * @param IShare $share + * @param array $users + * @param $exception + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataFormatShare')] + public function testFormatShare(array $expects, IShare $share, array $users, $exception): void { + $this->userManager->method('get')->willReturnMap($users); + + $recipientGroup = $this->createMock(IGroup::class); + $recipientGroup->method('getDisplayName')->willReturn('recipientGroupDisplayName'); + $this->groupManager->method('get')->willReturnMap([ + ['recipientGroup', $recipientGroup], + ]); + + $this->urlGenerator->method('linkToRouteAbsolute') + ->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken']) + ->willReturn('myLink'); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturnSelf(); + $this->dateTimeZone->method('getTimezone')->willReturn(new \DateTimeZone('UTC')); + + if (!$exception) { + $this->rootFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($share->getNode()); + + $this->rootFolder->method('getRelativePath') + ->with($share->getNode()->getPath()) + ->willReturnArgument(0); + } + + $cm = $this->createMock(\OCP\Contacts\IManager::class); + $this->overwriteService(\OCP\Contacts\IManager::class, $cm); + + $cm->method('search') + ->willReturnMap([ + ['user@server.com', ['CLOUD'], [ + 'limit' => 1, + 'enumeration' => false, + 'strict_search' => true, + ], + [ + [ + 'CLOUD' => [ + 'user@server.com', + ], + 'FN' => 'foobar', + ], + ], + ], + ['user@server.com', ['EMAIL'], [ + 'limit' => 1, + 'enumeration' => false, + 'strict_search' => true, + ], + [ + [ + 'EMAIL' => [ + 'user@server.com', + ], + 'FN' => 'mail display name', + ], + ], + ], + ]); + + try { + $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]); + $this->assertFalse($exception); + $this->assertEquals($expects, $result); + } catch (NotFoundException $e) { + $this->assertTrue($exception); + } + } + + public function dataFormatRoomShare() { + $file = $this->getMockBuilder(File::class)->getMock(); + $parent = $this->getMockBuilder(Folder::class)->getMock(); + + $file->method('getMimeType')->willReturn('myMimeType'); + + $file->method('getPath')->willReturn('file'); + + $parent->method('getId')->willReturn(1); + $file->method('getId')->willReturn(3); + + $file->method('getParent')->willReturn($parent); + + $file->method('getSize')->willReturn(123456); + $file->method('getMTime')->willReturn(1234567890); + + $mountPoint = $this->getMockBuilder(IMountPoint::class)->getMock(); + $mountPoint->method('getMountType')->willReturn(''); + $file->method('getMountPoint')->willReturn($mountPoint); + + $cache = $this->getMockBuilder('OCP\Files\Cache\ICache')->getMock(); + $cache->method('getNumericStorageId')->willReturn(100); + $storage = $this->createMock(IStorage::class); + $storage->method('getId')->willReturn('storageId'); + $storage->method('getCache')->willReturn($cache); + + $file->method('getStorage')->willReturn($storage); + + $result = []; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_ROOM) + ->setSharedWith('recipientRoom') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_ROOM, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipientRoom', + 'share_with_displayname' => '', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'label' => '', + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 1, + ], $share, false, [] + ]; + + $share = Server::get(IManager::class)->newShare(); + $share->setShareType(IShare::TYPE_ROOM) + ->setSharedWith('recipientRoom') + ->setSharedBy('initiator') + ->setShareOwner('owner') + ->setPermissions(Constants::PERMISSION_READ) + ->setNode($file) + ->setShareTime(new \DateTime('2000-01-01T00:01:02')) + ->setTarget('myTarget') + ->setNote('personal note') + ->setId(42); + + $result[] = [ + [ + 'id' => '42', + 'share_type' => IShare::TYPE_ROOM, + 'uid_owner' => 'initiator', + 'displayname_owner' => 'initiator', + 'permissions' => 1, + 'stime' => 946684862, + 'parent' => null, + 'expiration' => null, + 'token' => null, + 'uid_file_owner' => 'owner', + 'displayname_file_owner' => 'owner', + 'note' => 'personal note', + 'path' => 'file', + 'item_type' => 'file', + 'storage_id' => 'storageId', + 'storage' => 100, + 'item_source' => 3, + 'file_source' => 3, + 'file_parent' => 1, + 'file_target' => 'myTarget', + 'share_with' => 'recipientRoom', + 'share_with_displayname' => 'recipientRoomName', + 'mail_send' => 0, + 'mimetype' => 'myMimeType', + 'has_preview' => false, + 'hide_download' => 0, + 'label' => '', + 'can_edit' => false, + 'can_delete' => false, + 'item_size' => 123456, + 'item_mtime' => 1234567890, + 'is-mount-root' => false, + 'mount-type' => '', + 'attributes' => null, + 'item_permissions' => 9, + ], $share, true, [ + 'share_with_displayname' => 'recipientRoomName' + ] + ]; + + return $result; + } + + /** + * + * @param array $expects + * @param IShare $share + * @param bool $helperAvailable + * @param array $formatShareByHelper + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataFormatRoomShare')] + public function testFormatRoomShare(array $expects, IShare $share, bool $helperAvailable, array $formatShareByHelper): void { + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturnSelf(); + + $this->rootFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($share->getNode()); + + $this->rootFolder->method('getRelativePath') + ->with($share->getNode()->getPath()) + ->willReturnArgument(0); + + if (!$helperAvailable) { + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(false); + } else { + $this->appManager->method('isEnabledForUser') + ->with('spreed') + ->willReturn(true); + + // This is not possible anymore with PHPUnit 10+ + // as `setMethods` was removed and now real reflection is used, thus the class needs to exist. + // $helper = $this->getMockBuilder('\OCA\Talk\Share\Helper\ShareAPIController') + $helper = $this->getMockBuilder(\stdClass::class) + ->addMethods(['formatShare', 'canAccessShare']) + ->getMock(); + $helper->method('formatShare') + ->with($share) + ->willReturn($formatShareByHelper); + $helper->method('canAccessShare') + ->with($share) + ->willReturn(true); + + $this->serverContainer->method('get') + ->with('\OCA\Talk\Share\Helper\ShareAPIController') + ->willReturn($helper); + } + + $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]); + $this->assertEquals($expects, $result); + } + + /** + * @return list{Folder, Folder} + */ + private function getNonSharedUserFolder(): array { + $node = $this->getMockBuilder(Folder::class)->getMock(); + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); + $userFolder->method('getStorage')->willReturn($storage); + $node->method('getStorage')->willReturn($storage); + $node->method('getId')->willReturn(42); + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn($this->currentUser); + $node->method('getOwner')->willReturn($user); + return [$userFolder, $node]; + } + + /** + * @return list{Folder, File} + */ + private function getNonSharedUserFile(): array { + $node = $this->getMockBuilder(File::class)->getMock(); + $userFolder = $this->getMockBuilder(Folder::class)->getMock(); + $storage = $this->createMock(IStorage::class); + $storage->method('instanceOfStorage') + ->willReturnMap([ + ['OCA\Files_Sharing\External\Storage', false], + ['OCA\Files_Sharing\SharedStorage', false], + ]); + $userFolder->method('getStorage')->willReturn($storage); + $node->method('getStorage')->willReturn($storage); + $node->method('getId')->willReturn(42); + return [$userFolder, $node]; + } + + public function testPopulateTags(): void { + $tagger = $this->createMock(ITags::class); + $this->tagManager->method('load') + ->with('files') + ->willReturn($tagger); + $data = [ + ['file_source' => 10], + ['file_source' => 22, 'foo' => 'bar'], + ['file_source' => 42, 'x' => 'y'], + ]; + $tags = [ + 10 => ['tag3'], + 42 => ['tag1', 'tag2'], + ]; + $tagger->method('getTagsForObjects') + ->with([10, 22, 42]) + ->willReturn($tags); + + $result = self::invokePrivate($this->ocs, 'populateTags', [$data]); + $this->assertSame([ + ['file_source' => 10, 'tags' => ['tag3']], + ['file_source' => 22, 'foo' => 'bar', 'tags' => []], + ['file_source' => 42, 'x' => 'y', 'tags' => ['tag1', 'tag2']], + ], $result); + } + + public function trustedServerProvider(): array { + return [ + 'Trusted server' => [true, true], + 'Untrusted server' => [false, false], + ]; + } + + /** + * @dataProvider trustedServerProvider + */ + public function testFormatShareWithFederatedShare(bool $isKnownServer, bool $isTrusted): void { + $nodeId = 12; + $nodePath = '/test.txt'; + $share = $this->createShare( + 1, + IShare::TYPE_REMOTE, + 'recipient@remoteserver.com', // shared with + 'sender@testserver.com', // shared by + 'shareOwner', // share owner + $nodePath, // path + Constants::PERMISSION_READ, + time(), + null, + null, + $nodePath, + $nodeId + ); + + $node = $this->createMock(\OCP\Files\File::class); + $node->method('getId')->willReturn($nodeId); + $node->method('getPath')->willReturn($nodePath); + $node->method('getInternalPath')->willReturn(ltrim($nodePath, '/')); + $mountPoint = $this->createMock(\OCP\Files\Mount\IMountPoint::class); + $mountPoint->method('getMountType')->willReturn('local'); + $node->method('getMountPoint')->willReturn($mountPoint); + $node->method('getMimetype')->willReturn('text/plain'); + $storage = $this->createMock(\OCP\Files\Storage\IStorage::class); + $storageCache = $this->createMock(\OCP\Files\Cache\ICache::class); + $storageCache->method('getNumericStorageId')->willReturn(1); + $storage->method('getCache')->willReturn($storageCache); + $storage->method('getId')->willReturn('home::shareOwner'); + $node->method('getStorage')->willReturn($storage); + $parent = $this->createMock(\OCP\Files\Folder::class); + $parent->method('getId')->willReturn(2); + $node->method('getParent')->willReturn($parent); + $node->method('getSize')->willReturn(1234); + $node->method('getMTime')->willReturn(1234567890); + + $this->previewManager->method('isAvailable')->with($node)->willReturn(false); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturnSelf(); + + $this->rootFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($node); + + $this->rootFolder->method('getRelativePath') + ->with($node->getPath()) + ->willReturnArgument(0); + + $serverName = 'remoteserver.com'; + $this->trustedServers->method('isTrustedServer') + ->with($serverName) + ->willReturn($isKnownServer); + + $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]); + + $this->assertSame($isTrusted, $result['is_trusted_server']); + } + + public function testFormatShareWithFederatedShareWithAtInUsername(): void { + $nodeId = 12; + $nodePath = '/test.txt'; + $share = $this->createShare( + 1, + IShare::TYPE_REMOTE, + 'recipient@domain.com@remoteserver.com', + 'sender@testserver.com', + 'shareOwner', + $nodePath, + Constants::PERMISSION_READ, + time(), + null, + null, + $nodePath, + $nodeId + ); + + $node = $this->createMock(\OCP\Files\File::class); + $node->method('getId')->willReturn($nodeId); + $node->method('getPath')->willReturn($nodePath); + $node->method('getInternalPath')->willReturn(ltrim($nodePath, '/')); + $mountPoint = $this->createMock(\OCP\Files\Mount\IMountPoint::class); + $mountPoint->method('getMountType')->willReturn('local'); + $node->method('getMountPoint')->willReturn($mountPoint); + $node->method('getMimetype')->willReturn('text/plain'); + $storage = $this->createMock(\OCP\Files\Storage\IStorage::class); + $storageCache = $this->createMock(\OCP\Files\Cache\ICache::class); + $storageCache->method('getNumericStorageId')->willReturn(1); + $storage->method('getCache')->willReturn($storageCache); + $storage->method('getId')->willReturn('home::shareOwner'); + $node->method('getStorage')->willReturn($storage); + $parent = $this->createMock(\OCP\Files\Folder::class); + $parent->method('getId')->willReturn(2); + $node->method('getParent')->willReturn($parent); + $node->method('getSize')->willReturn(1234); + $node->method('getMTime')->willReturn(1234567890); + + $this->previewManager->method('isAvailable')->with($node)->willReturn(false); + + $this->rootFolder->method('getUserFolder') + ->with($this->currentUser) + ->willReturnSelf(); + + $this->rootFolder->method('getFirstNodeById') + ->with($share->getNodeId()) + ->willReturn($node); + + $this->rootFolder->method('getRelativePath') + ->with($node->getPath()) + ->willReturnArgument(0); + + $serverName = 'remoteserver.com'; + $this->trustedServers->method('isTrustedServer') + ->with($serverName) + ->willReturn(true); + + $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]); + + $this->assertTrue($result['is_trusted_server']); + } +} diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php new file mode 100644 index 00000000000..011210aff42 --- /dev/null +++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php @@ -0,0 +1,822 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Controllers; + +use OC\Files\Filesystem; +use OC\Files\Node\Folder; +use OC\Share20\Manager; +use OCA\FederatedFileSharing\FederatedShareProvider; +use OCA\Files_Sharing\Controller\ShareController; +use OCA\Files_Sharing\DefaultPublicShareTemplateProvider; +use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent; +use OCP\Accounts\IAccount; +use OCP\Accounts\IAccountManager; +use OCP\Accounts\IAccountProperty; +use OCP\Activity\IManager; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\Template\ExternalShareMenuAction; +use OCP\AppFramework\Http\Template\LinkMenuAction; +use OCP\AppFramework\Http\Template\PublicTemplateResponse; +use OCP\AppFramework\Http\Template\SimpleMenuAction; +use OCP\AppFramework\Services\IInitialState; +use OCP\Constants; +use OCP\Defaults; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\File; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IPreview; +use OCP\IRequest; +use OCP\ISession; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Security\ISecureRandom; +use OCP\Server; +use OCP\Share\Exceptions\ShareNotFound; +use OCP\Share\IAttributes; +use OCP\Share\IPublicShareTemplateFactory; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * @group DB + * + * @package OCA\Files_Sharing\Controllers + */ +class ShareControllerTest extends \Test\TestCase { + + private string $user; + private string $oldUser; + private string $appName = 'files_sharing'; + private ShareController $shareController; + + private IL10N&MockObject $l10n; + private IConfig&MockObject $config; + private ISession&MockObject $session; + private Defaults&MockObject $defaults; + private IAppConfig&MockObject $appConfig; + private Manager&MockObject $shareManager; + private IPreview&MockObject $previewManager; + private IUserManager&MockObject $userManager; + private IInitialState&MockObject $initialState; + private IURLGenerator&MockObject $urlGenerator; + private ISecureRandom&MockObject $secureRandom; + private IAccountManager&MockObject $accountManager; + private IEventDispatcher&MockObject $eventDispatcher; + private FederatedShareProvider&MockObject $federatedShareProvider; + private IPublicShareTemplateFactory&MockObject $publicShareTemplateFactory; + + protected function setUp(): void { + parent::setUp(); + $this->appName = 'files_sharing'; + + $this->shareManager = $this->createMock(Manager::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->session = $this->createMock(ISession::class); + $this->previewManager = $this->createMock(IPreview::class); + $this->config = $this->createMock(IConfig::class); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->initialState = $this->createMock(IInitialState::class); + $this->federatedShareProvider = $this->createMock(FederatedShareProvider::class); + $this->federatedShareProvider->expects($this->any()) + ->method('isOutgoingServer2serverShareEnabled')->willReturn(true); + $this->federatedShareProvider->expects($this->any()) + ->method('isIncomingServer2serverShareEnabled')->willReturn(true); + $this->accountManager = $this->createMock(IAccountManager::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->l10n = $this->createMock(IL10N::class); + $this->secureRandom = $this->createMock(ISecureRandom::class); + $this->defaults = $this->createMock(Defaults::class); + $this->publicShareTemplateFactory = $this->createMock(IPublicShareTemplateFactory::class); + $this->publicShareTemplateFactory + ->expects($this->any()) + ->method('getProvider') + ->willReturn( + new DefaultPublicShareTemplateProvider( + $this->userManager, + $this->accountManager, + $this->previewManager, + $this->federatedShareProvider, + $this->urlGenerator, + $this->eventDispatcher, + $this->l10n, + $this->defaults, + $this->config, + $this->createMock(IRequest::class), + $this->initialState, + $this->appConfig, + ) + ); + + $this->shareController = new ShareController( + $this->appName, + $this->createMock(IRequest::class), + $this->config, + $this->urlGenerator, + $this->userManager, + $this->createMock(IManager::class), + $this->shareManager, + $this->session, + $this->previewManager, + $this->createMock(IRootFolder::class), + $this->federatedShareProvider, + $this->accountManager, + $this->eventDispatcher, + $this->l10n, + $this->secureRandom, + $this->defaults, + $this->publicShareTemplateFactory, + ); + + + // Store current user + $this->oldUser = \OC_User::getUser(); + + // Create a dummy user + $this->user = Server::get(ISecureRandom::class)->generate(12, ISecureRandom::CHAR_LOWER); + + Server::get(IUserManager::class)->createUser($this->user, $this->user); + \OC_Util::tearDownFS(); + $this->loginAsUser($this->user); + } + + protected function tearDown(): void { + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + Filesystem::tearDown(); + $user = Server::get(IUserManager::class)->get($this->user); + if ($user !== null) { + $user->delete(); + } + \OC_User::setIncognitoMode(false); + + Server::get(ISession::class)->set('public_link_authenticated', ''); + + // Set old user + \OC_User::setUserId($this->oldUser); + \OC_Util::setupFS($this->oldUser); + parent::tearDown(); + } + + public function testShowShareInvalidToken(): void { + $this->shareController->setToken('invalidtoken'); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('invalidtoken') + ->willThrowException(new ShareNotFound()); + + $this->expectException(NotFoundException::class); + + // Test without a not existing token + $this->shareController->showShare(); + } + + public function testShowShareNotAuthenticated(): void { + $this->shareController->setToken('validtoken'); + + $share = Server::get(\OCP\Share\IManager::class)->newShare(); + $share->setPassword('password'); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('validtoken') + ->willReturn($share); + + $this->expectException(NotFoundException::class); + + // Test without a not existing token + $this->shareController->showShare(); + } + + + public function testShowShare(): void { + $note = 'personal note'; + $filename = 'file1.txt'; + + $this->shareController->setToken('token'); + + $owner = $this->createMock(IUser::class); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + $owner->method('getUID')->willReturn('ownerUID'); + $owner->method('isEnabled')->willReturn(true); + + $initiator = $this->createMock(IUser::class); + $initiator->method('getDisplayName')->willReturn('initiatorDisplay'); + $initiator->method('getUID')->willReturn('initiatorUID'); + $initiator->method('isEnabled')->willReturn(true); + + $file = $this->createMock(File::class); + $file->method('getName')->willReturn($filename); + $file->method('getMimetype')->willReturn('text/plain'); + $file->method('getSize')->willReturn(33); + $file->method('isReadable')->willReturn(true); + $file->method('isShareable')->willReturn(true); + $file->method('getId')->willReturn(111); + + $accountName = $this->createMock(IAccountProperty::class); + $accountName->method('getScope') + ->willReturn(IAccountManager::SCOPE_PUBLISHED); + $account = $this->createMock(IAccount::class); + $account->method('getProperty') + ->with(IAccountManager::PROPERTY_DISPLAYNAME) + ->willReturn($accountName); + $this->accountManager->expects($this->once()) + ->method('getAccount') + ->with($owner) + ->willReturn($account); + + /** @var Manager */ + $manager = Server::get(Manager::class); + $share = $manager->newShare(); + $share->setId(42) + ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE) + ->setPassword('password') + ->setShareOwner('ownerUID') + ->setSharedBy('initiatorUID') + ->setNode($file) + ->setNote($note) + ->setTarget("/$filename") + ->setToken('token'); + + $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); + $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); + + $this->urlGenerator->expects(self::atLeast(2)) + ->method('linkToRouteAbsolute') + ->willReturnMap([ + // every file has the show show share url in the opengraph url prop + ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'], + // this share is not an image to the default preview is used + ['files_sharing.PublicPreview.getPreview', ['x' => 256, 'y' => 256, 'file' => $share->getTarget(), 'token' => 'token'], 'previewUrl'], + ]); + + $this->urlGenerator->expects($this->once()) + ->method('getAbsoluteURL') + ->willReturnMap([ + ['/public.php/dav/files/token/?accept=zip', 'downloadUrl'], + ]); + + $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true); + + $this->config->method('getSystemValue') + ->willReturnMap( + [ + ['max_filesize_animated_gifs_public_sharing', 10, 10], + ['enable_previews', true, true], + ['preview_max_x', 1024, 1024], + ['preview_max_y', 1024, 1024], + ] + ); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) { + if ($uid === 'ownerUID') { + return $owner; + } + if ($uid === 'initiatorUID') { + return $initiator; + } + return null; + }); + + $this->eventDispatcher->method('dispatchTyped')->with( + $this->callback(function ($event) use ($share) { + if ($event instanceof BeforeTemplateRenderedEvent) { + return $event->getShare() === $share; + } else { + return true; + } + }) + ); + + $this->l10n->expects($this->any()) + ->method('t') + ->willReturnCallback(function ($text, $parameters) { + return vsprintf($text, $parameters); + }); + + $this->defaults->expects(self::any()) + ->method('getProductName') + ->willReturn('Nextcloud'); + + // Ensure the correct initial state is setup + // Shared node is a file so this is a single file share: + $view = 'public-file-share'; + // Set up initial state + $initialState = []; + $this->initialState->expects(self::any()) + ->method('provideInitialState') + ->willReturnCallback(function ($key, $value) use (&$initialState): void { + $initialState[$key] = $value; + }); + $expectedInitialState = [ + 'isPublic' => true, + 'sharingToken' => 'token', + 'sharePermissions' => (Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE), + 'filename' => $filename, + 'view' => $view, + 'fileId' => 111, + 'owner' => 'ownerUID', + 'ownerDisplayName' => 'ownerDisplay', + 'isFileRequest' => false, + ]; + + $response = $this->shareController->showShare(); + + $this->assertEquals($expectedInitialState, $initialState); + + $csp = new ContentSecurityPolicy(); + $csp->addAllowedFrameDomain('\'self\''); + $expectedResponse = new PublicTemplateResponse('files', 'index'); + $expectedResponse->setParams(['pageTitle' => $filename]); + $expectedResponse->setContentSecurityPolicy($csp); + $expectedResponse->setHeaderTitle($filename); + $expectedResponse->setHeaderDetails('shared by ownerDisplay'); + $expectedResponse->setHeaderActions([ + new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', 'downloadUrl', 0, '33'), + new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', 'owner', 'ownerDisplay', $filename), + new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'downloadUrl'), + ]); + + $this->assertEquals($expectedResponse, $response); + } + + public function testShowFileDropShare(): void { + $filename = 'folder1'; + + $this->shareController->setToken('token'); + + $owner = $this->createMock(IUser::class); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + $owner->method('getUID')->willReturn('ownerUID'); + $owner->method('isEnabled')->willReturn(true); + + $initiator = $this->createMock(IUser::class); + $initiator->method('getDisplayName')->willReturn('initiatorDisplay'); + $initiator->method('getUID')->willReturn('initiatorUID'); + $initiator->method('isEnabled')->willReturn(true); + + $file = $this->createMock(Folder::class); + $file->method('isReadable')->willReturn(true); + $file->method('isShareable')->willReturn(true); + $file->method('getId')->willReturn(1234); + $file->method('getName')->willReturn($filename); + + $accountName = $this->createMock(IAccountProperty::class); + $accountName->method('getScope') + ->willReturn(IAccountManager::SCOPE_PUBLISHED); + $account = $this->createMock(IAccount::class); + $account->method('getProperty') + ->with(IAccountManager::PROPERTY_DISPLAYNAME) + ->willReturn($accountName); + $this->accountManager->expects($this->once()) + ->method('getAccount') + ->with($owner) + ->willReturn($account); + + /** @var Manager */ + $manager = Server::get(Manager::class); + $share = $manager->newShare(); + $share->setId(42) + ->setPermissions(Constants::PERMISSION_CREATE) + ->setPassword('password') + ->setShareOwner('ownerUID') + ->setSharedBy('initiatorUID') + ->setNote('The note') + ->setLabel('A label') + ->setNode($file) + ->setTarget("/$filename") + ->setToken('token'); + + $this->appConfig + ->expects($this->once()) + ->method('getValueString') + ->with('core', 'shareapi_public_link_disclaimertext', '') + ->willReturn('My disclaimer text'); + + $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); + $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); + + $this->urlGenerator->expects(self::atLeastOnce()) + ->method('linkToRouteAbsolute') + ->willReturnMap([ + // every file has the show show share url in the opengraph url prop + ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'], + // there is no preview or folders so no other link for opengraph + ]); + + $this->config->method('getSystemValue') + ->willReturnMap( + [ + ['max_filesize_animated_gifs_public_sharing', 10, 10], + ['enable_previews', true, true], + ['preview_max_x', 1024, 1024], + ['preview_max_y', 1024, 1024], + ] + ); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) { + if ($uid === 'ownerUID') { + return $owner; + } + if ($uid === 'initiatorUID') { + return $initiator; + } + return null; + }); + + $this->eventDispatcher->method('dispatchTyped')->with( + $this->callback(function ($event) use ($share) { + if ($event instanceof BeforeTemplateRenderedEvent) { + return $event->getShare() === $share; + } else { + return true; + } + }) + ); + + $this->l10n->expects($this->any()) + ->method('t') + ->willReturnCallback(function ($text, $parameters) { + return vsprintf($text, $parameters); + }); + + // Set up initial state + $initialState = []; + $this->initialState->expects(self::any()) + ->method('provideInitialState') + ->willReturnCallback(function ($key, $value) use (&$initialState): void { + $initialState[$key] = $value; + }); + $expectedInitialState = [ + 'isPublic' => true, + 'sharingToken' => 'token', + 'sharePermissions' => Constants::PERMISSION_CREATE, + 'filename' => $filename, + 'view' => 'public-file-drop', + 'disclaimer' => 'My disclaimer text', + 'owner' => 'ownerUID', + 'ownerDisplayName' => 'ownerDisplay', + 'isFileRequest' => false, + 'note' => 'The note', + 'label' => 'A label', + ]; + + $response = $this->shareController->showShare(); + + $this->assertEquals($expectedInitialState, $initialState); + + $csp = new ContentSecurityPolicy(); + $csp->addAllowedFrameDomain('\'self\''); + $expectedResponse = new PublicTemplateResponse('files', 'index'); + $expectedResponse->setParams(['pageTitle' => 'A label']); + $expectedResponse->setContentSecurityPolicy($csp); + $expectedResponse->setHeaderTitle('A label'); + $expectedResponse->setHeaderDetails('shared by ownerDisplay'); + $expectedResponse->setHeaderActions([ + new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'shareUrl'), + ]); + + $this->assertEquals($expectedResponse, $response); + } + + public function testShowShareWithPrivateName(): void { + $note = 'personal note'; + $filename = 'file1.txt'; + + $this->shareController->setToken('token'); + + $owner = $this->createMock(IUser::class); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + $owner->method('getUID')->willReturn('ownerUID'); + $owner->method('isEnabled')->willReturn(true); + + $initiator = $this->createMock(IUser::class); + $initiator->method('getDisplayName')->willReturn('initiatorDisplay'); + $initiator->method('getUID')->willReturn('initiatorUID'); + $initiator->method('isEnabled')->willReturn(true); + + $file = $this->createMock(File::class); + $file->method('getName')->willReturn($filename); + $file->method('getMimetype')->willReturn('text/plain'); + $file->method('getSize')->willReturn(33); + $file->method('isReadable')->willReturn(true); + $file->method('isShareable')->willReturn(true); + $file->method('getId')->willReturn(111); + + $accountName = $this->createMock(IAccountProperty::class); + $accountName->method('getScope') + ->willReturn(IAccountManager::SCOPE_LOCAL); + $account = $this->createMock(IAccount::class); + $account->method('getProperty') + ->with(IAccountManager::PROPERTY_DISPLAYNAME) + ->willReturn($accountName); + $this->accountManager->expects($this->once()) + ->method('getAccount') + ->with($owner) + ->willReturn($account); + + /** @var IShare */ + $share = Server::get(Manager::class)->newShare(); + $share->setId(42); + $share->setPassword('password') + ->setShareOwner('ownerUID') + ->setSharedBy('initiatorUID') + ->setNode($file) + ->setNote($note) + ->setToken('token') + ->setPermissions(Constants::PERMISSION_ALL & ~Constants::PERMISSION_SHARE) + ->setTarget("/$filename"); + + $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); + $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); + + $this->urlGenerator->expects(self::atLeast(2)) + ->method('linkToRouteAbsolute') + ->willReturnMap([ + // every file has the show show share url in the opengraph url prop + ['files_sharing.sharecontroller.showShare', ['token' => 'token'], 'shareUrl'], + // this share is not an image to the default preview is used + ['files_sharing.PublicPreview.getPreview', ['x' => 256, 'y' => 256, 'file' => $share->getTarget(), 'token' => 'token'], 'previewUrl'], + ]); + + $this->urlGenerator->expects($this->once()) + ->method('getAbsoluteURL') + ->willReturnMap([ + ['/public.php/dav/files/token/?accept=zip', 'downloadUrl'], + ]); + + $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true); + + $this->config->method('getSystemValue') + ->willReturnMap( + [ + ['max_filesize_animated_gifs_public_sharing', 10, 10], + ['enable_previews', true, true], + ['preview_max_x', 1024, 1024], + ['preview_max_y', 1024, 1024], + ] + ); + $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); + $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) { + if ($uid === 'ownerUID') { + return $owner; + } + if ($uid === 'initiatorUID') { + return $initiator; + } + return null; + }); + + $this->eventDispatcher->method('dispatchTyped')->with( + $this->callback(function ($event) use ($share) { + if ($event instanceof BeforeTemplateRenderedEvent) { + return $event->getShare() === $share; + } else { + return true; + } + }) + ); + + $this->l10n->expects($this->any()) + ->method('t') + ->willReturnCallback(function ($text, $parameters) { + return vsprintf($text, $parameters); + }); + + $this->defaults->expects(self::any()) + ->method('getProductName') + ->willReturn('Nextcloud'); + + $response = $this->shareController->showShare(); + + $csp = new ContentSecurityPolicy(); + $csp->addAllowedFrameDomain('\'self\''); + $expectedResponse = new PublicTemplateResponse('files', 'index'); + $expectedResponse->setParams(['pageTitle' => $filename]); + $expectedResponse->setContentSecurityPolicy($csp); + $expectedResponse->setHeaderTitle($filename); + $expectedResponse->setHeaderDetails(''); + $expectedResponse->setHeaderActions([ + new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', 'downloadUrl', 0, '33'), + new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', 'owner', 'ownerDisplay', $filename), + new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'downloadUrl'), + ]); + + $this->assertEquals($expectedResponse, $response); + } + + + public function testShowShareInvalid(): void { + $this->expectException(NotFoundException::class); + + $filename = 'file1.txt'; + $this->shareController->setToken('token'); + + $owner = $this->getMockBuilder(IUser::class)->getMock(); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + $owner->method('getUID')->willReturn('ownerUID'); + + $file = $this->getMockBuilder('OCP\Files\File')->getMock(); + $file->method('getName')->willReturn($filename); + $file->method('getMimetype')->willReturn('text/plain'); + $file->method('getSize')->willReturn(33); + $file->method('isShareable')->willReturn(false); + $file->method('isReadable')->willReturn(true); + + $share = Server::get(\OCP\Share\IManager::class)->newShare(); + $share->setId(42); + $share->setPassword('password') + ->setShareOwner('ownerUID') + ->setNode($file) + ->setTarget("/$filename"); + + $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); + $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); + + $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true); + + $this->config->method('getSystemValue') + ->willReturnMap( + [ + ['max_filesize_animated_gifs_public_sharing', 10, 10], + ['enable_previews', true, true], + ] + ); + $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); + $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $this->userManager->method('get')->with('ownerUID')->willReturn($owner); + + $this->shareController->showShare(); + } + + public function testDownloadShareWithCreateOnlyShare(): void { + $share = $this->getMockBuilder(IShare::class)->getMock(); + $share->method('getPassword')->willReturn('password'); + $share + ->expects($this->once()) + ->method('getPermissions') + ->willReturn(Constants::PERMISSION_CREATE); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('validtoken') + ->willReturn($share); + + // Test with a password protected share and no authentication + $response = $this->shareController->downloadShare('validtoken'); + $expectedResponse = new DataResponse('Share has no read permission'); + $this->assertEquals($expectedResponse, $response); + } + + public function testDownloadShareWithoutDownloadPermission(): void { + $attributes = $this->createMock(IAttributes::class); + $attributes->expects(self::once()) + ->method('getAttribute') + ->with('permissions', 'download') + ->willReturn(false); + + $share = $this->createMock(IShare::class); + $share->method('getPassword')->willReturn('password'); + $share->expects(self::once()) + ->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + $share->expects(self::once()) + ->method('getAttributes') + ->willReturn($attributes); + + $this->shareManager + ->expects(self::once()) + ->method('getShareByToken') + ->with('validtoken') + ->willReturn($share); + + // Test with a password protected share and no authentication + $response = $this->shareController->downloadShare('validtoken'); + $expectedResponse = new DataResponse('Share has no download permission'); + $this->assertEquals($expectedResponse, $response); + } + + public function testDisabledOwner(): void { + $this->shareController->setToken('token'); + + $owner = $this->getMockBuilder(IUser::class)->getMock(); + $owner->method('isEnabled')->willReturn(false); + + $initiator = $this->createMock(IUser::class); + $initiator->method('isEnabled')->willReturn(false); + + /* @var MockObject|Folder $folder */ + $folder = $this->createMock(Folder::class); + + $share = Server::get(\OCP\Share\IManager::class)->newShare(); + $share->setId(42); + $share->setPermissions(Constants::PERMISSION_CREATE) + ->setShareOwner('ownerUID') + ->setSharedBy('initiatorUID') + ->setNode($folder) + ->setTarget('/share'); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) { + if ($uid === 'ownerUID') { + return $owner; + } + if ($uid === 'initiatorUID') { + return $initiator; + } + return null; + }); + + $this->expectException(NotFoundException::class); + + $this->shareController->showShare(); + } + + public function testDisabledInitiator(): void { + $this->shareController->setToken('token'); + + $owner = $this->getMockBuilder(IUser::class)->getMock(); + $owner->method('isEnabled')->willReturn(false); + + $initiator = $this->createMock(IUser::class); + $initiator->method('isEnabled')->willReturn(true); + + /* @var MockObject|Folder $folder */ + $folder = $this->createMock(Folder::class); + + $share = Server::get(\OCP\Share\IManager::class)->newShare(); + $share->setId(42); + $share->setPermissions(Constants::PERMISSION_CREATE) + ->setShareOwner('ownerUID') + ->setSharedBy('initiatorUID') + ->setNode($folder) + ->setTarget('/share'); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $this->userManager->method('get')->willReturnCallback(function (string $uid) use ($owner, $initiator) { + if ($uid === 'ownerUID') { + return $owner; + } + if ($uid === 'initiatorUID') { + return $initiator; + } + return null; + }); + + $this->expectException(NotFoundException::class); + + $this->shareController->showShare(); + } +} diff --git a/apps/files_sharing/tests/Controller/ShareInfoControllerTest.php b/apps/files_sharing/tests/Controller/ShareInfoControllerTest.php new file mode 100644 index 00000000000..1a678610805 --- /dev/null +++ b/apps/files_sharing/tests/Controller/ShareInfoControllerTest.php @@ -0,0 +1,277 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests\Controller; + +use OCA\Files_Sharing\Controller\ShareInfoController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\JSONResponse; +use OCP\Constants; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\IRequest; +use OCP\Share\Exceptions\ShareNotFound; +use OCP\Share\IManager as ShareManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class ShareInfoControllerTest extends TestCase { + + protected ShareInfoController $controller; + protected ShareManager&MockObject $shareManager; + + + protected function setUp(): void { + parent::setUp(); + + $this->shareManager = $this->createMock(ShareManager::class); + + $this->controller = new ShareInfoController( + 'files_sharing', + $this->createMock(IRequest::class), + $this->shareManager + ); + } + + public function testNoShare(): void { + $this->shareManager->method('getShareByToken') + ->with('token') + ->willThrowException(new ShareNotFound()); + + $expected = new JSONResponse([], Http::STATUS_NOT_FOUND); + $expected->throttle(['token' => 'token']); + $this->assertEquals($expected, $this->controller->info('token')); + } + + public function testWrongPassword(): void { + $share = $this->createMock(IShare::class); + $share->method('getPassword') + ->willReturn('sharePass'); + + $this->shareManager->method('getShareByToken') + ->with('token') + ->willReturn($share); + $this->shareManager->method('checkPassword') + ->with($share, 'pass') + ->willReturn(false); + + $expected = new JSONResponse([], Http::STATUS_FORBIDDEN); + $expected->throttle(['token' => 'token']); + $this->assertEquals($expected, $this->controller->info('token', 'pass')); + } + + public function testNoReadPermissions(): void { + $share = $this->createMock(IShare::class); + $share->method('getPassword') + ->willReturn('sharePass'); + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_CREATE); + + $this->shareManager->method('getShareByToken') + ->with('token') + ->willReturn($share); + $this->shareManager->method('checkPassword') + ->with($share, 'pass') + ->willReturn(true); + + $expected = new JSONResponse([], Http::STATUS_FORBIDDEN); + $expected->throttle(['token' => 'token']); + $this->assertEquals($expected, $this->controller->info('token', 'pass')); + } + + private function prepareFile() { + $file = $this->createMock(File::class); + + $file->method('getId')->willReturn(42); + + $parent = $this->createMock(Folder::class); + $parent->method('getId')->willReturn(41); + $file->method('getParent')->willReturn($parent); + + $file->method('getMTime')->willReturn(1337); + $file->method('getName')->willReturn('file'); + $file->method('getPermissions')->willReturn(Constants::PERMISSION_READ); + $file->method('getMimeType')->willReturn('mime/type'); + $file->method('getSize')->willReturn(1); + $file->method('getType')->willReturn('file'); + $file->method('getEtag')->willReturn('etag'); + + return $file; + } + + public function testInfoFile(): void { + $file = $this->prepareFile(); + + $share = $this->createMock(IShare::class); + $share->method('getPassword') + ->willReturn('sharePass'); + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE); + $share->method('getNode') + ->willReturn($file); + + $this->shareManager->method('getShareByToken') + ->with('token') + ->willReturn($share); + $this->shareManager->method('checkPassword') + ->with($share, 'pass') + ->willReturn(true); + + $expected = new JSONResponse([ + 'id' => 42, + 'parentId' => 41, + 'mtime' => 1337 , + 'name' => 'file', + 'permissions' => 1, + 'mimetype' => 'mime/type', + 'size' => 1, + 'type' => 'file', + 'etag' => 'etag', + ]); + $this->assertEquals($expected, $this->controller->info('token', 'pass')); + } + + public function testInfoFileRO(): void { + $file = $this->prepareFile(); + + $share = $this->createMock(IShare::class); + $share->method('getPassword') + ->willReturn('sharePass'); + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ); + $share->method('getNode') + ->willReturn($file); + + $this->shareManager->method('getShareByToken') + ->with('token') + ->willReturn($share); + $this->shareManager->method('checkPassword') + ->with($share, 'pass') + ->willReturn(true); + + $expected = new JSONResponse([ + 'id' => 42, + 'parentId' => 41, + 'mtime' => 1337 , + 'name' => 'file', + 'permissions' => 1, + 'mimetype' => 'mime/type', + 'size' => 1, + 'type' => 'file', + 'etag' => 'etag', + ]); + $this->assertEquals($expected, $this->controller->info('token', 'pass')); + } + + private function prepareFolder() { + $root = $this->createMock(Folder::class); + + $root->method('getId')->willReturn(42); + + $parent = $this->createMock(Folder::class); + $parent->method('getId')->willReturn(41); + $root->method('getParent')->willReturn($parent); + + $root->method('getMTime')->willReturn(1337); + $root->method('getName')->willReturn('root'); + $root->method('getPermissions')->willReturn(Constants::PERMISSION_READ); + $root->method('getMimeType')->willReturn('mime/type'); + $root->method('getSize')->willReturn(1); + $root->method('getType')->willReturn('folder'); + $root->method('getEtag')->willReturn('etag'); + + + //Subfolder + $sub = $this->createMock(Folder::class); + + $sub->method('getId')->willReturn(43); + $sub->method('getParent')->willReturn($root); + $sub->method('getMTime')->willReturn(1338); + $sub->method('getName')->willReturn('sub'); + $sub->method('getPermissions')->willReturn(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE); + $sub->method('getMimeType')->willReturn('mime/type'); + $sub->method('getSize')->willReturn(2); + $sub->method('getType')->willReturn('folder'); + $sub->method('getEtag')->willReturn('etag2'); + + $root->method('getDirectoryListing')->willReturn([$sub]); + + //Subfile + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(88); + $file->method('getParent')->willReturn($sub); + $file->method('getMTime')->willReturn(1339); + $file->method('getName')->willReturn('file'); + $file->method('getPermissions')->willReturn(Constants::PERMISSION_READ | Constants::PERMISSION_DELETE); + $file->method('getMimeType')->willReturn('mime/type'); + $file->method('getSize')->willReturn(3); + $file->method('getType')->willReturn('file'); + $file->method('getEtag')->willReturn('etag3'); + + $sub->method('getDirectoryListing')->willReturn([$file]); + + return $root; + } + + public function testInfoFolder(): void { + $file = $this->prepareFolder(); + + $share = $this->createMock(IShare::class); + $share->method('getPassword') + ->willReturn('sharePass'); + $share->method('getPermissions') + ->willReturn(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE); + $share->method('getNode') + ->willReturn($file); + + $this->shareManager->method('getShareByToken') + ->with('token') + ->willReturn($share); + $this->shareManager->method('checkPassword') + ->with($share, 'pass') + ->willReturn(true); + + $expected = new JSONResponse([ + 'id' => 42, + 'parentId' => 41, + 'mtime' => 1337, + 'name' => 'root', + 'permissions' => 1, + 'mimetype' => 'mime/type', + 'size' => 1, + 'type' => 'folder', + 'etag' => 'etag', + 'children' => [ + [ + 'id' => 43, + 'parentId' => 42, + 'mtime' => 1338, + 'name' => 'sub', + 'permissions' => 3, + 'mimetype' => 'mime/type', + 'size' => 2, + 'type' => 'folder', + 'etag' => 'etag2', + 'children' => [ + [ + 'id' => 88, + 'parentId' => 43, + 'mtime' => 1339, + 'name' => 'file', + 'permissions' => 1, + 'mimetype' => 'mime/type', + 'size' => 3, + 'type' => 'file', + 'etag' => 'etag3', + ] + ], + ] + ], + ]); + $this->assertEquals($expected, $this->controller->info('token', 'pass')); + } +} diff --git a/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php new file mode 100644 index 00000000000..18e1bf0347b --- /dev/null +++ b/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php @@ -0,0 +1,466 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Controller; + +use OCA\Files_Sharing\Controller\ShareesAPIController; +use OCA\Files_Sharing\Tests\TestCase; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCS\OCSBadRequestException; +use OCP\Collaboration\Collaborators\ISearch; +use OCP\GlobalScale\IConfig as GlobalScaleIConfig; +use OCP\IConfig; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\Share\IManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * Class ShareesTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests\API + */ +class ShareesAPIControllerTest extends TestCase { + /** @var ShareesAPIController */ + protected $sharees; + + /** @var string */ + protected $uid; + + /** @var IRequest|MockObject */ + protected $request; + + /** @var IManager|MockObject */ + protected $shareManager; + + /** @var ISearch|MockObject */ + protected $collaboratorSearch; + + /** @var IConfig|MockObject */ + protected $config; + + protected function setUp(): void { + parent::setUp(); + + $this->uid = 'test123'; + $this->request = $this->createMock(IRequest::class); + $this->shareManager = $this->createMock(IManager::class); + $this->config = $this->createMock(IConfig::class); + + /** @var IURLGenerator|MockObject $urlGeneratorMock */ + $urlGeneratorMock = $this->createMock(IURLGenerator::class); + + $this->collaboratorSearch = $this->createMock(ISearch::class); + + $this->sharees = new ShareesAPIController( + 'files_sharing', + $this->request, + $this->uid, + $this->config, + $urlGeneratorMock, + $this->shareManager, + $this->collaboratorSearch + ); + } + + public static function dataSearch(): array { + $noRemote = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_EMAIL]; + $allTypes = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_REMOTE_GROUP, IShare::TYPE_EMAIL]; + + return [ + [[], '', 'yes', false, true, true, true, $noRemote, false, true, true], + + // Test itemType + [[ + 'search' => '', + ], '', 'yes', false, true, true, true, $noRemote, false, true, true], + [[ + 'search' => 'foobar', + ], '', 'yes', false, true, true, true, $noRemote, false, true, true], + [[ + 'search' => 0, + ], '', 'yes', false, true, true, true, $noRemote, false, true, true], + + // Test itemType + [[ + 'itemType' => '', + ], '', 'yes', false, true, true, true, $noRemote, false, true, true], + [[ + 'itemType' => 'folder', + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 0, + ], '', 'yes', false, true, true , true, $noRemote, false, true, true], + // Test shareType + [[ + 'itemType' => 'call', + ], '', 'yes', false, true, true, true, $noRemote, false, true, true], + [[ + 'itemType' => 'call', + ], '', 'yes', false, true, true, true, [0, 4], false, true, false], + [[ + 'itemType' => 'folder', + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => 0, + ], '', 'yes', false, true, true, false, [0], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => '0', + ], '', 'yes', false, true, true, false, [0], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => 1, + ], '', 'yes', false, true, true, false, [1], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => 12, + ], '', 'yes', false, true, true, false, [], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => 'foobar', + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + + [[ + 'itemType' => 'folder', + 'shareType' => [0, 1, 2], + ], '', 'yes', false, false, false, false, [0, 1], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => [0, 1], + ], '', 'yes', false, false, false, false, [0, 1], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => $allTypes, + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => $allTypes, + ], '', 'yes', false, false, false, false, [0, 1], false, true, true], + [[ + 'itemType' => 'folder', + 'shareType' => $allTypes, + ], '', 'yes', false, true, false, false, [0, 6], false, true, false], + [[ + 'itemType' => 'folder', + 'shareType' => $allTypes, + ], '', 'yes', false, false, false, true, [0, 4], false, true, false], + [[ + 'itemType' => 'folder', + 'shareType' => $allTypes, + ], '', 'yes', false, true, true, false, [0, 6, 9], false, true, false], + + // Test pagination + [[ + 'itemType' => 'folder', + 'page' => 1, + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 'folder', + 'page' => 10, + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + + // Test perPage + [[ + 'itemType' => 'folder', + 'perPage' => 1, + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 'folder', + 'perPage' => 10, + ], '', 'yes', false, true, true, true, $allTypes, false, true, true], + + // Test $shareWithGroupOnly setting + [[ + 'itemType' => 'folder', + ], 'no', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 'folder', + ], 'yes', 'yes', false, true, true, true, $allTypes, true, true, true], + + // Test $shareeEnumeration setting + [[ + 'itemType' => 'folder', + ], 'no', 'yes', false, true, true, true, $allTypes, false, true, true], + [[ + 'itemType' => 'folder', + ], 'no', 'no', false, true, true, true, $allTypes, false, false, true], + + ]; + } + + /** + * + * @param array $getData + * @param string $apiSetting + * @param string $enumSetting + * @param bool $remoteSharingEnabled + * @param bool $isRemoteGroupSharingEnabled + * @param bool $emailSharingEnabled + * @param array $shareTypes + * @param bool $shareWithGroupOnly + * @param bool $shareeEnumeration + * @param bool $allowGroupSharing + * @throws OCSBadRequestException + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataSearch')] + public function testSearch( + array $getData, + string $apiSetting, + string $enumSetting, + bool $sharingDisabledForUser, + bool $remoteSharingEnabled, + bool $isRemoteGroupSharingEnabled, + bool $emailSharingEnabled, + array $shareTypes, + bool $shareWithGroupOnly, + bool $shareeEnumeration, + bool $allowGroupSharing, + ): void { + $search = $getData['search'] ?? ''; + $itemType = $getData['itemType'] ?? 'irrelevant'; + $page = $getData['page'] ?? 1; + $perPage = $getData['perPage'] ?? 200; + $shareType = $getData['shareType'] ?? null; + + $globalConfig = $this->createMock(GlobalScaleIConfig::class); + $globalConfig->expects(self::once()) + ->method('isGlobalScaleEnabled') + ->willReturn(true); + $this->overwriteService(GlobalScaleIConfig::class, $globalConfig); + + /** @var IConfig|MockObject $config */ + $config = $this->createMock(IConfig::class); + + $this->shareManager->expects($this->once()) + ->method('allowGroupSharing') + ->willReturn($allowGroupSharing); + + /** @var string */ + $uid = 'test123'; + /** @var IRequest|MockObject $request */ + $request = $this->createMock(IRequest::class); + /** @var IURLGenerator|MockObject $urlGenerator */ + $urlGenerator = $this->createMock(IURLGenerator::class); + + /** @var MockObject|ShareesAPIController $sharees */ + $sharees = $this->getMockBuilder(ShareesAPIController::class) + ->setConstructorArgs([ + 'files_sharing', + $request, + $uid, + $config, + $urlGenerator, + $this->shareManager, + $this->collaboratorSearch + ]) + ->onlyMethods(['isRemoteSharingAllowed', 'isRemoteGroupSharingAllowed']) + ->getMock(); + + $expectedShareTypes = $shareTypes; + sort($expectedShareTypes); + + $this->collaboratorSearch->expects($this->once()) + ->method('search') + ->with($search, $expectedShareTypes, $this->anything(), $perPage, $perPage * ($page - 1)) + ->willReturn([[], false]); + + $sharees->expects($this->any()) + ->method('isRemoteSharingAllowed') + ->with($itemType) + ->willReturn($remoteSharingEnabled); + + + $sharees->expects($this->any()) + ->method('isRemoteGroupSharingAllowed') + ->with($itemType) + ->willReturn($isRemoteGroupSharingEnabled); + + $this->shareManager->expects($this->any()) + ->method('sharingDisabledForUser') + ->with($uid) + ->willReturn($sharingDisabledForUser); + + $this->shareManager->expects($this->any()) + ->method('shareProviderExists') + ->willReturnCallback(function ($shareType) use ($emailSharingEnabled) { + if ($shareType === IShare::TYPE_EMAIL) { + return $emailSharingEnabled; + } else { + return false; + } + }); + + $this->assertInstanceOf(DataResponse::class, $sharees->search($search, $itemType, $page, $perPage, $shareType)); + } + + public static function dataSearchInvalid(): array { + return [ + // Test invalid pagination + [[ + 'page' => 0, + ], 'Invalid page'], + [[ + 'page' => '0', + ], 'Invalid page'], + [[ + 'page' => -1, + ], 'Invalid page'], + + // Test invalid perPage + [[ + 'perPage' => 0, + ], 'Invalid perPage argument'], + [[ + 'perPage' => '0', + ], 'Invalid perPage argument'], + [[ + 'perPage' => -1, + ], 'Invalid perPage argument'], + ]; + } + + /** + * + * @param array $getData + * @param string $message + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataSearchInvalid')] + public function testSearchInvalid($getData, $message): void { + $page = $getData['page'] ?? 1; + $perPage = $getData['perPage'] ?? 200; + + /** @var IConfig|MockObject $config */ + $config = $this->createMock(IConfig::class); + $config->expects($this->never()) + ->method('getAppValue'); + + /** @var string */ + $uid = 'test123'; + /** @var IRequest|MockObject $request */ + $request = $this->createMock(IRequest::class); + /** @var IURLGenerator|MockObject $urlGenerator */ + $urlGenerator = $this->createMock(IURLGenerator::class); + + /** @var MockObject|ShareesAPIController $sharees */ + $sharees = $this->getMockBuilder('\OCA\Files_Sharing\Controller\ShareesAPIController') + ->setConstructorArgs([ + 'files_sharing', + $request, + $uid, + $config, + $urlGenerator, + $this->shareManager, + $this->collaboratorSearch + ]) + ->onlyMethods(['isRemoteSharingAllowed']) + ->getMock(); + $sharees->expects($this->never()) + ->method('isRemoteSharingAllowed'); + + $this->collaboratorSearch->expects($this->never()) + ->method('search'); + + try { + $sharees->search('', null, $page, $perPage, null); + $this->fail(); + } catch (OCSBadRequestException $e) { + $this->assertEquals($message, $e->getMessage()); + } + } + + public static function dataIsRemoteSharingAllowed() { + return [ + ['file', true], + ['folder', true], + ['', false], + ['contacts', false], + ]; + } + + /** + * + * @param string $itemType + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataIsRemoteSharingAllowed')] + public function testIsRemoteSharingAllowed($itemType, $expected): void { + $this->assertSame($expected, $this->invokePrivate($this->sharees, 'isRemoteSharingAllowed', [$itemType])); + } + + public function testSearchSharingDisabled(): void { + $this->shareManager->expects($this->once()) + ->method('sharingDisabledForUser') + ->with($this->uid) + ->willReturn(true); + + $this->config->expects($this->once()) + ->method('getSystemValueInt') + ->with('sharing.minSearchStringLength', 0) + ->willReturn(0); + + $this->shareManager->expects($this->never()) + ->method('allowGroupSharing'); + + $this->assertInstanceOf(DataResponse::class, $this->sharees->search('', null, 1, 10, [], false)); + } + + public function testSearchNoItemType(): void { + $this->expectException(OCSBadRequestException::class); + $this->expectExceptionMessage('Missing itemType'); + + $this->sharees->search('', null, 1, 10, [], false); + } + + public static function dataGetPaginationLink() { + return [ + [1, '/ocs/v1.php', ['perPage' => 2], '<?perPage=2&page=2>; rel="next"'], + [10, '/ocs/v2.php', ['perPage' => 2], '<?perPage=2&page=11>; rel="next"'], + ]; + } + + /** + * + * @param int $page + * @param string $scriptName + * @param array $params + * @param array $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetPaginationLink')] + public function testGetPaginationLink($page, $scriptName, $params, $expected): void { + $this->request->expects($this->once()) + ->method('getScriptName') + ->willReturn($scriptName); + + $this->assertEquals($expected, $this->invokePrivate($this->sharees, 'getPaginationLink', [$page, $params])); + } + + public static function dataIsV2() { + return [ + ['/ocs/v1.php', false], + ['/ocs/v2.php', true], + ]; + } + + /** + * + * @param string $scriptName + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataIsV2')] + public function testIsV2($scriptName, $expected): void { + $this->request->expects($this->once()) + ->method('getScriptName') + ->willReturn($scriptName); + + $this->assertEquals($expected, $this->invokePrivate($this->sharees, 'isV2')); + } +} diff --git a/apps/files_sharing/tests/DeleteOrphanedSharesJobTest.php b/apps/files_sharing/tests/DeleteOrphanedSharesJobTest.php new file mode 100644 index 00000000000..c245d157151 --- /dev/null +++ b/apps/files_sharing/tests/DeleteOrphanedSharesJobTest.php @@ -0,0 +1,148 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Filesystem; +use OC\SystemConfig; +use OCA\Files_Sharing\DeleteOrphanedSharesJob; +use OCP\App\IAppManager; +use OCP\Constants; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class DeleteOrphanedSharesJobTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests + */ +class DeleteOrphanedSharesJobTest extends \Test\TestCase { + /** + * @var bool + */ + private static $trashBinStatus; + + /** + * @var DeleteOrphanedSharesJob + */ + private $job; + + /** + * @var IDBConnection + */ + private $connection; + + /** + * @var string + */ + private $user1; + + /** + * @var string + */ + private $user2; + + public static function setUpBeforeClass(): void { + $appManager = Server::get(IAppManager::class); + self::$trashBinStatus = $appManager->isEnabledForUser('files_trashbin'); + $appManager->disableApp('files_trashbin'); + + // just in case... + Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); + } + + public static function tearDownAfterClass(): void { + if (self::$trashBinStatus) { + Server::get(IAppManager::class)->enableApp('files_trashbin'); + } + } + + protected function setUp(): void { + parent::setUp(); + + $this->connection = Server::get(IDBConnection::class); + // clear occasional leftover shares from other tests + $this->connection->executeUpdate('DELETE FROM `*PREFIX*share`'); + + $this->user1 = $this->getUniqueID('user1_'); + $this->user2 = $this->getUniqueID('user2_'); + + $userManager = Server::get(IUserManager::class); + $userManager->createUser($this->user1, 'pass'); + $userManager->createUser($this->user2, 'pass'); + + \OC::registerShareHooks(Server::get(SystemConfig::class)); + + $this->job = Server::get(DeleteOrphanedSharesJob::class); + } + + protected function tearDown(): void { + $this->connection->executeUpdate('DELETE FROM `*PREFIX*share`'); + + $userManager = Server::get(IUserManager::class); + $user1 = $userManager->get($this->user1); + if ($user1) { + $user1->delete(); + } + $user2 = $userManager->get($this->user2); + if ($user2) { + $user2->delete(); + } + + $this->logout(); + + parent::tearDown(); + } + + private function getShares() { + $shares = []; + $result = $this->connection->executeQuery('SELECT * FROM `*PREFIX*share`'); + while ($row = $result->fetch()) { + $shares[] = $row; + } + $result->closeCursor(); + return $shares; + } + + /** + * Test clearing orphaned shares + */ + public function testClearShares(): void { + $this->loginAsUser($this->user1); + + $user1Folder = \OC::$server->getUserFolder($this->user1); + $testFolder = $user1Folder->newFolder('test'); + $testSubFolder = $testFolder->newFolder('sub'); + + $shareManager = Server::get(\OCP\Share\IManager::class); + $share = $shareManager->newShare(); + + $share->setNode($testSubFolder) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(Constants::PERMISSION_READ) + ->setSharedWith($this->user2) + ->setSharedBy($this->user1); + + $shareManager->createShare($share); + + $this->assertCount(1, $this->getShares()); + + $this->job->run([]); + + $this->assertCount(1, $this->getShares(), 'Linked shares not deleted'); + + $testFolder->delete(); + + $this->job->run([]); + + $this->assertCount(0, $this->getShares(), 'Orphaned shares deleted'); + } +} diff --git a/apps/files_sharing/tests/EncryptedSizePropagationTest.php b/apps/files_sharing/tests/EncryptedSizePropagationTest.php new file mode 100644 index 00000000000..1be17df3957 --- /dev/null +++ b/apps/files_sharing/tests/EncryptedSizePropagationTest.php @@ -0,0 +1,44 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\View; +use OCP\ITempManager; +use OCP\Server; +use Test\Traits\EncryptionTrait; + +/** + * @group DB + */ +class EncryptedSizePropagationTest extends SizePropagationTest { + use EncryptionTrait; + + protected function setUp(): void { + parent::setUp(); + $this->config->setAppValue('encryption', 'useMasterKey', '0'); + } + + protected function setupUser($name, $password = '') { + $this->createUser($name, $password); + $this->registerMountForUser($name); + $this->setupForUser($name, $password); + $this->loginWithEncryption($name); + return new View('/' . $name . '/files'); + } + + private function registerMountForUser($user): void { + $tmpFolder = Server::get(ITempManager::class)->getTemporaryFolder(); + $this->registerMount($user, '\OC\Files\Storage\Local', '/' . $user, ['datadir' => $tmpFolder]); + } + + protected function loginHelper($user, $create = false, $password = false) { + $this->registerMountForUser($user); + $this->setupForUser($user, $password); + parent::loginHelper($user, $create, $password); + } +} diff --git a/apps/files_sharing/tests/etagpropagation.php b/apps/files_sharing/tests/EtagPropagationTest.php index 55972dd9221..d8580ea92d5 100644 --- a/apps/files_sharing/tests/etagpropagation.php +++ b/apps/files_sharing/tests/EtagPropagationTest.php @@ -1,41 +1,27 @@ <?php + /** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - -namespace OCA\Files_sharing\Tests; +namespace OCA\Files_Sharing\Tests; use OC\Files\Filesystem; use OC\Files\View; +use OCP\Constants; +use OCP\Files\IRootFolder; +use OCP\Server; +use OCP\Share\IShare; /** - * Class EtagPropagation + * Class EtagPropagationTest * - * @group DB + * @group SLOWDB * - * @package OCA\Files_sharing\Tests + * @package OCA\Files_Sharing\Tests */ -class EtagPropagation extends PropagationTestCase { +class EtagPropagationTest extends PropagationTestCase { /** * "user1" is the admin who shares a folder "sub1/sub2/folder" with "user2" and "user3" @@ -50,13 +36,15 @@ class EtagPropagation extends PropagationTestCase { $this->fileIds[self::TEST_FILES_SHARING_API_USER3] = []; $this->fileIds[self::TEST_FILES_SHARING_API_USER4] = []; + $rootFolder = Server::get(IRootFolder::class); + $shareManager = Server::get(\OCP\Share\IManager::class); + $this->rootView = new View(''); $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); $view1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); $view1->mkdir('/sub1/sub2/folder/inside'); $view1->mkdir('/directReshare'); $view1->mkdir('/sub1/sub2/folder/other'); - $view1->mkdir('/sub1/sub2/folder/other'); $view1->file_put_contents('/foo.txt', 'foobar'); $view1->file_put_contents('/sub1/sub2/folder/file.txt', 'foobar'); $view1->file_put_contents('/sub1/sub2/folder/inside/file.txt', 'foobar'); @@ -64,30 +52,100 @@ class EtagPropagation extends PropagationTestCase { $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); $fileInfo = $view1->getFileInfo('/foo.txt'); $this->assertInstanceOf('\OC\Files\FileInfo', $fileInfo); - \OCP\Share::shareItem('file', $fileInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER3, 31); + + $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1) + ->get('/foo.txt'); + $share = $shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE); + $share = $shareManager->createShare($share); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); + $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1) + ->get('/sub1/sub2/folder'); + + $share = $shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $shareManager->createShare($share); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); + + $share = $shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $shareManager->createShare($share); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER3); + $folderInfo = $view1->getFileInfo('/directReshare'); $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); + + $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1) + ->get('/directReshare'); + $share = $shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $shareManager->createShare($share); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); + $this->fileIds[self::TEST_FILES_SHARING_API_USER1][''] = $view1->getFileInfo('')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER1]['sub1'] = $view1->getFileInfo('sub1')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER1]['sub1/sub2'] = $view1->getFileInfo('sub1/sub2')->getId(); + /* + * User 2 + */ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); $view2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); $view2->mkdir('/sub1/sub2'); $view2->rename('/folder', '/sub1/sub2/folder'); + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $insideInfo = $view2->getFileInfo('/sub1/sub2/folder/inside'); $this->assertInstanceOf('\OC\Files\FileInfo', $insideInfo); - \OCP\Share::shareItem('folder', $insideInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER4, 31); + + $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER2) + ->get('/sub1/sub2/folder/inside'); + $share = $shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER4) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $shareManager->createShare($share); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER4); + $folderInfo = $view2->getFileInfo('/directReshare'); $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER4, 31); + + $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER2) + ->get('/directReshare'); + $share = $shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER4) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) + ->setPermissions(Constants::PERMISSION_ALL); + $share = $shareManager->createShare($share); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER4); + $this->fileIds[self::TEST_FILES_SHARING_API_USER2][''] = $view2->getFileInfo('')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER2]['sub1'] = $view2->getFileInfo('sub1')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER2]['sub1/sub2'] = $view2->getFileInfo('sub1/sub2')->getId(); + /* + * User 3 + */ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER3); $view3 = new View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files'); $view3->mkdir('/sub1/sub2'); @@ -96,6 +154,9 @@ class EtagPropagation extends PropagationTestCase { $this->fileIds[self::TEST_FILES_SHARING_API_USER3]['sub1'] = $view3->getFileInfo('sub1')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER3]['sub1/sub2'] = $view3->getFileInfo('sub1/sub2')->getId(); + /* + * User 4 + */ $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4); $view4 = new View('/' . self::TEST_FILES_SHARING_API_USER4 . '/files'); $view4->mkdir('/sub1/sub2'); @@ -108,12 +169,13 @@ class EtagPropagation extends PropagationTestCase { $this->loginAsUser($user); foreach ($ids as $id) { $path = $this->rootView->getPath($id); + $ls = $this->rootView->getDirectoryContent($path); $this->fileEtags[$id] = $this->rootView->getFileInfo($path)->getEtag(); } } } - public function testOwnerWritesToShare() { + public function testOwnerWritesToShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::file_put_contents('/sub1/sub2/folder/asd.txt', 'bar'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4]); @@ -123,17 +185,18 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerWritesToSingleFileShare() { + public function testOwnerWritesToSingleFileShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::file_put_contents('/foo.txt', 'longer_bar'); - Filesystem::touch('/foo.txt', time() - 1); + $t = (int)Filesystem::filemtime('/foo.txt') - 1; + Filesystem::touch('/foo.txt', $t); $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]); $this->assertAllUnchanged(); } - public function testOwnerWritesToShareWithReshare() { + public function testOwnerWritesToShareWithReshare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::file_put_contents('/sub1/sub2/folder/inside/bar.txt', 'bar'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -142,7 +205,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerRenameInShare() { + public function testOwnerRenameInShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4]); Filesystem::rename('/sub1/sub2/folder/file.txt', '/sub1/sub2/folder/renamed.txt'); @@ -152,7 +215,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerRenameInReShare() { + public function testOwnerRenameInReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::rename('/sub1/sub2/folder/inside/file.txt', '/sub1/sub2/folder/inside/renamed.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -161,7 +224,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerRenameIntoReShare() { + public function testOwnerRenameIntoReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::rename('/sub1/sub2/folder/file.txt', '/sub1/sub2/folder/inside/renamed.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -170,7 +233,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerRenameOutOfReShare() { + public function testOwnerRenameOutOfReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::rename('/sub1/sub2/folder/inside/file.txt', '/sub1/sub2/folder/renamed.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -179,7 +242,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerDeleteInShare() { + public function testOwnerDeleteInShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::unlink('/sub1/sub2/folder/file.txt'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4]); @@ -189,7 +252,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerDeleteInReShare() { + public function testOwnerDeleteInReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); Filesystem::unlink('/sub1/sub2/folder/inside/file.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -198,55 +261,78 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testOwnerUnshares() { + public function testOwnerUnshares(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); $folderInfo = $this->rootView->getFileInfo('/' . self::TEST_FILES_SHARING_API_USER1 . '/files/sub1/sub2/folder'); $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); - $folderId = $folderInfo->getId(); - $this->assertTrue( - \OCP\Share::unshare( - 'folder', - $folderId, - \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2 - ) - ); + + $node = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1)->get('/sub1/sub2/folder'); + $shareManager = Server::get(\OCP\Share\IManager::class); + $shares = $shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER, $node, true); + + foreach ($shares as $share) { + if ($share->getSharedWith() === self::TEST_FILES_SHARING_API_USER2) { + $shareManager->deleteShare($share); + } + } + $this->assertEtagsForFoldersChanged([ // direct recipient affected self::TEST_FILES_SHARING_API_USER2, - // reshare recipient affected + ]); + + $this->assertAllUnchanged(); + } + + public function testOwnerUnsharesFlatReshares(): void { + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); + $folderInfo = $this->rootView->getFileInfo('/' . self::TEST_FILES_SHARING_API_USER1 . '/files/sub1/sub2/folder/inside'); + $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); + + $node = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1)->get('/sub1/sub2/folder/inside'); + $shareManager = Server::get(\OCP\Share\IManager::class); + $shares = $shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER, $node, true); + + foreach ($shares as $share) { + $shareManager->deleteShare($share); + } + + $this->assertEtagsForFoldersChanged([ + // direct recipient affected self::TEST_FILES_SHARING_API_USER4, ]); $this->assertAllUnchanged(); } - public function testRecipientUnsharesFromSelf() { + public function testRecipientUnsharesFromSelf(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $ls = $this->rootView->getDirectoryContent('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/sub1/sub2/'); $this->assertTrue( $this->rootView->unlink('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/sub1/sub2/folder') ); $this->assertEtagsForFoldersChanged([ // direct recipient affected self::TEST_FILES_SHARING_API_USER2, - // reshare recipient affected - self::TEST_FILES_SHARING_API_USER4, ]); $this->assertAllUnchanged(); } - public function testRecipientWritesToShare() { + public function testRecipientWritesToShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::file_put_contents('/sub1/sub2/folder/asd.txt', 'bar'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4]); - $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, - self::TEST_FILES_SHARING_API_USER3]); + $this->assertEtagsForFoldersChanged([ + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER3 + ]); $this->assertAllUnchanged(); } - public function testRecipientWritesToReshare() { + public function testRecipientWritesToReshare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::file_put_contents('/sub1/sub2/folder/inside/asd.txt', 'bar'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -255,7 +341,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientWritesToOtherRecipientsReshare() { + public function testRecipientWritesToOtherRecipientsReshare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER3); Filesystem::file_put_contents('/sub1/sub2/folder/inside/asd.txt', 'bar'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -264,7 +350,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientRenameInShare() { + public function testRecipientRenameInShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::rename('/sub1/sub2/folder/file.txt', '/sub1/sub2/folder/renamed.txt'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4]); @@ -274,7 +360,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientRenameInReShare() { + public function testRecipientRenameInReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::rename('/sub1/sub2/folder/inside/file.txt', '/sub1/sub2/folder/inside/renamed.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -283,7 +369,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientRenameResharedFolder() { + public function testRecipientRenameResharedFolder(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::rename('/directReshare', '/sub1/directReshare'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER4]); @@ -294,7 +380,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientDeleteInShare() { + public function testRecipientDeleteInShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::unlink('/sub1/sub2/folder/file.txt'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER4]); @@ -304,7 +390,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientDeleteInReShare() { + public function testRecipientDeleteInReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::unlink('/sub1/sub2/folder/inside/file.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -313,7 +399,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testReshareRecipientWritesToReshare() { + public function testReshareRecipientWritesToReshare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4); Filesystem::file_put_contents('/sub1/sub2/inside/asd.txt', 'bar'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -322,7 +408,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testReshareRecipientRenameInReShare() { + public function testReshareRecipientRenameInReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4); Filesystem::rename('/sub1/sub2/inside/file.txt', '/sub1/sub2/inside/renamed.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -331,7 +417,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testReshareRecipientDeleteInReShare() { + public function testReshareRecipientDeleteInReShare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4); Filesystem::unlink('/sub1/sub2/inside/file.txt'); $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, @@ -340,7 +426,7 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testRecipientUploadInDirectReshare() { + public function testRecipientUploadInDirectReshare(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); Filesystem::file_put_contents('/directReshare/test.txt', 'sad'); $this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER3]); @@ -349,15 +435,22 @@ class EtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testEtagChangeOnPermissionsChange() { - $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); + public function testEtagChangeOnPermissionsChange(): void { + $userFolder = $this->rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $userFolder->get('/sub1/sub2/folder'); - $view = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); - $folderInfo = $view->getFileInfo('/sub1/sub2/folder'); + $shares = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER, $node); + /** @var IShare[] $shares */ + $shares = array_filter($shares, function (IShare $share) { + return $share->getSharedWith() === self::TEST_FILES_SHARING_API_USER2; + }); + $this->assertCount(1, $shares); - \OCP\Share::setPermissions('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 17); + $share = $shares[0]; + $share->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE); + $this->shareManager->updateShare($share); - $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER4]); + $this->assertEtagsForFoldersChanged([self::TEST_FILES_SHARING_API_USER2]); $this->assertAllUnchanged(); } diff --git a/apps/files_sharing/tests/expiresharesjobtest.php b/apps/files_sharing/tests/ExpireSharesJobTest.php index bb4f756e6c7..42bc5a4b659 100644 --- a/apps/files_sharing/tests/expiresharesjobtest.php +++ b/apps/files_sharing/tests/ExpireSharesJobTest.php @@ -1,28 +1,21 @@ <?php + /** - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\Files_Sharing\Tests; +use OC\SystemConfig; use OCA\Files_Sharing\ExpireSharesJob; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Constants; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IManager; +use OCP\Share\IShare; /** * Class ExpireSharesJobTest @@ -33,55 +26,47 @@ use OCA\Files_Sharing\ExpireSharesJob; */ class ExpireSharesJobTest extends \Test\TestCase { - /** - * @var ExpireSharesJob - */ + /** @var ExpireSharesJob */ private $job; - /** - * @var \OCP\IDBConnection - */ + /** @var IDBConnection */ private $connection; - /** - * @var string - */ + /** @var string */ private $user1; - /** - * @var string - */ + /** @var string */ private $user2; - protected function setup() { + protected function setUp(): void { parent::setUp(); - $this->connection = \OC::$server->getDatabaseConnection(); + $this->connection = Server::get(IDBConnection::class); // clear occasional leftover shares from other tests $this->connection->executeUpdate('DELETE FROM `*PREFIX*share`'); $this->user1 = $this->getUniqueID('user1_'); $this->user2 = $this->getUniqueID('user2_'); - $userManager = \OC::$server->getUserManager(); - $userManager->createUser($this->user1, 'pass'); - $userManager->createUser($this->user2, 'pass'); + $userManager = Server::get(IUserManager::class); + $userManager->createUser($this->user1, 'longrandompassword'); + $userManager->createUser($this->user2, 'longrandompassword'); - \OC::registerShareHooks(); + \OC::registerShareHooks(Server::get(SystemConfig::class)); - $this->job = new ExpireSharesJob(); + $this->job = new ExpireSharesJob(Server::get(ITimeFactory::class), Server::get(IManager::class), $this->connection); } - protected function tearDown() { + protected function tearDown(): void { $this->connection->executeUpdate('DELETE FROM `*PREFIX*share`'); - $userManager = \OC::$server->getUserManager(); + $userManager = Server::get(IUserManager::class); $user1 = $userManager->get($this->user1); - if($user1) { + if ($user1) { $user1->delete(); } $user2 = $userManager->get($this->user2); - if($user2) { + if ($user2) { $user2->delete(); } @@ -105,7 +90,7 @@ class ExpireSharesJobTest extends \Test\TestCase { return $shares; } - public function dataExpireLinkShare() { + public static function dataExpireLinkShare() { return [ [false, '', false, false], [false, '', true, false], @@ -121,25 +106,28 @@ class ExpireSharesJobTest extends \Test\TestCase { } /** - * @dataProvider dataExpireLinkShare * * @param bool addExpiration Should we add an expire date * @param string $interval The dateInterval * @param bool $addInterval If true add to the current time if false subtract * @param bool $shouldExpire Should this share be expired */ - public function testExpireLinkShare($addExpiration, $interval, $addInterval, $shouldExpire) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataExpireLinkShare')] + public function testExpireLinkShare($addExpiration, $interval, $addInterval, $shouldExpire): void { $this->loginAsUser($this->user1); - $view = new \OC\Files\View('/' . $this->user1 . '/'); - $view->mkdir('files/test'); + $user1Folder = \OC::$server->getUserFolder($this->user1); + $testFolder = $user1Folder->newFolder('test'); + + $shareManager = Server::get(\OCP\Share\IManager::class); + $share = $shareManager->newShare(); - $fileInfo = $view->getFileInfo('files/test'); + $share->setNode($testFolder) + ->setShareType(IShare::TYPE_LINK) + ->setPermissions(Constants::PERMISSION_READ) + ->setSharedBy($this->user1); - $this->assertNotNull( - \OCP\Share::shareItem('folder', $fileInfo->getId(), \OCP\Share::SHARE_TYPE_LINK, null, \OCP\Constants::PERMISSION_READ), - 'Failed asserting that user 1 successfully shared "test" by link.' - ); + $shareManager->createShare($share); $shares = $this->getShares(); $this->assertCount(1, $shares); @@ -182,23 +170,25 @@ class ExpireSharesJobTest extends \Test\TestCase { } } - public function testDoNotExpireOtherShares() { + public function testDoNotExpireOtherShares(): void { $this->loginAsUser($this->user1); - $view = new \OC\Files\View('/' . $this->user1 . '/'); - $view->mkdir('files/test'); + $user1Folder = \OC::$server->getUserFolder($this->user1); + $testFolder = $user1Folder->newFolder('test'); - $fileInfo = $view->getFileInfo('files/test'); + $shareManager = Server::get(\OCP\Share\IManager::class); + $share = $shareManager->newShare(); - $this->assertNotNull( - \OCP\Share::shareItem('folder', $fileInfo->getId(), \OCP\Share::SHARE_TYPE_USER, $this->user2, \OCP\Constants::PERMISSION_READ), - 'Failed asserting that user 1 successfully shared "test" by link with user2.' - ); + $share->setNode($testFolder) + ->setShareType(IShare::TYPE_USER) + ->setPermissions(Constants::PERMISSION_READ) + ->setSharedBy($this->user1) + ->setSharedWith($this->user2); + + $shareManager->createShare($share); $shares = $this->getShares(); $this->assertCount(1, $shares); - reset($shares); - $share = current($shares); $this->logout(); @@ -207,6 +197,4 @@ class ExpireSharesJobTest extends \Test\TestCase { $shares = $this->getShares(); $this->assertCount(1, $shares); } - } - diff --git a/apps/files_sharing/tests/External/CacheTest.php b/apps/files_sharing/tests/External/CacheTest.php new file mode 100644 index 00000000000..39e2057a24c --- /dev/null +++ b/apps/files_sharing/tests/External/CacheTest.php @@ -0,0 +1,137 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\External; + +use OC\Federation\CloudIdManager; +use OC\Files\Storage\Storage; +use OCA\Files_Sharing\External\Cache; +use OCA\Files_Sharing\Tests\TestCase; +use OCP\Contacts\IManager; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Federation\ICloudIdManager; +use OCP\Files\Cache\ICacheEntry; +use OCP\ICacheFactory; +use OCP\IURLGenerator; +use OCP\IUserManager; + +/** + * Class Cache + * + * @group DB + * + * @package OCA\Files_Sharing\Tests\External + */ +class CacheTest extends TestCase { + /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + protected $contactsManager; + + /** + * @var Storage + **/ + private $storage; + + /** + * @var Cache + */ + private $cache; + + /** + * @var string + */ + private $remoteUser; + + /** @var ICloudIdManager */ + private $cloudIdManager; + + protected function setUp(): void { + parent::setUp(); + + $this->contactsManager = $this->createMock(IManager::class); + + $this->cloudIdManager = new CloudIdManager( + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class), + $this->contactsManager, + $this->createMock(IURLGenerator::class), + $this->createMock(IUserManager::class), + ); + $this->remoteUser = $this->getUniqueID('remoteuser'); + + $this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage') + ->disableOriginalConstructor() + ->getMock(); + $this->storage + ->expects($this->any()) + ->method('getId') + ->willReturn('dummystorage::'); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $this->cache = new Cache( + $this->storage, + $this->cloudIdManager->getCloudId($this->remoteUser, 'http://example.com/owncloud') + ); + $this->cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]); + $this->cache->put( + 'test.txt', + [ + 'mimetype' => 'text/plain', + 'size' => 5, + 'mtime' => 123, + ] + ); + } + + protected function tearDown(): void { + if ($this->cache) { + $this->cache->clear(); + } + parent::tearDown(); + } + + public function testGetInjectsOwnerDisplayName(): void { + $info = $this->cache->get('test.txt'); + $this->assertEquals( + $this->remoteUser . '@example.com/owncloud', + $info['displayname_owner'] + ); + } + + public function testGetReturnsFalseIfNotFound(): void { + $info = $this->cache->get('unexisting-entry.txt'); + $this->assertFalse($info); + } + + public function testGetFolderPopulatesOwner(): void { + $dirId = $this->cache->put( + 'subdir', + [ + 'mimetype' => 'httpd/unix-directory', + 'size' => 5, + 'mtime' => 123, + ] + ); + $this->cache->put( + 'subdir/contents.txt', + [ + 'mimetype' => 'text/plain', + 'size' => 5, + 'mtime' => 123, + ] + ); + + $results = $this->cache->getFolderContentsById($dirId); + $this->assertEquals(1, count($results)); + $this->assertEquals( + $this->remoteUser . '@example.com/owncloud', + $results[0]['displayname_owner'] + ); + } +} diff --git a/apps/files_sharing/tests/External/ManagerTest.php b/apps/files_sharing/tests/External/ManagerTest.php new file mode 100644 index 00000000000..14c6afec4d8 --- /dev/null +++ b/apps/files_sharing/tests/External/ManagerTest.php @@ -0,0 +1,730 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\External; + +use OC\Federation\CloudIdManager; +use OC\Files\Mount\MountPoint; +use OC\Files\SetupManagerFactory; +use OC\Files\Storage\StorageFactory; +use OC\Files\Storage\Temporary; +use OCA\Files_Sharing\External\Manager; +use OCA\Files_Sharing\External\MountProvider; +use OCA\Files_Sharing\Tests\TestCase; +use OCP\Contacts\IManager; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Federation\ICloudFederationFactory; +use OCP\Federation\ICloudFederationProviderManager; +use OCP\Files\NotFoundException; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IClientService; +use OCP\Http\Client\IResponse; +use OCP\ICacheFactory; +use OCP\IDBConnection; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\OCS\IDiscoveryService; +use OCP\Server; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\Traits\UserTrait; + +/** + * Class ManagerTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests\External + */ +class ManagerTest extends TestCase { + use UserTrait; + + protected string $uid; + protected IUser $user; + protected MountProvider $testMountProvider; + protected IEventDispatcher&MockObject $eventDispatcher; + protected LoggerInterface&MockObject $logger; + protected \OC\Files\Mount\Manager $mountManager; + protected IManager&MockObject $contactsManager; + protected Manager&MockObject $manager; + protected IClientService&MockObject $clientService; + protected ICloudFederationProviderManager&MockObject $cloudFederationProviderManager; + protected ICloudFederationFactory&MockObject $cloudFederationFactory; + protected IGroupManager&MockObject $groupManager; + protected IUserManager&MockObject $userManager; + + protected function setUp(): void { + parent::setUp(); + + $this->uid = $this->getUniqueID('user'); + $this->user = $this->createUser($this->uid, ''); + $this->mountManager = new \OC\Files\Mount\Manager($this->createMock(SetupManagerFactory::class)); + $this->clientService = $this->getMockBuilder(IClientService::class) + ->disableOriginalConstructor()->getMock(); + $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class); + $this->cloudFederationFactory = $this->createMock(ICloudFederationFactory::class); + $this->groupManager = $this->createMock(IGroupManager::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + + $this->contactsManager = $this->createMock(IManager::class); + // needed for MountProvider() initialization + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $this->logger = $this->createMock(LoggerInterface::class); + $this->logger->expects($this->never())->method('emergency'); + + $this->manager = $this->createManagerForUser($this->uid); + + $this->testMountProvider = new MountProvider(Server::get(IDBConnection::class), function () { + return $this->manager; + }, new CloudIdManager( + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class), + $this->contactsManager, + $this->createMock(IURLGenerator::class), + $this->userManager, + )); + + $group1 = $this->createMock(IGroup::class); + $group1->expects($this->any())->method('getGID')->willReturn('group1'); + $group1->expects($this->any())->method('inGroup')->with($this->user)->willReturn(true); + + $group2 = $this->createMock(IGroup::class); + $group2->expects($this->any())->method('getGID')->willReturn('group2'); + $group2->expects($this->any())->method('inGroup')->with($this->user)->willReturn(true); + + $this->userManager->expects($this->any())->method('get')->willReturn($this->user); + $this->groupManager->expects($this->any())->method(('getUserGroups'))->willReturn([$group1, $group2]); + $this->groupManager->expects($this->any())->method(('get')) + ->willReturnMap([ + ['group1', $group1], + ['group2', $group2], + ]); + } + + protected function tearDown(): void { + // clear the share external table to avoid side effects + $query = Server::get(IDBConnection::class)->prepare('DELETE FROM `*PREFIX*share_external`'); + $result = $query->execute(); + $result->closeCursor(); + + parent::tearDown(); + } + + private function createManagerForUser($userId) { + $user = $this->createMock(IUser::class); + $user->method('getUID') + ->willReturn($userId); + $userSession = $this->createMock(IUserSession::class); + $userSession->method('getUser') + ->willReturn($user); + + return $this->getMockBuilder(Manager::class) + ->setConstructorArgs( + [ + Server::get(IDBConnection::class), + $this->mountManager, + new StorageFactory(), + $this->clientService, + Server::get(\OCP\Notification\IManager::class), + Server::get(IDiscoveryService::class), + $this->cloudFederationProviderManager, + $this->cloudFederationFactory, + $this->groupManager, + $this->userManager, + $userSession, + $this->eventDispatcher, + $this->logger, + ] + )->onlyMethods(['tryOCMEndPoint'])->getMock(); + } + + private function setupMounts() { + $this->clearMounts(); + $mounts = $this->testMountProvider->getMountsForUser($this->user, new StorageFactory()); + foreach ($mounts as $mount) { + $this->mountManager->addMount($mount); + } + } + + private function clearMounts() { + $this->mountManager->clear(); + $this->mountManager->addMount(new MountPoint(Temporary::class, '', [])); + } + + public function testAddUserShare(): void { + $this->doTestAddShare([ + 'remote' => 'http://localhost', + 'token' => 'token1', + 'password' => '', + 'name' => '/SharedFolder', + 'owner' => 'foobar', + 'shareType' => IShare::TYPE_USER, + 'accepted' => false, + 'user' => $this->uid, + 'remoteId' => '2342' + ], false); + } + + public function testAddGroupShare(): void { + $this->doTestAddShare([ + 'remote' => 'http://localhost', + 'token' => 'token1', + 'password' => '', + 'name' => '/SharedFolder', + 'owner' => 'foobar', + 'shareType' => IShare::TYPE_GROUP, + 'accepted' => false, + 'user' => 'group1', + 'remoteId' => '2342' + ], true); + } + + public function doTestAddShare($shareData1, $isGroup = false) { + $shareData2 = $shareData1; + $shareData2['token'] = 'token2'; + $shareData3 = $shareData1; + $shareData3['token'] = 'token3'; + + if ($isGroup) { + $this->manager->expects($this->never())->method('tryOCMEndPoint'); + } else { + $this->manager->expects(self::atLeast(2)) + ->method('tryOCMEndPoint') + ->willReturnMap([ + ['http://localhost', 'token1', '2342', 'accept', false], + ['http://localhost', 'token3', '2342', 'decline', false], + ]); + } + + // Add a share for "user" + $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData1)); + $openShares = $this->manager->getOpenShares(); + $this->assertCount(1, $openShares); + $this->assertExternalShareEntry($shareData1, $openShares[0], 1, '{{TemporaryMountPointName#' . $shareData1['name'] . '}}', $shareData1['user']); + + $this->setupMounts(); + $this->assertNotMount('SharedFolder'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + + // Add a second share for "user" with the same name + $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData2)); + $openShares = $this->manager->getOpenShares(); + $this->assertCount(2, $openShares); + $this->assertExternalShareEntry($shareData1, $openShares[0], 1, '{{TemporaryMountPointName#' . $shareData1['name'] . '}}', $shareData1['user']); + // New share falls back to "-1" appendix, because the name is already taken + $this->assertExternalShareEntry($shareData2, $openShares[1], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1', $shareData2['user']); + + $this->setupMounts(); + $this->assertNotMount('SharedFolder'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); + + $newClientCalls = []; + $this->clientService + ->method('newClient') + ->willReturnCallback(function () use (&$newClientCalls): IClient { + if (!empty($newClientCalls)) { + return array_shift($newClientCalls); + } + return $this->createMock(IClient::class); + }); + if (!$isGroup) { + $client = $this->createMock(IClient::class); + $newClientCalls[] = $client; + $response = $this->createMock(IResponse::class); + $response->method('getBody') + ->willReturn(json_encode([ + 'ocs' => [ + 'meta' => [ + 'statuscode' => 200, + ] + ] + ])); + $client->expects($this->once()) + ->method('post') + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $openShares[0]['remote_id']), $this->anything()) + ->willReturn($response); + } + + // Accept the first share + $this->assertTrue($this->manager->acceptShare($openShares[0]['id'])); + + // Check remaining shares - Accepted + $acceptedShares = self::invokePrivate($this->manager, 'getShares', [true]); + $this->assertCount(1, $acceptedShares); + $shareData1['accepted'] = true; + $this->assertExternalShareEntry($shareData1, $acceptedShares[0], 1, $shareData1['name'], $this->uid); + // Check remaining shares - Open + $openShares = $this->manager->getOpenShares(); + $this->assertCount(1, $openShares); + $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1', $shareData2['user']); + + $this->setupMounts(); + $this->assertMount($shareData1['name']); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); + + // Add another share for "user" with the same name + $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData3)); + $openShares = $this->manager->getOpenShares(); + $this->assertCount(2, $openShares); + $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1', $shareData2['user']); + if (!$isGroup) { + // New share falls back to the original name (no "-\d", because the name is not taken) + $this->assertExternalShareEntry($shareData3, $openShares[1], 3, '{{TemporaryMountPointName#' . $shareData3['name'] . '}}', $shareData3['user']); + } else { + $this->assertExternalShareEntry($shareData3, $openShares[1], 3, '{{TemporaryMountPointName#' . $shareData3['name'] . '}}-2', $shareData3['user']); + } + + $this->setupMounts(); + $this->assertMount($shareData1['name']); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); + + if (!$isGroup) { + $client = $this->createMock(IClient::class); + $newClientCalls[] = $client; + $response = $this->createMock(IResponse::class); + $response->method('getBody') + ->willReturn(json_encode([ + 'ocs' => [ + 'meta' => [ + 'statuscode' => 200, + ] + ] + ])); + $client->expects($this->once()) + ->method('post') + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $openShares[1]['remote_id'] . '/decline'), $this->anything()) + ->willReturn($response); + } + + // Decline the third share + $this->assertTrue($this->manager->declineShare($openShares[1]['id'])); + + $this->setupMounts(); + $this->assertMount($shareData1['name']); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); + + // Check remaining shares - Accepted + $acceptedShares = self::invokePrivate($this->manager, 'getShares', [true]); + $this->assertCount(1, $acceptedShares); + $shareData1['accepted'] = true; + $this->assertExternalShareEntry($shareData1, $acceptedShares[0], 1, $shareData1['name'], $this->uid); + // Check remaining shares - Open + $openShares = $this->manager->getOpenShares(); + if ($isGroup) { + // declining a group share adds it back to pending instead of deleting it + $this->assertCount(2, $openShares); + // this is a group share that is still open + $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1', $shareData2['user']); + // this is the user share sub-entry matching the group share which got declined + $this->assertExternalShareEntry($shareData3, $openShares[1], 2, '{{TemporaryMountPointName#' . $shareData3['name'] . '}}-2', $this->uid); + } else { + $this->assertCount(1, $openShares); + $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1', $this->uid); + } + + $this->setupMounts(); + $this->assertMount($shareData1['name']); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); + + if ($isGroup) { + // no http requests here + $this->manager->removeGroupShares('group1'); + } else { + $client1 = $this->createMock(IClient::class); + $client2 = $this->createMock(IClient::class); + $newClientCalls[] = $client1; + $newClientCalls[] = $client2; + $response = $this->createMock(IResponse::class); + $response->method('getBody') + ->willReturn(json_encode([ + 'ocs' => [ + 'meta' => [ + 'statuscode' => 200, + ] + ] + ])); + + $client1->expects($this->once()) + ->method('post') + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $openShares[0]['remote_id'] . '/decline'), $this->anything()) + ->willReturn($response); + $client2->expects($this->once()) + ->method('post') + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $acceptedShares[0]['remote_id'] . '/decline'), $this->anything()) + ->willReturn($response); + + $this->manager->removeUserShares($this->uid); + } + + $this->assertEmpty(self::invokePrivate($this->manager, 'getShares', [null]), 'Asserting all shares for the user have been deleted'); + + $this->clearMounts(); + self::invokePrivate($this->manager, 'setupMounts'); + $this->assertNotMount($shareData1['name']); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); + $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); + } + + private function verifyAcceptedGroupShare($shareData) { + $openShares = $this->manager->getOpenShares(); + $this->assertCount(0, $openShares); + $acceptedShares = self::invokePrivate($this->manager, 'getShares', [true]); + $this->assertCount(1, $acceptedShares); + $shareData['accepted'] = true; + $this->assertExternalShareEntry($shareData, $acceptedShares[0], 0, $shareData['name'], $this->uid); + $this->setupMounts(); + $this->assertMount($shareData['name']); + } + + private function verifyDeclinedGroupShare($shareData, $tempMount = null) { + if ($tempMount === null) { + $tempMount = '{{TemporaryMountPointName#/SharedFolder}}'; + } + $openShares = $this->manager->getOpenShares(); + $this->assertCount(1, $openShares); + $acceptedShares = self::invokePrivate($this->manager, 'getShares', [true]); + $this->assertCount(0, $acceptedShares); + $this->assertExternalShareEntry($shareData, $openShares[0], 0, $tempMount, $this->uid); + $this->setupMounts(); + $this->assertNotMount($shareData['name']); + $this->assertNotMount($tempMount); + } + + private function createTestUserShare($userId = 'user1') { + $shareData = [ + 'remote' => 'http://localhost', + 'token' => 'token1', + 'password' => '', + 'name' => '/SharedFolder', + 'owner' => 'foobar', + 'shareType' => IShare::TYPE_USER, + 'accepted' => false, + 'user' => $userId, + 'remoteId' => '2342' + ]; + + $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData)); + + return $shareData; + } + private function createTestGroupShare($groupId = 'group1') { + $shareData = [ + 'remote' => 'http://localhost', + 'token' => 'token1', + 'password' => '', + 'name' => '/SharedFolder', + 'owner' => 'foobar', + 'shareType' => IShare::TYPE_GROUP, + 'accepted' => false, + 'user' => $groupId, + 'remoteId' => '2342' + ]; + + $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData)); + + $allShares = self::invokePrivate($this->manager, 'getShares', [null]); + foreach ($allShares as $share) { + if ($share['user'] === $groupId) { + // this will hold the main group entry + $groupShare = $share; + break; + } + } + + return [$shareData, $groupShare]; + } + + public function testAcceptOriginalGroupShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // a second time + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + } + + public function testAcceptGroupShareAgainThroughGroupShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // decline again, this keeps the sub-share + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + + // this will return sub-entries + $openShares = $this->manager->getOpenShares(); + $this->assertCount(1, $openShares); + + // accept through group share + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData, '/SharedFolder'); + + // accept a second time + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData, '/SharedFolder'); + } + + public function testAcceptGroupShareAgainThroughSubShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // decline again, this keeps the sub-share + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + + // this will return sub-entries + $openShares = $this->manager->getOpenShares(); + $this->assertCount(1, $openShares); + + // accept through sub-share + $this->assertTrue($this->manager->acceptShare($openShares[0]['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // accept a second time + $this->assertTrue($this->manager->acceptShare($openShares[0]['id'])); + $this->verifyAcceptedGroupShare($shareData); + } + + public function testDeclineOriginalGroupShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData); + + // a second time + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData); + } + + public function testDeclineGroupShareAgainThroughGroupShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // decline again, this keeps the sub-share + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + + // a second time + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + } + + public function testDeclineGroupShareAgainThroughSubshare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // this will return sub-entries + $allShares = self::invokePrivate($this->manager, 'getShares', [null]); + $this->assertCount(1, $allShares); + + // decline again through sub-share + $this->assertTrue($this->manager->declineShare($allShares[0]['id'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + + // a second time + $this->assertTrue($this->manager->declineShare($allShares[0]['id'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + } + + public function testDeclineGroupShareAgainThroughMountPoint(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // decline through mount point name + $this->assertTrue($this->manager->removeShare($this->uid . '/files/' . $shareData['name'])); + $this->verifyDeclinedGroupShare($shareData, '/SharedFolder'); + + // second time must fail as the mount point is gone + $this->assertFalse($this->manager->removeShare($this->uid . '/files/' . $shareData['name'])); + } + + public function testDeclineThenAcceptGroupShareAgainThroughGroupShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + // decline, this creates a declined sub-share + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData); + + // this will return sub-entries + $openShares = $this->manager->getOpenShares(); + + // accept through sub-share + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData, '/SharedFolder'); + + // accept a second time + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + $this->verifyAcceptedGroupShare($shareData, '/SharedFolder'); + } + + public function testDeclineThenAcceptGroupShareAgainThroughSubShare(): void { + [$shareData, $groupShare] = $this->createTestGroupShare(); + // decline, this creates a declined sub-share + $this->assertTrue($this->manager->declineShare($groupShare['id'])); + $this->verifyDeclinedGroupShare($shareData); + + // this will return sub-entries + $openShares = $this->manager->getOpenShares(); + + // accept through sub-share + $this->assertTrue($this->manager->acceptShare($openShares[0]['id'])); + $this->verifyAcceptedGroupShare($shareData); + + // accept a second time + $this->assertTrue($this->manager->acceptShare($openShares[0]['id'])); + $this->verifyAcceptedGroupShare($shareData); + } + + public function testDeleteUserShares(): void { + // user 1 shares + + $shareData = $this->createTestUserShare($this->uid); + + [$shareData, $groupShare] = $this->createTestGroupShare(); + + $shares = $this->manager->getOpenShares(); + $this->assertCount(2, $shares); + + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + + // user 2 shares + $manager2 = $this->createManagerForUser('user2'); + $shareData2 = [ + 'remote' => 'http://localhost', + 'token' => 'token1', + 'password' => '', + 'name' => '/SharedFolder', + 'owner' => 'foobar', + 'shareType' => IShare::TYPE_USER, + 'accepted' => false, + 'user' => 'user2', + 'remoteId' => '2342' + ]; + + $this->assertCount(1, $manager2->getOpenShares()); + $this->assertSame(null, call_user_func_array([$manager2, 'addShare'], $shareData2)); + $this->assertCount(2, $manager2->getOpenShares()); + + $this->manager->expects($this->once())->method('tryOCMEndPoint')->with('http://localhost', 'token1', '2342', 'decline')->willReturn([]); + $this->manager->removeUserShares($this->uid); + + $user1Shares = $this->manager->getOpenShares(); + // user share is gone, group is still there + $this->assertCount(1, $user1Shares); + $this->assertEquals($user1Shares[0]['share_type'], IShare::TYPE_GROUP); + + // user 2 shares untouched + $user2Shares = $manager2->getOpenShares(); + $this->assertCount(2, $user2Shares); + $this->assertEquals($user2Shares[0]['share_type'], IShare::TYPE_GROUP); + $this->assertEquals($user2Shares[0]['user'], 'group1'); + $this->assertEquals($user2Shares[1]['share_type'], IShare::TYPE_USER); + $this->assertEquals($user2Shares[1]['user'], 'user2'); + } + + public function testDeleteGroupShares(): void { + $shareData = $this->createTestUserShare($this->uid); + + [$shareData, $groupShare] = $this->createTestGroupShare(); + + $shares = $this->manager->getOpenShares(); + $this->assertCount(2, $shares); + + $this->assertTrue($this->manager->acceptShare($groupShare['id'])); + + // user 2 shares + $manager2 = $this->createManagerForUser('user2'); + $shareData2 = [ + 'remote' => 'http://localhost', + 'token' => 'token1', + 'password' => '', + 'name' => '/SharedFolder', + 'owner' => 'foobar', + 'shareType' => IShare::TYPE_USER, + 'accepted' => false, + 'user' => 'user2', + 'remoteId' => '2342' + ]; + + $this->assertCount(1, $manager2->getOpenShares()); + $this->assertSame(null, call_user_func_array([$manager2, 'addShare'], $shareData2)); + $this->assertCount(2, $manager2->getOpenShares()); + + $this->manager->expects($this->never())->method('tryOCMEndPoint'); + $this->manager->removeGroupShares('group1'); + + $user1Shares = $this->manager->getOpenShares(); + // user share is gone, group is still there + $this->assertCount(1, $user1Shares); + $this->assertEquals($user1Shares[0]['share_type'], IShare::TYPE_USER); + + // user 2 shares untouched + $user2Shares = $manager2->getOpenShares(); + $this->assertCount(1, $user2Shares); + $this->assertEquals($user2Shares[0]['share_type'], IShare::TYPE_USER); + $this->assertEquals($user2Shares[0]['user'], 'user2'); + } + + /** + * @param array $expected + * @param array $actual + * @param int $share + * @param string $mountPoint + */ + protected function assertExternalShareEntry($expected, $actual, $share, $mountPoint, $targetEntity) { + $this->assertEquals($expected['remote'], $actual['remote'], 'Asserting remote of a share #' . $share); + $this->assertEquals($expected['token'], $actual['share_token'], 'Asserting token of a share #' . $share); + $this->assertEquals($expected['name'], $actual['name'], 'Asserting name of a share #' . $share); + $this->assertEquals($expected['owner'], $actual['owner'], 'Asserting owner of a share #' . $share); + $this->assertEquals($expected['accepted'], (int)$actual['accepted'], 'Asserting accept of a share #' . $share); + $this->assertEquals($targetEntity, $actual['user'], 'Asserting user of a share #' . $share); + $this->assertEquals($mountPoint, $actual['mountpoint'], 'Asserting mountpoint of a share #' . $share); + } + + private function assertMount($mountPoint) { + $mountPoint = rtrim($mountPoint, '/'); + $mount = $this->mountManager->find($this->getFullPath($mountPoint)); + $this->assertInstanceOf('\OCA\Files_Sharing\External\Mount', $mount); + $this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount); + $this->assertEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/')); + $storage = $mount->getStorage(); + $this->assertInstanceOf('\OCA\Files_Sharing\External\Storage', $storage); + } + + private function assertNotMount($mountPoint) { + $mountPoint = rtrim($mountPoint, '/'); + try { + $mount = $this->mountManager->find($this->getFullPath($mountPoint)); + $this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount); + $this->assertNotEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/')); + } catch (NotFoundException $e) { + + } + } + + private function getFullPath($path) { + return '/' . $this->uid . '/files' . $path; + } +} diff --git a/apps/files_sharing/tests/External/ScannerTest.php b/apps/files_sharing/tests/External/ScannerTest.php new file mode 100644 index 00000000000..8b44d47f2b1 --- /dev/null +++ b/apps/files_sharing/tests/External/ScannerTest.php @@ -0,0 +1,60 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\External; + +use OC\Files\Cache\Cache; +use OCA\Files_Sharing\External\Scanner; +use OCA\Files_Sharing\External\Storage; +use Test\TestCase; + +/** + * @group DB + */ +class ScannerTest extends TestCase { + protected Scanner $scanner; + /** @var Storage|\PHPUnit\Framework\MockObject\MockObject */ + protected $storage; + /** @var Cache|\PHPUnit\Framework\MockObject\MockObject */ + protected $cache; + + protected function setUp(): void { + parent::setUp(); + + $this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage') + ->disableOriginalConstructor() + ->getMock(); + $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor() + ->getMock(); + $this->storage->expects($this->any()) + ->method('getCache') + ->willReturn($this->cache); + + $this->scanner = new Scanner($this->storage); + } + + public function testScan(): void { + $this->storage->expects($this->any()) + ->method('getShareInfo') + ->willReturn(['status' => 'success', 'data' => []]); + + // FIXME add real tests, we are currently only checking for + // Declaration of OCA\Files_Sharing\External\Scanner::*() should be + // compatible with OC\Files\Cache\Scanner::*() + $this->scanner->scan('test', Scanner::SCAN_RECURSIVE); + $this->addToAssertionCount(1); + } + + public function testScanFile(): void { + // FIXME add real tests, we are currently only checking for + // Declaration of OCA\Files_Sharing\External\Scanner::*() should be + // compatible with OC\Files\Cache\Scanner::*() + $this->scanner->scanFile('test', Scanner::SCAN_RECURSIVE); + $this->addToAssertionCount(1); + } +} diff --git a/apps/files_sharing/tests/ExternalStorageTest.php b/apps/files_sharing/tests/ExternalStorageTest.php new file mode 100644 index 00000000000..1d9d2eed7bd --- /dev/null +++ b/apps/files_sharing/tests/ExternalStorageTest.php @@ -0,0 +1,118 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Federation\CloudId; +use OCA\Files_Sharing\External\Manager as ExternalShareManager; +use OCA\Files_Sharing\External\Storage; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IClientService; +use OCP\Http\Client\IResponse; + +/** + * Tests for the external Storage class for remote shares. + * + * @group DB + */ +class ExternalStorageTest extends \Test\TestCase { + public static function optionsProvider() { + return [ + [ + 'http://remoteserver:8080/owncloud', + 'http://remoteserver:8080/owncloud/public.php/webdav/', + ], + // extra slash + [ + 'http://remoteserver:8080/owncloud/', + 'http://remoteserver:8080/owncloud/public.php/webdav/', + ], + // extra path + [ + 'http://remoteserver:8080/myservices/owncloud/', + 'http://remoteserver:8080/myservices/owncloud/public.php/webdav/', + ], + // root path + [ + 'http://remoteserver:8080/', + 'http://remoteserver:8080/public.php/webdav/', + ], + // without port + [ + 'http://remoteserver/oc.test', + 'http://remoteserver/oc.test/public.php/webdav/', + ], + // https + [ + 'https://remoteserver/', + 'https://remoteserver/public.php/webdav/', + ], + ]; + } + + private function getTestStorage($uri) { + $certificateManager = \OC::$server->getCertificateManager(); + $httpClientService = $this->createMock(IClientService::class); + $manager = $this->createMock(ExternalShareManager::class); + $client = $this->createMock(IClient::class); + $response = $this->createMock(IResponse::class); + $client + ->expects($this->any()) + ->method('get') + ->willReturn($response); + $client + ->expects($this->any()) + ->method('post') + ->willReturn($response); + $httpClientService + ->expects($this->any()) + ->method('newClient') + ->willReturn($client); + + return new TestSharingExternalStorage( + [ + 'cloudId' => new CloudId('testOwner@' . $uri, 'testOwner', $uri), + 'remote' => $uri, + 'owner' => 'testOwner', + 'mountpoint' => 'remoteshare', + 'token' => 'abcdef', + 'password' => '', + 'manager' => $manager, + 'certificateManager' => $certificateManager, + 'HttpClientService' => $httpClientService, + ] + ); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('optionsProvider')] + public function testStorageMountOptions($inputUri, $baseUri): void { + $storage = $this->getTestStorage($inputUri); + $this->assertEquals($baseUri, $storage->getBaseUri()); + } + + public function testIfTestReturnsTheValue(): void { + $storage = $this->getTestStorage('https://remoteserver'); + $result = $storage->test(); + $this->assertSame(true, $result); + } +} + +/** + * Dummy subclass to make it possible to access private members + */ +class TestSharingExternalStorage extends Storage { + public function getBaseUri() { + return $this->createBaseUri(); + } + + public function stat(string $path): array|false { + if ($path === '') { + return ['key' => 'value']; + } + return parent::stat($path); + } +} diff --git a/apps/files_sharing/tests/groupetagpropagation.php b/apps/files_sharing/tests/GroupEtagPropagationTest.php index 9f6b1e2f720..da9c7c6bd07 100644 --- a/apps/files_sharing/tests/groupetagpropagation.php +++ b/apps/files_sharing/tests/GroupEtagPropagationTest.php @@ -1,35 +1,23 @@ <?php + /** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - -namespace OCA\Files_sharing\Tests; +namespace OCA\Files_Sharing\Tests; use OC\Files\Filesystem; use OC\Files\View; +use OCP\Constants; +use OCP\Share\IShare; /** - * @group DB + * @group SLOWDB * - * @package OCA\Files_sharing\Tests + * @package OCA\Files_Sharing\Tests */ -class GroupEtagPropagation extends PropagationTestCase { +class GroupEtagPropagationTest extends PropagationTestCase { /** * "user1" creates /test, /test/sub and shares with group1 * "user2" (in group1) reshares /test with group2 and reshared /test/sub with group3 @@ -46,18 +34,39 @@ class GroupEtagPropagation extends PropagationTestCase { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); $view1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); $view1->mkdir('/test/sub'); - $folderInfo = $view1->getFileInfo('/test'); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_GROUP, 'group1', 31); + + $share = $this->share( + IShare::TYPE_GROUP, + '/test', + self::TEST_FILES_SHARING_API_USER1, + 'group1', + Constants::PERMISSION_ALL + ); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); $this->fileIds[self::TEST_FILES_SHARING_API_USER1][''] = $view1->getFileInfo('')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER1]['test'] = $view1->getFileInfo('test')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER1]['test/sub'] = $view1->getFileInfo('test/sub')->getId(); $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); $view2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $folderInfo = $view2->getFileInfo('/test'); - $subFolderInfo = $view2->getFileInfo('/test/sub'); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_GROUP, 'group2', 31); - \OCP\Share::shareItem('folder', $subFolderInfo->getId(), \OCP\Share::SHARE_TYPE_GROUP, 'group3', 31); + + $share = $this->share( + IShare::TYPE_GROUP, + '/test', + self::TEST_FILES_SHARING_API_USER2, + 'group2', + Constants::PERMISSION_ALL + ); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER3); + $share = $this->share( + IShare::TYPE_GROUP, + '/test/sub', + self::TEST_FILES_SHARING_API_USER2, + 'group3', + Constants::PERMISSION_ALL + ); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER4); + $this->fileIds[self::TEST_FILES_SHARING_API_USER2][''] = $view2->getFileInfo('')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER2]['test'] = $view2->getFileInfo('test')->getId(); $this->fileIds[self::TEST_FILES_SHARING_API_USER2]['test/sub'] = $view2->getFileInfo('test/sub')->getId(); @@ -82,7 +91,7 @@ class GroupEtagPropagation extends PropagationTestCase { } } - public function testGroupReShareRecipientWrites() { + public function testGroupReShareRecipientWrites(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER3); Filesystem::file_put_contents('/test/sub/file.txt', 'asd'); @@ -92,7 +101,7 @@ class GroupEtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } - public function testGroupReShareSubFolderRecipientWrites() { + public function testGroupReShareSubFolderRecipientWrites(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER4); Filesystem::file_put_contents('/sub/file.txt', 'asd'); @@ -101,4 +110,26 @@ class GroupEtagPropagation extends PropagationTestCase { $this->assertAllUnchanged(); } + + public function testRecipientUnsharesFromSelf(): void { + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue( + $this->rootView->unlink('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/test') + ); + $this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER2]); + + $this->assertAllUnchanged(); + } + + public function testRecipientUnsharesFromSelfUniqueGroupShare(): void { + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + // rename to create an extra entry in the share table + $this->rootView->rename('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/test', '/' . self::TEST_FILES_SHARING_API_USER2 . '/files/test_renamed'); + $this->assertTrue( + $this->rootView->unlink('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/test_renamed') + ); + $this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER2]); + + $this->assertAllUnchanged(); + } } diff --git a/apps/files_sharing/tests/HelperTest.php b/apps/files_sharing/tests/HelperTest.php new file mode 100644 index 00000000000..4d0d747b3e4 --- /dev/null +++ b/apps/files_sharing/tests/HelperTest.php @@ -0,0 +1,37 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Filesystem; +use OCA\Files_Sharing\Helper; +use OCP\IConfig; +use OCP\Server; + +/** + * Class HelperTest + * + * @group DB + */ +class HelperTest extends TestCase { + + /** + * test set and get share folder + */ + public function testSetGetShareFolder(): void { + $this->assertSame('/', Helper::getShareFolder()); + + Helper::setShareFolder('/Shared/Folder'); + + $sharedFolder = Helper::getShareFolder(); + $this->assertSame('/Shared/Folder', Helper::getShareFolder()); + $this->assertTrue(Filesystem::is_dir($sharedFolder)); + + // cleanup + Server::get(IConfig::class)->deleteSystemValue('share_folder'); + } +} diff --git a/apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php b/apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php new file mode 100644 index 00000000000..75bee35d58a --- /dev/null +++ b/apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\Files_Sharing\Tests\Listener; + +use OC\InitialStateService; +use OCA\Files\Event\LoadAdditionalScriptsEvent; +use OCA\Files_Sharing\Listener\LoadAdditionalListener; +use OCP\EventDispatcher\Event; +use OCP\IConfig; +use OCP\L10N\IFactory; +use OCP\Share\IManager; +use OCP\Util; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\TestCase; + +class LoadAdditionalListenerTest extends TestCase { + protected LoggerInterface&MockObject $logger; + protected LoadAdditionalScriptsEvent&MockObject $event; + protected IManager&MockObject $shareManager; + protected IFactory&MockObject $factory; + protected InitialStateService&MockObject $initialStateService; + protected IConfig&MockObject $config; + + protected function setUp(): void { + parent::setUp(); + + $this->logger = $this->createMock(LoggerInterface::class); + $this->event = $this->createMock(LoadAdditionalScriptsEvent::class); + $this->shareManager = $this->createMock(IManager::class); + $this->factory = $this->createMock(IFactory::class); + $this->initialStateService = $this->createMock(InitialStateService::class); + $this->config = $this->createMock(IConfig::class); + + /* Empty static array to avoid inter-test conflicts */ + \OC_Util::$styles = []; + self::invokePrivate(Util::class, 'scripts', [[]]); + self::invokePrivate(Util::class, 'scriptDeps', [[]]); + self::invokePrivate(Util::class, 'scriptsInit', [[]]); + } + + protected function tearDown(): void { + parent::tearDown(); + + \OC_Util::$styles = []; + self::invokePrivate(Util::class, 'scripts', [[]]); + self::invokePrivate(Util::class, 'scriptDeps', [[]]); + self::invokePrivate(Util::class, 'scriptsInit', [[]]); + } + + public function testHandleIgnoresNonMatchingEvent(): void { + $listener = new LoadAdditionalListener(); + $event = $this->createMock(Event::class); + + // Should not throw or call anything + $listener->handle($event); + + $this->assertTrue(true); // No exception means pass + } + + public function testHandleWithLoadAdditionalScriptsEvent(): void { + $listener = new LoadAdditionalListener(); + + $this->shareManager->method('shareApiEnabled')->willReturn(false); + $this->factory->method('findLanguage')->willReturn('language_mock'); + $this->config->method('getSystemValueBool')->willReturn(true); + + $this->overwriteService(IManager::class, $this->shareManager); + $this->overwriteService(IFactory::class, $this->factory); + $this->overwriteService(InitialStateService::class, $this->initialStateService); + $this->overwriteService(IConfig::class, $this->config); + + $scriptsBefore = Util::getScripts(); + $this->assertNotContains('files_sharing/l10n/language_mock', $scriptsBefore); + $this->assertNotContains('files_sharing/js/additionalScripts', $scriptsBefore); + $this->assertNotContains('files_sharing/js/init', $scriptsBefore); + $this->assertNotContains('files_sharing/css/icons', \OC_Util::$styles); + + // Util static methods can't be easily mocked, so just ensure no exceptions + $listener->handle($this->event); + + // assert array $scripts contains the expected scripts + $scriptsAfter = Util::getScripts(); + $this->assertContains('files_sharing/l10n/language_mock', $scriptsAfter); + $this->assertContains('files_sharing/js/additionalScripts', $scriptsAfter); + $this->assertNotContains('files_sharing/js/init', $scriptsAfter); + + $this->assertContains('files_sharing/css/icons', \OC_Util::$styles); + } + + public function testHandleWithLoadAdditionalScriptsEventWithShareApiEnabled(): void { + $listener = new LoadAdditionalListener(); + + $this->shareManager->method('shareApiEnabled')->willReturn(true); + $this->config->method('getSystemValueBool')->willReturn(true); + + $this->overwriteService(IManager::class, $this->shareManager); + $this->overwriteService(InitialStateService::class, $this->initialStateService); + $this->overwriteService(IConfig::class, $this->config); + $this->overwriteService(IFactory::class, $this->factory); + + $scriptsBefore = Util::getScripts(); + $this->assertNotContains('files_sharing/js/init', $scriptsBefore); + + // Util static methods can't be easily mocked, so just ensure no exceptions + $listener->handle($this->event); + + $scriptsAfter = Util::getScripts(); + + // assert array $scripts contains the expected scripts + $this->assertContains('files_sharing/js/init', $scriptsAfter); + } +} diff --git a/apps/files_sharing/tests/locking.php b/apps/files_sharing/tests/LockingTest.php index ef8b2bb1cd4..280c364a136 100644 --- a/apps/files_sharing/tests/locking.php +++ b/apps/files_sharing/tests/LockingTest.php @@ -1,40 +1,29 @@ <?php + /** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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/> - * + * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - -namespace OCA\Files_sharing\Tests; +namespace OCA\Files_Sharing\Tests; use OC\Files\Filesystem; use OC\Files\View; +use OCP\Constants; +use OCP\IUserManager; use OCP\Lock\ILockingProvider; +use OCP\Lock\LockedException; +use OCP\Server; +use OCP\Share\IShare; /** - * Class Locking + * Class LockingTest * * @group DB * - * @package OCA\Files_sharing\Tests + * @package OCA\Files_Sharing\Tests */ -class Locking extends TestCase { +class LockingTest extends TestCase { /** * @var \Test\Util\User\Dummy */ @@ -43,11 +32,11 @@ class Locking extends TestCase { private $ownerUid; private $recipientUid; - public function setUp() { + protected function setUp(): void { parent::setUp(); $this->userBackend = new \Test\Util\User\Dummy(); - \OC::$server->getUserManager()->registerBackend($this->userBackend); + Server::get(IUserManager::class)->registerBackend($this->userBackend); $this->ownerUid = $this->getUniqueID('owner_'); $this->recipientUid = $this->getUniqueID('recipient_'); @@ -59,21 +48,27 @@ class Locking extends TestCase { Filesystem::file_put_contents('/foo/bar.txt', 'asd'); $fileId = Filesystem::getFileInfo('/foo/bar.txt')->getId(); - \OCP\Share::shareItem('file', $fileId, \OCP\Share::SHARE_TYPE_USER, $this->recipientUid, 31); + $this->share( + IShare::TYPE_USER, + '/foo/bar.txt', + $this->ownerUid, + $this->recipientUid, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); $this->loginAsUser($this->recipientUid); $this->assertTrue(Filesystem::file_exists('bar.txt')); } - public function tearDown() { - \OC::$server->getUserManager()->removeBackend($this->userBackend); + protected function tearDown(): void { + Server::get(IUserManager::class)->removeBackend($this->userBackend); parent::tearDown(); } - /** - * @expectedException \OCP\Lock\LockedException - */ - public function testLockAsRecipient() { + + public function testLockAsRecipient(): void { + $this->expectException(LockedException::class); + $this->loginAsUser($this->ownerUid); Filesystem::initMountPoints($this->recipientUid); @@ -83,7 +78,7 @@ class Locking extends TestCase { Filesystem::rename('/foo', '/asd'); } - public function testUnLockAsRecipient() { + public function testUnLockAsRecipient(): void { $this->loginAsUser($this->ownerUid); Filesystem::initMountPoints($this->recipientUid); @@ -94,14 +89,13 @@ class Locking extends TestCase { $this->assertTrue(Filesystem::rename('/foo', '/asd')); } - public function testChangeLock() { - + public function testChangeLock(): void { Filesystem::initMountPoints($this->recipientUid); $recipientView = new View('/' . $this->recipientUid . '/files'); $recipientView->lockFile('bar.txt', ILockingProvider::LOCK_SHARED); $recipientView->changeLock('bar.txt', ILockingProvider::LOCK_EXCLUSIVE); $recipientView->unlockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE); - $this->assertTrue(true); + $this->addToAssertionCount(1); } } diff --git a/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php b/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php new file mode 100644 index 00000000000..efc6b3f7f7f --- /dev/null +++ b/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php @@ -0,0 +1,124 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests\Middleware; + +use OCA\Files_Sharing\Controller\ShareAPIController; +use OCA\Files_Sharing\Middleware\OCSShareAPIMiddleware; +use OCP\AppFramework\Controller; +use OCP\AppFramework\OCS\OCSNotFoundException; +use OCP\AppFramework\OCSController; +use OCP\IL10N; +use OCP\Share\IManager; + +/** + * @package OCA\Files_Sharing\Middleware\SharingCheckMiddleware + */ +class OCSShareAPIMiddlewareTest extends \Test\TestCase { + + /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + private $shareManager; + /** @var IL10N */ + private $l; + /** @var OCSShareAPIMiddleware */ + private $middleware; + + protected function setUp(): void { + parent::setUp(); + + $this->shareManager = $this->createMock(IManager::class); + $this->l = $this->createMock(IL10N::class); + + $this->l->method('t')->willReturnArgument(0); + + $this->middleware = new OCSShareAPIMiddleware($this->shareManager, $this->l); + } + + public function dataBeforeController() { + return [ + [ + $this->createMock(Controller::class), + false, + false + ], + [ + $this->createMock(Controller::class), + true, + false + ], + [ + $this->createMock(OCSController::class), + false, + false + ], + [ + $this->createMock(OCSController::class), + true, + false + ], + [ + $this->createMock(ShareAPIController::class), + false, + true + ], + [ + $this->createMock(ShareAPIController::class), + true, + false + ], + ]; + } + + /** + * + * @param Controller $controller + * @param bool $enabled + * @param bool $exception + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataBeforeController')] + public function testBeforeController(Controller $controller, $enabled, $exception): void { + $this->shareManager->method('shareApiEnabled')->willReturn($enabled); + + try { + $this->middleware->beforeController($controller, 'foo'); + $this->assertFalse($exception); + } catch (OCSNotFoundException $e) { + $this->assertTrue($exception); + } + } + + public function dataAfterController() { + return [ + [ + $this->createMock(Controller::class), + ], + [ + $this->createMock(OCSController::class), + ], + [ + $this->createMock(ShareAPIController::class), + ], + ]; + } + + /** + * + * @param Controller $controller + * @param bool $called + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterController')] + public function testAfterController(Controller $controller): void { + if ($controller instanceof ShareAPIController) { + $controller->expects($this->once())->method('cleanup'); + } + + $response = $this->getMockBuilder('OCP\AppFramework\Http\Response') + ->disableOriginalConstructor() + ->getMock(); + $this->middleware->afterController($controller, 'foo', $response); + $this->addToAssertionCount(1); + } +} diff --git a/apps/files_sharing/tests/Middleware/ShareInfoMiddlewareTest.php b/apps/files_sharing/tests/Middleware/ShareInfoMiddlewareTest.php new file mode 100644 index 00000000000..631b6a0f51c --- /dev/null +++ b/apps/files_sharing/tests/Middleware/ShareInfoMiddlewareTest.php @@ -0,0 +1,140 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests\Middleware; + +use OCA\Files_Sharing\Controller\ShareInfoController; +use OCA\Files_Sharing\Exceptions\S2SException; +use OCA\Files_Sharing\Middleware\ShareInfoMiddleware; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\Response; +use OCP\Share\IManager as ShareManager; +use Test\TestCase; + +class ShareInfoMiddlewareTest extends TestCase { + + /** @var ShareManager|\PHPUnit\Framework\MockObject\MockObject */ + private $shareManager; + + /** @var ShareInfoMiddleware */ + private $middleware; + + protected function setUp(): void { + parent::setUp(); + + $this->shareManager = $this->createMock(ShareManager::class); + $this->middleware = new ShareInfoMiddleware($this->shareManager); + } + + public function testBeforeControllerNoShareInfo(): void { + $this->shareManager->expects($this->never()) + ->method($this->anything()); + + $this->middleware->beforeController($this->createMock(ShareInfoMiddlewareTestController::class), 'foo'); + } + + public function testBeforeControllerShareInfoNoS2s(): void { + $this->shareManager->expects($this->once()) + ->method('outgoingServer2ServerSharesAllowed') + ->willReturn(false); + + $this->expectException(S2SException::class); + $this->middleware->beforeController($this->createMock(ShareInfoController::class), 'foo'); + } + + public function testBeforeControllerShareInfo(): void { + $this->shareManager->expects($this->once()) + ->method('outgoingServer2ServerSharesAllowed') + ->willReturn(true); + + $this->middleware->beforeController($this->createMock(ShareInfoController::class), 'foo'); + } + + public function testAfterExceptionNoShareInfo(): void { + $exeption = new \Exception(); + + try { + $this->middleware->afterException($this->createMock(ShareInfoMiddlewareTestController::class), 'foo', $exeption); + $this->fail(); + } catch (\Exception $e) { + $this->assertSame($exeption, $e); + } + } + + + public function testAfterExceptionNoS2S(): void { + $exeption = new \Exception(); + + try { + $this->middleware->afterException($this->createMock(ShareInfoController::class), 'foo', $exeption); + $this->fail(); + } catch (\Exception $e) { + $this->assertSame($exeption, $e); + } + } + + public function testAfterExceptionS2S(): void { + $expected = new JSONResponse([], Http::STATUS_NOT_FOUND); + + $this->assertEquals( + $expected, + $this->middleware->afterException($this->createMock(ShareInfoController::class), 'foo', new S2SException()) + ); + } + + public function testAfterControllerNoShareInfo(): void { + $response = $this->createMock(Response::class); + + $this->assertEquals( + $response, + $this->middleware->afterController($this->createMock(ShareInfoMiddlewareTestController::class), 'foo', $response) + ); + } + + public function testAfterControllerNoJSON(): void { + $response = $this->createMock(Response::class); + + $this->assertEquals( + $response, + $this->middleware->afterController($this->createMock(ShareInfoController::class), 'foo', $response) + ); + } + + public function testAfterControllerJSONok(): void { + $data = ['foo' => 'bar']; + $response = new JSONResponse($data); + + $expected = new JSONResponse([ + 'data' => $data, + 'status' => 'success', + ]); + + $this->assertEquals( + $expected, + $this->middleware->afterController($this->createMock(ShareInfoController::class), 'foo', $response) + ); + } + + public function testAfterControllerJSONerror(): void { + $data = ['foo' => 'bar']; + $response = new JSONResponse($data, Http::STATUS_FORBIDDEN); + + $expected = new JSONResponse([ + 'data' => $data, + 'status' => 'error', + ], Http::STATUS_FORBIDDEN); + + $this->assertEquals( + $expected, + $this->middleware->afterController($this->createMock(ShareInfoController::class), 'foo', $response) + ); + } +} + +class ShareInfoMiddlewareTestController extends Controller { +} diff --git a/apps/files_sharing/tests/Middleware/SharingCheckMiddlewareTest.php b/apps/files_sharing/tests/Middleware/SharingCheckMiddlewareTest.php new file mode 100644 index 00000000000..3d86007a54c --- /dev/null +++ b/apps/files_sharing/tests/Middleware/SharingCheckMiddlewareTest.php @@ -0,0 +1,205 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Middleware; + +use OCA\Files_Sharing\Controller\ExternalSharesController; +use OCA\Files_Sharing\Controller\ShareController; +use OCA\Files_Sharing\Exceptions\S2SException; +use OCP\App\IAppManager; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\NotFoundResponse; +use OCP\AppFramework\Utility\IControllerMethodReflector; +use OCP\Files\NotFoundException; +use OCP\IConfig; +use OCP\IRequest; +use OCP\Share\IManager; +use OCP\Share\IShare; + +/** + * @package OCA\Files_Sharing\Middleware\SharingCheckMiddleware + */ +class SharingCheckMiddlewareTest extends \Test\TestCase { + + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; + /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ + private $appManager; + /** @var SharingCheckMiddleware */ + private $sharingCheckMiddleware; + /** @var Controller|\PHPUnit\Framework\MockObject\MockObject */ + private $controllerMock; + /** @var IControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */ + private $reflector; + /** @var IManager | \PHPUnit\Framework\MockObject\MockObject */ + private $shareManager; + /** @var IRequest | \PHPUnit\Framework\MockObject\MockObject */ + private $request; + + protected function setUp(): void { + parent::setUp(); + + $this->config = $this->createMock(IConfig::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->controllerMock = $this->createMock(Controller::class); + $this->reflector = $this->createMock(IControllerMethodReflector::class); + $this->shareManager = $this->createMock(IManager::class); + $this->request = $this->createMock(IRequest::class); + + $this->sharingCheckMiddleware = new SharingCheckMiddleware( + 'files_sharing', + $this->config, + $this->appManager, + $this->reflector, + $this->shareManager, + $this->request); + } + + public function testIsSharingEnabledWithAppEnabled(): void { + $this->appManager + ->expects($this->once()) + ->method('isEnabledForUser') + ->with('files_sharing') + ->willReturn(true); + + $this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled')); + } + + public function testIsSharingEnabledWithAppDisabled(): void { + $this->appManager + ->expects($this->once()) + ->method('isEnabledForUser') + ->with('files_sharing') + ->willReturn(false); + + $this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled')); + } + + public static function externalSharesChecksDataProvider() { + $data = []; + + foreach ([false, true] as $annIn) { + foreach ([false, true] as $annOut) { + foreach ([false, true] as $confIn) { + foreach ([false, true] as $confOut) { + $res = true; + if (!$annIn && !$confIn) { + $res = false; + } elseif (!$annOut && !$confOut) { + $res = false; + } + + $d = [ + [ + ['NoIncomingFederatedSharingRequired', $annIn], + ['NoOutgoingFederatedSharingRequired', $annOut], + ], + [ + ['files_sharing', 'incoming_server2server_share_enabled', 'yes', $confIn ? 'yes' : 'no'], + ['files_sharing', 'outgoing_server2server_share_enabled', 'yes', $confOut ? 'yes' : 'no'], + ], + $res + ]; + + $data[] = $d; + } + } + } + } + + return $data; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('externalSharesChecksDataProvider')] + public function testExternalSharesChecks($annotations, $config, $expectedResult): void { + $this->reflector + ->expects($this->atLeastOnce()) + ->method('hasAnnotation') + ->willReturnMap($annotations); + + $this->config + ->method('getAppValue') + ->willReturnMap($config); + + $this->assertEquals($expectedResult, self::invokePrivate($this->sharingCheckMiddleware, 'externalSharesChecks')); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('externalSharesChecksDataProvider')] + public function testBeforeControllerWithExternalShareControllerWithSharingEnabled($annotations, $config, $noException): void { + $this->appManager + ->expects($this->once()) + ->method('isEnabledForUser') + ->with('files_sharing') + ->willReturn(true); + + $this->reflector + ->expects($this->atLeastOnce()) + ->method('hasAnnotation') + ->willReturnMap($annotations); + + $this->config + ->method('getAppValue') + ->willReturnMap($config); + + $controller = $this->createMock(ExternalSharesController::class); + + $exceptionThrown = false; + + try { + $this->sharingCheckMiddleware->beforeController($controller, 'myMethod'); + } catch (S2SException $exception) { + $exceptionThrown = true; + } + + $this->assertNotEquals($noException, $exceptionThrown); + } + + public function testBeforeControllerWithShareControllerWithSharingEnabled(): void { + $share = $this->createMock(IShare::class); + + $this->appManager + ->expects($this->once()) + ->method('isEnabledForUser') + ->with('files_sharing') + ->willReturn(true); + + $controller = $this->createMock(ShareController::class); + + $this->sharingCheckMiddleware->beforeController($controller, 'myMethod'); + } + + + public function testBeforeControllerWithSharingDisabled(): void { + $this->expectException(NotFoundException::class); + $this->expectExceptionMessage('Sharing is disabled.'); + + $this->appManager + ->expects($this->once()) + ->method('isEnabledForUser') + ->with('files_sharing') + ->willReturn(false); + + $this->sharingCheckMiddleware->beforeController($this->controllerMock, 'myMethod'); + } + + + public function testAfterExceptionWithRegularException(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('My Exception message'); + + $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new \Exception('My Exception message')); + } + + public function testAfterExceptionWithNotFoundException(): void { + $this->assertEquals(new NotFoundResponse(), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new NotFoundException('My Exception message'))); + } + + public function testAfterExceptionWithS2SException(): void { + $this->assertEquals(new JSONResponse('My Exception message', 405), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new S2SException('My Exception message'))); + } +} diff --git a/apps/files_sharing/tests/Migration/SetPasswordColumnTest.php b/apps/files_sharing/tests/Migration/SetPasswordColumnTest.php new file mode 100644 index 00000000000..3cbbad0f8bc --- /dev/null +++ b/apps/files_sharing/tests/Migration/SetPasswordColumnTest.php @@ -0,0 +1,108 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests\Migration; + +use OCA\Files_Sharing\Migration\SetPasswordColumn; +use OCA\Files_Sharing\Tests\TestCase; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class SetPasswordColumnTest + * + * @group DB + */ +class SetPasswordColumnTest extends TestCase { + + /** @var IDBConnection */ + private $connection; + + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; + + /** @var SetPasswordColumn */ + private $migration; + + private $table = 'share'; + + protected function setUp(): void { + parent::setUp(); + + $this->connection = Server::get(IDBConnection::class); + $this->config = $this->createMock(IConfig::class); + $this->migration = new SetPasswordColumn($this->connection, $this->config); + + $this->cleanDB(); + } + + protected function tearDown(): void { + parent::tearDown(); + $this->cleanDB(); + } + + private function cleanDB() { + $query = $this->connection->getQueryBuilder(); + $query->delete($this->table)->execute(); + } + + public function testAddPasswordColumn(): void { + $this->config->expects($this->once()) + ->method('getAppValue') + ->with('files_sharing', 'installed_version', '0.0.0') + ->willReturn('1.3.0'); + + $shareTypes = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL, IShare::TYPE_LINK]; + + foreach ($shareTypes as $shareType) { + for ($i = 0; $i < 5; $i++) { + $query = $this->connection->getQueryBuilder(); + $query->insert($this->table) + ->values([ + 'share_type' => $query->createNamedParameter($shareType), + 'share_with' => $query->createNamedParameter('shareWith'), + 'uid_owner' => $query->createNamedParameter('user' . $i), + 'uid_initiator' => $query->createNamedParameter(null), + 'parent' => $query->createNamedParameter(0), + 'item_type' => $query->createNamedParameter('file'), + 'item_source' => $query->createNamedParameter('2'), + 'item_target' => $query->createNamedParameter('/2'), + 'file_source' => $query->createNamedParameter(2), + 'file_target' => $query->createNamedParameter('/foobar'), + 'permissions' => $query->createNamedParameter(31), + 'stime' => $query->createNamedParameter(time()), + ]); + + $this->assertSame(1, $query->execute()); + } + } + + /** @var IOutput $output */ + $output = $this->createMock(IOutput::class); + $this->migration->run($output); + + $query = $this->connection->getQueryBuilder(); + $query->select('*') + ->from('share'); + $result = $query->execute(); + $allShares = $result->fetchAll(); + $result->closeCursor(); + + foreach ($allShares as $share) { + if ((int)$share['share_type'] === IShare::TYPE_LINK) { + $this->assertNull($share['share_with']); + $this->assertSame('shareWith', $share['password']); + } else { + $this->assertSame('shareWith', $share['share_with']); + $this->assertNull($share['password']); + } + } + } +} diff --git a/apps/files_sharing/tests/MountProviderTest.php b/apps/files_sharing/tests/MountProviderTest.php new file mode 100644 index 00000000000..e043a1cb1ef --- /dev/null +++ b/apps/files_sharing/tests/MountProviderTest.php @@ -0,0 +1,409 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Memcache\NullCache; +use OC\Share20\Share; +use OCA\Files_Sharing\MountProvider; +use OCA\Files_Sharing\SharedMount; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountManager; +use OCP\Files\Storage\IStorageFactory; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Share\IAttributes as IShareAttributes; +use OCP\Share\IManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; + +/** + * @group DB + */ +class MountProviderTest extends \Test\TestCase { + + protected MountProvider $provider; + + protected IUser&MockObject $user; + protected IConfig&MockObject $config; + protected IManager&MockObject $shareManager; + protected IStorageFactory&MockObject $loader; + protected LoggerInterface&MockObject $logger; + + protected function setUp(): void { + parent::setUp(); + + $this->config = $this->getMockBuilder(IConfig::class)->getMock(); + $this->user = $this->getMockBuilder(IUser::class)->getMock(); + $this->loader = $this->getMockBuilder('OCP\Files\Storage\IStorageFactory')->getMock(); + $this->shareManager = $this->getMockBuilder(IManager::class)->getMock(); + $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $eventDispatcher = $this->createMock(IEventDispatcher::class); + $cacheFactory = $this->createMock(ICacheFactory::class); + $cacheFactory->method('createLocal') + ->willReturn(new NullCache()); + $mountManager = $this->createMock(IMountManager::class); + + $this->provider = new MountProvider($this->config, $this->shareManager, $this->logger, $eventDispatcher, $cacheFactory, $mountManager); + } + + private function makeMockShareAttributes($attrs) { + if ($attrs === null) { + return null; + } + + $shareAttributes = $this->createMock(IShareAttributes::class); + $shareAttributes->method('toArray')->willReturn($attrs); + $shareAttributes->method('getAttribute')->willReturnCallback( + function ($scope, $key) use ($attrs) { + $result = null; + foreach ($attrs as $attr) { + if ($attr['key'] === $key && $attr['scope'] === $scope) { + $result = $attr['value']; + } + } + return $result; + } + ); + return $shareAttributes; + } + + private function makeMockShare($id, $nodeId, $owner = 'user2', $target = null, $permissions = 31, $attributes = null) { + $share = $this->createMock(IShare::class); + $share->expects($this->any()) + ->method('getPermissions') + ->willReturn($permissions); + $share->expects($this->any()) + ->method('getAttributes') + ->willReturn($this->makeMockShareAttributes($attributes)); + $share->expects($this->any()) + ->method('getShareOwner') + ->willReturn($owner); + $share->expects($this->any()) + ->method('getTarget') + ->willReturn($target); + $share->expects($this->any()) + ->method('getId') + ->willReturn($id); + $share->expects($this->any()) + ->method('getNodeId') + ->willReturn($nodeId); + $share->expects($this->any()) + ->method('getShareTime') + ->willReturn( + // compute share time based on id, simulating share order + new \DateTime('@' . (1469193980 + 1000 * $id)) + ); + return $share; + } + + /** + * Tests excluding shares from the current view. This includes: + * - shares that were opted out of (permissions === 0) + * - shares with a group in which the owner is already in + */ + public function testExcludeShares(): void { + $rootFolder = $this->createMock(IRootFolder::class); + $userManager = $this->createMock(IUserManager::class); + $attr1 = []; + $attr2 = [['scope' => 'permission', 'key' => 'download', 'value' => true]]; + $userShares = [ + $this->makeMockShare(1, 100, 'user2', '/share2', 0, $attr1), + $this->makeMockShare(2, 100, 'user2', '/share2', 31, $attr2), + ]; + $groupShares = [ + $this->makeMockShare(3, 100, 'user2', '/share2', 0, $attr1), + $this->makeMockShare(4, 101, 'user2', '/share4', 31, $attr2), + $this->makeMockShare(5, 100, 'user1', '/share4', 31, $attr2), + ]; + $roomShares = [ + $this->makeMockShare(6, 102, 'user2', '/share6', 0), + $this->makeMockShare(7, 102, 'user1', '/share6', 31), + $this->makeMockShare(8, 102, 'user2', '/share6', 31), + $this->makeMockShare(9, 102, 'user2', '/share6', 31), + ]; + $deckShares = [ + $this->makeMockShare(10, 103, 'user2', '/share7', 0), + $this->makeMockShare(11, 103, 'user1', '/share7', 31), + $this->makeMockShare(12, 103, 'user2', '/share7', 31), + $this->makeMockShare(13, 103, 'user2', '/share7', 31), + ]; + // tests regarding circles and sciencemesh are made in the apps themselves. + $circleShares = []; + $scienceMeshShares = []; + $this->user->expects($this->any()) + ->method('getUID') + ->willReturn('user1'); + $this->shareManager->expects($this->exactly(6)) + ->method('getSharedWith') + ->willReturnMap([ + ['user1', IShare::TYPE_USER, null, -1, 0, $userShares], + ['user1', IShare::TYPE_GROUP, null, -1, 0, $groupShares], + ['user1', IShare::TYPE_CIRCLE, null, -1, 0, $circleShares], + ['user1', IShare::TYPE_ROOM, null, -1, 0, $roomShares], + ['user1', IShare::TYPE_DECK, null, -1, 0, $deckShares], + ['user1', IShare::TYPE_SCIENCEMESH, null, -1, 0, $scienceMeshShares], + ]); + + $this->shareManager->expects($this->any()) + ->method('newShare') + ->willReturnCallback(function () use ($rootFolder, $userManager) { + return new Share($rootFolder, $userManager); + }); + + $mounts = $this->provider->getMountsForUser($this->user, $this->loader); + $this->assertCount(4, $mounts); + $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[0]); + $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[1]); + $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[2]); + $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[3]); + /** @var SharedMount[] $mounts */ + $mountedShare1 = $mounts[0]->getShare(); + $this->assertEquals('2', $mountedShare1->getId()); + $this->assertEquals('user2', $mountedShare1->getShareOwner()); + $this->assertEquals(100, $mountedShare1->getNodeId()); + $this->assertEquals('/share2', $mountedShare1->getTarget()); + $this->assertEquals(31, $mountedShare1->getPermissions()); + $this->assertEquals(true, $mountedShare1->getAttributes()->getAttribute('permission', 'download')); + $mountedShare2 = $mounts[1]->getShare(); + $this->assertEquals('4', $mountedShare2->getId()); + $this->assertEquals('user2', $mountedShare2->getShareOwner()); + $this->assertEquals(101, $mountedShare2->getNodeId()); + $this->assertEquals('/share4', $mountedShare2->getTarget()); + $this->assertEquals(31, $mountedShare2->getPermissions()); + $this->assertEquals(true, $mountedShare2->getAttributes()->getAttribute('permission', 'download')); + $mountedShare3 = $mounts[2]->getShare(); + $this->assertEquals('8', $mountedShare3->getId()); + $this->assertEquals('user2', $mountedShare3->getShareOwner()); + $this->assertEquals(102, $mountedShare3->getNodeId()); + $this->assertEquals('/share6', $mountedShare3->getTarget()); + $this->assertEquals(31, $mountedShare3->getPermissions()); + $mountedShare4 = $mounts[3]->getShare(); + $this->assertEquals('12', $mountedShare4->getId()); + $this->assertEquals('user2', $mountedShare4->getShareOwner()); + $this->assertEquals(103, $mountedShare4->getNodeId()); + $this->assertEquals('/share7', $mountedShare4->getTarget()); + $this->assertEquals(31, $mountedShare4->getPermissions()); + } + + public static function mergeSharesDataProvider(): array { + // note: the user in the specs here is the shareOwner not recipient + // the recipient is always "user1" + return [ + // #0: share as outsider with "group1" and "user1" with same permissions + [ + [ + [1, 100, 'user2', '/share2', 31, null], + ], + [ + [2, 100, 'user2', '/share2', 31, null], + ], + [ + // combined, user share has higher priority + ['1', 100, 'user2', '/share2', 31, []], + ], + ], + // #1: share as outsider with "group1" and "user1" with different permissions + [ + [ + [1, 100, 'user2', '/share', 31, [['scope' => 'permission', 'key' => 'download', 'value' => true], ['scope' => 'app', 'key' => 'attribute1', 'value' => true]]], + ], + [ + [2, 100, 'user2', '/share', 15, [['scope' => 'permission', 'key' => 'download', 'value' => false], ['scope' => 'app', 'key' => 'attribute2', 'value' => false]]], + ], + [ + // use highest permissions + ['1', 100, 'user2', '/share', 31, [['scope' => 'permission', 'key' => 'download', 'value' => true], ['scope' => 'app', 'key' => 'attribute1', 'value' => true], ['scope' => 'app', 'key' => 'attribute2', 'value' => false]]], + ], + ], + // #2: share as outsider with "group1" and "group2" with same permissions + [ + [ + ], + [ + [1, 100, 'user2', '/share', 31, null], + [2, 100, 'user2', '/share', 31, []], + ], + [ + // combined, first group share has higher priority + ['1', 100, 'user2', '/share', 31, []], + ], + ], + // #3: share as outsider with "group1" and "group2" with different permissions + [ + [ + ], + [ + [1, 100, 'user2', '/share', 31, [['scope' => 'permission', 'key' => 'download', 'value' => false]]], + [2, 100, 'user2', '/share', 15, [['scope' => 'permission', 'key' => 'download', 'value' => true]]], + ], + [ + // use higher permissions (most permissive) + ['1', 100, 'user2', '/share', 31, [['scope' => 'permission', 'key' => 'download', 'value' => true]]], + ], + ], + // #4: share as insider with "group1" + [ + [ + ], + [ + [1, 100, 'user1', '/share', 31, []], + ], + [ + // no received share since "user1" is the sharer/owner + ], + ], + // #5: share as insider with "group1" and "group2" with different permissions + [ + [ + ], + [ + [1, 100, 'user1', '/share', 31, [['scope' => 'permission', 'key' => 'download', 'value' => true]]], + [2, 100, 'user1', '/share', 15, [['scope' => 'permission', 'key' => 'download', 'value' => false]]], + ], + [ + // no received share since "user1" is the sharer/owner + ], + ], + // #6: share as outside with "group1", recipient opted out + [ + [ + ], + [ + [1, 100, 'user2', '/share', 0, []], + ], + [ + // no received share since "user1" opted out + ], + ], + // #7: share as outsider with "group1" and "user1" where recipient renamed in between + [ + [ + [1, 100, 'user2', '/share2-renamed', 31, []], + ], + [ + [2, 100, 'user2', '/share2', 31, []], + ], + [ + // use target of least recent share + ['1', 100, 'user2', '/share2-renamed', 31, []], + ], + ], + // #8: share as outsider with "group1" and "user1" where recipient renamed in between + [ + [ + [2, 100, 'user2', '/share2', 31, []], + ], + [ + [1, 100, 'user2', '/share2-renamed', 31, []], + ], + [ + // use target of least recent share + ['1', 100, 'user2', '/share2-renamed', 31, []], + ], + ], + // #9: share as outsider with "nullgroup" and "user1" where recipient renamed in between + [ + [ + [2, 100, 'user2', '/share2', 31, []], + ], + [ + [1, 100, 'nullgroup', '/share2-renamed', 31, []], + ], + [ + // use target of least recent share + ['1', 100, 'nullgroup', '/share2-renamed', 31, []], + ], + true + ], + ]; + } + + /** + * Tests merging shares. + * + * Happens when sharing the same entry to a user through multiple ways, + * like several groups and also direct shares at the same time. + * + * + * @param array $userShares array of user share specs + * @param array $groupShares array of group share specs + * @param array $expectedShares array of expected supershare specs + */ + #[\PHPUnit\Framework\Attributes\DataProvider('mergeSharesDataProvider')] + public function testMergeShares($userShares, $groupShares, $expectedShares, $moveFails = false): void { + $rootFolder = $this->createMock(IRootFolder::class); + $userManager = $this->createMock(IUserManager::class); + + $userShares = array_map(function ($shareSpec) { + return $this->makeMockShare($shareSpec[0], $shareSpec[1], $shareSpec[2], $shareSpec[3], $shareSpec[4], $shareSpec[5]); + }, $userShares); + $groupShares = array_map(function ($shareSpec) { + return $this->makeMockShare($shareSpec[0], $shareSpec[1], $shareSpec[2], $shareSpec[3], $shareSpec[4], $shareSpec[5]); + }, $groupShares); + + $this->user->expects($this->any()) + ->method('getUID') + ->willReturn('user1'); + + // tests regarding circles are made in the app itself. + $circleShares = []; + $roomShares = []; + $deckShares = []; + $scienceMeshShares = []; + $this->shareManager->expects($this->exactly(6)) + ->method('getSharedWith') + ->willReturnMap([ + ['user1', IShare::TYPE_USER, null, -1, 0, $userShares], + ['user1', IShare::TYPE_GROUP, null, -1, 0, $groupShares], + ['user1', IShare::TYPE_CIRCLE, null, -1, 0, $circleShares], + ['user1', IShare::TYPE_ROOM, null, -1, 0, $roomShares], + ['user1', IShare::TYPE_DECK, null, -1, 0, $deckShares], + ['user1', IShare::TYPE_SCIENCEMESH, null, -1, 0, $scienceMeshShares], + ]); + + $this->shareManager->expects($this->any()) + ->method('newShare') + ->willReturnCallback(function () use ($rootFolder, $userManager) { + return new Share($rootFolder, $userManager); + }); + + if ($moveFails) { + $this->shareManager->expects($this->any()) + ->method('moveShare') + ->willThrowException(new \InvalidArgumentException()); + } + + $mounts = $this->provider->getMountsForUser($this->user, $this->loader); + + $this->assertCount(count($expectedShares), $mounts); + + foreach ($mounts as $index => $mount) { + $expectedShare = $expectedShares[$index]; + $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mount); + + // supershare + /** @var SharedMount $mount */ + $share = $mount->getShare(); + + $this->assertEquals($expectedShare[0], $share->getId()); + $this->assertEquals($expectedShare[1], $share->getNodeId()); + $this->assertEquals($expectedShare[2], $share->getShareOwner()); + $this->assertEquals($expectedShare[3], $share->getTarget()); + $this->assertEquals($expectedShare[4], $share->getPermissions()); + if ($expectedShare[5] === null) { + $this->assertNull($share->getAttributes()); + } else { + $this->assertEquals($expectedShare[5], $share->getAttributes()->toArray()); + } + } + } +} diff --git a/apps/files_sharing/tests/propagationtestcase.php b/apps/files_sharing/tests/PropagationTestCase.php index 159a7b859aa..98bf5ad92fd 100644 --- a/apps/files_sharing/tests/propagationtestcase.php +++ b/apps/files_sharing/tests/PropagationTestCase.php @@ -1,45 +1,36 @@ <?php + /** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ +namespace OCA\Files_Sharing\Tests; -namespace OCA\Files_sharing\Tests; +use OC\Files\View; +use OCA\Files_Sharing\Helper; +use OCP\IUserSession; +use OCP\Server; abstract class PropagationTestCase extends TestCase { /** - * @var \OC\Files\View + * @var View */ protected $rootView; protected $fileIds = []; // [$user=>[$path=>$id]] protected $fileEtags = []; // [$id=>$etag] - public static function setUpBeforeClass() { + public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); - \OCA\Files_Sharing\Helper::registerHooks(); + Helper::registerHooks(); } - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->setUpShares(); } - protected function tearDown() { + protected function tearDown(): void { \OC_Hook::clear('OC_Filesystem', 'post_write'); \OC_Hook::clear('OC_Filesystem', 'post_delete'); \OC_Hook::clear('OC_Filesystem', 'post_rename'); @@ -54,7 +45,7 @@ abstract class PropagationTestCase extends TestCase { * @param string $subPath */ protected function assertEtagsChanged($users, $subPath = '') { - $oldUser = \OC::$server->getUserSession()->getUser(); + $oldUser = Server::get(IUserSession::class)->getUser(); foreach ($users as $user) { $this->loginAsUser($user); $id = $this->fileIds[$user][$subPath]; @@ -71,7 +62,7 @@ abstract class PropagationTestCase extends TestCase { * @param string $subPath */ protected function assertEtagsNotChanged($users, $subPath = '') { - $oldUser = \OC::$server->getUserSession()->getUser(); + $oldUser = Server::get(IUserSession::class)->getUser(); foreach ($users as $user) { $this->loginAsUser($user); $id = $this->fileIds[$user][$subPath]; diff --git a/apps/files_sharing/tests/ShareTest.php b/apps/files_sharing/tests/ShareTest.php new file mode 100644 index 00000000000..737ad6dcb4e --- /dev/null +++ b/apps/files_sharing/tests/ShareTest.php @@ -0,0 +1,242 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\FileInfo; +use OC\Files\Filesystem; +use OCA\Files_Sharing\Helper; +use OCP\Constants; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class ShareTest + * + * @group DB + */ +class ShareTest extends TestCase { + public const TEST_FOLDER_NAME = '/folder_share_api_test'; + + private static $tempStorage; + + private string $subsubfolder = ''; + + protected function setUp(): void { + parent::setUp(); + + $this->folder = self::TEST_FOLDER_NAME; + $this->subfolder = '/subfolder_share_api_test'; + $this->subsubfolder = '/subsubfolder_share_api_test'; + + $this->filename = '/share-api-test.txt'; + + // save file with content + $this->view->file_put_contents($this->filename, $this->data); + $this->view->mkdir($this->folder); + $this->view->mkdir($this->folder . $this->subfolder); + $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); + $this->view->file_put_contents($this->folder . $this->filename, $this->data); + $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); + } + + protected function tearDown(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->view->unlink($this->filename); + $this->view->deleteAll($this->folder); + + self::$tempStorage = null; + + parent::tearDown(); + } + + public function testUnshareFromSelf(): void { + $groupManager = Server::get(IGroupManager::class); + $userManager = Server::get(IUserManager::class); + + $testGroup = $groupManager->createGroup('testGroup'); + $user1 = $userManager->get(self::TEST_FILES_SHARING_API_USER2); + $user2 = $userManager->get(self::TEST_FILES_SHARING_API_USER3); + $testGroup->addUser($user1); + $testGroup->addUser($user2); + + $share1 = $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + + $share2 = $this->share( + IShare::TYPE_GROUP, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + 'testGroup', + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + $this->shareManager->acceptShare($share2, self::TEST_FILES_SHARING_API_USER2); + $this->shareManager->acceptShare($share2, self::TEST_FILES_SHARING_API_USER3); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(Filesystem::file_exists($this->filename)); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + $this->assertTrue(Filesystem::file_exists($this->filename)); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + Filesystem::unlink($this->filename); + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + // both group share and user share should be gone + $this->assertFalse(Filesystem::file_exists($this->filename)); + + // for user3 nothing should change + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + $this->assertTrue(Filesystem::file_exists($this->filename)); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + /** + * @param FileInfo[] $content + * @param string[] $expected + */ + public function verifyDirContent($content, $expected) { + foreach ($content as $c) { + if (!in_array($c['name'], $expected)) { + $this->assertTrue(false, "folder should only contain '" . implode(',', $expected) . "', found: " . $c['name']); + } + } + } + + public function testShareWithDifferentShareFolder(): void { + $fileinfo = $this->view->getFileInfo($this->filename); + $folderinfo = $this->view->getFileInfo($this->folder); + + $share = $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + + Helper::setShareFolder('/Shared/subfolder'); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $this->assertTrue(Filesystem::file_exists($this->filename)); + $this->assertTrue(Filesystem::file_exists('/Shared/subfolder/' . $this->folder)); + + //cleanup + Server::get(IConfig::class)->deleteSystemValue('share_folder'); + } + + public function testShareWithGroupUniqueName(): void { + $this->markTestSkipped('TODO: Disable because fails on drone'); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); + Filesystem::file_put_contents('test.txt', 'test'); + + $share = $this->share( + IShare::TYPE_GROUP, + 'test.txt', + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_GROUP1, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $shares = $this->shareManager->getSharedWith(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_GROUP); + $share = $shares[0]; + $this->assertSame('/test.txt', $share->getTarget()); + $this->assertSame(19, $share->getPermissions()); + + Filesystem::rename('test.txt', 'new test.txt'); + + $shares = $this->shareManager->getSharedWith(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_GROUP); + $share = $shares[0]; + $this->assertSame('/new test.txt', $share->getTarget()); + $this->assertSame(19, $share->getPermissions()); + + $share->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE); + $this->shareManager->updateShare($share); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + $shares = $this->shareManager->getSharedWith(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_GROUP); + $share = $shares[0]; + + $this->assertSame('/new test.txt', $share->getTarget()); + $this->assertSame(3, $share->getPermissions()); + } + + /** + * shared files should never have delete permissions + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataProviderTestFileSharePermissions')] + public function testFileSharePermissions($permission, $expectedvalid): void { + $pass = true; + try { + $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + $permission + ); + } catch (\Exception $e) { + $pass = false; + } + + $this->assertEquals($expectedvalid, $pass); + } + + public static function dataProviderTestFileSharePermissions() { + $permission1 = Constants::PERMISSION_ALL; + $permission3 = Constants::PERMISSION_READ; + $permission4 = Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE; + $permission5 = Constants::PERMISSION_READ | Constants::PERMISSION_DELETE; + $permission6 = Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; + + return [ + [$permission1, false], + [$permission3, true], + [$permission4, true], + [$permission5, false], + [$permission6, false], + ]; + } + + public function testFileOwner(): void { + $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ + ); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $info = Filesystem::getFileInfo($this->filename); + + $this->assertSame(self::TEST_FILES_SHARING_API_USER1, $info->getOwner()->getUID()); + } +} diff --git a/apps/files_sharing/tests/SharedMountTest.php b/apps/files_sharing/tests/SharedMountTest.php new file mode 100644 index 00000000000..cc9c70a241f --- /dev/null +++ b/apps/files_sharing/tests/SharedMountTest.php @@ -0,0 +1,436 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Filesystem; +use OC\Files\View; +use OC\Memcache\ArrayCache; +use OCA\Files_Sharing\MountProvider; +use OCA\Files_Sharing\SharedMount; +use OCP\Constants; +use OCP\ICacheFactory; +use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class SharedMountTest + * + * @group SLOWDB + */ +class SharedMountTest extends TestCase { + + /** @var IGroupManager */ + private $groupManager; + + /** @var IUserManager */ + private $userManager; + + private $folder2; + + protected function setUp(): void { + parent::setUp(); + + $this->folder = '/folder_share_storage_test'; + $this->folder2 = '/folder_share_storage_test2'; + + $this->filename = '/share-api-storage.txt'; + + + $this->view->mkdir($this->folder); + $this->view->mkdir($this->folder2); + + // save file with content + $this->view->file_put_contents($this->filename, 'root file'); + $this->view->file_put_contents($this->folder . $this->filename, 'file in subfolder'); + $this->view->file_put_contents($this->folder2 . $this->filename, 'file in subfolder2'); + + $this->groupManager = Server::get(IGroupManager::class); + $this->userManager = Server::get(IUserManager::class); + } + + protected function tearDown(): void { + if ($this->view) { + if ($this->view->file_exists($this->folder)) { + $this->view->unlink($this->folder); + } + if ($this->view->file_exists($this->filename)) { + $this->view->unlink($this->filename); + } + } + + parent::tearDown(); + } + + /** + * test if the mount point moves up if the parent folder no longer exists + */ + public function testShareMountLoseParentFolder(): void { + + // share to user + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); + + $share->setTarget('/foo/bar' . $this->folder); + $this->shareManager->moveShare($share, self::TEST_FILES_SHARING_API_USER2); + + $share = $this->shareManager->getShareById($share->getFullId()); + $this->assertSame('/foo/bar' . $this->folder, $share->getTarget()); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + // share should have moved up + + $share = $this->shareManager->getShareById($share->getFullId()); + $this->assertSame($this->folder, $share->getTarget()); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->shareManager->deleteShare($share); + $this->view->unlink($this->folder); + } + + /** + * @medium + */ + public function testDeleteParentOfMountPoint(): void { + // share to user + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $this->assertTrue($user2View->file_exists($this->folder)); + + // create a local folder + $result = $user2View->mkdir('localfolder'); + $this->assertTrue($result); + + // move mount point to local folder + $result = $user2View->rename($this->folder, '/localfolder/' . $this->folder); + $this->assertTrue($result); + + // mount point in the root folder should no longer exist + $this->assertFalse($user2View->is_dir($this->folder)); + + // delete the local folder + $result = $user2View->unlink('/localfolder'); + $this->assertTrue($result); + + //enforce reload of the mount points + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + //mount point should be back at the root + $this->assertTrue($user2View->is_dir($this->folder)); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->view->unlink($this->folder); + } + + public function testMoveSharedFile(): void { + $share = $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + Filesystem::rename($this->filename, $this->filename . '_renamed'); + + $this->assertTrue(Filesystem::file_exists($this->filename . '_renamed')); + $this->assertFalse(Filesystem::file_exists($this->filename)); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->assertTrue(Filesystem::file_exists($this->filename)); + $this->assertFalse(Filesystem::file_exists($this->filename . '_renamed')); + + // rename back to original name + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + Filesystem::rename($this->filename . '_renamed', $this->filename); + $this->assertFalse(Filesystem::file_exists($this->filename . '_renamed')); + $this->assertTrue(Filesystem::file_exists($this->filename)); + + //cleanup + $this->shareManager->deleteShare($share); + } + + /** + * share file with a group if a user renames the file the filename should not change + * for the other users + */ + public function testMoveGroupShare(): void { + $testGroup = $this->groupManager->createGroup('testGroup'); + $user1 = $this->userManager->get(self::TEST_FILES_SHARING_API_USER1); + $user2 = $this->userManager->get(self::TEST_FILES_SHARING_API_USER2); + $user3 = $this->userManager->get(self::TEST_FILES_SHARING_API_USER3); + $testGroup->addUser($user1); + $testGroup->addUser($user2); + $testGroup->addUser($user3); + + $fileinfo = $this->view->getFileInfo($this->filename); + $share = $this->share( + IShare::TYPE_GROUP, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + 'testGroup', + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + $this->shareManager->acceptShare($share, $user1->getUID()); + $this->shareManager->acceptShare($share, $user2->getUID()); + $this->shareManager->acceptShare($share, $user3->getUID()); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $this->assertTrue(Filesystem::file_exists($this->filename)); + + Filesystem::rename($this->filename, 'newFileName'); + + $this->assertTrue(Filesystem::file_exists('newFileName')); + $this->assertFalse(Filesystem::file_exists($this->filename)); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + $this->assertTrue(Filesystem::file_exists($this->filename)); + $this->assertFalse(Filesystem::file_exists('newFileName')); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + $this->assertTrue(Filesystem::file_exists($this->filename)); + $this->assertFalse(Filesystem::file_exists('newFileName')); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->shareManager->deleteShare($share); + $testGroup->removeUser($user1); + $testGroup->removeUser($user2); + $testGroup->removeUser($user3); + } + + /** + * @param string $path + * @param string $expectedResult + * @param bool $exception if a exception is expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataProviderTestStripUserFilesPath')] + public function testStripUserFilesPath($path, $expectedResult, $exception): void { + $testClass = new DummyTestClassSharedMount(null, null); + try { + $result = $testClass->stripUserFilesPathDummy($path); + $this->assertSame($expectedResult, $result); + } catch (\Exception $e) { + if ($exception) { + $this->assertSame(10, $e->getCode()); + } else { + $this->assertTrue(false, 'Exception caught, but expected: ' . $expectedResult); + } + } + } + + public static function dataProviderTestStripUserFilesPath() { + return [ + ['/user/files/foo.txt', '/foo.txt', false], + ['/user/files/folder/foo.txt', '/folder/foo.txt', false], + ['/data/user/files/foo.txt', null, true], + ['/data/user/files/', null, true], + ['/files/foo.txt', null, true], + ['/foo.txt', null, true], + ]; + } + + /** + * If the permissions on a group share are upgraded be sure to still respect + * removed shares by a member of that group + */ + public function testPermissionUpgradeOnUserDeletedGroupShare(): void { + $testGroup = $this->groupManager->createGroup('testGroup'); + $user1 = $this->userManager->get(self::TEST_FILES_SHARING_API_USER1); + $user2 = $this->userManager->get(self::TEST_FILES_SHARING_API_USER2); + $user3 = $this->userManager->get(self::TEST_FILES_SHARING_API_USER3); + $testGroup->addUser($user1); + $testGroup->addUser($user2); + $testGroup->addUser($user3); + + $connection = Server::get(IDBConnection::class); + + // Share item with group + $fileinfo = $this->view->getFileInfo($this->folder); + $share = $this->share( + IShare::TYPE_GROUP, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + 'testGroup', + Constants::PERMISSION_READ + ); + $this->shareManager->acceptShare($share, $user1->getUID()); + $this->shareManager->acceptShare($share, $user2->getUID()); + $this->shareManager->acceptShare($share, $user3->getUID()); + + // Login as user 2 and verify the item exists + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue(Filesystem::file_exists($this->folder)); + $result = $this->shareManager->getShareById($share->getFullId(), self::TEST_FILES_SHARING_API_USER2); + $this->assertNotEmpty($result); + $this->assertEquals(Constants::PERMISSION_READ, $result->getPermissions()); + + // Delete the share + $this->assertTrue(Filesystem::rmdir($this->folder)); + $this->assertFalse(Filesystem::file_exists($this->folder)); + + // Verify we do not get a share + $result = $this->shareManager->getShareById($share->getFullId(), self::TEST_FILES_SHARING_API_USER2); + $this->assertEquals(0, $result->getPermissions()); + + // Login as user 1 again and change permissions + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $share->setPermissions(Constants::PERMISSION_ALL); + $share = $this->shareManager->updateShare($share); + + // Login as user 2 and verify + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertFalse(Filesystem::file_exists($this->folder)); + $result = $this->shareManager->getShareById($share->getFullId(), self::TEST_FILES_SHARING_API_USER2); + $this->assertEquals(0, $result->getPermissions()); + + $this->shareManager->deleteShare($share); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $testGroup->removeUser($user1); + $testGroup->removeUser($user2); + $testGroup->removeUser($user3); + } + + /** + * test if the mount point gets renamed if a folder exists at the target + */ + public function testShareMountOverFolder(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->view2->mkdir('bar'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + // share to user + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); + + $share->setTarget('/bar'); + $this->shareManager->moveShare($share, self::TEST_FILES_SHARING_API_USER2); + + $share = $this->shareManager->getShareById($share->getFullId()); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + // share should have been moved + + $share = $this->shareManager->getShareById($share->getFullId()); + $this->assertSame('/bar (2)', $share->getTarget()); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->shareManager->deleteShare($share); + $this->view->unlink($this->folder); + } + + /** + * test if the mount point gets renamed if another share exists at the target + */ + public function testShareMountOverShare(): void { + // create a shared cache + $caches = []; + $cacheFactory = $this->createMock(ICacheFactory::class); + $cacheFactory->method('createLocal') + ->willReturnCallback(function (string $prefix) use (&$caches) { + if (!isset($caches[$prefix])) { + $caches[$prefix] = new ArrayCache($prefix); + } + return $caches[$prefix]; + }); + $cacheFactory->method('createDistributed') + ->willReturnCallback(function (string $prefix) use (&$caches) { + if (!isset($caches[$prefix])) { + $caches[$prefix] = new ArrayCache($prefix); + } + return $caches[$prefix]; + }); + + // hack to overwrite the cache factory, we can't use the proper "overwriteService" since the mount provider is created before this test is called + $mountProvider = Server::get(MountProvider::class); + $reflectionClass = new \ReflectionClass($mountProvider); + $reflectionCacheFactory = $reflectionClass->getProperty('cacheFactory'); + $reflectionCacheFactory->setAccessible(true); + $reflectionCacheFactory->setValue($mountProvider, $cacheFactory); + + // share to user + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL); + $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2); + + $share->setTarget('/foobar'); + $this->shareManager->moveShare($share, self::TEST_FILES_SHARING_API_USER2); + + + // share to user + $share2 = $this->share( + IShare::TYPE_USER, + $this->folder2, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL); + $this->shareManager->acceptShare($share2, self::TEST_FILES_SHARING_API_USER2); + + $share2->setTarget('/foobar'); + $this->shareManager->moveShare($share2, self::TEST_FILES_SHARING_API_USER2); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + // one of the shares should have been moved + + $share = $this->shareManager->getShareById($share->getFullId()); + $share2 = $this->shareManager->getShareById($share2->getFullId()); + + // we don't know or care which share got the "(2)" just that one of them did + $this->assertNotEquals($share->getTarget(), $share2->getTarget()); + $this->assertSame('/foobar', min($share->getTarget(), $share2->getTarget())); + $this->assertSame('/foobar (2)', max($share->getTarget(), $share2->getTarget())); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->shareManager->deleteShare($share); + $this->view->unlink($this->folder); + } +} + +class DummyTestClassSharedMount extends SharedMount { + public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { + // noop + } + + public function stripUserFilesPathDummy($path) { + return $this->stripUserFilesPath($path); + } +} diff --git a/apps/files_sharing/tests/SharedStorageTest.php b/apps/files_sharing/tests/SharedStorageTest.php new file mode 100644 index 00000000000..1c1f0a7b71d --- /dev/null +++ b/apps/files_sharing/tests/SharedStorageTest.php @@ -0,0 +1,612 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Cache\FailedCache; +use OC\Files\Filesystem; +use OC\Files\Storage\FailedStorage; +use OC\Files\Storage\Storage; +use OC\Files\Storage\Temporary; +use OC\Files\View; +use OCA\Files_Sharing\SharedStorage; +use OCA\Files_Trashbin\AppInfo\Application; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\Constants; +use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\NotFoundException; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class SharedStorageTest + * + * @group DB + */ +class SharedStorageTest extends TestCase { + protected function setUp(): void { + parent::setUp(); + // register trashbin hooks + $trashbinApp = new Application(); + $trashbinApp->boot($this->createMock(IBootContext::class)); + $this->folder = '/folder_share_storage_test'; + + $this->filename = '/share-api-storage.txt'; + + + $this->view->mkdir($this->folder); + + // save file with content + $this->view->file_put_contents($this->filename, 'root file'); + $this->view->file_put_contents($this->folder . $this->filename, 'file in subfolder'); + } + + protected function tearDown(): void { + if ($this->view) { + if ($this->view->file_exists($this->folder)) { + $this->view->unlink($this->folder); + } + if ($this->view->file_exists($this->filename)) { + $this->view->unlink($this->filename); + } + } + + Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); + + parent::tearDown(); + } + + /** + * if the parent of the mount point is gone then the mount point should move up + * + * @medium + */ + public function testParentOfMountPointIsGone(): void { + + // share to user + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $this->assertTrue($user2View->file_exists($this->folder)); + + // create a local folder + $result = $user2View->mkdir('localfolder'); + $this->assertTrue($result); + + // move mount point to local folder + $result = $user2View->rename($this->folder, '/localfolder/' . $this->folder); + $this->assertTrue($result); + + // mount point in the root folder should no longer exist + $this->assertFalse($user2View->is_dir($this->folder)); + + // delete the local folder + /** @var Storage $storage */ + [$storage, $internalPath] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/localfolder'); + $storage->rmdir($internalPath); + + //enforce reload of the mount points + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + //mount point should be back at the root + $this->assertTrue($user2View->is_dir($this->folder)); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->view->unlink($this->folder); + } + + /** + * @medium + */ + public function testRenamePartFile(): void { + + // share to user + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + $this->assertTrue($user2View->file_exists($this->folder)); + + // create part file + $result = $user2View->file_put_contents($this->folder . '/foo.txt.part', 'some test data'); + + $this->assertTrue(is_int($result)); + // rename part file to real file + $result = $user2View->rename($this->folder . '/foo.txt.part', $this->folder . '/foo.txt'); + + $this->assertTrue($result); + + // check if the new file really exists + $this->assertTrue($user2View->file_exists($this->folder . '/foo.txt')); + + // check if the rename also affected the owner + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->assertTrue($this->view->file_exists($this->folder . '/foo.txt')); + + //cleanup + $this->shareManager->deleteShare($share); + } + + public function testFilesize(): void { + $folderSize = $this->view->filesize($this->folder); + $file1Size = $this->view->filesize($this->folder . $this->filename); + $file2Size = $this->view->filesize($this->filename); + + $share1 = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + $share2 = $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // compare file size between user1 and user2, should always be the same + $this->assertSame($folderSize, Filesystem::filesize($this->folder)); + $this->assertSame($file1Size, Filesystem::filesize($this->folder . $this->filename)); + $this->assertSame($file2Size, Filesystem::filesize($this->filename)); + + //cleanup + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + public function testGetPermissions(): void { + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ + ); + + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $this->assertTrue(Filesystem::is_dir($this->folder)); + + // for the share root we expect: + // the read permissions (1) + // the delete permission (8), to enable unshare + $rootInfo = Filesystem::getFileInfo($this->folder); + $this->assertSame(9, $rootInfo->getPermissions()); + + // for the file within the shared folder we expect: + // the read permissions (1) + $subfileInfo = Filesystem::getFileInfo($this->folder . $this->filename); + $this->assertSame(1, $subfileInfo->getPermissions()); + + + //cleanup + $this->shareManager->deleteShare($share); + } + + public function testFopenWithReadOnlyPermission(): void { + $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + // part file should be forbidden + $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); + $this->assertFalse($handle); + + // regular file forbidden + $handle = $user2View->fopen($this->folder . '/test.txt', 'w'); + $this->assertFalse($handle); + + // rename forbidden + $this->assertFalse($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing2.txt')); + + // delete forbidden + $this->assertFalse($user2View->unlink($this->folder . '/existing.txt')); + + //cleanup + $this->shareManager->deleteShare($share); + } + + public function testFopenWithCreateOnlyPermission(): void { + $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); + $fileinfoFolder = $this->view->getFileInfo($this->folder); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_CREATE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + // create part file allowed + $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); + $this->assertNotFalse($handle); + fclose($handle); + + // create regular file allowed + $handle = $user2View->fopen($this->folder . '/test-create.txt', 'w'); + $this->assertNotFalse($handle); + fclose($handle); + + // rename file never allowed + $this->assertFalse($user2View->rename($this->folder . '/test-create.txt', $this->folder . '/newtarget.txt')); + $this->assertFalse($user2View->file_exists($this->folder . '/newtarget.txt')); + + // rename file not allowed if target exists + $this->assertFalse($user2View->rename($this->folder . '/newtarget.txt', $this->folder . '/existing.txt')); + + // overwriting file not allowed + $handle = $user2View->fopen($this->folder . '/existing.txt', 'w'); + $this->assertFalse($handle); + + // overwrite forbidden (no update permission) + $this->assertFalse($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/existing.txt')); + + // delete forbidden + $this->assertFalse($user2View->unlink($this->folder . '/existing.txt')); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->shareManager->deleteShare($share); + } + + public function testFopenWithUpdateOnlyPermission(): void { + $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + // create part file allowed + $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); + $this->assertNotFalse($handle); + fclose($handle); + + // create regular file not allowed + $handle = $user2View->fopen($this->folder . '/test-create.txt', 'w'); + $this->assertFalse($handle); + + // rename part file not allowed to non-existing file + $this->assertFalse($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/nonexist.txt')); + + // rename part file allowed to target existing file + $this->assertTrue($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/existing.txt')); + $this->assertTrue($user2View->file_exists($this->folder . '/existing.txt')); + + // rename regular file allowed + $this->assertTrue($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing-renamed.txt')); + $this->assertTrue($user2View->file_exists($this->folder . '/existing-renamed.txt')); + + // overwriting file directly is allowed + $handle = $user2View->fopen($this->folder . '/existing-renamed.txt', 'w'); + $this->assertNotFalse($handle); + fclose($handle); + + // delete forbidden + $this->assertFalse($user2View->unlink($this->folder . '/existing-renamed.txt')); + + //cleanup + $this->shareManager->deleteShare($share); + } + + public function testFopenWithDeleteOnlyPermission(): void { + $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_DELETE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $user2View = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + // part file should be forbidden + $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); + $this->assertFalse($handle); + + // regular file forbidden + $handle = $user2View->fopen($this->folder . '/test.txt', 'w'); + $this->assertFalse($handle); + + // rename forbidden + $this->assertFalse($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing2.txt')); + + // delete allowed + $this->assertTrue($user2View->unlink($this->folder . '/existing.txt')); + + //cleanup + $this->shareManager->deleteShare($share); + } + + public function testMountSharesOtherUser(): void { + $rootView = new View(''); + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + // share 2 different files with 2 different users + $share1 = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + $share2 = $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER3, + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $this->assertTrue($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . $this->folder)); + + $mountConfigManager = Server::get(IMountProviderCollection::class); + $mounts = $mountConfigManager->getMountsForUser(Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER3)); + array_walk($mounts, [Filesystem::getMountManager(), 'addMount']); + + $this->assertTrue($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER3 . '/files/' . $this->filename)); + + // make sure we didn't double setup shares for user 2 or mounted the shares for user 3 in user's 2 home + $this->assertFalse($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . $this->folder . ' (2)')); + $this->assertFalse($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . $this->filename)); + + //cleanup + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->view->unlink($this->folder); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + public function testCopyFromStorage(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $this->assertTrue($view->file_exists($this->folder)); + + [$sharedStorage,] = $view->resolvePath($this->folder); + $this->assertTrue($sharedStorage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')); + + $sourceStorage = new Temporary([]); + $sourceStorage->file_put_contents('foo.txt', 'asd'); + + $sharedStorage->copyFromStorage($sourceStorage, 'foo.txt', 'bar.txt'); + $this->assertTrue($sharedStorage->file_exists('bar.txt')); + $this->assertEquals('asd', $sharedStorage->file_get_contents('bar.txt')); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->view->unlink($this->folder); + $this->shareManager->deleteShare($share); + } + + public function testMoveFromStorage(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $this->assertTrue($view->file_exists($this->folder)); + + [$sharedStorage,] = $view->resolvePath($this->folder); + $this->assertTrue($sharedStorage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')); + + $sourceStorage = new Temporary([]); + $sourceStorage->file_put_contents('foo.txt', 'asd'); + $sourceStorage->getScanner()->scan(''); + + $sharedStorage->moveFromStorage($sourceStorage, 'foo.txt', 'bar.txt'); + $this->assertTrue($sharedStorage->file_exists('bar.txt')); + $this->assertEquals('asd', $sharedStorage->file_get_contents('bar.txt')); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->view->unlink($this->folder); + $this->shareManager->deleteShare($share); + } + + public function testNameConflict(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $view1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); + $view1->mkdir('foo'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + $view3 = new View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files'); + $view3->mkdir('foo'); + + // share a folder with the same name from two different users to the same user + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share1 = $this->share( + IShare::TYPE_GROUP, + 'foo', + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_GROUP1, + Constants::PERMISSION_ALL + ); + $this->shareManager->acceptShare($share1, self::TEST_FILES_SHARING_API_USER2); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER3); + + $share2 = $this->share( + IShare::TYPE_GROUP, + 'foo', + self::TEST_FILES_SHARING_API_USER3, + self::TEST_FILES_SHARING_API_GROUP1, + Constants::PERMISSION_ALL + ); + $this->shareManager->acceptShare($share2, self::TEST_FILES_SHARING_API_USER2); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $view2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + $this->assertTrue($view2->file_exists('/foo')); + $this->assertTrue($view2->file_exists('/foo (2)')); + + $mount = $view2->getMount('/foo'); + $this->assertInstanceOf('\OCA\Files_Sharing\SharedMount', $mount); + /** @var SharedStorage $storage */ + $storage = $mount->getStorage(); + + $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $storage->getOwner('')); + + $this->shareManager->deleteShare($share1); + $this->shareManager->deleteShare($share2); + } + + public function testOwnerPermissions(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $this->assertTrue($view->file_exists($this->folder)); + + $view->file_put_contents($this->folder . '/newfile.txt', 'asd'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->assertTrue($this->view->file_exists($this->folder . '/newfile.txt')); + $this->assertEquals(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE, + $this->view->getFileInfo($this->folder . '/newfile.txt')->getPermissions()); + + $this->view->unlink($this->folder); + $this->shareManager->deleteShare($share); + } + + public function testInitWithNonExistingUser(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareOwner')->willReturn('unexist'); + $ownerView = $this->createMock(View::class); + $storage = new SharedStorage([ + 'ownerView' => $ownerView, + 'superShare' => $share, + 'groupedShares' => [$share], + 'user' => 'user1', + ]); + + // trigger init + $this->assertInstanceOf(FailedStorage::class, $storage->getSourceStorage()); + $this->assertInstanceOf(FailedCache::class, $storage->getCache()); + } + + public function testInitWithNotFoundSource(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareOwner')->willReturn(self::TEST_FILES_SHARING_API_USER1); + $share->method('getNodeId')->willReturn(1); + $ownerView = $this->createMock(View::class); + $ownerView->method('getPath')->willThrowException(new NotFoundException()); + $storage = new SharedStorage([ + 'ownerView' => $ownerView, + 'superShare' => $share, + 'groupedShares' => [$share], + 'user' => 'user1', + ]); + + // trigger init + $this->assertInstanceOf(FailedStorage::class, $storage->getSourceStorage()); + $this->assertInstanceOf(FailedCache::class, $storage->getCache()); + } + + public function testCopyPermissions(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share = $this->share( + IShare::TYPE_USER, + $this->filename, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE - Constants::PERMISSION_DELETE + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + $this->assertTrue($view->file_exists($this->filename)); + + $this->assertTrue($view->copy($this->filename, '/target.txt')); + + $this->assertTrue($view->file_exists('/target.txt')); + + $info = $view->getFileInfo('/target.txt'); + $this->assertEquals(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE, $info->getPermissions()); + + $this->view->unlink($this->filename); + $this->shareManager->deleteShare($share); + } +} diff --git a/apps/files_sharing/tests/SharesReminderJobTest.php b/apps/files_sharing/tests/SharesReminderJobTest.php new file mode 100644 index 00000000000..ce468e279ec --- /dev/null +++ b/apps/files_sharing/tests/SharesReminderJobTest.php @@ -0,0 +1,193 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\Files_Sharing\Tests; + +use OC\SystemConfig; +use OCA\Files_Sharing\SharesReminderJob; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Constants; +use OCP\Defaults; +use OCP\Files\IMimeTypeLoader; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\L10N\IFactory; +use OCP\Mail\IMailer; +use OCP\Mail\IMessage; +use OCP\Server; +use OCP\Share\IManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; + +/** + * Class SharesReminderJobTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests + */ +class SharesReminderJobTest extends \Test\TestCase { + private SharesReminderJob $job; + private IDBConnection $db; + private IManager $shareManager; + private IUserManager $userManager; + private IMailer|MockObject $mailer; + private string $user1; + private string $user2; + + protected function setUp(): void { + parent::setUp(); + + $this->db = Server::get(IDBConnection::class); + $this->shareManager = Server::get(IManager::class); + $this->userManager = Server::get(IUserManager::class); + $this->mailer = $this->createMock(IMailer::class); + + // Clear occasional leftover shares from other tests + $this->db->executeUpdate('DELETE FROM `*PREFIX*share`'); + + $this->user1 = $this->getUniqueID('user1_'); + $this->user2 = $this->getUniqueID('user2_'); + + $user1 = $this->userManager->createUser($this->user1, 'longrandompassword'); + $user2 = $this->userManager->createUser($this->user2, 'longrandompassword'); + $user1->setSystemEMailAddress('user1@test.com'); + $user2->setSystemEMailAddress('user2@test.com'); + + \OC::registerShareHooks(Server::get(SystemConfig::class)); + + $this->job = new SharesReminderJob( + Server::get(ITimeFactory::class), + $this->db, + Server::get(IManager::class), + $this->userManager, + Server::get(LoggerInterface::class), + Server::get(IURLGenerator::class), + Server::get(IFactory::class), + $this->mailer, + Server::get(Defaults::class), + Server::get(IMimeTypeLoader::class), + ); + } + + protected function tearDown(): void { + $this->db->executeUpdate('DELETE FROM `*PREFIX*share`'); + + $userManager = Server::get(IUserManager::class); + $user1 = $userManager->get($this->user1); + if ($user1) { + $user1->delete(); + } + $user2 = $userManager->get($this->user2); + if ($user2) { + $user2->delete(); + } + + $this->logout(); + + parent::tearDown(); + } + + public static function dataSharesReminder() { + $someMail = 'test@test.com'; + $noExpirationDate = null; + $today = new \DateTime(); + // For expiration dates, the time is always automatically set to zero by ShareAPIController + $today->setTime(0, 0); + $nearFuture = new \DateTime(); + $nearFuture->setTimestamp($today->getTimestamp() + 86400 * 1); + $farFuture = new \DateTime(); + $farFuture->setTimestamp($today->getTimestamp() + 86400 * 2); + $permissionRead = Constants::PERMISSION_READ; + $permissionCreate = $permissionRead | Constants::PERMISSION_CREATE; + $permissionUpdate = $permissionRead | Constants::PERMISSION_UPDATE; + $permissionDelete = $permissionRead | Constants::PERMISSION_DELETE; + $permissionAll = Constants::PERMISSION_ALL; + + return [ + // No reminders for folders without expiration date + [$noExpirationDate, '', false, $permissionRead, false], + [$noExpirationDate, '', false, $permissionCreate, false], + [$noExpirationDate, '', true, $permissionDelete, false], + [$noExpirationDate, '', true, $permissionCreate, false], + [$noExpirationDate, $someMail, false, $permissionUpdate, false], + [$noExpirationDate, $someMail, false, $permissionCreate, false], + [$noExpirationDate, $someMail, true, $permissionRead, false], + [$noExpirationDate, $someMail, true, $permissionAll, false], + // No reminders for folders with expiration date in the far future + [$farFuture, '', false, $permissionRead, false], + [$farFuture, '', false, $permissionCreate, false], + [$farFuture, '', true, $permissionDelete, false], + [$farFuture, '', true, $permissionCreate, false], + [$farFuture, $someMail, false, $permissionUpdate, false], + [$farFuture, $someMail, false, $permissionCreate, false], + [$farFuture, $someMail, true, $permissionRead, false], + [$farFuture, $someMail, true, $permissionAll, false], + /* Should send reminders for folders with expiration date in the near future + if the folder is empty and the user has write permission */ + [$nearFuture, '', false, $permissionRead, false], + [$nearFuture, '', false, $permissionCreate, false], + [$nearFuture, '', true, $permissionDelete, false], + [$nearFuture, '', true, $permissionCreate, true], + [$nearFuture, $someMail, false, $permissionUpdate, false], + [$nearFuture, $someMail, false, $permissionCreate, false], + [$nearFuture, $someMail, true, $permissionRead, false], + [$nearFuture, $someMail, true, $permissionAll, true], + ]; + } + + /** + * + * @param \DateTime|null $expirationDate Share expiration date + * @param string $email Share with this email. If empty, the share is of type TYPE_USER and the sharee is user2 + * @param bool $isEmpty Is share folder empty? + * @param int $permissions + * @param bool $shouldBeReminded + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataSharesReminder')] + public function testSharesReminder( + ?\DateTime $expirationDate, string $email, bool $isEmpty, int $permissions, bool $shouldBeReminded, + ): void { + $this->loginAsUser($this->user1); + + $user1Folder = Server::get(IRootFolder::class)->getUserFolder($this->user1); + $testFolder = $user1Folder->newFolder('test'); + + if (!$isEmpty) { + $testFolder->newFile('some_file.txt', 'content'); + } + + $share = $this->shareManager->newShare(); + + $share->setNode($testFolder) + ->setShareType(($email ? IShare::TYPE_EMAIL : IShare::TYPE_USER)) + ->setPermissions($permissions) + ->setSharedBy($this->user1) + ->setSharedWith(($email ?: $this->user2)) + ->setExpirationDate($expirationDate); + $share = $this->shareManager->createShare($share); + + $this->logout(); + $messageMock = $this->createMock(IMessage::class); + $this->mailer->method('createMessage')->willReturn($messageMock); + $this->mailer + ->expects(($shouldBeReminded ? $this->once() : $this->never())) + ->method('send') + ->with($messageMock); + $messageMock + ->expects(($shouldBeReminded ? $this->once() : $this->never())) + ->method('setTo') + ->with([$email ?: $this->userManager->get($this->user2)->getSystemEMailAddress()]); + $this->assertSame(false, $share->getReminderSent()); + $this->job->run([]); + $share = $this->shareManager->getShareById($share->getFullId()); + $this->assertEquals($shouldBeReminded, $share->getReminderSent()); + } +} diff --git a/apps/files_sharing/tests/SizePropagationTest.php b/apps/files_sharing/tests/SizePropagationTest.php new file mode 100644 index 00000000000..e1b67abca90 --- /dev/null +++ b/apps/files_sharing/tests/SizePropagationTest.php @@ -0,0 +1,108 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\View; +use OCP\Constants; +use OCP\ITempManager; +use OCP\Server; +use OCP\Share\IShare; +use Test\Traits\UserTrait; + +/** + * Class SizePropagationTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests + */ +class SizePropagationTest extends TestCase { + use UserTrait; + + protected function setupUser($name, $password = '') { + $this->createUser($name, $password); + $tmpFolder = Server::get(ITempManager::class)->getTemporaryFolder(); + $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]); + $this->loginAsUser($name); + return new View('/' . $name . '/files'); + } + + public function testSizePropagationWhenOwnerChangesFile(): void { + $recipientView = $this->setupUser(self::TEST_FILES_SHARING_API_USER1); + + $ownerView = $this->setupUser(self::TEST_FILES_SHARING_API_USER2); + $ownerView->mkdir('/sharedfolder/subfolder'); + $ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar'); + + $this->share( + IShare::TYPE_USER, + '/sharedfolder', + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER1, + Constants::PERMISSION_ALL + ); + $ownerRootInfo = $ownerView->getFileInfo('', false); + + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); + $this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt')); + $recipientRootInfo = $recipientView->getFileInfo('', false); + + // when file changed as owner + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar'); + + // size of recipient's root stays the same + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); + $newRecipientRootInfo = $recipientView->getFileInfo('', false); + $this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize()); + + // size of owner's root increases + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $newOwnerRootInfo = $ownerView->getFileInfo('', false); + $this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize()); + } + + public function testSizePropagationWhenRecipientChangesFile(): void { + $recipientView = $this->setupUser(self::TEST_FILES_SHARING_API_USER1); + + $ownerView = $this->setupUser(self::TEST_FILES_SHARING_API_USER2); + $ownerView->mkdir('/sharedfolder/subfolder'); + $ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar'); + + $this->share( + IShare::TYPE_USER, + '/sharedfolder', + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER1, + Constants::PERMISSION_ALL + ); + $ownerRootInfo = $ownerView->getFileInfo('', false); + + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); + $this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt')); + $recipientRootInfo = $recipientView->getFileInfo('', false); + $recipientRootInfoWithMounts = $recipientView->getFileInfo('', true); + $oldRecipientSize = $recipientRootInfoWithMounts->getSize(); + + // when file changed as recipient + $recipientView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar'); + + // size of recipient's root stays the same + $newRecipientRootInfo = $recipientView->getFileInfo('', false); + $this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize()); + + // but the size including mountpoints increases + $newRecipientRootInfo = $recipientView->getFileInfo('', true); + $this->assertEquals($oldRecipientSize + 3, $newRecipientRootInfo->getSize()); + + // size of owner's root increases + $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); + $newOwnerRootInfo = $ownerView->getFileInfo('', false); + $this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize()); + } +} diff --git a/apps/files_sharing/tests/TestCase.php b/apps/files_sharing/tests/TestCase.php new file mode 100644 index 00000000000..9a6935e46b6 --- /dev/null +++ b/apps/files_sharing/tests/TestCase.php @@ -0,0 +1,247 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Cache\Storage; +use OC\Files\Filesystem; +use OC\Files\View; +use OC\Group\Database; +use OC\SystemConfig; +use OC\User\DisplayNameCache; +use OCA\Files_Sharing\AppInfo\Application; +use OCA\Files_Sharing\External\MountProvider as ExternalMountProvider; +use OCA\Files_Sharing\MountProvider; +use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\Server; +use OCP\Share\IShare; +use Test\Traits\MountProviderTrait; + +/** + * Class TestCase + * + * @group DB + * + * Base class for sharing tests. + */ +abstract class TestCase extends \Test\TestCase { + use MountProviderTrait; + + public const TEST_FILES_SHARING_API_USER1 = 'test-share-user1'; + public const TEST_FILES_SHARING_API_USER2 = 'test-share-user2'; + public const TEST_FILES_SHARING_API_USER3 = 'test-share-user3'; + public const TEST_FILES_SHARING_API_USER4 = 'test-share-user4'; + + public const TEST_FILES_SHARING_API_GROUP1 = 'test-share-group1'; + + public $filename; + public $data; + /** + * @var View + */ + public $view; + /** + * @var View + */ + public $view2; + public $folder; + public $subfolder; + + /** @var \OCP\Share\IManager */ + protected $shareManager; + /** @var IRootFolder */ + protected $rootFolder; + + public static function setUpBeforeClass(): void { + parent::setUpBeforeClass(); + + $app = new Application(); + $app->registerMountProviders( + Server::get(IMountProviderCollection::class), + Server::get(MountProvider::class), + Server::get(ExternalMountProvider::class), + ); + + // reset backend + Server::get(IUserManager::class)->clearBackends(); + Server::get(IGroupManager::class)->clearBackends(); + + // clear share hooks + \OC_Hook::clear('OCP\\Share'); + \OC::registerShareHooks(Server::get(SystemConfig::class)); + + // create users + $backend = new \Test\Util\User\Dummy(); + Server::get(IUserManager::class)->registerBackend($backend); + $backend->createUser(self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER1); + $backend->createUser(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER2); + $backend->createUser(self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER3); + $backend->createUser(self::TEST_FILES_SHARING_API_USER4, self::TEST_FILES_SHARING_API_USER4); + + // create group + $groupBackend = new \Test\Util\Group\Dummy(); + $groupBackend->createGroup(self::TEST_FILES_SHARING_API_GROUP1); + $groupBackend->createGroup('group'); + $groupBackend->createGroup('group1'); + $groupBackend->createGroup('group2'); + $groupBackend->createGroup('group3'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER1, 'group'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, 'group'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER3, 'group'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, 'group1'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER3, 'group2'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER4, 'group3'); + $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_GROUP1); + Server::get(IGroupManager::class)->addBackend($groupBackend); + } + + protected function setUp(): void { + parent::setUp(); + Server::get(DisplayNameCache::class)->clear(); + + //login as user1 + $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $this->data = 'foobar'; + $this->view = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); + $this->view2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + $this->shareManager = Server::get(\OCP\Share\IManager::class); + $this->rootFolder = Server::get(IRootFolder::class); + } + + protected function tearDown(): void { + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $qb->delete('share'); + $qb->execute(); + + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $qb->delete('mounts'); + $qb->execute(); + + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $qb->delete('filecache')->runAcrossAllShards(); + $qb->execute(); + + parent::tearDown(); + } + + public static function tearDownAfterClass(): void { + // cleanup users + $user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER1); + if ($user !== null) { + $user->delete(); + } + $user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER2); + if ($user !== null) { + $user->delete(); + } + $user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER3); + if ($user !== null) { + $user->delete(); + } + + // delete group + $group = Server::get(IGroupManager::class)->get(self::TEST_FILES_SHARING_API_GROUP1); + if ($group) { + $group->delete(); + } + + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + Filesystem::tearDown(); + + // reset backend + Server::get(IUserManager::class)->clearBackends(); + Server::get(IUserManager::class)->registerBackend(new \OC\User\Database()); + Server::get(IGroupManager::class)->clearBackends(); + Server::get(IGroupManager::class)->addBackend(new Database()); + + parent::tearDownAfterClass(); + } + + /** + * @param string $user + * @param bool $create + * @param bool $password + */ + protected function loginHelper($user, $create = false, $password = false) { + if ($password === false) { + $password = $user; + } + + if ($create) { + $userManager = Server::get(IUserManager::class); + $groupManager = Server::get(IGroupManager::class); + + $userObject = $userManager->createUser($user, $password); + $group = $groupManager->createGroup('group'); + + if ($group && $userObject) { + $group->addUser($userObject); + } + } + + \OC_Util::tearDownFS(); + Storage::getGlobalCache()->clearCache(); + Server::get(IUserSession::class)->setUser(null); + Filesystem::tearDown(); + Server::get(IUserSession::class)->login($user, $password); + \OC::$server->getUserFolder($user); + + \OC_Util::setupFS($user); + } + + /** + * get some information from a given share + * @param int $shareID + * @return array with: item_source, share_type, share_with, item_type, permissions + */ + protected function getShareFromId($shareID) { + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $qb->select('item_source', '`share_type', 'share_with', 'item_type', 'permissions') + ->from('share') + ->where( + $qb->expr()->eq('id', $qb->createNamedParameter($shareID)) + ); + $result = $qb->execute(); + $share = $result->fetch(); + $result->closeCursor(); + + return $share; + } + + /** + * @param int $type The share type + * @param string $path The path to share relative to $initiators root + * @param string $initiator + * @param string $recipient + * @param int $permissions + * @return IShare + */ + protected function share($type, $path, $initiator, $recipient, $permissions) { + $userFolder = $this->rootFolder->getUserFolder($initiator); + $node = $userFolder->get($path); + + $share = $this->shareManager->newShare(); + $share->setShareType($type) + ->setSharedWith($recipient) + ->setSharedBy($initiator) + ->setNode($node) + ->setPermissions($permissions); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $share = $this->shareManager->updateShare($share); + + return $share; + } +} diff --git a/apps/files_sharing/tests/UnshareChildrenTest.php b/apps/files_sharing/tests/UnshareChildrenTest.php new file mode 100644 index 00000000000..ac870212c99 --- /dev/null +++ b/apps/files_sharing/tests/UnshareChildrenTest.php @@ -0,0 +1,96 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Filesystem; +use OCP\Constants; +use OCP\Share\IShare; +use OCP\Util; + +/** + * Class UnshareChildrenTest + * + * @group DB + * + * @package OCA\Files_Sharing\Tests + */ +class UnshareChildrenTest extends TestCase { + protected $subsubfolder; + + public const TEST_FOLDER_NAME = '/folder_share_api_test'; + + private static $tempStorage; + + protected function setUp(): void { + parent::setUp(); + + Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren'); + + $this->folder = self::TEST_FOLDER_NAME; + $this->subfolder = '/subfolder_share_api_test'; + $this->subsubfolder = '/subsubfolder_share_api_test'; + + $this->filename = '/share-api-test'; + + // save file with content + $this->view->mkdir($this->folder); + $this->view->mkdir($this->folder . $this->subfolder); + $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); + $this->view->file_put_contents($this->folder . $this->filename, $this->data); + $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); + } + + protected function tearDown(): void { + if ($this->view) { + $this->view->deleteAll($this->folder); + } + + self::$tempStorage = null; + + parent::tearDown(); + } + + /** + * @medium + */ + public function testUnshareChildren(): void { + $fileInfo2 = Filesystem::getFileInfo($this->folder); + + $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // one folder should be shared with the user + $shares = $this->shareManager->getSharedWith(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_USER); + $this->assertCount(1, $shares); + + // move shared folder to 'localDir' + Filesystem::mkdir('localDir'); + $result = Filesystem::rename($this->folder, '/localDir/' . $this->folder); + $this->assertTrue($result); + + Filesystem::unlink('localDir'); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // after the parent directory was deleted the share should be unshared + $shares = $this->shareManager->getSharedWith(self::TEST_FILES_SHARING_API_USER2, IShare::TYPE_USER); + $this->assertEmpty($shares); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + // the folder for the owner should still exists + $this->assertTrue(Filesystem::file_exists($this->folder)); + } +} diff --git a/apps/files_sharing/tests/UpdaterTest.php b/apps/files_sharing/tests/UpdaterTest.php new file mode 100644 index 00000000000..23044e0b2f3 --- /dev/null +++ b/apps/files_sharing/tests/UpdaterTest.php @@ -0,0 +1,345 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\FileInfo; +use OC\Files\Filesystem; +use OC\Files\View; +use OCA\Files_Sharing\Helper; +use OCA\Files_Trashbin\AppInfo\Application; +use OCP\App\IAppManager; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\Constants; +use OCP\IConfig; +use OCP\Server; +use OCP\Share\IShare; + +/** + * Class UpdaterTest + * + * @group DB + */ +class UpdaterTest extends TestCase { + public const TEST_FOLDER_NAME = '/folder_share_updater_test'; + + public static function setUpBeforeClass(): void { + parent::setUpBeforeClass(); + Helper::registerHooks(); + } + + protected function setUp(): void { + parent::setUp(); + + $this->folder = self::TEST_FOLDER_NAME; + + $this->filename = '/share-updater-test.txt'; + + // save file with content + $this->view->file_put_contents($this->filename, $this->data); + $this->view->mkdir($this->folder); + $this->view->file_put_contents($this->folder . '/' . $this->filename, $this->data); + } + + protected function tearDown(): void { + if ($this->view) { + $this->view->unlink($this->filename); + $this->view->deleteAll($this->folder); + } + + parent::tearDown(); + } + + /** + * test deletion of a folder which contains share mount points. Share mount + * points should be unshared before the folder gets deleted so + * that the mount point doesn't end up at the trash bin + */ + public function testDeleteParentFolder(): void { + $appManager = Server::get(IAppManager::class); + $status = $appManager->isEnabledForUser('files_trashbin'); + $appManager->enableApp('files_trashbin'); + + // register trashbin hooks + $trashbinApp = new Application(); + $trashbinApp->boot($this->createMock(IBootContext::class)); + + $fileinfo = Filesystem::getFileInfo($this->folder); + $this->assertTrue($fileinfo instanceof FileInfo); + + $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + + // check if user2 can see the shared folder + $this->assertTrue($view->file_exists($this->folder)); + + $foldersShared = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER); + $this->assertCount(1, $foldersShared); + + $view->mkdir('localFolder'); + $view->file_put_contents('localFolder/localFile.txt', 'local file'); + + $view->rename($this->folder, 'localFolder/' . $this->folder); + + // share mount point should now be moved to the subfolder + $this->assertFalse($view->file_exists($this->folder)); + $this->assertTrue($view->file_exists('localFolder/' . $this->folder)); + + $view->unlink('localFolder'); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // shared folder should be unshared + $foldersShared = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER); + $this->assertCount(0, $foldersShared); + + // trashbin should contain the local file but not the mount point + $rootView = new View('/' . self::TEST_FILES_SHARING_API_USER2); + $trashContent = \OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_FILES_SHARING_API_USER2); + $this->assertSame(1, count($trashContent)); + $firstElement = reset($trashContent); + $timestamp = $firstElement['mtime']; + $this->assertTrue($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/localFile.txt')); + $this->assertFalse($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/' . $this->folder)); + + //cleanup + $rootView->deleteAll('files_trashin'); + + if ($status === false) { + $appManager->disableApp('files_trashbin'); + } + + Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); + } + + public static function shareFolderProvider() { + return [ + ['/'], + ['/my_shares'], + ]; + } + + /** + * if a file gets shared the etag for the recipients root should change + * + * + * @param string $shareFolder share folder to use + */ + #[\PHPUnit\Framework\Attributes\DataProvider('shareFolderProvider')] + public function testShareFile($shareFolder): void { + $config = Server::get(IConfig::class); + $oldShareFolder = $config->getSystemValue('share_folder'); + $config->setSystemValue('share_folder', $shareFolder); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $beforeShareRoot = Filesystem::getFileInfo(''); + $etagBeforeShareRoot = $beforeShareRoot->getEtag(); + + Filesystem::mkdir($shareFolder); + + $beforeShareDir = Filesystem::getFileInfo($shareFolder); + $etagBeforeShareDir = $beforeShareDir->getEtag(); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $afterShareRoot = Filesystem::getFileInfo(''); + $etagAfterShareRoot = $afterShareRoot->getEtag(); + + $afterShareDir = Filesystem::getFileInfo($shareFolder); + $etagAfterShareDir = $afterShareDir->getEtag(); + + $this->assertTrue(is_string($etagBeforeShareRoot)); + $this->assertTrue(is_string($etagBeforeShareDir)); + $this->assertTrue(is_string($etagAfterShareRoot)); + $this->assertTrue(is_string($etagAfterShareDir)); + $this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot); + $this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir); + + // cleanup + $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); + $this->shareManager->deleteShare($share); + + $config->setSystemValue('share_folder', $oldShareFolder); + } + + /** + * if a folder gets renamed all children mount points should be renamed too + */ + public function testRename(): void { + $fileinfo = Filesystem::getFileInfo($this->folder); + + $share = $this->share( + IShare::TYPE_USER, + $this->folder, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + // make sure that the shared folder exists + $this->assertTrue(Filesystem::file_exists($this->folder)); + + Filesystem::mkdir('oldTarget'); + Filesystem::mkdir('oldTarget/subfolder'); + Filesystem::mkdir('newTarget'); + + Filesystem::rename($this->folder, 'oldTarget/subfolder/' . $this->folder); + + // re-login to make sure that the new mount points are initialized + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + Filesystem::rename('/oldTarget', '/newTarget/oldTarget'); + + // re-login to make sure that the new mount points are initialized + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $this->assertTrue(Filesystem::file_exists('/newTarget/oldTarget/subfolder/' . $this->folder)); + + // cleanup + $this->shareManager->deleteShare($share); + } + + /** + * If a folder gets moved into shared folder, children shares should have their uid_owner and permissions adjusted + * user1 + * |-folder1 --> shared with user2 + * user2 + * |-folder2 --> shared with user3 and moved into folder1 + * |-subfolder1 --> shared with user3 + * |-file1.txt --> shared with user3 + * |-subfolder2 + * |-file2.txt --> shared with user3 + */ + public function testMovedIntoShareChangeOwner(): void { + $this->markTestSkipped('Skipped because this is failing with S3 as primary as file id are change when moved.'); + + // user1 creates folder1 + $viewUser1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); + $folder1 = 'folder1'; + $viewUser1->mkdir($folder1); + + // user1 shares folder1 to user2 + $folder1Share = $this->share( + IShare::TYPE_USER, + $folder1, + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_READ | Constants::PERMISSION_SHARE + ); + + $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); + $viewUser2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); + // Create user2 files + $folder2 = 'folder2'; + $viewUser2->mkdir($folder2); + $file1 = 'folder2/file1.txt'; + $viewUser2->touch($file1); + $subfolder1 = 'folder2/subfolder1'; + $viewUser2->mkdir($subfolder1); + $subfolder2 = 'folder2/subfolder2'; + $viewUser2->mkdir($subfolder2); + $file2 = 'folder2/subfolder2/file2.txt'; + $viewUser2->touch($file2); + + // user2 shares folder2 to user3 + $folder2Share = $this->share( + IShare::TYPE_USER, + $folder2, + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER3, + Constants::PERMISSION_ALL + ); + // user2 shares folder2/file1 to user3 + $file1Share = $this->share( + IShare::TYPE_USER, + $file1, + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER3, + Constants::PERMISSION_READ | Constants::PERMISSION_SHARE + ); + // user2 shares subfolder1 to user3 + $subfolder1Share = $this->share( + IShare::TYPE_USER, + $subfolder1, + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER3, + Constants::PERMISSION_ALL + ); + // user2 shares subfolder2/file2.txt to user3 + $file2Share = $this->share( + IShare::TYPE_USER, + $file2, + self::TEST_FILES_SHARING_API_USER2, + self::TEST_FILES_SHARING_API_USER3, + Constants::PERMISSION_READ | Constants::PERMISSION_SHARE + ); + + // user2 moves folder2 into folder1 + $viewUser2->rename($folder2, $folder1 . '/' . $folder2); + $folder2Share = $this->shareManager->getShareById($folder2Share->getFullId()); + $file1Share = $this->shareManager->getShareById($file1Share->getFullId()); + $subfolder1Share = $this->shareManager->getShareById($subfolder1Share->getFullId()); + $file2Share = $this->shareManager->getShareById($file2Share->getFullId()); + + // Expect uid_owner of both shares to be user1 + $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $folder2Share->getShareOwner()); + $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $file1Share->getShareOwner()); + $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $subfolder1Share->getShareOwner()); + $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $file2Share->getShareOwner()); + // Expect permissions to be limited by the permissions of the destination share + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $folder2Share->getPermissions()); + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file1Share->getPermissions()); + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $subfolder1Share->getPermissions()); + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file2Share->getPermissions()); + + // user2 moves folder2 out of folder1 + $viewUser2->rename($folder1 . '/' . $folder2, $folder2); + $folder2Share = $this->shareManager->getShareById($folder2Share->getFullId()); + $file1Share = $this->shareManager->getShareById($file1Share->getFullId()); + $subfolder1Share = $this->shareManager->getShareById($subfolder1Share->getFullId()); + $file2Share = $this->shareManager->getShareById($file2Share->getFullId()); + + // Expect uid_owner of both shares to be user2 + $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $folder2Share->getShareOwner()); + $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $file1Share->getShareOwner()); + $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $subfolder1Share->getShareOwner()); + $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $file2Share->getShareOwner()); + // Expect permissions to not change + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $folder2Share->getPermissions()); + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file1Share->getPermissions()); + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $subfolder1Share->getPermissions()); + $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file2Share->getPermissions()); + + // cleanup + $this->shareManager->deleteShare($folder1Share); + $this->shareManager->deleteShare($folder2Share); + $this->shareManager->deleteShare($file1Share); + $this->shareManager->deleteShare($subfolder1Share); + $this->shareManager->deleteShare($file2Share); + } +} diff --git a/apps/files_sharing/tests/watcher.php b/apps/files_sharing/tests/WatcherTest.php index 247fb59f351..15676836915 100644 --- a/apps/files_sharing/tests/watcher.php +++ b/apps/files_sharing/tests/WatcherTest.php @@ -1,87 +1,76 @@ <?php + /** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ +namespace OCA\Files_Sharing\Tests; + +use OC\Files\Cache\Cache; +use OC\Files\Storage\Storage; +use OC\Files\View; +use OCP\Constants; +use OCP\Share\IShare; /** - * Class Test_Files_Sharing_Watcher + * Class WatcherTest * * @group DB */ -class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase { +class WatcherTest extends TestCase { - /** - * @var \OC\Files\Storage\Storage - */ + /** @var Storage */ private $ownerStorage; - /** - * @var \OC\Files\Cache\Cache - */ + /** @var Cache */ private $ownerCache; - /** - * @var \OC\Files\Storage\Storage - */ + /** @var Storage */ private $sharedStorage; - /** - * @var \OC\Files\Cache\Cache - */ + /** @var Cache */ private $sharedCache; - protected function setUp() { + /** @var IShare */ + private $_share; + + protected function setUp(): void { parent::setUp(); self::loginHelper(self::TEST_FILES_SHARING_API_USER1); // prepare user1's dir structure - $textData = "dummy file data\n"; $this->view->mkdir('container'); $this->view->mkdir('container/shareddir'); $this->view->mkdir('container/shareddir/subdir'); - list($this->ownerStorage, $internalPath) = $this->view->resolvePath(''); + [$this->ownerStorage, $internalPath] = $this->view->resolvePath(''); $this->ownerCache = $this->ownerStorage->getCache(); $this->ownerStorage->getScanner()->scan(''); // share "shareddir" with user2 - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); + $this->_share = $this->share( + IShare::TYPE_USER, + 'container/shareddir', + self::TEST_FILES_SHARING_API_USER1, + self::TEST_FILES_SHARING_API_USER2, + Constants::PERMISSION_ALL + ); + + $this->_share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($this->_share); // login as user2 self::loginHelper(self::TEST_FILES_SHARING_API_USER2); // retrieve the shared storage - $secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2); - list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/shareddir'); + $secondView = new View('/' . self::TEST_FILES_SHARING_API_USER2); + [$this->sharedStorage, $internalPath] = $secondView->resolvePath('files/shareddir'); $this->sharedCache = $this->sharedStorage->getCache(); } - protected function tearDown() { + protected function tearDown(): void { if ($this->sharedCache) { $this->sharedCache->clear(); } @@ -89,9 +78,7 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase { self::loginHelper(self::TEST_FILES_SHARING_API_USER1); if ($this->view) { - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); + $this->shareManager->deleteShare($this->_share); $this->view->deleteAll('container'); @@ -105,14 +92,14 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase { * Tests that writing a file using the shared storage will propagate the file * size to the owner's parent folders. */ - function testFolderSizePropagationToOwnerStorage() { + public function testFolderSizePropagationToOwnerStorage(): void { $initialSizes = self::getOwnerDirSizes('files/container/shareddir'); $textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $dataLen = strlen($textData); - $this->sharedCache->put('bar.txt', array('mtime' => 10, 'storage_mtime' => 10, 'size' => $dataLen, 'mimetype' => 'text/plain')); + $this->sharedCache->put('bar.txt', ['mtime' => 10, 'storage_mtime' => 10, 'size' => $dataLen, 'mimetype' => 'text/plain']); $this->sharedStorage->file_put_contents('bar.txt', $textData); - $this->sharedCache->put('', array('mtime' => 10, 'storage_mtime' => 10, 'size' => '-1', 'mimetype' => 'httpd/unix-directory')); + $this->sharedCache->put('', ['mtime' => 10, 'storage_mtime' => 10, 'size' => '-1', 'mimetype' => 'httpd/unix-directory']); // run the propagation code $this->sharedStorage->getWatcher()->checkUpdate(''); @@ -135,14 +122,14 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase { * Tests that writing a file using the shared storage will propagate the file * size to the owner's parent folders. */ - function testSubFolderSizePropagationToOwnerStorage() { + public function testSubFolderSizePropagationToOwnerStorage(): void { $initialSizes = self::getOwnerDirSizes('files/container/shareddir/subdir'); $textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $dataLen = strlen($textData); - $this->sharedCache->put('subdir/bar.txt', array('mtime' => 10, 'storage_mtime' => 10, 'size' => $dataLen, 'mimetype' => 'text/plain')); + $this->sharedCache->put('subdir/bar.txt', ['mtime' => 10, 'storage_mtime' => 10, 'size' => $dataLen, 'mimetype' => 'text/plain']); $this->sharedStorage->file_put_contents('subdir/bar.txt', $textData); - $this->sharedCache->put('subdir', array('mtime' => 10, 'storage_mtime' => 10, 'size' => $dataLen, 'mimetype' => 'text/plain')); + $this->sharedCache->put('subdir', ['mtime' => 10, 'storage_mtime' => 10, 'size' => $dataLen, 'mimetype' => 'text/plain']); // run the propagation code $this->sharedStorage->getWatcher()->checkUpdate('subdir'); @@ -167,8 +154,8 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase { * where the key is the path and the value is the size. * @param string $path */ - function getOwnerDirSizes($path) { - $result = array(); + public function getOwnerDirSizes($path) { + $result = []; while ($path != '' && $path != '' && $path != '.') { $cachedData = $this->ownerCache->get($path); diff --git a/apps/files_sharing/tests/activity.php b/apps/files_sharing/tests/activity.php deleted file mode 100644 index 40a1031f779..00000000000 --- a/apps/files_sharing/tests/activity.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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; - -/** - * Class Activity - * - * @group DB - * - * @package OCA\Files_sharing\Tests - */ -class Activity extends \OCA\Files_Sharing\Tests\TestCase { - - /** - * @var \OCA\Files_Sharing\Activity - */ - private $activity; - - protected function setUp() { - parent::setUp(); - $this->activity = new \OCA\Files_Sharing\Activity( - $this->getMockBuilder('OCP\L10N\IFactory') - ->disableOriginalConstructor() - ->getMock(), - $this->getMockBuilder('OCP\IURLGenerator') - ->disableOriginalConstructor() - ->getMock(), - $this->getMockBuilder('OCP\Activity\IManager') - ->disableOriginalConstructor() - ->getMock() - ); - } - - /** - * @dataProvider dataTestGetDefaultType - */ - public function testGetDefaultTypes($method, $expectedResult) { - $result = $this->activity->getDefaultTypes($method); - - if (is_array($expectedResult)) { - $this->assertSame(count($expectedResult), count($result)); - foreach ($expectedResult as $key => $expected) { - $this->assertSame($expected, $result[$key]); - } - } else { - $this->assertSame($expectedResult, $result); - } - - } - - public function dataTestGetDefaultType() { - return array( - array('email', array(\OCA\Files_Sharing\Activity::TYPE_SHARED, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE)), - array('stream', array(\OCA\Files_Sharing\Activity::TYPE_SHARED, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::TYPE_PUBLIC_LINKS)), - ); - } - -} diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php deleted file mode 100644 index 08f8b6f243d..00000000000 --- a/apps/files_sharing/tests/api.php +++ /dev/null @@ -1,1586 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -use OCA\Files\Share; -use OCA\Files_sharing\Tests\TestCase; - -/** - * Class Test_Files_Sharing_Api - * - * @group DB - */ -class Test_Files_Sharing_Api extends TestCase { - - const TEST_FOLDER_NAME = '/folder_share_api_test'; - - private static $tempStorage; - - /** @var \OCP\Share\IManager */ - private $shareManager; - - /** @var \OCP\Files\Folder */ - private $userFolder; - - protected function setUp() { - parent::setUp(); - - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups', 'no'); - \OC::$server->getAppConfig()->setValue('core', 'shareapi_expire_after_n_days', '7'); - - $this->folder = self::TEST_FOLDER_NAME; - $this->subfolder = '/subfolder_share_api_test'; - $this->subsubfolder = '/subsubfolder_share_api_test'; - - $this->filename = '/share-api-test.txt'; - - // save file with content - $this->view->file_put_contents($this->filename, $this->data); - $this->view->mkdir($this->folder); - $this->view->mkdir($this->folder . $this->subfolder); - $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); - $this->view->file_put_contents($this->folder.$this->filename, $this->data); - $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); - - $this->shareManager = \OC::$server->getShareManager(); - $this->userFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); - } - - protected function tearDown() { - if($this->view instanceof \OC\Files\View) { - $this->view->unlink($this->filename); - $this->view->deleteAll($this->folder); - } - - self::$tempStorage = null; - - parent::tearDown(); - } - - /** - * @param array $data - * @return \OCP\IRequest - */ - private function createRequest(array $data) { - $request = $this->getMock('\OCP\IRequest'); - $request->method('getParam') - ->will($this->returnCallback(function($param, $default = null) use ($data) { - if (isset($data[$param])) { - return $data[$param]; - } - return $default; - })); - return $request; - } - - /** - * @param \OCP\IRequest $request - * @param string $userId The userId of the caller - * @return \OCA\Files_Sharing\API\Share20OCS - */ - private function createOCS($request, $userId) { - $currentUser = \OC::$server->getUserManager()->get($userId); - - return new \OCA\Files_Sharing\API\Share20OCS( - $this->shareManager, - \OC::$server->getGroupManager(), - \OC::$server->getUserManager(), - $request, - \OC::$server->getRootFolder(), - \OC::$server->getURLGenerator(), - $currentUser - ); - } - - /** - * @medium - */ - function testCreateShareUserFile() { - // simulate a post request - $data['path'] = $this->filename; - $data['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2; - $data['shareType'] = \OCP\Share::SHARE_TYPE_USER; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - $this->assertEquals(19, $data['permissions']); - $this->assertEmpty($data['expiration']); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - } - - function testCreateShareUserFolder() { - // simulate a post request - $data['path'] = $this->folder; - $data['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2; - $data['shareType'] = \OCP\Share::SHARE_TYPE_USER; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - $this->assertEquals(31, $data['permissions']); - $this->assertEmpty($data['expiration']); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - } - - - function testCreateShareGroupFile() { - // simulate a post request - $data['path'] = $this->filename; - $data['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_GROUP1; - $data['shareType'] = \OCP\Share::SHARE_TYPE_GROUP; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - $this->assertEquals(19, $data['permissions']); - $this->assertEmpty($data['expiration']); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - } - - function testCreateShareGroupFolder() { - // simulate a post request - $data['path'] = $this->folder; - $data['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_GROUP1; - $data['shareType'] = \OCP\Share::SHARE_TYPE_GROUP; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - $this->assertEquals(31, $data['permissions']); - $this->assertEmpty($data['expiration']); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - } - - public function testCreateShareLink() { - // simulate a post request - $data['path'] = $this->folder; - $data['shareType'] = \OCP\Share::SHARE_TYPE_LINK; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - // check if API call was successful - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertEquals(1, $data['permissions']); - $this->assertEmpty($data['expiration']); - $this->assertTrue(is_string($data['token'])); - - // check for correct link - $url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']); - $this->assertEquals($url, $data['url']); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - } - - public function testCreateShareLinkPublicUpload() { - // simulate a post request - $data['path'] = $this->folder; - $data['shareType'] = \OCP\Share::SHARE_TYPE_LINK; - $data['publicUpload'] = 'true'; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - // check if API call was successful - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertEquals(7, $data['permissions']); - $this->assertEmpty($data['expiration']); - $this->assertTrue(is_string($data['token'])); - - // check for correct link - $url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']); - $this->assertEquals($url, $data['url']); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - } - - function testEnfoceLinkPassword() { - - $appConfig = \OC::$server->getAppConfig(); - $appConfig->setValue('core', 'shareapi_enforce_links_password', 'yes'); - - // don't allow to share link without a password - $data['path'] = $this->folder; - $data['shareType'] = \OCP\Share::SHARE_TYPE_LINK; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertFalse($result->succeeded()); - - // don't allow to share link without a empty password - $data = []; - $data['path'] = $this->folder; - $data['shareType'] = \OCP\Share::SHARE_TYPE_LINK; - $data['password'] = ''; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertFalse($result->succeeded()); - - // share with password should succeed - $data = []; - $data['path'] = $this->folder; - $data['shareType'] = \OCP\Share::SHARE_TYPE_LINK; - $data['password'] = 'foo'; - - $request = $this->createRequest($data); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - - // setting new password should succeed - $data2 = [ - 'password' => 'bar', - ]; - $request = $this->createRequest($data2); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($data['id']); - $this->assertTrue($result->succeeded()); - - // removing password should fail - $data2 = [ - 'password' => '', - ]; - $request = $this->createRequest($data2); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($data['id']); - $this->assertFalse($result->succeeded()); - - // cleanup - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - - $appConfig->setValue('core', 'shareapi_enforce_links_password', 'no'); - } - - /** - * @medium - */ - function testSharePermissions() { - // sharing file to a user should work if shareapi_exclude_groups is set - // to no - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups', 'no'); - $post['path'] = $this->filename; - $post['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2; - $post['shareType'] = \OCP\Share::SHARE_TYPE_USER; - - $request = $this->createRequest($post); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - - $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - - // exclude groups, but not the group the user belongs to. Sharing should still work - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups', 'yes'); - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups_list', 'admin,group1,group2'); - - $post = []; - $post['path'] = $this->filename; - $post['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2; - $post['shareType'] = \OCP\Share::SHARE_TYPE_USER; - - $request = $this->createRequest($post); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - - $this->shareManager->getShareById('ocinternal:' . $data['id']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($data['id']); - $this->assertTrue($result->succeeded()); - - // now we exclude the group the user belongs to ('group'), sharing should fail now - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups_list', 'admin,group'); - - $post = []; - $post['path'] = $this->filename; - $post['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2; - $post['shareType'] = \OCP\Share::SHARE_TYPE_USER; - - $request = $this->createRequest($post); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - // cleanup - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups', 'no'); - \OC::$server->getAppConfig()->setValue('core', 'shareapi_exclude_groups_list', ''); - } - - - /** - * @medium - */ - function testGetAllShares() { - $node = $this->userFolder->get($this->filename); - - $share = $this->shareManager->newShare(); - $share->setNode($node) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - - $share = $this->shareManager->createShare($share); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - - $this->assertTrue($result->succeeded()); - $this->assertTrue(count($result->getData()) === 1); - - $this->shareManager->deleteShare($share); - } - - function testGetAllSharesWithMe() { - $node1 = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $node2 = $this->userFolder->get($this->folder); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share2 = $this->shareManager->createShare($share2); - - $request = $this->createRequest(['shared_with_me' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result = $ocs->getShares(); - - $this->assertTrue($result->succeeded()); - $this->assertTrue(count($result->getData()) === 2); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - } - - /** - * @medium - */ - function testPublicLinkUrl() { - // simulate a post request - $post['path'] = $this->folder; - $post['shareType'] = \OCP\Share::SHARE_TYPE_LINK; - - $request = $this->createRequest($post); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - - // check if we have a token - $this->assertTrue(is_string($data['token'])); - $id = $data['id']; - - // check for correct link - $url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']); - $this->assertEquals($url, $data['url']); - - // check for link in getall shares - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertEquals($url, current($data)['url']); - - // check for path - $request = $this->createRequest(['path' => $this->folder]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertEquals($url, current($data)['url']); - - // check in share id - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShare($id); - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertEquals($url, current($data)['url']); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($id); - $this->assertTrue($result->succeeded()); - } - - /** - * @medium - * @depends testCreateShareUserFile - * @depends testCreateShareLink - */ - function testGetShareFromSource() { - $node = $this->userFolder->get($this->filename); - $share = $this->shareManager->newShare(); - $share->setNode($node) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share); - - $share = $this->shareManager->newShare(); - $share->setNode($node) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share); - - $request = $this->createRequest(['path' => $this->filename]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share created from testCreateShare() - $this->assertTrue(count($result->getData()) === 2); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - } - - /** - * @medium - * @depends testCreateShareUserFile - * @depends testCreateShareLink - */ - function testGetShareFromSourceWithReshares() { - $node = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $share2 = $this->shareManager->newShare(); - $share2->setNode($node) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share2 = $this->shareManager->createShare($share2); - - $request = $this->createRequest(['path' => $this->filename]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share - $this->assertTrue(count($result->getData()) === 1); - - // now also ask for the reshares - $request = $this->createRequest(['path' => $this->filename, 'reshares' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - $this->assertTrue($result->succeeded()); - - // now we should get two shares, the initial share and the reshare - $this->assertCount(2, $result->getData()); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - } - - /** - * @medium - * @depends testCreateShareUserFile - */ - function testGetShareFromId() { - $node = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - // call getShare() with share ID - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShare($share1->getId()); - $this->assertTrue($result->succeeded()); - - // test should return one share created from testCreateShare() - $this->assertEquals(1, count($result->getData())); - - $this->shareManager->deleteShare($share1); - } - - /** - * @medium - */ - function testGetShareFromFolder() { - $node1 = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $node2 = $this->userFolder->get($this->folder.'/'.$this->filename); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share2); - - - $request = $this->createRequest(['path' => $this->folder, 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share within $this->folder - $this->assertTrue(count($result->getData()) === 1); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - } - - function testGetShareFromFolderWithFile() { - $node1 = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $request = $this->createRequest(['path' => $this->filename, 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - - $this->assertFalse($result->succeeded()); - $this->assertEquals(400, $result->getStatusCode()); - $this->assertEquals('not a directory', $result->getMeta()['message']); - - $this->shareManager->deleteShare($share1); - } - - /** - * share a folder, than reshare a file within the shared folder and check if we construct the correct path - * @medium - */ - function testGetShareFromFolderReshares() { - $node1 = $this->userFolder->get($this->folder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share1 = $this->shareManager->createShare($share1); - - $node2 = $this->userFolder->get($this->folder.'/'.$this->filename); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share2); - - $node3 = $this->userFolder->get($this->folder.'/'.$this->subfolder.'/'.$this->filename); - $share3 = $this->shareManager->newShare(); - $share3->setNode($node3) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share3 = $this->shareManager->createShare($share3); - - $testValues=array( - array('query' => $this->folder, - 'expectedResult' => $this->folder . $this->filename), - array('query' => $this->folder . $this->subfolder, - 'expectedResult' => $this->folder . $this->subfolder . $this->filename), - ); - foreach ($testValues as $value) { - - $request = $this->createRequest(['path' => $value['query'], 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share within $this->folder - $data = $result->getData(); - - $this->assertEquals($value['expectedResult'], $data[0]['path']); - } - - // cleanup - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - $this->shareManager->deleteShare($share3); - } - - /** - * reshare a sub folder and check if we get the correct path - * @medium - */ - function testGetShareFromSubFolderReShares() { - $node1 = $this->userFolder->get($this->folder . $this->subfolder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share1 = $this->shareManager->createShare($share1); - - $node2 = \OC::$server->getRootFolder()->getUserFolder(self::TEST_FILES_SHARING_API_USER2)->get($this->subfolder); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share2); - - $request = $this->createRequest(['path' => '/', 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share within $this->folder - $data = $result->getData(); - - // we should get exactly one result - $this->assertCount(1, $data); - - $expectedPath = $this->folder . $this->subfolder; - $this->assertEquals($expectedPath, $data[0]['path']); - - $this->shareManager->deleteShare($share2); - $this->shareManager->deleteShare($share1); - } - - /** - * test re-re-share of folder if the path gets constructed correctly - * @medium - */ - function testGetShareFromFolderReReShares() { - $node1 = $this->userFolder->get($this->folder . $this->subfolder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share1 = $this->shareManager->createShare($share1); - - $node2 = $this->userFolder->get($this->folder . $this->subfolder . $this->subsubfolder); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share2 = $this->shareManager->createShare($share2); - - $share3 = $this->shareManager->newShare(); - $share3->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER3) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share3 = $this->shareManager->createShare($share3); - - $request = $this->createRequest(['path' => '/', 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER3); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share within $this->folder - $data = $result->getData(); - - // we should get exactly one result - $this->assertCount(1, $data); - - $expectedPath = $this->folder . $this->subfolder . $this->subsubfolder; - $this->assertEquals($expectedPath, $data[0]['path']); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - $this->shareManager->deleteShare($share3); - } - - /** - * test multiple shared folder if the path gets constructed correctly - * @medium - */ - function testGetShareMultipleSharedFolder() { - $node1 = $this->userFolder->get($this->folder . $this->subfolder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share1 = $this->shareManager->createShare($share1); - - $node2 = $this->userFolder->get($this->folder); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share2 = $this->shareManager->createShare($share2); - - $share3 = $this->shareManager->newShare(); - $share3->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share3 = $this->shareManager->createShare($share3); - - $request = $this->createRequest(['path' => $this->subfolder]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result1 = $ocs->getShares(); - $this->assertTrue($result1->succeeded()); - - // test should return one share within $this->folder - $data1 = $result1->getData(); - $this->assertCount(1, $data1); - $s1 = reset($data1); - - $request = $this->createRequest(['path' => $this->folder.$this->subfolder]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result2 = $ocs->getShares(); - $this->assertTrue($result2->succeeded()); - - // test should return one share within $this->folder - $data2 = $result2->getData(); - $this->assertCount(1, $data2); - $s2 = reset($data2); - - $this->assertEquals($this->folder.$this->subfolder, $s1['path']); - $this->assertEquals($this->folder.$this->subfolder, $s2['path']); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - $this->shareManager->deleteShare($share3); - } - - /** - * test re-re-share of folder if the path gets constructed correctly - * @medium - */ - function testGetShareFromFileReReShares() { - $node1 = $this->userFolder->get($this->folder . $this->subfolder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share1 = $this->shareManager->createShare($share1); - - $user2Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2); - $node2 = $user2Folder->get($this->subfolder . $this->filename); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER3) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share2 = $this->shareManager->createShare($share2); - - $user3Folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER3); - $node3 = $user3Folder->get($this->filename); - $share3 = $this->shareManager->newShare(); - $share3->setNode($node3) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER3) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share3 = $this->shareManager->createShare($share3); - - $request = $this->createRequest(['path' => '/', 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER3); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - // test should return one share within $this->folder - $data = $result->getData(); - - // we should get exactly one result - $this->assertCount(1, $data); - - $expectedPath = $this->folder.$this->subfolder.$this->filename; - $this->assertEquals($expectedPath, $data[0]['path']); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - $this->shareManager->deleteShare($share3); - } - - /** - * @medium - */ - function testGetShareFromUnknownId() { - $request = $this->createRequest(['path' => '/', 'subfiles' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER3); - $result = $ocs->getShare(0); - $this->assertFalse($result->succeeded()); - - $this->assertEquals(404, $result->getStatusCode()); - $meta = $result->getMeta(); - $this->assertEquals('wrong share ID, share doesn\'t exist.', $meta['message']); - } - - /** - * @medium - * @depends testCreateShareUserFile - * @depends testCreateShareLink - */ - function testUpdateShare() { - $node1 = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $share2 = $this->shareManager->newShare(); - $share2->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share2); - - // update permissions - $params = array(); - $params['permissions'] = 1; - - $request = $this->createRequest(['permissions' => 1]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share1->getId()); - $this->assertTrue($result->succeeded()); - - $meta = $result->getMeta(); - $this->assertTrue($result->succeeded(), $meta['message']); - - $share1 = $this->shareManager->getShareById('ocinternal:' . $share1->getId()); - $this->assertEquals(1, $share1->getPermissions()); - - // update password for link share - $this->assertNull($share2->getPassword()); - - $request = $this->createRequest(['password' => 'foo']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share2->getId()); - $this->assertTrue($result->succeeded()); - - $share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId()); - $this->assertNotNull($share2->getPassword()); - - $request = $this->createRequest(['password' => '']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share2->getId()); - $this->assertTrue($result->succeeded()); - - $share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId()); - $this->assertNull($share2->getPassword()); - - $this->shareManager->deleteShare($share1); - $this->shareManager->deleteShare($share2); - } - - /** - * @medium - * @depends testCreateShareUserFile - */ - public function testUpdateShareInvalidPermissions() { - $node1 = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $request = $this->createRequest(['permissions' => \OCP\Constants::PERMISSION_ALL]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share1->getId()); - - //Updating should fail with 400 - $this->assertFalse($result->succeeded()); - $this->assertEquals(400, $result->getStatusCode()); - - //Permissions should not have changed! - $share1 = $this->shareManager->getShareById('ocinternal:' . $share1->getId()); - $this->assertEquals(19, $share1->getPermissions()); - - $this->shareManager->deleteShare($share1); - } - - /** - * @medium - */ - function testUpdateShareUpload() { - $node1 = $this->userFolder->get($this->folder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share1 = $this->shareManager->createShare($share1); - - // update public upload - $request = $this->createRequest(['publicUpload' => 'true']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share1->getId()); - $this->assertTrue($result->succeeded()); - - $share1 = $this->shareManager->getShareById($share1->getFullId()); - $this->assertEquals(7, $share1->getPermissions()); - - // cleanup - $this->shareManager->deleteShare($share1); - } - - /** - * @medium - */ - function testUpdateShareExpireDate() { - $node1 = $this->userFolder->get($this->folder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share1 = $this->shareManager->createShare($share1); - - $config = \OC::$server->getConfig(); - - // enforce expire date, by default 7 days after the file was shared - $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); - - $dateWithinRange = new \DateTime(); - $dateWithinRange->setTime(0,0,0); - $dateWithinRange->add(new \DateInterval('P5D')); - $dateOutOfRange = new \DateTime(); - $dateOutOfRange->setTime(0,0,0); - $dateOutOfRange->add(new \DateInterval('P8D')); - - // update expire date to a valid value - $request = $this->createRequest(['expireDate' => $dateWithinRange->format('Y-m-d')]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share1->getId()); - $this->assertTrue($result->succeeded()); - - $share1 = $this->shareManager->getShareById($share1->getFullId()); - - // date should be changed - $this->assertEquals($dateWithinRange, $share1->getExpirationDate()); - - // update expire date to a value out of range - $request = $this->createRequest(['expireDate' => $dateOutOfRange->format('Y-m-d')]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share1->getId()); - $this->assertFalse($result->succeeded()); - - $share1 = $this->shareManager->getShareById($share1->getFullId()); - - // date shouldn't be changed - $this->assertEquals($dateWithinRange, $share1->getExpirationDate()); - - // Try to remove expire date - $request = $this->createRequest(['expireDate' => '']); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->updateShare($share1->getId()); - $this->assertFalse($result->succeeded()); - - $share1 = $this->shareManager->getShareById($share1->getFullId()); - - - // date shouldn't be changed - $this->assertEquals($dateWithinRange, $share1->getExpirationDate()); - // cleanup - $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); - $this->shareManager->deleteShare($share1); - } - - /** - * @medium - * @depends testCreateShareUserFile - */ - function testDeleteShare() { - $node1 = $this->userFolder->get($this->filename); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(19); - $share1 = $this->shareManager->createShare($share1); - - $share2 = $this->shareManager->newShare(); - $share2->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share1); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($share1->getId()); - $this->assertTrue($result->succeeded()); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($share2->getId()); - $this->assertTrue($result->succeeded()); - - $this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, \OCP\Share::SHARE_TYPE_USER)); - $this->assertEmpty($this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER2, \OCP\Share::SHARE_TYPE_LINK)); - } - - /** - * test unshare of a reshared file - */ - function testDeleteReshare() { - $node1 = $this->userFolder->get($this->folder); - $share1 = $this->shareManager->newShare(); - $share1->setNode($node1) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) - ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setPermissions(31); - $share1 = $this->shareManager->createShare($share1); - - $user2folder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER2); - $node2 = $user2folder->get($this->folder.'/'.$this->filename); - $share2 = $this->shareManager->newShare(); - $share2->setNode($node2) - ->setSharedBy(self::TEST_FILES_SHARING_API_USER2) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPermissions(1); - $share2 = $this->shareManager->createShare($share2); - - // test if we can unshare the link again - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result = $ocs->deleteShare($share2->getId()); - $this->assertTrue($result->succeeded()); - - $this->shareManager->deleteShare($share1); - } - - /** - * share a folder which contains a share mount point, should be forbidden - */ - public function testShareFolderWithAMountPoint() { - // user 1 shares a folder with user2 - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - $fileInfo = $this->view->getFileInfo($this->folder); - - $result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - - $this->assertTrue($result); - - // user2 shares a file from the folder as link - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - - $view = new \OC\Files\View('/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2 . '/files'); - $view->mkdir("localDir"); - - // move mount point to the folder "localDir" - $result = $view->rename($this->folder, 'localDir/'.$this->folder); - $this->assertTrue($result !== false); - - // try to share "localDir" - $fileInfo2 = $view->getFileInfo('localDir'); - - $this->assertTrue($fileInfo2 instanceof \OC\Files\FileInfo); - - try { - $result2 = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, 31); - } catch (\Exception $e) { - $result2 = false; - } - - $this->assertFalse($result2); - - //cleanup - - $result = $view->rename('localDir/' . $this->folder, $this->folder); - $this->assertTrue($result !== false); - $view->unlink('localDir'); - - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - } - - /** - * Post init mount points hook for mounting simulated ext storage - */ - public static function initTestMountPointsHook($data) { - if ($data['user'] === \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1) { - \OC\Files\Filesystem::mount(self::$tempStorage, array(), '/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME); - } - } - - /** - * Tests mounting a folder that is an external storage mount point. - */ - public function testShareStorageMountPoint() { - self::$tempStorage = new \OC\Files\Storage\Temporary(array()); - self::$tempStorage->file_put_contents('test.txt', 'abcdef'); - self::$tempStorage->getScanner()->scan(''); - - // needed because the sharing code sometimes switches the user internally and mounts the user's - // storages. In our case the temp storage isn't mounted automatically, so doing it in the post hook - // (similar to how ext storage works) - OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\Test_Files_Sharing_Api', 'initTestMountPointsHook'); - - // logging in will auto-mount the temp storage for user1 as well - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - $fileInfo = $this->view->getFileInfo($this->folder); - - // user 1 shares the mount point folder with user2 - $result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - - $this->assertTrue($result); - - // user2: check that mount point name appears correctly - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - - $view = new \OC\Files\View('/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2 . '/files'); - - $this->assertTrue($view->file_exists($this->folder)); - $this->assertTrue($view->file_exists($this->folder . '/test.txt')); - - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - - \OC_Hook::clear('OC_Filesystem', 'post_initMountPoints', '\Test_Files_Sharing_Api', 'initTestMountPointsHook'); - } - /** - * @expectedException \Exception - */ - public function testShareNonExisting() { - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - $id = PHP_INT_MAX - 1; - \OCP\Share::shareItem('file', $id, \OCP\Share::SHARE_TYPE_LINK, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - } - - /** - * @expectedException \Exception - */ - public function testShareNotOwner() { - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - \OC\Files\Filesystem::file_put_contents('foo.txt', 'bar'); - $info = \OC\Files\Filesystem::getFileInfo('foo.txt'); - - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_LINK, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - } - - public function testDefaultExpireDate() { - \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); - - // TODO drop this once all code paths use the DI version - otherwise - // the cache inside this config object is out of date because - // OC_Appconfig is used and bypasses this cache which lead to integrity - // constraint violations - $config = \OC::$server->getConfig(); - $config->deleteAppValue('core', 'shareapi_default_expire_date'); - $config->deleteAppValue('core', 'shareapi_enforce_expire_date'); - $config->deleteAppValue('core', 'shareapi_expire_after_n_days'); - - $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); - $config->setAppValue('core', 'shareapi_expire_after_n_days', '2'); - - // default expire date is set to 2 days - // the time when the share was created is set to 3 days in the past - // user defined expire date is set to +2 days from now on - // -> link should be already expired by the default expire date but the user - // share should still exists. - $now = time(); - $dateFormat = 'Y-m-d H:i:s'; - $shareCreated = $now - 3 * 24 * 60 * 60; - $expireDate = date($dateFormat, $now + 2 * 24 * 60 * 60); - - $info = OC\Files\Filesystem::getFileInfo($this->filename); - $this->assertTrue($info instanceof \OC\Files\FileInfo); - - $result = \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_LINK, null, \OCP\Constants::PERMISSION_READ); - $this->assertTrue(is_string($result)); - - $result = \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_USER, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($result); - - $result = \OCP\Share::setExpirationDate('file', $info->getId() , $expireDate, $now); - $this->assertTrue($result); - - //manipulate stime so that both shares are older then the default expire date - $statement = "UPDATE `*PREFIX*share` SET `stime` = ? WHERE `share_type` = ?"; - $query = \OCP\DB::prepare($statement); - $result = $query->execute(array($shareCreated, \OCP\Share::SHARE_TYPE_LINK)); - $this->assertSame(1, $result); - $query = \OCP\DB::prepare($statement); - $result = $query->execute(array($shareCreated, \OCP\Share::SHARE_TYPE_USER)); - $this->assertSame(1, $result); - - // now the link share should expire because of enforced default expire date - // the user share should still exist - $result = \OCP\Share::getItemShared('file', $info->getId()); - $this->assertTrue(is_array($result)); - $this->assertSame(1, count($result)); - $share = reset($result); - $this->assertSame(\OCP\Share::SHARE_TYPE_USER, $share['share_type']); - - //cleanup - $result = \OCP\Share::unshare('file', $info->getId(), \OCP\Share::SHARE_TYPE_USER, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); - - } - - public function datesProvider() { - $date = new \DateTime(); - $date->add(new \DateInterval('P5D')); - - return [ - [$date->format('Y-m-d'), true], - ['abc', false], - [$date->format('Y-m-d') . 'xyz', false], - ]; - } - - /** - * Make sure only ISO 8601 dates are accepted - * - * @dataProvider datesProvider - */ - public function testPublicLinkExpireDate($date, $valid) { - $request = $this->createRequest([ - 'path' => $this->folder, - 'shareType' => \OCP\Share::SHARE_TYPE_LINK, - 'expireDate' => $date, - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - - if ($valid === false) { - $this->assertFalse($result->succeeded()); - $this->assertEquals(404, $result->getStatusCode()); - $this->assertEquals('Invalid Date. Format must be YYYY-MM-DD.', $result->getMeta()['message']); - return; - } - - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertTrue(is_string($data['token'])); - $this->assertEquals($date, substr($data['expiration'], 0, 10)); - - // check for correct link - $url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']); - $this->assertEquals($url, $data['url']); - - $share = $this->shareManager->getShareById('ocinternal:'.$data['id']); - - $this->assertEquals($date, $share->getExpirationDate()->format('Y-m-d')); - - $this->shareManager->deleteShare($share); - } - - public function testCreatePublicLinkExpireDateValid() { - $config = \OC::$server->getConfig(); - - // enforce expire date, by default 7 days after the file was shared - $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); - - $date = new \DateTime(); - $date->add(new \DateInterval('P5D')); - - $request = $this->createRequest([ - 'path' => $this->folder, - 'shareType' => \OCP\Share::SHARE_TYPE_LINK, - 'expireDate' => $date->format('Y-m-d'), - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - - $data = $result->getData(); - $this->assertTrue(is_string($data['token'])); - $this->assertEquals($date->format('Y-m-d') . ' 00:00:00', $data['expiration']); - - // check for correct link - $url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']); - $this->assertEquals($url, $data['url']); - - $share = $this->shareManager->getShareById('ocinternal:'.$data['id']); - $date->setTime(0,0,0); - $this->assertEquals($date, $share->getExpirationDate()); - - $this->shareManager->deleteShare($share); - - $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); - } - - public function testCreatePublicLinkExpireDateInvalidFuture() { - $config = \OC::$server->getConfig(); - - // enforce expire date, by default 7 days after the file was shared - $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); - - $date = new \DateTime(); - $date->add(new \DateInterval('P8D')); - - $request = $this->createRequest([ - 'path' => $this->folder, - 'shareType' => \OCP\Share::SHARE_TYPE_LINK, - 'expireDate' => $date->format('Y-m-d'), - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertFalse($result->succeeded()); - $this->assertEquals(404, $result->getStatusCode()); - $this->assertEquals('Cannot set expiration date more than 7 days in the future', $result->getMeta()['message']); - - $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); - } - - public function testCreatePublicLinkExpireDateInvalidPast() { - $config = \OC::$server->getConfig(); - - $date = new \DateTime(); - $date->sub(new \DateInterval('P8D')); - - $request = $this->createRequest([ - 'path' => $this->folder, - 'shareType' => \OCP\Share::SHARE_TYPE_LINK, - 'expireDate' => $date->format('Y-m-d'), - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertFalse($result->succeeded()); - $this->assertEquals(404, $result->getStatusCode()); - $this->assertEquals('Expiration date is in the past', $result->getMeta()['message']); - - $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); - $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); - } - - /** - * test for no invisible shares - * See: https://github.com/owncloud/core/issues/22295 - */ - public function testInvisibleSharesUser() { - // simulate a post request - $request = $this->createRequest([ - 'path' => $this->folder, - 'shareWith' => self::TEST_FILES_SHARING_API_USER2, - 'shareType' => \OCP\Share::SHARE_TYPE_USER - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - - $topId = $data['id']; - - $request = $this->createRequest([ - 'path' => $this->folder . $this->subfolder, - 'shareType' => \OCP\Share::SHARE_TYPE_LINK, - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($topId); - $this->assertTrue($result->succeeded()); - - $request = $this->createRequest([ - 'reshares' => 'true', - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - $this->assertEmpty($result->getData()); - } - - /** - * test for no invisible shares - * See: https://github.com/owncloud/core/issues/22295 - */ - public function testInvisibleSharesGroup() { - // simulate a post request - $request = $this->createRequest([ - 'path' => $this->folder, - 'shareWith' => self::TEST_FILES_SHARING_API_GROUP1, - 'shareType' => \OCP\Share::SHARE_TYPE_GROUP - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - $data = $result->getData(); - - $topId = $data['id']; - - $request = $this->createRequest([ - 'path' => $this->folder . $this->subfolder, - 'shareType' => \OCP\Share::SHARE_TYPE_LINK, - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER2); - $result = $ocs->createShare(); - $this->assertTrue($result->succeeded()); - - $request = $this->createRequest([]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->deleteShare($topId); - $this->assertTrue($result->succeeded()); - - $request = $this->createRequest([ - 'reshares' => 'true', - ]); - $ocs = $this->createOCS($request, self::TEST_FILES_SHARING_API_USER1); - $result = $ocs->getShares(); - $this->assertTrue($result->succeeded()); - - $this->assertEmpty($result->getData()); - } -} diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php deleted file mode 100644 index 42a23b43ce1..00000000000 --- a/apps/files_sharing/tests/api/share20ocstest.php +++ /dev/null @@ -1,1952 +0,0 @@ -<?php -/** - * @author Roeland Jago Douma <rullzer@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\API; - -use OCA\Files_Sharing\API\Share20OCS; -use OCP\Files\NotFoundException; -use OCP\IGroupManager; -use OCP\IUserManager; -use OCP\IRequest; -use OCP\IURLGenerator; -use OCP\IUser; -use OCP\Files\IRootFolder; - -/** - * Class Share20OCSTest - * - * @package OCA\Files_Sharing\Tests\API - * @group DB - */ -class Share20OCSTest extends \Test\TestCase { - - /** @var \OC\Share20\Manager | \PHPUnit_Framework_MockObject_MockObject */ - private $shareManager; - - /** @var IGroupManager | \PHPUnit_Framework_MockObject_MockObject */ - private $groupManager; - - /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */ - private $userManager; - - /** @var IRequest | \PHPUnit_Framework_MockObject_MockObject */ - private $request; - - /** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */ - private $rootFolder; - - /** @var IURLGenerator */ - private $urlGenerator; - - /** @var IUser */ - private $currentUser; - - /** @var Share20OCS */ - private $ocs; - - protected function setUp() { - $this->shareManager = $this->getMockBuilder('OCP\Share\IManager') - ->disableOriginalConstructor() - ->getMock(); - $this->shareManager - ->expects($this->any()) - ->method('shareApiEnabled') - ->willReturn(true); - $this->groupManager = $this->getMock('OCP\IGroupManager'); - $this->userManager = $this->getMock('OCP\IUserManager'); - $this->request = $this->getMock('OCP\IRequest'); - $this->rootFolder = $this->getMock('OCP\Files\IRootFolder'); - $this->urlGenerator = $this->getMock('OCP\IURLGenerator'); - $this->currentUser = $this->getMock('OCP\IUser'); - $this->currentUser->method('getUID')->willReturn('currentUser'); - - $this->ocs = new Share20OCS( - $this->shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->rootFolder, - $this->urlGenerator, - $this->currentUser - ); - } - - private function mockFormatShare() { - return $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') - ->setConstructorArgs([ - $this->shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->rootFolder, - $this->urlGenerator, - $this->currentUser - ])->setMethods(['formatShare']) - ->getMock(); - } - - private function newShare() { - return \OC::$server->getShareManager()->newShare(); - } - - public function testDeleteShareShareNotFound() { - $this->shareManager - ->expects($this->exactly(2)) - ->method('getShareById') - ->will($this->returnCallback(function($id) { - if ($id === 'ocinternal:42' || $id === 'ocFederatedSharing:42') { - throw new \OCP\Share\Exceptions\ShareNotFound(); - } else { - throw new \Exception(); - } - })); - - $this->shareManager->method('outgoingServer2ServerSharesAllowed')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); - $this->assertEquals($expected, $this->ocs->deleteShare(42)); - } - - public function testDeleteShare() { - $share = $this->newShare(); - $share->setSharedBy($this->currentUser->getUID()); - $this->shareManager - ->expects($this->once()) - ->method('getShareById') - ->with('ocinternal:42') - ->willReturn($share); - $this->shareManager - ->expects($this->once()) - ->method('deleteShare') - ->with($share); - - $expected = new \OC_OCS_Result(); - $this->assertEquals($expected, $this->ocs->deleteShare(42)); - } - - /* - * FIXME: Enable once we have a federated Share Provider - - public function testGetGetShareNotExists() { - $this->shareManager - ->expects($this->once()) - ->method('getShareById') - ->with('ocinternal:42') - ->will($this->throwException(new \OC\Share20\Exception\ShareNotFound())); - - $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); - $this->assertEquals($expected, $this->ocs->getShare(42)); - } - */ - - public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner, $path, $permissions, - $shareTime, $expiration, $parent, $target, $mail_send, $token=null, - $password=null) { - $share = $this->getMock('\OCP\Share\IShare'); - $share->method('getId')->willReturn($id); - $share->method('getShareType')->willReturn($shareType); - $share->method('getSharedWith')->willReturn($sharedWith); - $share->method('getSharedBy')->willReturn($sharedBy); - $share->method('getShareOwner')->willReturn($shareOwner); - $share->method('getNode')->willReturn($path); - $share->method('getPermissions')->willReturn($permissions); - $time = new \DateTime(); - $time->setTimestamp($shareTime); - $share->method('getShareTime')->willReturn($time); - $share->method('getExpirationDate')->willReturn($expiration); - $share->method('getTarget')->willReturn($target); - $share->method('getMailSend')->willReturn($mail_send); - $share->method('getToken')->willReturn($token); - $share->method('getPassword')->willReturn($password); - - if ($shareType === \OCP\Share::SHARE_TYPE_USER || - $shareType === \OCP\Share::SHARE_TYPE_GROUP || - $shareType === \OCP\Share::SHARE_TYPE_LINK) { - $share->method('getFullId')->willReturn('ocinternal:'.$id); - } - - return $share; - } - - public function dataGetShare() { - $data = []; - - $cache = $this->getMockBuilder('OC\Files\Cache\Cache') - ->disableOriginalConstructor() - ->getMock(); - $cache->method('getNumericStorageId')->willReturn(101); - - $storage = $this->getMockBuilder('OC\Files\Storage\Storage') - ->disableOriginalConstructor() - ->getMock(); - $storage->method('getId')->willReturn('STORAGE'); - $storage->method('getCache')->willReturn($cache); - - $parentFolder = $this->getMock('OCP\Files\Folder'); - $parentFolder->method('getId')->willReturn(3); - - $file = $this->getMock('OCP\Files\File'); - $file->method('getId')->willReturn(1); - $file->method('getPath')->willReturn('file'); - $file->method('getStorage')->willReturn($storage); - $file->method('getParent')->willReturn($parentFolder); - $file->method('getMimeType')->willReturn('myMimeType'); - - $folder = $this->getMock('OCP\Files\Folder'); - $folder->method('getId')->willReturn(2); - $folder->method('getPath')->willReturn('folder'); - $folder->method('getStorage')->willReturn($storage); - $folder->method('getParent')->willReturn($parentFolder); - $folder->method('getMimeType')->willReturn('myFolderMimeType'); - - // File shared with user - $share = $this->createShare( - 100, - \OCP\Share::SHARE_TYPE_USER, - 'userId', - 'initiatorId', - 'ownerId', - $file, - 4, - 5, - null, - 6, - 'target', - 0 - ); - $expected = [ - 'id' => 100, - 'share_type' => \OCP\Share::SHARE_TYPE_USER, - 'share_with' => 'userId', - 'share_with_displayname' => 'userDisplay', - 'uid_owner' => 'initiatorId', - 'displayname_owner' => 'initiatorDisplay', - 'item_type' => 'file', - 'item_source' => 1, - 'file_source' => 1, - 'file_target' => 'target', - 'file_parent' => 3, - 'token' => null, - 'expiration' => null, - 'permissions' => 4, - 'stime' => 5, - 'parent' => null, - 'storage_id' => 'STORAGE', - 'path' => 'file', - 'storage' => 101, - 'mail_send' => 0, - 'uid_file_owner' => 'ownerId', - 'displayname_file_owner' => 'ownerDisplay', - 'mimetype' => 'myMimeType', - ]; - $data[] = [$share, $expected]; - - // Folder shared with group - $share = $this->createShare( - 101, - \OCP\Share::SHARE_TYPE_GROUP, - 'groupId', - 'initiatorId', - 'ownerId', - $folder, - 4, - 5, - null, - 6, - 'target', - 0 - ); - $expected = [ - 'id' => 101, - 'share_type' => \OCP\Share::SHARE_TYPE_GROUP, - 'share_with' => 'groupId', - 'share_with_displayname' => 'groupId', - 'uid_owner' => 'initiatorId', - 'displayname_owner' => 'initiatorDisplay', - 'item_type' => 'folder', - 'item_source' => 2, - 'file_source' => 2, - 'file_target' => 'target', - 'file_parent' => 3, - 'token' => null, - 'expiration' => null, - 'permissions' => 4, - 'stime' => 5, - 'parent' => null, - 'storage_id' => 'STORAGE', - 'path' => 'folder', - 'storage' => 101, - 'mail_send' => 0, - 'uid_file_owner' => 'ownerId', - 'displayname_file_owner' => 'ownerDisplay', - 'mimetype' => 'myFolderMimeType', - ]; - $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, - 'initiatorId', - 'ownerId', - $folder, - 4, - 5, - $expire, - 6, - 'target', - 0, - 'token', - 'password' - ); - $expected = [ - 'id' => 101, - 'share_type' => \OCP\Share::SHARE_TYPE_LINK, - 'share_with' => 'password', - 'share_with_displayname' => 'password', - 'uid_owner' => 'initiatorId', - 'displayname_owner' => 'initiatorDisplay', - 'item_type' => 'folder', - 'item_source' => 2, - 'file_source' => 2, - 'file_target' => 'target', - 'file_parent' => 3, - 'token' => 'token', - 'expiration' => '2000-01-02 00:00:00', - 'permissions' => 4, - 'stime' => 5, - 'parent' => null, - 'storage_id' => 'STORAGE', - 'path' => 'folder', - 'storage' => 101, - 'mail_send' => 0, - 'url' => 'url', - 'uid_file_owner' => 'ownerId', - 'displayname_file_owner' => 'ownerDisplay', - 'mimetype' => 'myFolderMimeType', - ]; - $data[] = [$share, $expected]; - - return $data; - } - - /** - * @dataProvider dataGetShare - */ - public function testGetShare(\OCP\Share\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->getFullId()) - ->willReturn($share); - - $userFolder = $this->getMock('OCP\Files\Folder'); - $userFolder - ->method('getRelativePath') - ->will($this->returnArgument(0)); - - $this->rootFolder->method('getUserFolder') - ->with($share->getShareOwner()) - ->willReturn($userFolder); - - $this->urlGenerator - ->method('linkToRouteAbsolute') - ->willReturn('url'); - - $initiator = $this->getMock('OCP\IUser'); - $initiator->method('getUID')->willReturn('initiatorId'); - $initiator->method('getDisplayName')->willReturn('initiatorDisplay'); - - $owner = $this->getMock('OCP\IUser'); - $owner->method('getUID')->willReturn('ownerId'); - $owner->method('getDisplayName')->willReturn('ownerDisplay'); - - $user = $this->getMock('OCP\IUser'); - $user->method('getUID')->willReturn('userId'); - $user->method('getDisplayName')->willReturn('userDisplay'); - - $group = $this->getMock('OCP\IGroup'); - $group->method('getGID')->willReturn('groupId'); - - $this->userManager->method('get')->will($this->returnValueMap([ - ['userId', $user], - ['initiatorId', $initiator], - ['ownerId', $owner], - ])); - $this->groupManager->method('get')->will($this->returnValueMap([ - ['group', $group], - ])); - - $expected = new \OC_OCS_Result([$result]); - $this->assertEquals($expected->getData(), $ocs->getShare($share->getId())->getData()); - } - - public function testGetShareInvalidNode() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setSharedBy('initiator') - ->setSharedWith('recipient') - ->setShareOwner('owner'); - - $this->shareManager - ->expects($this->once()) - ->method('getShareById') - ->with('ocinternal:42') - ->willReturn($share); - - $expected = new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); - $this->assertEquals($expected->getMeta(), $this->ocs->getShare(42)->getMeta()); - } - - public function testCanAccessShare() { - $share = $this->getMock('OCP\Share\IShare'); - $share->method('getShareOwner')->willReturn($this->currentUser->getUID()); - $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); - - $share = $this->getMock('OCP\Share\IShare'); - $share->method('getSharedBy')->willReturn($this->currentUser->getUID()); - $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); - - $share = $this->getMock('OCP\Share\IShare'); - $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER); - $share->method('getSharedWith')->willReturn($this->currentUser->getUID()); - $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); - - $share = $this->getMock('OCP\Share\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('OCP\Share\IShare'); - $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP); - $share->method('getSharedWith')->willReturn('group'); - - $group = $this->getMock('OCP\IGroup'); - $group->method('inGroup')->with($this->currentUser)->willReturn(true); - $group2 = $this->getMock('OCP\IGroup'); - $group2->method('inGroup')->with($this->currentUser)->willReturn(false); - - - $this->groupManager->method('get')->will($this->returnValueMap([ - ['group', $group], - ['group2', $group2], - ])); - $this->assertTrue($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); - - $share = $this->getMock('OCP\Share\IShare'); - $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP); - $share->method('getSharedWith')->willReturn('group2'); - - $this->groupManager->method('get')->with('group2')->willReturn($group); - $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); - - $share = $this->getMock('OCP\Share\IShare'); - $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK); - $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); - } - - public function testCreateShareNoPath() { - $expected = new \OC_OCS_Result(null, 404, 'please specify a file or folder path'); - - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareInvalidPath() { - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'invalid-path'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $userFolder->expects($this->once()) - ->method('get') - ->with('invalid-path') - ->will($this->throwException(new \OCP\Files\NotFoundException())); - - $expected = new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist'); - - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareInvalidPermissions() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, 32], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\File'); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $expected = new \OC_OCS_Result(null, 404, 'invalid permissions'); - - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareUserNoShareWith() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\File'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user'); - - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareUserNoValidShareWith() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], - ['shareWith', $this->any(), 'invalidUser'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\File'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user'); - - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareUser() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - $this->shareManager->method('createShare')->will($this->returnArgument(0)); - - $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') - ->setConstructorArgs([ - $this->shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->rootFolder, - $this->urlGenerator, - $this->currentUser - ])->setMethods(['formatShare']) - ->getMock(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], - ['shareWith', null, 'validUser'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\File'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $user = $this->getMock('\OCP\IUser'); - $this->userManager->method('userExists')->with('validUser')->willReturn(true); - - $share->method('setPath')->with($path); - $share->method('setPermissions') - ->with( - \OCP\Constants::PERMISSION_ALL & - ~\OCP\Constants::PERMISSION_DELETE & - ~\OCP\Constants::PERMISSION_CREATE); - $share->method('setShareType')->with(\OCP\Share::SHARE_TYPE_USER); - $share->method('setSharedWith')->with('validUser'); - $share->method('setSharedBy')->with('currentUser'); - - $expected = new \OC_OCS_Result(); - $result = $ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareGroupNoValidShareWith() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - $this->shareManager->method('createShare')->will($this->returnArgument(0)); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_GROUP], - ['shareWith', $this->any(), 'invalidGroup'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\File'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user'); - - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareGroup() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - $this->shareManager->method('createShare')->will($this->returnArgument(0)); - - $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') - ->setConstructorArgs([ - $this->shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->rootFolder, - $this->urlGenerator, - $this->currentUser - ])->setMethods(['formatShare']) - ->getMock(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_GROUP], - ['shareWith', null, 'validGroup'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true); - - $this->shareManager->expects($this->once()) - ->method('allowGroupSharing') - ->willReturn(true); - - $share->method('setPath')->with($path); - $share->method('setPermissions')->with(\OCP\Constants::PERMISSION_ALL); - $share->method('setShareType')->with(\OCP\Share::SHARE_TYPE_GROUP); - $share->method('setSharedWith')->with('validGroup'); - $share->method('setSharedBy')->with('currentUser'); - - $expected = new \OC_OCS_Result(); - $result = $ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareGroupNotAllowed() { - $share = $this->getMock('\OCP\Share\IShare'); - $this->shareManager->method('newShare')->willReturn($share); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_GROUP], - ['shareWith', null, 'validGroup'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true); - - $this->shareManager->expects($this->once()) - ->method('allowGroupSharing') - ->willReturn(false); - - $share->method('setPath')->with($path); - - $expected = new \OC_OCS_Result(null, 404, 'group sharing is disabled by the administrator'); - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareLinkNoLinksAllowed() { - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ])); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - - $expected = new \OC_OCS_Result(null, 404, 'public link sharing is disabled by the administrator'); - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareLinkNoPublicUpload() { - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ['publicUpload', null, 'true'], - ])); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - $this->shareManager->method('shareApiAllowLinks')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator'); - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareLinkPublicUploadFile() { - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ['publicUpload', null, 'true'], - ])); - - $path = $this->getMock('\OCP\Files\File'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - $this->shareManager->method('shareApiAllowLinks')->willReturn(true); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 404, 'public upload is only possible for public shared folders'); - $result = $this->ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareLinkPublicUploadFolder() { - $ocs = $this->mockFormatShare(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ['publicUpload', null, 'true'], - ['expireDate', '', ''], - ['password', '', ''], - ])); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - $this->shareManager->method('shareApiAllowLinks')->willReturn(true); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('createShare')->with( - $this->callback(function (\OCP\Share\IShare $share) use ($path) { - return $share->getNode() === $path && - $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK && - $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE && - $share->getSharedBy() === 'currentUser' && - $share->getPassword() === null && - $share->getExpirationDate() === null; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareLinkPassword() { - $ocs = $this->mockFormatShare(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ['publicUpload', null, 'false'], - ['expireDate', '', ''], - ['password', '', 'password'], - ])); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - $this->shareManager->method('shareApiAllowLinks')->willReturn(true); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('createShare')->with( - $this->callback(function (\OCP\Share\IShare $share) use ($path) { - return $share->getNode() === $path && - $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK && - $share->getPermissions() === \OCP\Constants::PERMISSION_READ && - $share->getSharedBy() === 'currentUser' && - $share->getPassword() === 'password' && - $share->getExpirationDate() === null; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareValidExpireDate() { - $ocs = $this->mockFormatShare(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ['publicUpload', null, 'false'], - ['expireDate', '', '2000-01-01'], - ['password', '', ''], - ])); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - $this->shareManager->method('shareApiAllowLinks')->willReturn(true); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('createShare')->with( - $this->callback(function (\OCP\Share\IShare $share) use ($path) { - $date = new \DateTime('2000-01-01'); - $date->setTime(0,0,0); - - return $share->getNode() === $path && - $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK && - $share->getPermissions() === \OCP\Constants::PERMISSION_READ && - $share->getSharedBy() === 'currentUser' && - $share->getPassword() === null && - $share->getExpirationDate() == $date; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testCreateShareInvalidExpireDate() { - $ocs = $this->mockFormatShare(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['shareType', '-1', \OCP\Share::SHARE_TYPE_LINK], - ['publicUpload', null, 'false'], - ['expireDate', '', 'a1b2d3'], - ['password', '', ''], - ])); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $path->method('getStorage')->willReturn($storage); - $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); - $this->rootFolder->method('get')->with('valid-path')->willReturn($path); - - $this->shareManager->method('newShare')->willReturn(\OC::$server->getShareManager()->newShare()); - $this->shareManager->method('shareApiAllowLinks')->willReturn(true); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 404, 'Invalid Date. Format must be YYYY-MM-DD.'); - $result = $ocs->createShare(); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - /** - * Test for https://github.com/owncloud/core/issues/22587 - * TODO: Remove once proper solution is in place - */ - public function testCreateReshareOfFederatedMountNoDeletePermissions() { - $share = \OC::$server->getShareManager()->newShare(); - $this->shareManager->method('newShare')->willReturn($share); - - $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') - ->setConstructorArgs([ - $this->shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->rootFolder, - $this->urlGenerator, - $this->currentUser - ])->setMethods(['formatShare']) - ->getMock(); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['path', null, 'valid-path'], - ['permissions', null, \OCP\Constants::PERMISSION_ALL], - ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], - ['shareWith', null, 'validUser'], - ])); - - $userFolder = $this->getMock('\OCP\Files\Folder'); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('currentUser') - ->willReturn($userFolder); - - $path = $this->getMock('\OCP\Files\Folder'); - $storage = $this->getMock('OCP\Files\Storage'); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(true); - $path->method('getStorage')->willReturn($storage); - $path->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); - $userFolder->expects($this->once()) - ->method('get') - ->with('valid-path') - ->willReturn($path); - - $this->userManager->method('userExists')->with('validUser')->willReturn(true); - - $this->shareManager - ->expects($this->once()) - ->method('createShare') - ->with($this->callback(function (\OCP\Share\IShare $share) { - return $share->getPermissions() === \OCP\Constants::PERMISSION_READ; - })) - ->will($this->returnArgument(0)); - - $ocs->createShare(); - } - - public function testUpdateShareCantAccess() { - $share = \OC::$server->getShareManager()->newShare(); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - - $expected = new \OC_OCS_Result(null, 404, 'wrong share Id, share doesn\'t exist.'); - $result = $this->ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateNoParametersLink() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - - $expected = new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given'); - $result = $this->ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateNoParametersOther() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_GROUP); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - - $expected = new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given'); - $result = $this->ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkShareClear() { - $ocs = $this->mockFormatShare(); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPassword('password') - ->setExpirationDate(new \DateTime()) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['publicUpload', null, 'false'], - ['expireDate', null, ''], - ['password', null, ''], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) { - return $share->getPermissions() === \OCP\Constants::PERMISSION_READ && - $share->getPassword() === null && - $share->getExpirationDate() === null; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkShareSet() { - $ocs = $this->mockFormatShare(); - - $folder = $this->getMock('\OCP\Files\Folder'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setNode($folder); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['publicUpload', null, 'true'], - ['expireDate', null, '2000-01-01'], - ['password', null, 'password'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) { - $date = new \DateTime('2000-01-01'); - $date->setTime(0,0,0); - - return $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE && \OCP\Constants::PERMISSION_DELETE && - $share->getPassword() === 'password' && - $share->getExpirationDate() == $date; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkShareInvalidDate() { - $ocs = $this->mockFormatShare(); - - $folder = $this->getMock('\OCP\Files\Folder'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setNode($folder); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['publicUpload', null, 'true'], - ['expireDate', null, '2000-01-a'], - ['password', null, 'password'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 400, 'Invalid date. Format must be YYYY-MM-DD'); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkSharePublicUploadNotAllowed() { - $ocs = $this->mockFormatShare(); - - $folder = $this->getMock('\OCP\Files\Folder'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setNode($folder); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['publicUpload', null, 'true'], - ['expireDate', '', null], - ['password', '', 'password'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(false); - - $expected = new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator'); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkSharePublicUploadOnFile() { - $ocs = $this->mockFormatShare(); - - $file = $this->getMock('\OCP\Files\File'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setNode($file); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['publicUpload', null, 'true'], - ['expireDate', '', ''], - ['password', '', 'password'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 400, 'public upload is only possible for public shared folders'); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkSharePasswordDoesNotChangeOther() { - $ocs = $this->mockFormatShare(); - - $date = new \DateTime('2000-01-01'); - $date->setTime(0,0,0); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPassword('password') - ->setExpirationDate($date) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['password', null, 'newpassword'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) use ($date) { - return $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && - $share->getPassword() === 'newpassword' && - $share->getExpirationDate() === $date; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkShareExpireDateDoesNotChangeOther() { - $ocs = $this->mockFormatShare(); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPassword('password') - ->setExpirationDate(new \DateTime()) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['expireDate', null, '2010-12-23'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) { - $date = new \DateTime('2010-12-23'); - $date->setTime(0,0,0); - - return $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && - $share->getPassword() === 'password' && - $share->getExpirationDate() == $date; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkSharePublicUploadDoesNotChangeOther() { - $ocs = $this->mockFormatShare(); - - $date = new \DateTime('2000-01-01'); - - $folder = $this->getMock('\OCP\Files\Folder'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPassword('password') - ->setExpirationDate($date) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setNode($folder); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['publicUpload', null, 'true'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) use ($date) { - return $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE && - $share->getPassword() === 'password' && - $share->getExpirationDate() === $date; - }) - )->will($this->returnArgument(0)); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkSharePermissions() { - $ocs = $this->mockFormatShare(); - - $date = new \DateTime('2000-01-01'); - - $folder = $this->getMock('\OCP\Files\Folder'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPassword('password') - ->setExpirationDate($date) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setNode($folder); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['permissions', null, '7'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) use ($date) { - return $share->getPermissions() === \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE && - $share->getPassword() === 'password' && - $share->getExpirationDate() === $date; - }) - )->will($this->returnArgument(0)); - - $this->shareManager->method('getSharedWith')->willReturn([]); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateLinkShareInvalidPermissions() { - $ocs = $this->mockFormatShare(); - - $date = new \DateTime('2000-01-01'); - - $folder = $this->getMock('\OCP\Files\Folder'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setPassword('password') - ->setExpirationDate($date) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setNode($folder); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['permissions', null, '31'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $expected = new \OC_OCS_Result(null, 400, 'can\'t change permission for public link share'); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function testUpdateOtherPermissions() { - $ocs = $this->mockFormatShare(); - - $file = $this->getMock('\OCP\Files\File'); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setSharedBy($this->currentUser->getUID()) - ->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setNode($file); - - $this->request - ->method('getParam') - ->will($this->returnValueMap([ - ['permissions', null, '31'], - ])); - - $this->shareManager->method('getShareById')->with('ocinternal:42')->willReturn($share); - $this->shareManager->method('shareApiLinkAllowPublicUpload')->willReturn(true); - - $this->shareManager->expects($this->once())->method('updateShare')->with( - $this->callback(function (\OCP\Share\IShare $share) { - return $share->getPermissions() === \OCP\Constants::PERMISSION_ALL; - }) - )->will($this->returnArgument(0)); - - $this->shareManager->method('getSharedWith')->willReturn([]); - - $expected = new \OC_OCS_Result(null); - $result = $ocs->updateShare(42); - - $this->assertEquals($expected->getMeta(), $result->getMeta()); - $this->assertEquals($expected->getData(), $result->getData()); - } - - public function dataFormatShare() { - $file = $this->getMock('\OCP\Files\File'); - $folder = $this->getMock('\OCP\Files\Folder'); - $parent = $this->getMock('\OCP\Files\Folder'); - - $file->method('getMimeType')->willReturn('myMimeType'); - $folder->method('getMimeType')->willReturn('myFolderMimeType'); - - $file->method('getPath')->willReturn('file'); - $folder->method('getPath')->willReturn('folder'); - - $parent->method('getId')->willReturn(1); - $folder->method('getId')->willReturn(2); - $file->method('getId')->willReturn(3); - - $file->method('getParent')->willReturn($parent); - $folder->method('getParent')->willReturn($parent); - - $cache = $this->getMock('OCP\Files\Cache\ICache'); - $cache->method('getNumericStorageId')->willReturn(100); - $storage = $this->getMock('\OCP\Files\Storage'); - $storage->method('getId')->willReturn('storageId'); - $storage->method('getCache')->willReturn($cache); - - $file->method('getStorage')->willReturn($storage); - $folder->method('getStorage')->willReturn($storage); - - $owner = $this->getMock('\OCP\IUser'); - $owner->method('getDisplayName')->willReturn('ownerDN'); - $initiator = $this->getMock('\OCP\IUser'); - $initiator->method('getDisplayName')->willReturn('initiatorDN'); - $recipient = $this->getMock('\OCP\IUser'); - $recipient->method('getDisplayName')->willReturn('recipientDN'); - - $result = []; - - $share = \OC::$server->getShareManager()->newShare(); - $share->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setSharedWith('recipient') - ->setSharedBy('initiator') - ->setShareOwner('owner') - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setNode($file) - ->setShareTime(new \DateTime('2000-01-01T00:01:02')) - ->setTarget('myTarget') - ->setId(42); - - /* User backend down */ - $result[] = [ - [ - 'id' => 42, - 'share_type' => \OCP\Share::SHARE_TYPE_USER, - 'uid_owner' => 'initiator', - 'displayname_owner' => 'initiator', - 'permissions' => 1, - 'stime' => 946684862, - 'parent' => null, - 'expiration' => null, - 'token' => null, - 'uid_file_owner' => 'owner', - 'displayname_file_owner' => 'owner', - 'path' => 'file', - 'item_type' => 'file', - 'storage_id' => 'storageId', - 'storage' => 100, - 'item_source' => 3, - 'file_source' => 3, - 'file_parent' => 1, - 'file_target' => 'myTarget', - 'share_with' => 'recipient', - 'share_with_displayname' => 'recipient', - 'mail_send' => 0, - 'mimetype' => 'myMimeType', - ], $share, [], false - ]; - - /* User backend up */ - $result[] = [ - [ - 'id' => 42, - 'share_type' => \OCP\Share::SHARE_TYPE_USER, - 'uid_owner' => 'initiator', - 'displayname_owner' => 'initiatorDN', - 'permissions' => 1, - 'stime' => 946684862, - 'parent' => null, - 'expiration' => null, - 'token' => null, - 'uid_file_owner' => 'owner', - 'displayname_file_owner' => 'ownerDN', - 'path' => 'file', - 'item_type' => 'file', - 'storage_id' => 'storageId', - 'storage' => 100, - 'item_source' => 3, - 'file_source' => 3, - 'file_parent' => 1, - 'file_target' => 'myTarget', - 'share_with' => 'recipient', - 'share_with_displayname' => 'recipientDN', - 'mail_send' => 0, - 'mimetype' => 'myMimeType', - ], $share, [ - ['owner', $owner], - ['initiator', $initiator], - ['recipient', $recipient], - ], false - ]; - - $share = \OC::$server->getShareManager()->newShare(); - $share->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setSharedWith('recipient') - ->setSharedBy('initiator') - ->setShareOwner('owner') - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setNode($file) - ->setShareTime(new \DateTime('2000-01-01T00:01:02')) - ->setTarget('myTarget') - ->setId(42); - - /* User backend down */ - $result[] = [ - [ - 'id' => 42, - 'share_type' => \OCP\Share::SHARE_TYPE_USER, - 'uid_owner' => 'initiator', - 'displayname_owner' => 'initiator', - 'permissions' => 1, - 'stime' => 946684862, - 'parent' => null, - 'expiration' => null, - 'token' => null, - 'uid_file_owner' => 'owner', - 'displayname_file_owner' => 'owner', - 'path' => 'file', - 'item_type' => 'file', - 'storage_id' => 'storageId', - 'storage' => 100, - 'item_source' => 3, - 'file_source' => 3, - 'file_parent' => 1, - 'file_target' => 'myTarget', - 'share_with' => 'recipient', - 'share_with_displayname' => 'recipient', - 'mail_send' => 0, - 'mimetype' => 'myMimeType', - ], $share, [], false - ]; - - $share = \OC::$server->getShareManager()->newShare(); - $share->setShareType(\OCP\Share::SHARE_TYPE_GROUP) - ->setSharedWith('recipient') - ->setSharedBy('initiator') - ->setShareOwner('owner') - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setNode($file) - ->setShareTime(new \DateTime('2000-01-01T00:01:02')) - ->setTarget('myTarget') - ->setId(42); - - $result[] = [ - [ - 'id' => 42, - 'share_type' => \OCP\Share::SHARE_TYPE_GROUP, - 'uid_owner' => 'initiator', - 'displayname_owner' => 'initiator', - 'permissions' => 1, - 'stime' => 946684862, - 'parent' => null, - 'expiration' => null, - 'token' => null, - 'uid_file_owner' => 'owner', - 'displayname_file_owner' => 'owner', - 'path' => 'file', - 'item_type' => 'file', - 'storage_id' => 'storageId', - 'storage' => 100, - 'item_source' => 3, - 'file_source' => 3, - 'file_parent' => 1, - 'file_target' => 'myTarget', - 'share_with' => 'recipient', - 'share_with_displayname' => 'recipient', - 'mail_send' => 0, - 'mimetype' => 'myMimeType', - ], $share, [], false - ]; - - $share = \OC::$server->getShareManager()->newShare(); - $share->setShareType(\OCP\Share::SHARE_TYPE_LINK) - ->setSharedBy('initiator') - ->setShareOwner('owner') - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setNode($file) - ->setShareTime(new \DateTime('2000-01-01T00:01:02')) - ->setTarget('myTarget') - ->setPassword('mypassword') - ->setExpirationDate(new \DateTime('2001-01-02T00:00:00')) - ->setToken('myToken') - ->setId(42); - - $result[] = [ - [ - 'id' => 42, - 'share_type' => \OCP\Share::SHARE_TYPE_LINK, - 'uid_owner' => 'initiator', - 'displayname_owner' => 'initiator', - 'permissions' => 1, - 'stime' => 946684862, - 'parent' => null, - 'expiration' => '2001-01-02 00:00:00', - 'token' => 'myToken', - 'uid_file_owner' => 'owner', - 'displayname_file_owner' => 'owner', - 'path' => 'file', - 'item_type' => 'file', - 'storage_id' => 'storageId', - 'storage' => 100, - 'item_source' => 3, - 'file_source' => 3, - 'file_parent' => 1, - 'file_target' => 'myTarget', - 'share_with' => 'mypassword', - 'share_with_displayname' => 'mypassword', - 'mail_send' => 0, - 'url' => 'myLink', - 'mimetype' => 'myMimeType', - ], $share, [], false - ]; - - $share = \OC::$server->getShareManager()->newShare(); - $share->setShareType(\OCP\Share::SHARE_TYPE_REMOTE) - ->setSharedBy('initiator') - ->setSharedWith('user@server.com') - ->setShareOwner('owner') - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setNode($folder) - ->setShareTime(new \DateTime('2000-01-01T00:01:02')) - ->setTarget('myTarget') - ->setId(42); - - $result[] = [ - [ - 'id' => 42, - 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE, - 'uid_owner' => 'initiator', - 'displayname_owner' => 'initiator', - 'permissions' => 1, - 'stime' => 946684862, - 'parent' => null, - 'expiration' => null, - 'token' => null, - 'uid_file_owner' => 'owner', - 'displayname_file_owner' => 'owner', - 'path' => 'folder', - 'item_type' => 'folder', - 'storage_id' => 'storageId', - 'storage' => 100, - 'item_source' => 2, - 'file_source' => 2, - 'file_parent' => 1, - 'file_target' => 'myTarget', - 'share_with' => 'user@server.com', - 'share_with_displayname' => 'user@server.com', - 'mail_send' => 0, - 'mimetype' => 'myFolderMimeType', - ], $share, [], false - ]; - - $share = \OC::$server->getShareManager()->newShare(); - $share->setShareType(\OCP\Share::SHARE_TYPE_USER) - ->setSharedBy('initiator') - ->setSharedWith('recipient') - ->setShareOwner('owner') - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setShareTime(new \DateTime('2000-01-01T00:01:02')) - ->setTarget('myTarget') - ->setId(42); - - $result[] = [ - [], $share, [], true - ]; - - - - return $result; - } - - /** - * @dataProvider dataFormatShare - * - * @param array $expects - * @param \OCP\Share\IShare $share - * @param array $users - * @param $exception - */ - public function testFormatShare(array $expects, \OCP\Share\IShare $share, array $users, $exception) { - $this->userManager->method('get')->will($this->returnValueMap($users)); - $this->urlGenerator->method('linkToRouteAbsolute') - ->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken']) - ->willReturn('myLink'); - - - $this->rootFolder->method('getUserFolder')->with($share->getShareOwner())->will($this->returnSelf()); - $this->rootFolder->method('getRelativePath')->will($this->returnArgument(0)); - - try { - $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]); - $this->assertFalse($exception); - $this->assertEquals($expects, $result); - } catch (NotFoundException $e) { - $this->assertTrue($exception); - } - } - - /** - * @return Share20OCS - */ - public function getOcsDisabledAPI() { - $shareManager = $this->getMockBuilder('OCP\Share\IManager') - ->disableOriginalConstructor() - ->getMock(); - $shareManager - ->expects($this->any()) - ->method('shareApiEnabled') - ->willReturn(false); - - return new Share20OCS( - $shareManager, - $this->groupManager, - $this->userManager, - $this->request, - $this->rootFolder, - $this->urlGenerator, - $this->currentUser - ); - } - - public function testGetShareApiDisabled() { - $ocs = $this->getOcsDisabledAPI(); - - $expected = new \OC_OCS_Result(null, 404, 'Share API is disabled'); - $result = $ocs->getShare('my:id'); - - $this->assertEquals($expected, $result); - } - - public function testDeleteShareApiDisabled() { - $ocs = $this->getOcsDisabledAPI(); - - $expected = new \OC_OCS_Result(null, 404, 'Share API is disabled'); - $result = $ocs->deleteShare('my:id'); - - $this->assertEquals($expected, $result); - } - - - public function testCreateShareApiDisabled() { - $ocs = $this->getOcsDisabledAPI(); - - $expected = new \OC_OCS_Result(null, 404, 'Share API is disabled'); - $result = $ocs->createShare(); - - $this->assertEquals($expected, $result); - } - - public function testGetSharesApiDisabled() { - $ocs = $this->getOcsDisabledAPI(); - - $expected = new \OC_OCS_Result(); - $result = $ocs->getShares(); - - $this->assertEquals($expected, $result); - } - - public function testUpdateShareApiDisabled() { - $ocs = $this->getOcsDisabledAPI(); - - $expected = new \OC_OCS_Result(null, 404, 'Share API is disabled'); - $result = $ocs->updateShare('my:id'); - - $this->assertEquals($expected, $result); - } -} diff --git a/apps/files_sharing/tests/api/shareestest.php b/apps/files_sharing/tests/api/shareestest.php deleted file mode 100644 index cda41f55183..00000000000 --- a/apps/files_sharing/tests/api/shareestest.php +++ /dev/null @@ -1,1553 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\API; - -use OCA\Files_Sharing\API\Sharees; -use OCA\Files_sharing\Tests\TestCase; -use OCP\AppFramework\Http; -use OCP\Share; - -/** - * Class ShareesTest - * - * @group DB - * - * @package OCA\Files_Sharing\Tests\API - */ -class ShareesTest extends TestCase { - /** @var Sharees */ - protected $sharees; - - /** @var \OCP\IUserManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $userManager; - - /** @var \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $groupManager; - - /** @var \OCP\Contacts\IManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $contactsManager; - - /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject */ - protected $session; - - /** @var \OCP\IRequest|\PHPUnit_Framework_MockObject_MockObject */ - protected $request; - - /** @var \OCP\Share\IManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $shareManager; - - protected function setUp() { - parent::setUp(); - - $this->userManager = $this->getMockBuilder('OCP\IUserManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->groupManager = $this->getMockBuilder('OCP\IGroupManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->contactsManager = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->session = $this->getMockBuilder('OCP\IUserSession') - ->disableOriginalConstructor() - ->getMock(); - - $this->request = $this->getMockBuilder('OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - - $this->shareManager = $this->getMockBuilder('OCP\Share\IManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->sharees = new Sharees( - $this->groupManager, - $this->userManager, - $this->contactsManager, - $this->getMockBuilder('OCP\IConfig')->disableOriginalConstructor()->getMock(), - $this->session, - $this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(), - $this->request, - $this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(), - $this->shareManager - ); - } - - /** - * @param string $uid - * @param string $displayName - * @return \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject - */ - protected function getUserMock($uid, $displayName) { - $user = $this->getMockBuilder('OCP\IUser') - ->disableOriginalConstructor() - ->getMock(); - - $user->expects($this->any()) - ->method('getUID') - ->willReturn($uid); - - $user->expects($this->any()) - ->method('getDisplayName') - ->willReturn($displayName); - - return $user; - } - - /** - * @param string $gid - * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject - */ - protected function getGroupMock($gid) { - $group = $this->getMockBuilder('OCP\IGroup') - ->disableOriginalConstructor() - ->getMock(); - - $group->expects($this->any()) - ->method('getGID') - ->willReturn($gid); - - return $group; - } - - public function dataGetUsers() { - return [ - ['test', false, true, [], [], [], [], true, false], - ['test', false, false, [], [], [], [], true, false], - ['test', true, true, [], [], [], [], true, false], - ['test', true, false, [], [], [], [], true, false], - [ - 'test', false, true, [], [], - [ - ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']], - ], [], true, $this->getUserMock('test', 'Test') - ], - [ - 'test', false, false, [], [], - [ - ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']], - ], [], true, $this->getUserMock('test', 'Test') - ], - [ - 'test', true, true, [], [], - [], [], true, $this->getUserMock('test', 'Test') - ], - [ - 'test', true, false, [], [], - [], [], true, $this->getUserMock('test', 'Test') - ], - [ - 'test', true, true, ['test-group'], [['test-group', 'test', 2, 0, []]], - [ - ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']], - ], [], true, $this->getUserMock('test', 'Test') - ], - [ - 'test', true, false, ['test-group'], [['test-group', 'test', 2, 0, []]], - [ - ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']], - ], [], true, $this->getUserMock('test', 'Test') - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test1', 'Test One'), - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], - true, - false, - ], - [ - 'test', - false, - false, - [], - [ - $this->getUserMock('test1', 'Test One'), - ], - [], - [], - true, - false, - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], - ], - false, - false, - ], - [ - 'test', - false, - false, - [], - [ - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [], - [], - true, - false, - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test0', 'Test'), - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [ - ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test0']], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], - ], - false, - false, - ], - [ - 'test', - false, - false, - [], - [ - $this->getUserMock('test0', 'Test'), - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [ - ['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test0']], - ], - [], - true, - false, - ], - [ - 'test', - true, - true, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, ['test1' => 'Test One']], - ['xyz', 'test', 2, 0, []], - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], - true, - false, - ], - [ - 'test', - true, - false, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, ['test1' => 'Test One']], - ['xyz', 'test', 2, 0, []], - ], - [], - [], - true, - false, - ], - [ - 'test', - true, - true, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ['xyz', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], - ], - false, - false, - ], - [ - 'test', - true, - false, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ['xyz', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ], - [], - [], - true, - false, - ], - [ - 'test', - true, - true, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test' => 'Test One', - ]], - ['xyz', 'test', 2, 0, [ - 'test2' => 'Test Two', - ]], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']], - ], - [ - ['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], - ], - false, - false, - ], - [ - 'test', - true, - false, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test' => 'Test One', - ]], - ['xyz', 'test', 2, 0, [ - 'test2' => 'Test Two', - ]], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']], - ], - [], - true, - false, - ], - ]; - } - - /** - * @dataProvider dataGetUsers - * - * @param string $searchTerm - * @param bool $shareWithGroupOnly - * @param bool $shareeEnumeration - * @param array $groupResponse - * @param array $userResponse - * @param array $exactExpected - * @param array $expected - * @param bool $reachedEnd - * @param mixed $singleUser - */ - public function testGetUsers($searchTerm, $shareWithGroupOnly, $shareeEnumeration, $groupResponse, $userResponse, $exactExpected, $expected, $reachedEnd, $singleUser) { - $this->invokePrivate($this->sharees, 'limit', [2]); - $this->invokePrivate($this->sharees, 'offset', [0]); - $this->invokePrivate($this->sharees, 'shareWithGroupOnly', [$shareWithGroupOnly]); - $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]); - - $user = $this->getUserMock('admin', 'Administrator'); - $this->session->expects($this->any()) - ->method('getUser') - ->willReturn($user); - - if (!$shareWithGroupOnly) { - $this->userManager->expects($this->once()) - ->method('searchDisplayName') - ->with($searchTerm, $this->invokePrivate($this->sharees, 'limit'), $this->invokePrivate($this->sharees, 'offset')) - ->willReturn($userResponse); - } else { - if ($singleUser !== false) { - $this->groupManager->expects($this->exactly(2)) - ->method('getUserGroupIds') - ->withConsecutive( - $user, - $singleUser - ) - ->willReturn($groupResponse); - } else { - $this->groupManager->expects($this->once()) - ->method('getUserGroupIds') - ->with($user) - ->willReturn($groupResponse); - } - - $this->groupManager->expects($this->exactly(sizeof($groupResponse))) - ->method('displayNamesInGroup') - ->with($this->anything(), $searchTerm, $this->invokePrivate($this->sharees, 'limit'), $this->invokePrivate($this->sharees, 'offset')) - ->willReturnMap($userResponse); - } - - if ($singleUser !== false) { - $this->userManager->expects($this->once()) - ->method('get') - ->with($searchTerm) - ->willReturn($singleUser); - } - - $this->invokePrivate($this->sharees, 'getUsers', [$searchTerm]); - $result = $this->invokePrivate($this->sharees, 'result'); - - $this->assertEquals($exactExpected, $result['exact']['users']); - $this->assertEquals($expected, $result['users']); - $this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor')); - } - - public function dataGetGroups() { - return [ - ['test', false, true, [], [], [], [], true, false], - ['test', false, false, [], [], [], [], true, false], - [ - 'test', false, true, - [$this->getGroupMock('test1')], - [], - [], - [['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]], - true, - false, - ], - [ - 'test', false, false, - [$this->getGroupMock('test1')], - [], - [], - [], - true, - false, - ], - [ - 'test', false, true, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [], - [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]], - [['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]], - false, - false, - ], - [ - 'test', false, false, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [], - [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]], - [], - true, - false, - ], - [ - 'test', false, true, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [], - [], - [ - ['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']], - ['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']], - ], - false, - null, - ], - [ - 'test', false, false, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [], - [], - [], - true, - null, - ], - [ - 'test', false, true, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [], - [ - ['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']], - ], - [ - ['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']], - ['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']], - ], - false, - $this->getGroupMock('test'), - ], - [ - 'test', false, false, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [], - [ - ['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']], - ], - [], - true, - $this->getGroupMock('test'), - ], - ['test', true, true, [], [], [], [], true, false], - ['test', true, false, [], [], [], [], true, false], - [ - 'test', true, true, - [ - $this->getGroupMock('test1'), - $this->getGroupMock('test2'), - ], - [$this->getGroupMock('test1')], - [], - [['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]], - false, - false, - ], - [ - 'test', true, false, - [ - $this->getGroupMock('test1'), - $this->getGroupMock('test2'), - ], - [$this->getGroupMock('test1')], - [], - [], - true, - false, - ], - [ - 'test', true, true, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test')], - [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]], - [], - false, - false, - ], - [ - 'test', true, false, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test')], - [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]], - [], - true, - false, - ], - [ - 'test', true, true, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test1')], - [], - [['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]], - false, - false, - ], - [ - 'test', true, false, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test1')], - [], - [], - true, - false, - ], - [ - 'test', true, true, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')], - [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]], - [['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]], - false, - false, - ], - [ - 'test', true, false, - [ - $this->getGroupMock('test'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')], - [['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]], - [], - true, - false, - ], - [ - 'test', true, true, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')], - [], - [ - ['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']], - ['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']], - ], - false, - null, - ], - [ - 'test', true, false, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')], - [], - [], - true, - null, - ], - [ - 'test', true, true, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')], - [ - ['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']], - ], - [ - ['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']], - ['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']], - ], - false, - $this->getGroupMock('test'), - ], - [ - 'test', true, false, - [ - $this->getGroupMock('test0'), - $this->getGroupMock('test1'), - ], - [$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')], - [ - ['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']], - ], - [], - true, - $this->getGroupMock('test'), - ], - ]; - } - - /** - * @dataProvider dataGetGroups - * - * @param string $searchTerm - * @param bool $shareWithGroupOnly - * @param bool $shareeEnumeration - * @param array $groupResponse - * @param array $userGroupsResponse - * @param array $exactExpected - * @param array $expected - * @param bool $reachedEnd - * @param mixed $singleGroup - */ - public function testGetGroups($searchTerm, $shareWithGroupOnly, $shareeEnumeration, $groupResponse, $userGroupsResponse, $exactExpected, $expected, $reachedEnd, $singleGroup) { - $this->invokePrivate($this->sharees, 'limit', [2]); - $this->invokePrivate($this->sharees, 'offset', [0]); - $this->invokePrivate($this->sharees, 'shareWithGroupOnly', [$shareWithGroupOnly]); - $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]); - - $this->groupManager->expects($this->once()) - ->method('search') - ->with($searchTerm, $this->invokePrivate($this->sharees, 'limit'), $this->invokePrivate($this->sharees, 'offset')) - ->willReturn($groupResponse); - - if ($singleGroup !== false) { - $this->groupManager->expects($this->once()) - ->method('get') - ->with($searchTerm) - ->willReturn($singleGroup); - } - - if ($shareWithGroupOnly) { - $user = $this->getUserMock('admin', 'Administrator'); - $this->session->expects($this->any()) - ->method('getUser') - ->willReturn($user); - - $numGetUserGroupsCalls = empty($groupResponse) ? 0 : 1; - $this->groupManager->expects($this->exactly($numGetUserGroupsCalls)) - ->method('getUserGroups') - ->with($user) - ->willReturn($userGroupsResponse); - } - - $this->invokePrivate($this->sharees, 'getGroups', [$searchTerm]); - $result = $this->invokePrivate($this->sharees, 'result'); - - $this->assertEquals($exactExpected, $result['exact']['groups']); - $this->assertEquals($expected, $result['groups']); - $this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor')); - } - - public function dataGetRemote() { - return [ - ['test', [], true, [], [], true], - ['test', [], false, [], [], true], - [ - 'test@remote', - [], - true, - [ - ['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']], - ], - [], - true, - ], - [ - 'test@remote', - [], - false, - [ - ['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']], - ], - [], - true, - ], - [ - 'test', - [ - [ - 'FN' => 'User3 @ Localhost', - ], - [ - 'FN' => 'User2 @ Localhost', - 'CLOUD' => [ - ], - ], - [ - 'FN' => 'User @ Localhost', - 'CLOUD' => [ - 'username@localhost', - ], - ], - ], - true, - [], - [ - ['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']], - ], - true, - ], - [ - 'test', - [ - [ - 'FN' => 'User3 @ Localhost', - ], - [ - 'FN' => 'User2 @ Localhost', - 'CLOUD' => [ - ], - ], - [ - 'FN' => 'User @ Localhost', - 'CLOUD' => [ - 'username@localhost', - ], - ], - ], - false, - [], - [], - true, - ], - [ - 'test@remote', - [ - [ - 'FN' => 'User3 @ Localhost', - ], - [ - 'FN' => 'User2 @ Localhost', - 'CLOUD' => [ - ], - ], - [ - 'FN' => 'User @ Localhost', - 'CLOUD' => [ - 'username@localhost', - ], - ], - ], - true, - [ - ['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']], - ], - [ - ['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']], - ], - true, - ], - [ - 'test@remote', - [ - [ - 'FN' => 'User3 @ Localhost', - ], - [ - 'FN' => 'User2 @ Localhost', - 'CLOUD' => [ - ], - ], - [ - 'FN' => 'User @ Localhost', - 'CLOUD' => [ - 'username@localhost', - ], - ], - ], - false, - [ - ['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']], - ], - [], - true, - ], - [ - 'username@localhost', - [ - [ - 'FN' => 'User3 @ Localhost', - ], - [ - 'FN' => 'User2 @ Localhost', - 'CLOUD' => [ - ], - ], - [ - 'FN' => 'User @ Localhost', - 'CLOUD' => [ - 'username@localhost', - ], - ], - ], - true, - [ - ['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']], - ], - [], - true, - ], - [ - 'username@localhost', - [ - [ - 'FN' => 'User3 @ Localhost', - ], - [ - 'FN' => 'User2 @ Localhost', - 'CLOUD' => [ - ], - ], - [ - 'FN' => 'User @ Localhost', - 'CLOUD' => [ - 'username@localhost', - ], - ], - ], - false, - [ - ['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']], - ], - [], - true, - ], - ]; - } - - /** - * @dataProvider dataGetRemote - * - * @param string $searchTerm - * @param array $contacts - * @param bool $shareeEnumeration - * @param array $exactExpected - * @param array $expected - * @param bool $reachedEnd - */ - public function testGetRemote($searchTerm, $contacts, $shareeEnumeration, $exactExpected, $expected, $reachedEnd) { - $this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]); - $this->contactsManager->expects($this->any()) - ->method('search') - ->with($searchTerm, ['CLOUD', 'FN']) - ->willReturn($contacts); - - $this->invokePrivate($this->sharees, 'getRemote', [$searchTerm]); - $result = $this->invokePrivate($this->sharees, 'result'); - - $this->assertEquals($exactExpected, $result['exact']['remotes']); - $this->assertEquals($expected, $result['remotes']); - $this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor')); - } - - public function dataSearch() { - $allTypes = [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE]; - - return [ - [[], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - - // Test itemType - [[ - 'search' => '', - ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[ - 'search' => 'foobar', - ], '', 'yes', true, 'foobar', null, $allTypes, 1, 200, false, true, true], - [[ - 'search' => 0, - ], '', 'yes', true, '0', null, $allTypes, 1, 200, false, true, true], - - // Test itemType - [[ - 'itemType' => '', - ], '', 'yes', true, '', '', $allTypes, 1, 200, false, true, true], - [[ - 'itemType' => 'folder', - ], '', 'yes', true, '', 'folder', $allTypes, 1, 200, false, true, true], - [[ - 'itemType' => 0, - ], '', 'yes', true, '', '0', $allTypes, 1, 200, false, true, true], - - // Test shareType - [[ - ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[ - 'shareType' => 0, - ], '', 'yes', true, '', null, [0], 1, 200, false, true, true], - [[ - 'shareType' => '0', - ], '', 'yes', true, '', null, [0], 1, 200, false, true, true], - [[ - 'shareType' => 1, - ], '', 'yes', true, '', null, [1], 1, 200, false, true, true], - [[ - 'shareType' => 12, - ], '', 'yes', true, '', null, [], 1, 200, false, true, true], - [[ - 'shareType' => 'foobar', - ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[ - 'shareType' => [0, 1, 2], - ], '', 'yes', true, '', null, [0, 1], 1, 200, false, true, true], - [[ - 'shareType' => [0, 1], - ], '', 'yes', true, '', null, [0, 1], 1, 200, false, true, true], - [[ - 'shareType' => $allTypes, - ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[ - 'shareType' => $allTypes, - ], '', 'yes', false, '', null, [0, 1], 1, 200, false, true, true], - [[ - 'shareType' => $allTypes, - ], '', 'yes', true, '', null, [0, 6], 1, 200, false, true, false], - [[ - 'shareType' => $allTypes, - ], '', 'yes', false, '', null, [0], 1, 200, false, true, false], - - // Test pagination - [[ - 'page' => 1, - ], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[ - 'page' => 10, - ], '', 'yes', true, '', null, $allTypes, 10, 200, false, true, true], - - // Test perPage - [[ - 'perPage' => 1, - ], '', 'yes', true, '', null, $allTypes, 1, 1, false, true, true], - [[ - 'perPage' => 10, - ], '', 'yes', true, '', null, $allTypes, 1, 10, false, true, true], - - // Test $shareWithGroupOnly setting - [[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[], 'yes', 'yes', true, '', null, $allTypes, 1, 200, true, true, true], - - // Test $shareeEnumeration setting - [[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true, true], - [[], 'no', 'no', true, '', null, $allTypes, 1, 200, false, false, true], - - // Test keep case for search - [[ - 'search' => 'foo@example.com/ownCloud', - ], '', 'yes', true, 'foo@example.com/ownCloud', null, $allTypes, 1, 200, false, true, true], - ]; - } - - /** - * @dataProvider dataSearch - * - * @param array $getData - * @param string $apiSetting - * @param string $enumSetting - * @param bool $remoteSharingEnabled - * @param string $search - * @param string $itemType - * @param array $shareTypes - * @param int $page - * @param int $perPage - * @param bool $shareWithGroupOnly - * @param bool $shareeEnumeration - * @param bool $allowGroupSharing - */ - public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEnabled, $search, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly, $shareeEnumeration, $allowGroupSharing) { - $oldGet = $_GET; - $_GET = $getData; - - $config = $this->getMockBuilder('OCP\IConfig') - ->disableOriginalConstructor() - ->getMock(); - $config->expects($this->exactly(2)) - ->method('getAppValue') - ->with('core', $this->anything(), $this->anything()) - ->willReturnMap([ - ['core', 'shareapi_only_share_with_group_members', 'no', $apiSetting], - ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', $enumSetting], - ]); - - $this->shareManager->expects($this->once()) - ->method('allowGroupSharing') - ->willReturn($allowGroupSharing); - - $sharees = $this->getMockBuilder('\OCA\Files_Sharing\API\Sharees') - ->setConstructorArgs([ - $this->groupManager, - $this->userManager, - $this->contactsManager, - $config, - $this->session, - $this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(), - $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock(), - $this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(), - $this->shareManager - ]) - ->setMethods(array('searchSharees', 'isRemoteSharingAllowed')) - ->getMock(); - $sharees->expects($this->once()) - ->method('searchSharees') - ->with($search, $itemType, $shareTypes, $page, $perPage) - ->willReturnCallback(function - ($isearch, $iitemType, $ishareTypes, $ipage, $iperPage) - use ($search, $itemType, $shareTypes, $page, $perPage) { - - // We are doing strict comparisons here, so we can differ 0/'' and null on shareType/itemType - $this->assertSame($search, $isearch); - $this->assertSame($itemType, $iitemType); - $this->assertSame($shareTypes, $ishareTypes); - $this->assertSame($page, $ipage); - $this->assertSame($perPage, $iperPage); - return new \OC_OCS_Result([]); - }); - $sharees->expects($this->any()) - ->method('isRemoteSharingAllowed') - ->with($itemType) - ->willReturn($remoteSharingEnabled); - - /** @var \PHPUnit_Framework_MockObject_MockObject|\OCA\Files_Sharing\API\Sharees $sharees */ - $this->assertInstanceOf('\OC_OCS_Result', $sharees->search()); - - $this->assertSame($shareWithGroupOnly, $this->invokePrivate($sharees, 'shareWithGroupOnly')); - $this->assertSame($shareeEnumeration, $this->invokePrivate($sharees, 'shareeEnumeration')); - - $_GET = $oldGet; - } - - public function dataSearchInvalid() { - return [ - // Test invalid pagination - [[ - 'page' => 0, - ], 'Invalid page'], - [[ - 'page' => '0', - ], 'Invalid page'], - [[ - 'page' => -1, - ], 'Invalid page'], - - // Test invalid perPage - [[ - 'perPage' => 0, - ], 'Invalid perPage argument'], - [[ - 'perPage' => '0', - ], 'Invalid perPage argument'], - [[ - 'perPage' => -1, - ], 'Invalid perPage argument'], - ]; - } - - /** - * @dataProvider dataSearchInvalid - * - * @param array $getData - * @param string $message - */ - public function testSearchInvalid($getData, $message) { - $oldGet = $_GET; - $_GET = $getData; - - $config = $this->getMockBuilder('OCP\IConfig') - ->disableOriginalConstructor() - ->getMock(); - $config->expects($this->never()) - ->method('getAppValue'); - - $sharees = $this->getMockBuilder('\OCA\Files_Sharing\API\Sharees') - ->setConstructorArgs([ - $this->groupManager, - $this->userManager, - $this->contactsManager, - $config, - $this->session, - $this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(), - $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock(), - $this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(), - $this->shareManager - ]) - ->setMethods(array('searchSharees', 'isRemoteSharingAllowed')) - ->getMock(); - $sharees->expects($this->never()) - ->method('searchSharees'); - $sharees->expects($this->never()) - ->method('isRemoteSharingAllowed'); - - /** @var \PHPUnit_Framework_MockObject_MockObject|\OCA\Files_Sharing\API\Sharees $sharees */ - $ocs = $sharees->search(); - $this->assertInstanceOf('\OC_OCS_Result', $ocs); - - $this->assertOCSError($ocs, $message); - - $_GET = $oldGet; - } - - public function dataIsRemoteSharingAllowed() { - return [ - ['file', true], - ['folder', true], - ['', false], - ['contacts', false], - ]; - } - - /** - * @dataProvider dataIsRemoteSharingAllowed - * - * @param string $itemType - * @param bool $expected - */ - public function testIsRemoteSharingAllowed($itemType, $expected) { - $this->assertSame($expected, $this->invokePrivate($this->sharees, 'isRemoteSharingAllowed', [$itemType])); - } - - public function dataSearchSharees() { - return [ - ['test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [], [], [], - [ - 'exact' => ['users' => [], 'groups' => [], 'remotes' => []], - 'users' => [], - 'groups' => [], - 'remotes' => [], - ], false], - ['test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [], [], [], - [ - 'exact' => ['users' => [], 'groups' => [], 'remotes' => []], - 'users' => [], - 'groups' => [], - 'remotes' => [], - ], false], - [ - 'test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [ - ['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], [ - ['label' => 'testgroup1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'testgroup1']], - ], [ - ['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']], - ], - [ - 'exact' => ['users' => [], 'groups' => [], 'remotes' => []], - 'users' => [ - ['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], - 'groups' => [ - ['label' => 'testgroup1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'testgroup1']], - ], - 'remotes' => [ - ['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']], - ], - ], true, - ], - // No groups requested - [ - 'test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_REMOTE], 1, 2, false, [ - ['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], null, [ - ['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']], - ], - [ - 'exact' => ['users' => [], 'groups' => [], 'remotes' => []], - 'users' => [ - ['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], - 'groups' => [], - 'remotes' => [ - ['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']], - ], - ], false, - ], - // Share type restricted to user - Only one user - [ - 'test', 'folder', [Share::SHARE_TYPE_USER], 1, 2, false, [ - ['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], null, null, - [ - 'exact' => ['users' => [], 'groups' => [], 'remotes' => []], - 'users' => [ - ['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ], - 'groups' => [], - 'remotes' => [], - ], false, - ], - // Share type restricted to user - Multipage result - [ - 'test', 'folder', [Share::SHARE_TYPE_USER], 1, 2, false, [ - ['label' => 'test 1', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ['label' => 'test 2', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], - ], null, null, - [ - 'exact' => ['users' => [], 'groups' => [], 'remotes' => []], - 'users' => [ - ['label' => 'test 1', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ['label' => 'test 2', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], - ], - 'groups' => [], - 'remotes' => [], - ], true, - ], - ]; - } - - /** - * @dataProvider dataSearchSharees - * - * @param string $searchTerm - * @param string $itemType - * @param array $shareTypes - * @param int $page - * @param int $perPage - * @param bool $shareWithGroupOnly - * @param array $mockedUserResult - * @param array $mockedGroupsResult - * @param array $mockedRemotesResult - * @param array $expected - * @param bool $nextLink - */ - public function testSearchSharees($searchTerm, $itemType, array $shareTypes, $page, $perPage, $shareWithGroupOnly, - $mockedUserResult, $mockedGroupsResult, $mockedRemotesResult, $expected, $nextLink) { - /** @var \PHPUnit_Framework_MockObject_MockObject|\OCA\Files_Sharing\API\Sharees $sharees */ - $sharees = $this->getMockBuilder('\OCA\Files_Sharing\API\Sharees') - ->setConstructorArgs([ - $this->groupManager, - $this->userManager, - $this->contactsManager, - $this->getMockBuilder('OCP\IConfig')->disableOriginalConstructor()->getMock(), - $this->session, - $this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(), - $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock(), - $this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(), - $this->shareManager - ]) - ->setMethods(array('getShareesForShareIds', 'getUsers', 'getGroups', 'getRemote')) - ->getMock(); - $sharees->expects(($mockedUserResult === null) ? $this->never() : $this->once()) - ->method('getUsers') - ->with($searchTerm) - ->willReturnCallback(function() use ($sharees, $mockedUserResult) { - $result = $this->invokePrivate($sharees, 'result'); - $result['users'] = $mockedUserResult; - $this->invokePrivate($sharees, 'result', [$result]); - }); - $sharees->expects(($mockedGroupsResult === null) ? $this->never() : $this->once()) - ->method('getGroups') - ->with($searchTerm) - ->willReturnCallback(function() use ($sharees, $mockedGroupsResult) { - $result = $this->invokePrivate($sharees, 'result'); - $result['groups'] = $mockedGroupsResult; - $this->invokePrivate($sharees, 'result', [$result]); - }); - $sharees->expects(($mockedRemotesResult === null) ? $this->never() : $this->once()) - ->method('getRemote') - ->with($searchTerm) - ->willReturnCallback(function() use ($sharees, $mockedRemotesResult) { - $result = $this->invokePrivate($sharees, 'result'); - $result['remotes'] = $mockedRemotesResult; - $this->invokePrivate($sharees, 'result', [$result]); - }); - - /** @var \OC_OCS_Result $ocs */ - $ocs = $this->invokePrivate($sharees, 'searchSharees', [$searchTerm, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly]); - $this->assertInstanceOf('\OC_OCS_Result', $ocs); - $this->assertEquals($expected, $ocs->getData()); - - // Check if next link is set - if ($nextLink) { - $headers = $ocs->getHeaders(); - $this->assertArrayHasKey('Link', $headers); - $this->assertStringStartsWith('<', $headers['Link']); - $this->assertStringEndsWith('>; rel="next"', $headers['Link']); - } - } - - public function testSearchShareesNoItemType() { - /** @var \OC_OCS_Result $ocs */ - $ocs = $this->invokePrivate($this->sharees, 'searchSharees', ['', null, [], [], 0, 0, false]); - $this->assertInstanceOf('\OC_OCS_Result', $ocs); - - $this->assertOCSError($ocs, 'Missing itemType'); - } - - public function dataGetPaginationLink() { - return [ - [1, '/ocs/v1.php', ['perPage' => 2], '<?perPage=2&page=2>; rel="next"'], - [10, '/ocs/v2.php', ['perPage' => 2], '<?perPage=2&page=11>; rel="next"'], - ]; - } - - /** - * @dataProvider dataGetPaginationLink - * - * @param int $page - * @param string $scriptName - * @param array $params - * @param array $expected - */ - public function testGetPaginationLink($page, $scriptName, $params, $expected) { - $this->request->expects($this->once()) - ->method('getScriptName') - ->willReturn($scriptName); - - $this->assertEquals($expected, $this->invokePrivate($this->sharees, 'getPaginationLink', [$page, $params])); - } - - public function dataIsV2() { - return [ - ['/ocs/v1.php', false], - ['/ocs/v2.php', true], - ]; - } - - /** - * @dataProvider dataIsV2 - * - * @param string $scriptName - * @param bool $expected - */ - public function testIsV2($scriptName, $expected) { - $this->request->expects($this->once()) - ->method('getScriptName') - ->willReturn($scriptName); - - $this->assertEquals($expected, $this->invokePrivate($this->sharees, 'isV2')); - } - - /** - * @param \OC_OCS_Result $ocs - * @param string $message - */ - protected function assertOCSError(\OC_OCS_Result $ocs, $message) { - $this->assertSame(Http::STATUS_BAD_REQUEST, $ocs->getStatusCode(), 'Expected status code 400'); - $this->assertSame([], $ocs->getData(), 'Expected that no data is send'); - - $meta = $ocs->getMeta(); - $this->assertNotEmpty($meta); - $this->assertArrayHasKey('message', $meta); - $this->assertSame($message, $meta['message']); - } - - /** - * @dataProvider dataTestSplitUserRemote - * - * @param string $remote - * @param string $expectedUser - * @param string $expectedUrl - */ - public function testSplitUserRemote($remote, $expectedUser, $expectedUrl) { - list($remoteUser, $remoteUrl) = $this->sharees->splitUserRemote($remote); - $this->assertSame($expectedUser, $remoteUser); - $this->assertSame($expectedUrl, $remoteUrl); - } - - public function dataTestSplitUserRemote() { - $userPrefix = ['user@name', 'username']; - $protocols = ['', 'http://', 'https://']; - $remotes = [ - 'localhost', - 'local.host', - 'dev.local.host', - 'dev.local.host/path', - 'dev.local.host/at@inpath', - '127.0.0.1', - '::1', - '::192.0.2.128', - '::192.0.2.128/at@inpath', - ]; - - $testCases = []; - foreach ($userPrefix as $user) { - foreach ($remotes as $remote) { - foreach ($protocols as $protocol) { - $baseUrl = $user . '@' . $protocol . $remote; - - $testCases[] = [$baseUrl, $user, $protocol . $remote]; - $testCases[] = [$baseUrl . '/', $user, $protocol . $remote]; - $testCases[] = [$baseUrl . '/index.php', $user, $protocol . $remote]; - $testCases[] = [$baseUrl . '/index.php/s/token', $user, $protocol . $remote]; - } - } - } - return $testCases; - } - - public function dataTestSplitUserRemoteError() { - return array( - // Invalid path - array('user@'), - - // Invalid user - array('@server'), - array('us/er@server'), - array('us:er@server'), - - // Invalid splitting - array('user'), - array(''), - array('us/erserver'), - array('us:erserver'), - ); - } - - /** - * @dataProvider dataTestSplitUserRemoteError - * - * @param string $id - * @expectedException \Exception - */ - public function testSplitUserRemoteError($id) { - $this->sharees->splitUserRemote($id); - } - - /** - * @dataProvider dataTestFixRemoteUrl - * - * @param string $url - * @param string $expected - */ - public function testFixRemoteUrl($url, $expected) { - $this->assertSame($expected, - $this->invokePrivate($this->sharees, 'fixRemoteURL', [$url]) - ); - } - - public function dataTestFixRemoteUrl() { - return [ - ['http://localhost', 'http://localhost'], - ['http://localhost/', 'http://localhost'], - ['http://localhost/index.php', 'http://localhost'], - ['http://localhost/index.php/s/AShareToken', 'http://localhost'], - ]; - } -} diff --git a/apps/files_sharing/tests/backend.php b/apps/files_sharing/tests/backend.php deleted file mode 100644 index e5e6ceb6315..00000000000 --- a/apps/files_sharing/tests/backend.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -use OCA\Files\Share; -use OCA\Files_sharing\Tests\TestCase; - -/** - * Class Test_Files_Sharing - * - * @group DB - */ -class Test_Files_Sharing_Backend extends TestCase { - - const TEST_FOLDER_NAME = '/folder_share_api_test'; - - public $folder; - public $subfolder; - public $subsubfolder; - - protected function setUp() { - parent::setUp(); - - $this->folder = self::TEST_FOLDER_NAME; - $this->subfolder = '/subfolder_share_backend_test'; - $this->subsubfolder = '/subsubfolder_share_backend_test'; - - $this->filename = '/share-backend-test.txt'; - - // save file with content - $this->view->file_put_contents($this->filename, $this->data); - $this->view->mkdir($this->folder); - $this->view->mkdir($this->folder . $this->subfolder); - $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); - $this->view->file_put_contents($this->folder.$this->filename, $this->data); - $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); - $this->view->file_put_contents($this->folder . $this->subfolder . $this->subsubfolder . $this->filename, $this->data); - } - - protected function tearDown() { - if ($this->view) { - $this->view->unlink($this->filename); - $this->view->deleteAll($this->folder); - } - - parent::tearDown(); - } - - function testGetParents() { - - $fileinfo1 = $this->view->getFileInfo($this->folder); - $fileinfo2 = $this->view->getFileInfo($this->folder . $this->subfolder . $this->subsubfolder); - $fileinfo3 = $this->view->getFileInfo($this->folder . $this->subfolder . $this->subsubfolder . $this->filename); - - $this->assertTrue(\OCP\Share::shareItem('folder', $fileinfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31)); - $this->assertTrue(\OCP\Share::shareItem('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER3, 31)); - - $backend = new \OC_Share_Backend_Folder(); - - $result = $backend->getParents($fileinfo3['fileid']); - $this->assertSame(2, count($result)); - - $count1 = 0; - $count2 = 0; - foreach($result as $r) { - if ($r['path'] === 'files' . $this->folder) { - $this->assertSame(ltrim($this->folder, '/'), $r['collection']['path']); - $count1++; - } elseif ($r['path'] === 'files' . $this->folder . $this->subfolder . $this->subsubfolder) { - $this->assertSame(ltrim($this->subsubfolder, '/'), $r['collection']['path']); - $count2++; - } else { - $this->assertTrue(false, 'unexpected result'); - } - } - - $this->assertSame(1, $count1); - $this->assertSame(1, $count2); - - $result1 = $backend->getParents($fileinfo3['fileid'], self::TEST_FILES_SHARING_API_USER3); - $this->assertSame(1, count($result1)); - $elemet = reset($result1); - $this->assertSame('files' . $this->folder . $this->subfolder . $this->subsubfolder ,$elemet['path']); - $this->assertSame(ltrim($this->subsubfolder, '/') ,$elemet['collection']['path']); - - } - -} diff --git a/apps/files_sharing/tests/cache.php b/apps/files_sharing/tests/cache.php deleted file mode 100644 index c137ba0728d..00000000000 --- a/apps/files_sharing/tests/cache.php +++ /dev/null @@ -1,508 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ -use OCA\Files_sharing\Tests\TestCase; - -/** - * ownCloud - * - * @author Vincent Petry, Bjoern Schiessle - * @copyright 2014 Vincent Petry <pvince81@owncloud.com> - * 2014 Bjoern Schiessle <schiessle@owncloud.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/** - * Class Test_Files_Sharing_Cache - * - * @group DB - */ -class Test_Files_Sharing_Cache extends TestCase { - - /** - * @var OC\Files\View - */ - public $user2View; - - /** @var \OC\Files\Cache\Cache */ - protected $ownerCache; - - /** @var \OC\Files\Cache\Cache */ - protected $sharedCache; - - /** @var \OC\Files\Storage\Storage */ - protected $ownerStorage; - - /** @var \OC\Files\Storage\Storage */ - protected $sharedStorage; - - protected function setUp() { - parent::setUp(); - - \OC_User::setDisplayName(self::TEST_FILES_SHARING_API_USER1, 'User One'); - \OC_User::setDisplayName(self::TEST_FILES_SHARING_API_USER2, 'User Two'); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $this->user2View = new \OC\Files\View('/'. self::TEST_FILES_SHARING_API_USER2 . '/files'); - - // prepare user1's dir structure - $this->view->mkdir('container'); - $this->view->mkdir('container/shareddir'); - $this->view->mkdir('container/shareddir/subdir'); - $this->view->mkdir('container/shareddir/emptydir'); - - $textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $this->view->file_put_contents('container/not shared.txt', $textData); - $this->view->file_put_contents('container/shared single file.txt', $textData); - $this->view->file_put_contents('container/shareddir/bar.txt', $textData); - $this->view->file_put_contents('container/shareddir/subdir/another.txt', $textData); - $this->view->file_put_contents('container/shareddir/subdir/another too.txt', $textData); - $this->view->file_put_contents('container/shareddir/subdir/not a text file.xml', '<xml></xml>'); - - list($this->ownerStorage,) = $this->view->resolvePath(''); - $this->ownerCache = $this->ownerStorage->getCache(); - $this->ownerStorage->getScanner()->scan(''); - - // share "shareddir" with user2 - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - $fileinfo = $this->view->getFileInfo('container/shared single file.txt'); - \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - // login as user2 - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // retrieve the shared storage - $secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2); - list($this->sharedStorage,) = $secondView->resolvePath('files/shareddir'); - $this->sharedCache = $this->sharedStorage->getCache(); - } - - protected function tearDown() { - if($this->sharedCache) { - $this->sharedCache->clear(); - } - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - - $fileinfo = $this->view->getFileInfo('container/shared single file.txt'); - \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - - $this->view->deleteAll('container'); - - $this->ownerCache->clear(); - - parent::tearDown(); - } - - function searchDataProvider() { - return array( - array('%another%', - array( - array('name' => 'another too.txt', 'path' => 'subdir/another too.txt'), - array('name' => 'another.txt', 'path' => 'subdir/another.txt'), - ) - ), - array('%Another%', - array( - array('name' => 'another too.txt', 'path' => 'subdir/another too.txt'), - array('name' => 'another.txt', 'path' => 'subdir/another.txt'), - ) - ), - array('%dir%', - array( - array('name' => 'emptydir', 'path' => 'emptydir'), - array('name' => 'subdir', 'path' => 'subdir'), - array('name' => 'shareddir', 'path' => ''), - ) - ), - array('%Dir%', - array( - array('name' => 'emptydir', 'path' => 'emptydir'), - array('name' => 'subdir', 'path' => 'subdir'), - array('name' => 'shareddir', 'path' => ''), - ) - ), - array('%txt%', - array( - array('name' => 'bar.txt', 'path' => 'bar.txt'), - array('name' => 'another too.txt', 'path' => 'subdir/another too.txt'), - array('name' => 'another.txt', 'path' => 'subdir/another.txt'), - ) - ), - array('%Txt%', - array( - array('name' => 'bar.txt', 'path' => 'bar.txt'), - array('name' => 'another too.txt', 'path' => 'subdir/another too.txt'), - array('name' => 'another.txt', 'path' => 'subdir/another.txt'), - ) - ), - array('%', - array( - array('name' => 'bar.txt', 'path' => 'bar.txt'), - array('name' => 'emptydir', 'path' => 'emptydir'), - array('name' => 'subdir', 'path' => 'subdir'), - array('name' => 'another too.txt', 'path' => 'subdir/another too.txt'), - array('name' => 'another.txt', 'path' => 'subdir/another.txt'), - array('name' => 'not a text file.xml', 'path' => 'subdir/not a text file.xml'), - array('name' => 'shareddir', 'path' => ''), - ) - ), - array('%nonexistant%', - array( - ) - ), - ); - } - - /** - * we cannot use a dataProvider because that would cause the stray hook detection to remove the hooks - * that were added in setUpBeforeClass. - */ - function testSearch() { - foreach ($this->searchDataProvider() as $data) { - list($pattern, $expectedFiles) = $data; - - $results = $this->sharedStorage->getCache()->search($pattern); - - $this->verifyFiles($expectedFiles, $results); - } - - } - /** - * Test searching by mime type - */ - function testSearchByMime() { - $results = $this->sharedStorage->getCache()->searchByMime('text'); - $check = array( - array( - 'name' => 'bar.txt', - 'path' => 'bar.txt' - ), - array( - 'name' => 'another too.txt', - 'path' => 'subdir/another too.txt' - ), - array( - 'name' => 'another.txt', - 'path' => 'subdir/another.txt' - ), - ); - $this->verifyFiles($check, $results); - } - - /** - * Test searching by tag - */ - function testSearchByTag() { - $userId = \OC::$server->getUserSession()->getUser()->getUId(); - $id1 = $this->sharedCache->get('bar.txt')['fileid']; - $id2 = $this->sharedCache->get('subdir/another too.txt')['fileid']; - $id3 = $this->sharedCache->get('subdir/not a text file.xml')['fileid']; - $id4 = $this->sharedCache->get('subdir/another.txt')['fileid']; - $tagManager = \OC::$server->getTagManager()->load('files', null, null, $userId); - $tagManager->tagAs($id1, 'tag1'); - $tagManager->tagAs($id1, 'tag2'); - $tagManager->tagAs($id2, 'tag1'); - $tagManager->tagAs($id3, 'tag1'); - $tagManager->tagAs($id4, 'tag2'); - $results = $this->sharedStorage->getCache()->searchByTag('tag1', $userId); - $check = array( - array( - 'name' => 'bar.txt', - 'path' => 'bar.txt' - ), - array( - 'name' => 'another too.txt', - 'path' => 'subdir/another too.txt' - ), - array( - 'name' => 'not a text file.xml', - 'path' => 'subdir/not a text file.xml' - ), - ); - $this->verifyFiles($check, $results); - $tagManager->delete(array('tag1', 'tag2')); - } - - /** - * Test searching by tag for multiple sections of the tree - */ - function testSearchByTagTree() { - $userId = \OC::$server->getUserSession()->getUser()->getUId(); - $this->sharedStorage->mkdir('subdir/emptydir'); - $this->sharedStorage->mkdir('subdir/emptydir2'); - $this->ownerStorage->getScanner()->scan(''); - $allIds = array( - $this->sharedCache->get('')['fileid'], - $this->sharedCache->get('bar.txt')['fileid'], - $this->sharedCache->get('subdir/another too.txt')['fileid'], - $this->sharedCache->get('subdir/not a text file.xml')['fileid'], - $this->sharedCache->get('subdir/another.txt')['fileid'], - $this->sharedCache->get('subdir/emptydir')['fileid'], - $this->sharedCache->get('subdir/emptydir2')['fileid'], - ); - $tagManager = \OC::$server->getTagManager()->load('files', null, null, $userId); - foreach ($allIds as $id) { - $tagManager->tagAs($id, 'tag1'); - } - $results = $this->sharedStorage->getCache()->searchByTag('tag1', $userId); - $check = array( - array( - 'name' => 'shareddir', - 'path' => '' - ), - array( - 'name' => 'bar.txt', - 'path' => 'bar.txt' - ), - array( - 'name' => 'another.txt', - 'path' => 'subdir/another.txt' - ), - array( - 'name' => 'another too.txt', - 'path' => 'subdir/another too.txt' - ), - array( - 'name' => 'emptydir', - 'path' => 'subdir/emptydir' - ), - array( - 'name' => 'emptydir2', - 'path' => 'subdir/emptydir2' - ), - array( - 'name' => 'not a text file.xml', - 'path' => 'subdir/not a text file.xml' - ), - ); - $this->verifyFiles($check, $results); - $tagManager->delete(array('tag1')); - } - - function testGetFolderContentsInRoot() { - $results = $this->user2View->getDirectoryContent('/'); - - // we should get the shared items "shareddir" and "shared single file.txt" - // additional root will always contain the example file "welcome.txt", - // so this will be part of the result - $this->verifyFiles( - array( - array( - 'name' => 'welcome.txt', - 'path' => 'files/welcome.txt', - 'mimetype' => 'text/plain', - ), - array( - 'name' => 'shareddir', - 'path' => 'files/shareddir', - 'mimetype' => 'httpd/unix-directory', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - array( - 'name' => 'shared single file.txt', - 'path' => 'files/shared single file.txt', - 'mimetype' => 'text/plain', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - ), - $results - ); - } - - function testGetFolderContentsInSubdir() { - $results = $this->user2View->getDirectoryContent('/shareddir'); - - $this->verifyFiles( - array( - array( - 'name' => 'bar.txt', - 'path' => 'bar.txt', - 'mimetype' => 'text/plain', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - array( - 'name' => 'emptydir', - 'path' => 'emptydir', - 'mimetype' => 'httpd/unix-directory', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - array( - 'name' => 'subdir', - 'path' => 'subdir', - 'mimetype' => 'httpd/unix-directory', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - ), - $results - ); - } - - function testGetFolderContentsWhenSubSubdirShared() { - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $fileinfo = $this->view->getFileInfo('container/shareddir/subdir'); - \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER3, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - - $thirdView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files'); - $results = $thirdView->getDirectoryContent('/subdir'); - - $this->verifyFiles( - array( - array( - 'name' => 'another too.txt', - 'path' => 'another too.txt', - 'mimetype' => 'text/plain', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - array( - 'name' => 'another.txt', - 'path' => 'another.txt', - 'mimetype' => 'text/plain', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - array( - 'name' => 'not a text file.xml', - 'path' => 'not a text file.xml', - 'mimetype' => 'application/xml', - 'uid_owner' => self::TEST_FILES_SHARING_API_USER1, - 'displayname_owner' => 'User One', - ), - ), - $results - ); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER3); - } - - /** - * Check if 'results' contains the expected 'examples' only. - * - * @param array $examples array of example files - * @param array $results array of files - */ - private function verifyFiles($examples, $results) { - $this->assertEquals(count($examples), count($results)); - - foreach ($examples as $example) { - foreach ($results as $key => $result) { - if ($result['name'] === $example['name']) { - $this->verifyKeys($example, $result); - unset($results[$key]); - break; - } - } - } - $this->assertEquals(array(), $results); - } - - /** - * verify if each value from the result matches the expected result - * @param array $example array with the expected results - * @param array $result array with the results - */ - private function verifyKeys($example, $result) { - foreach ($example as $key => $value) { - $this->assertEquals($value, $result[$key]); - } - } - - public function testGetPathByIdDirectShare() { - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OC\Files\Filesystem::file_put_contents('test.txt', 'foo'); - $info = \OC\Files\Filesystem::getFileInfo('test.txt'); - \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_ALL); - \OC_Util::tearDownFS(); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue(\OC\Files\Filesystem::file_exists('/test.txt')); - list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/test.txt'); - /** - * @var \OC\Files\Storage\Shared $sharedStorage - */ - - $sharedCache = $sharedStorage->getCache(); - $this->assertEquals('', $sharedCache->getPathById($info->getId())); - } - - public function testGetPathByIdShareSubFolder() { - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OC\Files\Filesystem::mkdir('foo'); - \OC\Files\Filesystem::mkdir('foo/bar'); - \OC\Files\Filesystem::touch('foo/bar/test.txt'); - $folderInfo = \OC\Files\Filesystem::getFileInfo('foo'); - $fileInfo = \OC\Files\Filesystem::getFileInfo('foo/bar/test.txt'); - \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_ALL); - \OC_Util::tearDownFS(); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue(\OC\Files\Filesystem::file_exists('/foo')); - list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/foo'); - /** - * @var \OC\Files\Storage\Shared $sharedStorage - */ - - $sharedCache = $sharedStorage->getCache(); - $this->assertEquals('', $sharedCache->getPathById($folderInfo->getId())); - $this->assertEquals('bar/test.txt', $sharedCache->getPathById($fileInfo->getId())); - } -} diff --git a/apps/files_sharing/tests/capabilities.php b/apps/files_sharing/tests/capabilities.php deleted file mode 100644 index 7572f5c84aa..00000000000 --- a/apps/files_sharing/tests/capabilities.php +++ /dev/null @@ -1,282 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\Capabilities; -use OCA\Files_Sharing\Tests\TestCase; - -/** - * Class FilesSharingCapabilitiesTest - * - * @group DB - */ -class FilesSharingCapabilitiesTest extends \Test\TestCase { - - /** - * Test for the general part in each return statement and assert. - * Strip of the general part on the way. - * - * @param string[] $data Capabilities - * @return string[] - */ - private function getFilesSharingPart(array $data) { - $this->assertArrayHasKey('files_sharing', $data); - return $data['files_sharing']; - } - - /** - * Create a mock config object and insert the values in $map tot the getAppValue - * function. Then obtain the capabilities and extract the first few - * levels in the array - * - * @param (string[])[] $map Map of arguments to return types for the getAppValue function in the mock - * @return string[] - */ - private function getResults(array $map) { - $stub = $this->getMockBuilder('\OCP\IConfig')->disableOriginalConstructor()->getMock(); - $stub->method('getAppValue')->will($this->returnValueMap($map)); - $cap = new Capabilities($stub); - $result = $this->getFilesSharingPart($cap->getCapabilities()); - return $result; - } - - public function testEnabledSharingAPI() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertTrue($result['api_enabled']); - $this->assertContains('public', $result); - $this->assertContains('user', $result); - $this->assertContains('resharing', $result); - } - - public function testDisabledSharingAPI() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'no'], - ]; - $result = $this->getResults($map); - $this->assertFalse($result['api_enabled']); - $this->assertNotContains('public', $result); - $this->assertNotContains('user', $result); - $this->assertNotContains('resharing', $result); - } - - public function testNoLinkSharing() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'no'], - ]; - $result = $this->getResults($map); - $this->assertInternalType('array', $result['public']); - $this->assertFalse($result['public']['enabled']); - } - - public function testOnlyLinkSharing() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertInternalType('array', $result['public']); - $this->assertTrue($result['public']['enabled']); - } - - public function testLinkPassword() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_enforce_links_password', 'no', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('password', $result['public']); - $this->assertArrayHasKey('enforced', $result['public']['password']); - $this->assertTrue($result['public']['password']['enforced']); - } - - public function testLinkNoPassword() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_enforce_links_password', 'no', 'no'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('password', $result['public']); - $this->assertArrayHasKey('enforced', $result['public']['password']); - $this->assertFalse($result['public']['password']['enforced']); - } - - public function testLinkNoExpireDate() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_default_expire_date', 'no', 'no'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('expire_date', $result['public']); - $this->assertInternalType('array', $result['public']['expire_date']); - $this->assertFalse($result['public']['expire_date']['enabled']); - } - - public function testLinkExpireDate() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '7'], - ['core', 'shareapi_enforce_expire_date', 'no', 'no'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('expire_date', $result['public']); - $this->assertInternalType('array', $result['public']['expire_date']); - $this->assertTrue($result['public']['expire_date']['enabled']); - $this->assertArrayHasKey('days', $result['public']['expire_date']); - $this->assertFalse($result['public']['expire_date']['enforced']); - } - - public function testLinkExpireDateEnforced() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('expire_date', $result['public']); - $this->assertInternalType('array', $result['public']['expire_date']); - $this->assertTrue($result['public']['expire_date']['enforced']); - } - - public function testLinkSendMail() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_notification', 'no', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertTrue($result['public']['send_mail']); - } - - public function testLinkNoSendMail() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_notification', 'no', 'no'], - ]; - $result = $this->getResults($map); - $this->assertFalse($result['public']['send_mail']); - } - - public function testUserSendMail() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_mail_notification', 'no', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertTrue($result['user']['send_mail']); - } - - public function testUserNoSendMail() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_mail_notification', 'no', 'no'], - ]; - $result = $this->getResults($map); - $this->assertFalse($result['user']['send_mail']); - } - - public function testResharing() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_resharing', 'yes', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertTrue($result['resharing']); - } - - public function testNoResharing() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_resharing', 'yes', 'no'], - ]; - $result = $this->getResults($map); - $this->assertFalse($result['resharing']); - } - - public function testLinkPublicUpload() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertTrue($result['public']['upload']); - } - - public function testLinkNoPublicUpload() { - $map = [ - ['core', 'shareapi_enabled', 'yes', 'yes'], - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'no'], - ]; - $result = $this->getResults($map); - $this->assertFalse($result['public']['upload']); - } - - public function testFederatedSharingIncomming() { - $map = [ - ['files_sharing', 'incoming_server2server_share_enabled', 'yes', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('federation', $result); - $this->assertTrue($result['federation']['incoming']); - } - - public function testFederatedSharingNoIncomming() { - $map = [ - ['files_sharing', 'incoming_server2server_share_enabled', 'yes', 'no'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('federation', $result); - $this->assertFalse($result['federation']['incoming']); - } - - public function testFederatedSharingOutgoing() { - $map = [ - ['files_sharing', 'outgoing_server2server_share_enabled', 'yes', 'yes'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('federation', $result); - $this->assertTrue($result['federation']['outgoing']); - } - - public function testFederatedSharingNoOutgoing() { - $map = [ - ['files_sharing', 'outgoing_server2server_share_enabled', 'yes', 'no'], - ]; - $result = $this->getResults($map); - $this->assertArrayHasKey('federation', $result); - $this->assertFalse($result['federation']['outgoing']); - } - -} diff --git a/apps/files_sharing/tests/controller/externalsharecontroller.php b/apps/files_sharing/tests/controller/externalsharecontroller.php deleted file mode 100644 index bd20bffb36c..00000000000 --- a/apps/files_sharing/tests/controller/externalsharecontroller.php +++ /dev/null @@ -1,152 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\Controllers; - -use OCP\AppFramework\Http\DataResponse; -use OCP\AppFramework\Http\JSONResponse; -use OCP\Http\Client\IClientService; -use OCP\IRequest; - -/** - * Class ExternalShareControllerTest - * - * @package OCA\Files_Sharing\Controllers - */ -class ExternalShareControllerTest extends \Test\TestCase { - /** @var IRequest */ - private $request; - /** @var \OCA\Files_Sharing\External\Manager */ - private $externalManager; - /** @var IClientService */ - private $clientService; - - public function setUp() { - $this->request = $this->getMockBuilder('\\OCP\\IRequest') - ->disableOriginalConstructor()->getMock(); - $this->externalManager = $this->getMockBuilder('\\OCA\\Files_Sharing\\External\\Manager') - ->disableOriginalConstructor()->getMock(); - $this->clientService = $this->getMockBuilder('\\OCP\Http\\Client\\IClientService') - ->disableOriginalConstructor()->getMock(); - } - - /** - * @return ExternalSharesController - */ - public function getExternalShareController() { - return new ExternalSharesController( - 'files_sharing', - $this->request, - $this->externalManager, - $this->clientService - ); - } - - public function testIndex() { - $this->externalManager - ->expects($this->once()) - ->method('getOpenShares') - ->will($this->returnValue(['MyDummyArray'])); - - $this->assertEquals(new JSONResponse(['MyDummyArray']), $this->getExternalShareController()->index()); - } - - public function testCreate() { - $this->externalManager - ->expects($this->once()) - ->method('acceptShare') - ->with(4); - - $this->assertEquals(new JSONResponse(), $this->getExternalShareController()->create(4)); - } - - public function testDestroy() { - $this->externalManager - ->expects($this->once()) - ->method('declineShare') - ->with(4); - - $this->assertEquals(new JSONResponse(), $this->getExternalShareController()->destroy(4)); - } - - public function testRemoteWithValidHttps() { - $client = $this->getMockBuilder('\\OCP\\Http\\Client\\IClient') - ->disableOriginalConstructor()->getMock(); - $response = $this->getMockBuilder('\\OCP\\Http\\Client\\IResponse') - ->disableOriginalConstructor()->getMock(); - $response - ->expects($this->exactly(2)) - ->method('getBody') - ->will($this->onConsecutiveCalls('Certainly not a JSON string', '{"installed":true,"maintenance":false,"version":"8.1.0.8","versionstring":"8.1.0","edition":""}')); - $client - ->expects($this->any()) - ->method('get') - ->will($this->returnValue($response)); - - $this->clientService - ->expects($this->exactly(2)) - ->method('newClient') - ->will($this->returnValue($client)); - - $this->assertEquals(new DataResponse('https'), $this->getExternalShareController()->testRemote('owncloud.org')); - } - - public function testRemoteWithWorkingHttp() { - $client = $this->getMockBuilder('\\OCP\\Http\\Client\\IClient') - ->disableOriginalConstructor()->getMock(); - $response = $this->getMockBuilder('\\OCP\\Http\\Client\\IResponse') - ->disableOriginalConstructor()->getMock(); - $client - ->method('get') - ->will($this->returnValue($response)); - $response - ->expects($this->exactly(5)) - ->method('getBody') - ->will($this->onConsecutiveCalls('Certainly not a JSON string', 'Certainly not a JSON string', 'Certainly not a JSON string', 'Certainly not a JSON string', '{"installed":true,"maintenance":false,"version":"8.1.0.8","versionstring":"8.1.0","edition":""}')); - $this->clientService - ->expects($this->exactly(5)) - ->method('newClient') - ->will($this->returnValue($client)); - - $this->assertEquals(new DataResponse('http'), $this->getExternalShareController()->testRemote('owncloud.org')); - } - - public function testRemoteWithInvalidRemote() { - $client = $this->getMockBuilder('\\OCP\\Http\\Client\\IClient') - ->disableOriginalConstructor()->getMock(); - $response = $this->getMockBuilder('\\OCP\\Http\\Client\\IResponse') - ->disableOriginalConstructor()->getMock(); - $client - ->method('get') - ->will($this->returnValue($response)); - $response - ->expects($this->exactly(6)) - ->method('getBody') - ->will($this->returnValue('Certainly not a JSON string')); - $this->clientService - ->expects($this->exactly(6)) - ->method('newClient') - ->will($this->returnValue($client)); - - $this->assertEquals(new DataResponse(false), $this->getExternalShareController()->testRemote('owncloud.org')); - } -} diff --git a/apps/files_sharing/tests/controller/sharecontroller.php b/apps/files_sharing/tests/controller/sharecontroller.php deleted file mode 100644 index db8c7fe553c..00000000000 --- a/apps/files_sharing/tests/controller/sharecontroller.php +++ /dev/null @@ -1,437 +0,0 @@ -<?php -/** - * @author Georg Ehrke <georg@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Cloutier <vincent1cloutier@gmail.com> - * - * @copyright Copyright (c) 2016, 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\Controllers; - -use OC\Files\Filesystem; -use OCP\Share\Exceptions\ShareNotFound; -use OCP\AppFramework\Http\NotFoundResponse; -use OCP\AppFramework\Http\RedirectResponse; -use OCP\AppFramework\Http\TemplateResponse; -use OCP\ISession; -use OCP\IUserManager; -use OCP\Security\ISecureRandom; -use OCP\IURLGenerator; - -/** - * @group DB - * - * @package OCA\Files_Sharing\Controllers - */ -class ShareControllerTest extends \Test\TestCase { - - /** @var string */ - private $user; - /** @var string */ - private $oldUser; - - /** @var string */ - private $appName = 'files_sharing'; - /** @var ShareController */ - private $shareController; - /** @var IURLGenerator | \PHPUnit_Framework_MockObject_MockObject */ - private $urlGenerator; - /** @var ISession | \PHPUnit_Framework_MockObject_MockObject */ - private $session; - /** @var \OCP\IPreview | \PHPUnit_Framework_MockObject_MockObject */ - private $previewManager; - /** @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject */ - private $config; - /** @var \OC\Share20\Manager | \PHPUnit_Framework_MockObject_MockObject */ - private $shareManager; - /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */ - private $userManager; - - protected function setUp() { - $this->appName = 'files_sharing'; - - $this->shareManager = $this->getMockBuilder('\OC\Share20\Manager')->disableOriginalConstructor()->getMock(); - $this->urlGenerator = $this->getMock('\OCP\IURLGenerator'); - $this->session = $this->getMock('\OCP\ISession'); - $this->previewManager = $this->getMock('\OCP\IPreview'); - $this->config = $this->getMock('\OCP\IConfig'); - $this->userManager = $this->getMock('\OCP\IUserManager'); - - $this->shareController = new \OCA\Files_Sharing\Controllers\ShareController( - $this->appName, - $this->getMock('\OCP\IRequest'), - $this->config, - $this->urlGenerator, - $this->userManager, - $this->getMock('\OCP\ILogger'), - $this->getMock('\OCP\Activity\IManager'), - $this->shareManager, - $this->session, - $this->previewManager, - $this->getMock('\OCP\Files\IRootFolder') - ); - - - // Store current user - $this->oldUser = \OC_User::getUser(); - - // Create a dummy user - $this->user = \OC::$server->getSecureRandom()->generate(12, ISecureRandom::CHAR_LOWER); - - \OC::$server->getUserManager()->createUser($this->user, $this->user); - \OC_Util::tearDownFS(); - $this->loginAsUser($this->user); - } - - protected function tearDown() { - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - Filesystem::tearDown(); - $user = \OC::$server->getUserManager()->get($this->user); - if ($user !== null) { $user->delete(); } - \OC_User::setIncognitoMode(false); - - \OC::$server->getSession()->set('public_link_authenticated', ''); - - // Set old user - \OC_User::setUserId($this->oldUser); - \OC_Util::setupFS($this->oldUser); - } - - public function testShowAuthenticateNotAuthenticated() { - $share = \OC::$server->getShareManager()->newShare(); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $response = $this->shareController->showAuthenticate('token'); - $expectedResponse = new TemplateResponse($this->appName, 'authenticate', [], 'guest'); - $this->assertEquals($expectedResponse, $response); - } - - public function testShowAuthenticateAuthenticatedForDifferentShare() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setId(1); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('2'); - - $response = $this->shareController->showAuthenticate('token'); - $expectedResponse = new TemplateResponse($this->appName, 'authenticate', [], 'guest'); - $this->assertEquals($expectedResponse, $response); - } - - public function testShowAuthenticateCorrectShare() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setId(1); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('1'); - - $this->urlGenerator->expects($this->once()) - ->method('linkToRoute') - ->with('files_sharing.sharecontroller.showShare', ['token' => 'token']) - ->willReturn('redirect'); - - $response = $this->shareController->showAuthenticate('token'); - $expectedResponse = new RedirectResponse('redirect'); - $this->assertEquals($expectedResponse, $response); - } - - public function testAutehnticateInvalidToken() { - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->will($this->throwException(new \OCP\Share\Exceptions\ShareNotFound())); - - $response = $this->shareController->authenticate('token'); - $expectedResponse = new NotFoundResponse(); - $this->assertEquals($expectedResponse, $response); - } - - public function testAuthenticateValidPassword() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setId(42); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $this->shareManager - ->expects($this->once()) - ->method('checkPassword') - ->with($share, 'validpassword') - ->willReturn(true); - - $this->session - ->expects($this->once()) - ->method('set') - ->with('public_link_authenticated', '42'); - - $this->urlGenerator->expects($this->once()) - ->method('linkToRoute') - ->with('files_sharing.sharecontroller.showShare', ['token'=>'token']) - ->willReturn('redirect'); - - $response = $this->shareController->authenticate('token', 'validpassword'); - $expectedResponse = new RedirectResponse('redirect'); - $this->assertEquals($expectedResponse, $response); - } - - public function testAuthenticateInvalidPassword() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setNodeId(100) - ->setNodeType('file') - ->setToken('token') - ->setSharedBy('initiator') - ->setId(42); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $this->shareManager - ->expects($this->once()) - ->method('checkPassword') - ->with($share, 'invalidpassword') - ->willReturn(false); - - $this->session - ->expects($this->never()) - ->method('set'); - - $hookListner = $this->getMockBuilder('Dummy')->setMethods(['access'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'share_link_access', $hookListner, 'access'); - - $hookListner->expects($this->once()) - ->method('access') - ->with($this->callback(function(array $data) { - return $data['itemType'] === 'file' && - $data['itemSource'] === 100 && - $data['uidOwner'] === 'initiator' && - $data['token'] === 'token' && - $data['errorCode'] === 403 && - $data['errorMessage'] === 'Wrong password'; - })); - - $response = $this->shareController->authenticate('token', 'invalidpassword'); - $expectedResponse = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest'); - $this->assertEquals($expectedResponse, $response); - } - - public function testShowShareInvalidToken() { - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('invalidtoken') - ->will($this->throwException(new ShareNotFound())); - - // Test without a not existing token - $response = $this->shareController->showShare('invalidtoken'); - $expectedResponse = new NotFoundResponse(); - $this->assertEquals($expectedResponse, $response); - } - - public function testShowShareNotAuthenticated() { - $share = \OC::$server->getShareManager()->newShare(); - $share->setPassword('password'); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('validtoken') - ->willReturn($share); - - $this->urlGenerator->expects($this->once()) - ->method('linkToRoute') - ->with('files_sharing.sharecontroller.authenticate', ['token' => 'validtoken']) - ->willReturn('redirect'); - - // Test without a not existing token - $response = $this->shareController->showShare('validtoken'); - $expectedResponse = new RedirectResponse('redirect'); - $this->assertEquals($expectedResponse, $response); - } - - - public function testShowShare() { - $owner = $this->getMock('OCP\IUser'); - $owner->method('getDisplayName')->willReturn('ownerDisplay'); - $owner->method('getUID')->willReturn('ownerUID'); - - $file = $this->getMock('OCP\Files\File'); - $file->method('getName')->willReturn('file1.txt'); - $file->method('getMimetype')->willReturn('text/plain'); - $file->method('getSize')->willReturn(33); - $file->method('isReadable')->willReturn(true); - $file->method('isShareable')->willReturn(true); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setId(42); - $share->setPassword('password') - ->setShareOwner('ownerUID') - ->setNode($file) - ->setTarget('/file1.txt'); - - $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); - - $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true); - - $this->config->method('getSystemValue') - ->willReturnMap( - [ - ['max_filesize_animated_gifs_public_sharing', 10, 10], - ['enable_previews', true, true], - ] - ); - $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); - $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $this->userManager->method('get')->with('ownerUID')->willReturn($owner); - - $response = $this->shareController->showShare('token'); - $sharedTmplParams = array( - 'displayName' => 'ownerDisplay', - 'owner' => 'ownerUID', - 'filename' => 'file1.txt', - 'directory_path' => '/file1.txt', - 'mimetype' => 'text/plain', - 'dirToken' => 'token', - 'sharingToken' => 'token', - 'server2serversharing' => true, - 'protected' => 'true', - 'dir' => '', - 'downloadURL' => null, - 'fileSize' => '33 B', - 'nonHumanFileSize' => 33, - 'maxSizeAnimateGif' => 10, - 'previewSupported' => true, - 'previewEnabled' => true, - ); - - $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); - $csp->addAllowedFrameDomain('\'self\''); - $expectedResponse = new TemplateResponse($this->appName, 'public', $sharedTmplParams, 'base'); - $expectedResponse->setContentSecurityPolicy($csp); - - $this->assertEquals($expectedResponse, $response); - } - - /** - * @expectedException \OCP\Files\NotFoundException - */ - public function testShowShareInvalid() { - $owner = $this->getMock('OCP\IUser'); - $owner->method('getDisplayName')->willReturn('ownerDisplay'); - $owner->method('getUID')->willReturn('ownerUID'); - - $file = $this->getMock('OCP\Files\File'); - $file->method('getName')->willReturn('file1.txt'); - $file->method('getMimetype')->willReturn('text/plain'); - $file->method('getSize')->willReturn(33); - $file->method('isShareable')->willReturn(false); - $file->method('isReadable')->willReturn(true); - - $share = \OC::$server->getShareManager()->newShare(); - $share->setId(42); - $share->setPassword('password') - ->setShareOwner('ownerUID') - ->setNode($file) - ->setTarget('/file1.txt'); - - $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); - - $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true); - - $this->config->method('getSystemValue') - ->willReturnMap( - [ - ['max_filesize_animated_gifs_public_sharing', 10, 10], - ['enable_previews', true, true], - ] - ); - $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); - $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $this->userManager->method('get')->with('ownerUID')->willReturn($owner); - - $this->shareController->showShare('token'); - } - - - public function testDownloadShare() { - $share = $this->getMock('\OCP\Share\IShare'); - $share->method('getPassword')->willReturn('password'); - - $this->shareManager - ->expects($this->once()) - ->method('getShareByToken') - ->with('validtoken') - ->willReturn($share); - - $this->urlGenerator->expects($this->once()) - ->method('linkToRoute') - ->with('files_sharing.sharecontroller.authenticate', ['token' => 'validtoken']) - ->willReturn('redirect'); - - // Test with a password protected share and no authentication - $response = $this->shareController->downloadShare('validtoken'); - $expectedResponse = new RedirectResponse('redirect'); - $this->assertEquals($expectedResponse, $response); - } - -} diff --git a/apps/files_sharing/tests/deleteorphanedsharesjobtest.php b/apps/files_sharing/tests/deleteorphanedsharesjobtest.php deleted file mode 100644 index 353520bd604..00000000000 --- a/apps/files_sharing/tests/deleteorphanedsharesjobtest.php +++ /dev/null @@ -1,171 +0,0 @@ -<?php -/** - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 Test\BackgroundJob; - -use OCA\Files_sharing\Lib\DeleteOrphanedSharesJob; - -/** - * Class DeleteOrphanedSharesJobTest - * - * @group DB - * - * @package Test\BackgroundJob - */ -class DeleteOrphanedSharesJobTest extends \Test\TestCase { - - /** - * @var bool - */ - private static $trashBinStatus; - - /** - * @var DeleteOrphanedSharesJob - */ - private $job; - - /** - * @var \OCP\IDBConnection - */ - private $connection; - - /** - * @var string - */ - private $user1; - - /** - * @var string - */ - private $user2; - - public static function setUpBeforeClass() { - $appManager = \OC::$server->getAppManager(); - self::$trashBinStatus = $appManager->isEnabledForUser('files_trashbin'); - $appManager->disableApp('files_trashbin'); - - // just in case... - \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); - } - - public static function tearDownAfterClass() { - if (self::$trashBinStatus) { - \OC::$server->getAppManager()->enableApp('files_trashbin'); - } - } - - protected function setup() { - parent::setUp(); - - $this->connection = \OC::$server->getDatabaseConnection(); - // clear occasional leftover shares from other tests - $this->connection->executeUpdate('DELETE FROM `*PREFIX*share`'); - - $this->user1 = $this->getUniqueID('user1_'); - $this->user2 = $this->getUniqueID('user2_'); - - $userManager = \OC::$server->getUserManager(); - $userManager->createUser($this->user1, 'pass'); - $userManager->createUser($this->user2, 'pass'); - - \OC::registerShareHooks(); - - $this->job = new DeleteOrphanedSharesJob(); - } - - protected function tearDown() { - $this->connection->executeUpdate('DELETE FROM `*PREFIX*share`'); - - $userManager = \OC::$server->getUserManager(); - $user1 = $userManager->get($this->user1); - if($user1) { - $user1->delete(); - } - $user2 = $userManager->get($this->user2); - if($user2) { - $user2->delete(); - } - - $this->logout(); - - parent::tearDown(); - } - - private function getShares() { - $shares = []; - $result = $this->connection->executeQuery('SELECT * FROM `*PREFIX*share`'); - while ($row = $result->fetch()) { - $shares[] = $row; - } - $result->closeCursor(); - return $shares; - } - - /** - * Test clearing orphaned shares - */ - public function testClearShares() { - $this->loginAsUser($this->user1); - - $view = new \OC\Files\View('/' . $this->user1 . '/'); - $view->mkdir('files/test'); - $view->mkdir('files/test/sub'); - - $fileInfo = $view->getFileInfo('files/test/sub'); - $fileId = $fileInfo->getId(); - - $this->assertTrue( - \OCP\Share::shareItem('folder', $fileId, \OCP\Share::SHARE_TYPE_USER, $this->user2, \OCP\Constants::PERMISSION_READ), - 'Failed asserting that user 1 successfully shared "test/sub" with user 2.' - ); - - $this->assertCount(1, $this->getShares()); - - $this->job->run([]); - - $this->assertCount(1, $this->getShares(), 'Linked shares not deleted'); - - $view->unlink('files/test'); - - $this->job->run([]); - - $this->assertCount(0, $this->getShares(), 'Orphaned shares deleted'); - } - - public function testKeepNonFileShares() { - $this->loginAsUser($this->user1); - - \OCP\Share::registerBackend('test', 'Test_Share_Backend'); - - $this->assertTrue( - \OCP\Share::shareItem('test', 'test.txt', \OCP\Share::SHARE_TYPE_USER, $this->user2, \OCP\Constants::PERMISSION_READ), - 'Failed asserting that user 1 successfully shared something with user 2.' - ); - - $this->assertCount(1, $this->getShares()); - - $this->job->run([]); - - $this->assertCount(1, $this->getShares(), 'Non-file shares kept'); - } -} - diff --git a/apps/files_sharing/tests/external/cache.php b/apps/files_sharing/tests/external/cache.php deleted file mode 100644 index 4ae1bc563df..00000000000 --- a/apps/files_sharing/tests/external/cache.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\External; - -use OCA\Files_sharing\Tests\TestCase; - -/** - * Class Cache - * - * @group DB - * - * @package OCA\Files_sharing\Tests\External - */ -class Cache extends TestCase { - - /** - * @var \OC\Files\Storage\Storage - **/ - private $storage; - - /** - * @var \OCA\Files_Sharing\External\Cache - */ - private $cache; - - /** - * @var string - */ - private $remoteUser; - - protected function setUp() { - parent::setUp(); - - $this->remoteUser = $this->getUniqueID('remoteuser'); - - $this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage') - ->disableOriginalConstructor() - ->getMock(); - $this->storage - ->expects($this->any()) - ->method('getId') - ->will($this->returnValue('dummystorage::')); - $this->cache = new \OCA\Files_Sharing\External\Cache( - $this->storage, - 'http://example.com/owncloud', - $this->remoteUser - ); - $this->cache->put( - 'test.txt', - array( - 'mimetype' => 'text/plain', - 'size' => 5, - 'mtime' => 123, - ) - ); - } - - protected function tearDown() { - if ($this->cache) { - $this->cache->clear(); - } - parent::tearDown(); - } - - public function testGetInjectsOwnerDisplayName() { - $info = $this->cache->get('test.txt'); - $this->assertEquals( - $this->remoteUser . '@example.com/owncloud', - $info['displayname_owner'] - ); - } - - public function testGetReturnsFalseIfNotFound() { - $info = $this->cache->get('unexisting-entry.txt'); - $this->assertFalse($info); - } - - public function testGetFolderPopulatesOwner() { - $dirId = $this->cache->put( - 'subdir', - array( - 'mimetype' => 'httpd/unix-directory', - 'size' => 5, - 'mtime' => 123, - ) - ); - $this->cache->put( - 'subdir/contents.txt', - array( - 'mimetype' => 'text/plain', - 'size' => 5, - 'mtime' => 123, - ) - ); - - $results = $this->cache->getFolderContentsById($dirId); - $this->assertEquals(1, count($results)); - $this->assertEquals( - $this->remoteUser . '@example.com/owncloud', - $results[0]['displayname_owner'] - ); - } - -} diff --git a/apps/files_sharing/tests/external/managertest.php b/apps/files_sharing/tests/external/managertest.php deleted file mode 100644 index 48a9098ae1d..00000000000 --- a/apps/files_sharing/tests/external/managertest.php +++ /dev/null @@ -1,253 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\External; - -use OC\Files\Storage\StorageFactory; -use OCA\FederatedFileSharing\DiscoveryManager; -use OCA\Files_Sharing\External\Manager; -use OCA\Files_Sharing\External\MountProvider; -use OCA\Files_Sharing\Tests\TestCase; -use Test\Traits\UserTrait; - -/** - * Class ManagerTest - * - * @group DB - * - * @package OCA\Files_Sharing\Tests\External - */ -class ManagerTest extends TestCase { - use UserTrait; - - /** @var Manager **/ - private $manager; - - /** @var \OC\Files\Mount\Manager */ - private $mountManager; - - /** @var \PHPUnit_Framework_MockObject_MockObject */ - private $httpHelper; - - private $uid; - - /** - * @var \OCP\IUser - */ - private $user; - private $mountProvider; - - protected function setUp() { - parent::setUp(); - - $this->uid = $this->getUniqueID('user'); - $this->createUser($this->uid, ''); - $this->user = \OC::$server->getUserManager()->get($this->uid); - $this->mountManager = new \OC\Files\Mount\Manager(); - $this->httpHelper = $httpHelper = $this->getMockBuilder('\OC\HTTPHelper')->disableOriginalConstructor()->getMock(); - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); - /** @var \OC\HTTPHelper $httpHelper */ - $this->manager = new Manager( - \OC::$server->getDatabaseConnection(), - $this->mountManager, - new StorageFactory(), - $httpHelper, - \OC::$server->getNotificationManager(), - $discoveryManager, - $this->uid - ); - $this->mountProvider = new MountProvider(\OC::$server->getDatabaseConnection(), function() { - return $this->manager; - }); - } - - private function setupMounts() { - $mounts = $this->mountProvider->getMountsForUser($this->user, new StorageFactory()); - foreach ($mounts as $mount) { - $this->mountManager->addMount($mount); - } - } - - public function testAddShare() { - - $shareData1 = [ - 'remote' => 'http://localhost', - 'token' => 'token1', - 'password' => '', - 'name' => '/SharedFolder', - 'owner' => 'foobar', - 'accepted' => false, - 'user' => $this->uid, - ]; - $shareData2 = $shareData1; - $shareData2['token'] = 'token2'; - $shareData3 = $shareData1; - $shareData3['token'] = 'token3'; - - // Add a share for "user" - $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData1)); - $openShares = $this->manager->getOpenShares(); - $this->assertCount(1, $openShares); - $this->assertExternalShareEntry($shareData1, $openShares[0], 1, '{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - - $this->setupMounts(); - $this->assertNotMount('SharedFolder'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - - // Add a second share for "user" with the same name - $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData2)); - $openShares = $this->manager->getOpenShares(); - $this->assertCount(2, $openShares); - $this->assertExternalShareEntry($shareData1, $openShares[0], 1, '{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - // New share falls back to "-1" appendix, because the name is already taken - $this->assertExternalShareEntry($shareData2, $openShares[1], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1'); - - $this->setupMounts(); - $this->assertNotMount('SharedFolder'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); - - $this->httpHelper->expects($this->at(0)) - ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[0]['remote_id']), $this->anything()); - - // Accept the first share - $this->manager->acceptShare($openShares[0]['id']); - - // Check remaining shares - Accepted - $acceptedShares = self::invokePrivate($this->manager, 'getShares', [true]); - $this->assertCount(1, $acceptedShares); - $shareData1['accepted'] = true; - $this->assertExternalShareEntry($shareData1, $acceptedShares[0], 1, $shareData1['name']); - // Check remaining shares - Open - $openShares = $this->manager->getOpenShares(); - $this->assertCount(1, $openShares); - $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1'); - - $this->setupMounts(); - $this->assertMount($shareData1['name']); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); - - // Add another share for "user" with the same name - $this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData3)); - $openShares = $this->manager->getOpenShares(); - $this->assertCount(2, $openShares); - $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1'); - // New share falls back to the original name (no "-\d", because the name is not taken) - $this->assertExternalShareEntry($shareData3, $openShares[1], 3, '{{TemporaryMountPointName#' . $shareData3['name'] . '}}'); - - $this->setupMounts(); - $this->assertMount($shareData1['name']); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); - - $this->httpHelper->expects($this->at(0)) - ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[1]['remote_id'] . '/decline'), $this->anything()); - - // Decline the third share - $this->manager->declineShare($openShares[1]['id']); - - $this->setupMounts(); - $this->assertMount($shareData1['name']); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); - - // Check remaining shares - Accepted - $acceptedShares = self::invokePrivate($this->manager, 'getShares', [true]); - $this->assertCount(1, $acceptedShares); - $shareData1['accepted'] = true; - $this->assertExternalShareEntry($shareData1, $acceptedShares[0], 1, $shareData1['name']); - // Check remaining shares - Open - $openShares = $this->manager->getOpenShares(); - $this->assertCount(1, $openShares); - $this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1'); - - $this->setupMounts(); - $this->assertMount($shareData1['name']); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); - - $this->httpHelper->expects($this->at(0)) - ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[0]['remote_id'] . '/decline'), $this->anything()); - $this->httpHelper->expects($this->at(1)) - ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $acceptedShares[0]['remote_id'] . '/decline'), $this->anything()); - - $this->manager->removeUserShares($this->uid); - $this->assertEmpty(self::invokePrivate($this->manager, 'getShares', [null]), 'Asserting all shares for the user have been deleted'); - - $this->mountManager->clear(); - self::invokePrivate($this->manager, 'setupMounts'); - $this->assertNotMount($shareData1['name']); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}'); - $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); - } - - /** - * @param array $expected - * @param array $actual - * @param int $share - * @param string $mountPoint - */ - protected function assertExternalShareEntry($expected, $actual, $share, $mountPoint) { - $this->assertEquals($expected['remote'], $actual['remote'], 'Asserting remote of a share #' . $share); - $this->assertEquals($expected['token'], $actual['share_token'], 'Asserting token of a share #' . $share); - $this->assertEquals($expected['name'], $actual['name'], 'Asserting name of a share #' . $share); - $this->assertEquals($expected['owner'], $actual['owner'], 'Asserting owner of a share #' . $share); - $this->assertEquals($expected['accepted'], (int) $actual['accepted'], 'Asserting accept of a share #' . $share); - $this->assertEquals($expected['user'], $actual['user'], 'Asserting user of a share #' . $share); - $this->assertEquals($mountPoint, $actual['mountpoint'], 'Asserting mountpoint of a share #' . $share); - } - - private function assertMount($mountPoint) { - $mountPoint = rtrim($mountPoint, '/'); - $mount = $this->mountManager->find($this->getFullPath($mountPoint)); - $this->assertInstanceOf('\OCA\Files_Sharing\External\Mount', $mount); - $this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount); - $this->assertEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/')); - $storage = $mount->getStorage(); - $this->assertInstanceOf('\OCA\Files_Sharing\External\Storage', $storage); - } - - private function assertNotMount($mountPoint) { - $mountPoint = rtrim($mountPoint, '/'); - $mount = $this->mountManager->find($this->getFullPath($mountPoint)); - if ($mount) { - $this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount); - $this->assertNotEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/')); - } else { - $this->assertNull($mount); - } - } - - private function getFullPath($path) { - return '/' . $this->uid . '/files' . $path; - } -} diff --git a/apps/files_sharing/tests/external/scannertest.php b/apps/files_sharing/tests/external/scannertest.php deleted file mode 100644 index f16e9952fce..00000000000 --- a/apps/files_sharing/tests/external/scannertest.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\External; - -use OCA\Files_Sharing\External\Scanner; -use Test\TestCase; - -class ScannerTest extends TestCase { - /** @var \OCA\Files_Sharing\External\Scanner */ - protected $scanner; - /** @var \OCA\Files_Sharing\External\Storage|\PHPUnit_Framework_MockObject_MockObject */ - protected $storage; - /** @var \OC\Files\Cache\Cache|\PHPUnit_Framework_MockObject_MockObject */ - protected $cache; - - protected function setUp() { - parent::setUp(); - - $this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage') - ->disableOriginalConstructor() - ->getMock(); - $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor() - ->getMock(); - $this->storage->expects($this->any()) - ->method('getCache') - ->willReturn($this->cache); - - $this->scanner = new Scanner($this->storage); - } - - public function testScanAll() { - $this->storage->expects($this->any()) - ->method('getShareInfo') - ->willReturn(['status' => 'success', 'data' => []]); - - // FIXME add real tests, we are currently only checking for - // Declaration of OCA\Files_Sharing\External\Scanner::*() should be - // compatible with OC\Files\Cache\Scanner::*() - $this->scanner->scanAll(); - $this->assertTrue(true); - } - - public function testScan() { - $this->storage->expects($this->any()) - ->method('getShareInfo') - ->willReturn(['status' => 'success', 'data' => []]); - - // FIXME add real tests, we are currently only checking for - // Declaration of OCA\Files_Sharing\External\Scanner::*() should be - // compatible with OC\Files\Cache\Scanner::*() - $this->scanner->scan('test', Scanner::SCAN_RECURSIVE); - $this->assertTrue(true); - } - - public function testScanFile() { - // FIXME add real tests, we are currently only checking for - // Declaration of OCA\Files_Sharing\External\Scanner::*() should be - // compatible with OC\Files\Cache\Scanner::*() - $this->scanner->scanFile('test', Scanner::SCAN_RECURSIVE); - $this->assertTrue(true); - } -} diff --git a/apps/files_sharing/tests/externalstorage.php b/apps/files_sharing/tests/externalstorage.php deleted file mode 100644 index 54cd7d1645c..00000000000 --- a/apps/files_sharing/tests/externalstorage.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php -/** - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -/** - * Tests for the external Storage class for remote shares. - * - * @group DB - */ -class Test_Files_Sharing_External_Storage extends \Test\TestCase { - - function optionsProvider() { - return array( - array( - 'http://remoteserver:8080/owncloud', - 'http://remoteserver:8080/owncloud/public.php/webdav/', - ), - // extra slash - array( - 'http://remoteserver:8080/owncloud/', - 'http://remoteserver:8080/owncloud/public.php/webdav/', - ), - // extra path - array( - 'http://remoteserver:8080/myservices/owncloud/', - 'http://remoteserver:8080/myservices/owncloud/public.php/webdav/', - ), - // root path - array( - 'http://remoteserver:8080/', - 'http://remoteserver:8080/public.php/webdav/', - ), - // without port - array( - 'http://remoteserver/oc.test', - 'http://remoteserver/oc.test/public.php/webdav/', - ), - // https - array( - 'https://remoteserver/', - 'https://remoteserver/public.php/webdav/', - ), - ); - } - - /** - * @dataProvider optionsProvider - */ - public function testStorageMountOptions($inputUri, $baseUri) { - $certificateManager = \OC::$server->getCertificateManager(); - $storage = new TestSharingExternalStorage( - array( - 'remote' => $inputUri, - 'owner' => 'testOwner', - 'mountpoint' => 'remoteshare', - 'token' => 'abcdef', - 'password' => '', - 'manager' => null, - 'certificateManager' => $certificateManager - ) - ); - $this->assertEquals($baseUri, $storage->getBaseUri()); - } -} - -/** - * Dummy subclass to make it possible to access private members - */ -class TestSharingExternalStorage extends \OCA\Files_Sharing\External\Storage { - - public function getBaseUri() { - return $this->createBaseUri(); - } -} diff --git a/apps/files_sharing/tests/helper.php b/apps/files_sharing/tests/helper.php deleted file mode 100644 index 07f07f911cb..00000000000 --- a/apps/files_sharing/tests/helper.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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/> - * - */ -use OCA\Files_sharing\Tests\TestCase; - -/** - * Class Test_Files_Sharing_Helper - * - * @group DB - */ -class Test_Files_Sharing_Helper extends TestCase { - - /** - * test set and get share folder - */ - function testSetGetShareFolder() { - $this->assertSame('/', \OCA\Files_Sharing\Helper::getShareFolder()); - - \OCA\Files_Sharing\Helper::setShareFolder('/Shared/Folder'); - - $sharedFolder = \OCA\Files_Sharing\Helper::getShareFolder(); - $this->assertSame('/Shared/Folder', \OCA\Files_Sharing\Helper::getShareFolder()); - $this->assertTrue(\OC\Files\Filesystem::is_dir($sharedFolder)); - - // cleanup - \OC::$server->getConfig()->deleteSystemValue('share_folder'); - - } - -} diff --git a/apps/files_sharing/tests/js/appSpec.js b/apps/files_sharing/tests/js/appSpec.js deleted file mode 100644 index 133bd44f750..00000000000 --- a/apps/files_sharing/tests/js/appSpec.js +++ /dev/null @@ -1,148 +0,0 @@ -/** -* ownCloud -* -* @author Vincent Petry -* @copyright 2014 Vincent Petry <pvince81@owncloud.com> -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 along with this library. If not, see <http://www.gnu.org/licenses/>. -* -*/ - -describe('OCA.Sharing.App tests', function() { - var App = OCA.Sharing.App; - var fileListIn; - var fileListOut; - - beforeEach(function() { - $('#testArea').append( - '<div id="app-navigation">' + - '<ul><li data-id="files"><a>Files</a></li>' + - '<li data-id="sharingin"><a></a></li>' + - '<li data-id="sharingout"><a></a></li>' + - '</ul></div>' + - '<div id="app-content">' + - '<div id="app-content-files" class="hidden">' + - '</div>' + - '<div id="app-content-sharingin" class="hidden">' + - '</div>' + - '<div id="app-content-sharingout" class="hidden">' + - '</div>' + - '</div>' + - '</div>' - ); - fileListIn = App.initSharingIn($('#app-content-sharingin')); - fileListOut = App.initSharingOut($('#app-content-sharingout')); - }); - afterEach(function() { - App.destroy(); - }); - - describe('initialization', function() { - it('inits sharing-in list on show', function() { - expect(fileListIn._sharedWithUser).toEqual(true); - }); - it('inits sharing-out list on show', function() { - expect(fileListOut._sharedWithUser).toBeFalsy(); - }); - }); - describe('file actions', function() { - var oldLegacyFileActions; - - beforeEach(function() { - oldLegacyFileActions = window.FileActions; - window.FileActions = new OCA.Files.FileActions(); - }); - - afterEach(function() { - window.FileActions = oldLegacyFileActions; - }); - it('provides default file actions', function() { - _.each([fileListIn, fileListOut], function(fileList) { - var fileActions = fileList.fileActions; - - expect(fileActions.actions.all).toBeDefined(); - expect(fileActions.actions.all.Delete).toBeDefined(); - expect(fileActions.actions.all.Rename).toBeDefined(); - expect(fileActions.actions.all.Download).toBeDefined(); - - expect(fileActions.defaults.dir).toEqual('Open'); - }); - }); - it('provides custom file actions', function() { - var actionStub = sinon.stub(); - // regular file action - OCA.Files.fileActions.register( - 'all', - 'RegularTest', - OC.PERMISSION_READ, - OC.imagePath('core', 'actions/shared'), - actionStub - ); - - App._inFileList = null; - fileListIn = App.initSharingIn($('#app-content-sharingin')); - - expect(fileListIn.fileActions.actions.all.RegularTest).toBeDefined(); - }); - it('does not provide legacy file actions', function() { - var actionStub = sinon.stub(); - // legacy file action - window.FileActions.register( - 'all', - 'LegacyTest', - OC.PERMISSION_READ, - OC.imagePath('core', 'actions/shared'), - actionStub - ); - - App._inFileList = null; - fileListIn = App.initSharingIn($('#app-content-sharingin')); - - expect(fileListIn.fileActions.actions.all.LegacyTest).not.toBeDefined(); - }); - it('redirects to files app when opening a directory', function() { - var oldList = OCA.Files.App.fileList; - // dummy new list to make sure it exists - OCA.Files.App.fileList = new OCA.Files.FileList($('<table><thead></thead><tbody></tbody></table>')); - - var setActiveViewStub = sinon.stub(OCA.Files.App, 'setActiveView'); - // create dummy table so we can click the dom - var $table = '<table><thead></thead><tbody id="fileList"></tbody></table>'; - $('#app-content-sharingin').append($table); - - App._inFileList = null; - fileListIn = App.initSharingIn($('#app-content-sharingin')); - - fileListIn.setFiles([{ - name: 'testdir', - type: 'dir', - path: '/somewhere/inside/subdir', - counterParts: ['user2'], - shareOwner: 'user2' - }]); - - fileListIn.findFileEl('testdir').find('td .nametext').click(); - - expect(OCA.Files.App.fileList.getCurrentDirectory()).toEqual('/somewhere/inside/subdir/testdir'); - - expect(setActiveViewStub.calledOnce).toEqual(true); - expect(setActiveViewStub.calledWith('files')).toEqual(true); - - setActiveViewStub.restore(); - - // restore old list - OCA.Files.App.fileList = oldList; - }); - }); -}); diff --git a/apps/files_sharing/tests/js/externalSpec.js b/apps/files_sharing/tests/js/externalSpec.js deleted file mode 100644 index 362df49252b..00000000000 --- a/apps/files_sharing/tests/js/externalSpec.js +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -describe('OCA.Sharing external tests', function() { - var plugin; - var urlQueryStub; - var promptDialogStub; - var confirmDialogStub; - - function dummyShowDialog() { - var deferred = $.Deferred(); - deferred.resolve(); - return deferred.promise(); - } - - beforeEach(function() { - plugin = OCA.Sharing.ExternalShareDialogPlugin; - urlQueryStub = sinon.stub(OC.Util.History, 'parseUrlQuery'); - - confirmDialogStub = sinon.stub(OC.dialogs, 'confirm', dummyShowDialog); - promptDialogStub = sinon.stub(OC.dialogs, 'prompt', dummyShowDialog); - - plugin.filesApp = { - fileList: { - reload: sinon.stub() - } - }; - }); - afterEach(function() { - urlQueryStub.restore(); - confirmDialogStub.restore(); - promptDialogStub.restore(); - plugin = null; - }); - describe('confirmation dialog from URL', function() { - var testShare; - - /** - * Checks that the server call's query matches what is - * expected. - * - * @param {Object} expectedQuery expected query params - */ - function checkRequest(expectedQuery) { - var request = fakeServer.requests[0]; - var query = OC.parseQueryString(request.requestBody); - expect(request.method).toEqual('POST'); - expect(query).toEqual(expectedQuery); - - request.respond( - 200, - {'Content-Type': 'application/json'}, - JSON.stringify({status: 'success'}) - ); - expect(plugin.filesApp.fileList.reload.calledOnce).toEqual(true); - } - - beforeEach(function() { - testShare = { - remote: 'http://example.com/owncloud', - token: 'abcdefg', - owner: 'theowner', - ownerDisplayName: 'The Generous Owner', - name: 'the share name' - }; - }); - it('does nothing when no share was passed in URL', function() { - urlQueryStub.returns({}); - plugin.processIncomingShareFromUrl(); - expect(promptDialogStub.notCalled).toEqual(true); - expect(confirmDialogStub.notCalled).toEqual(true); - expect(fakeServer.requests.length).toEqual(0); - }); - it('sends share info to server on confirm', function() { - urlQueryStub.returns(testShare); - plugin.processIncomingShareFromUrl(); - expect(promptDialogStub.notCalled).toEqual(true); - expect(confirmDialogStub.calledOnce).toEqual(true); - confirmDialogStub.getCall(0).args[2](true); - expect(fakeServer.requests.length).toEqual(1); - checkRequest({ - remote: 'http://example.com/owncloud', - token: 'abcdefg', - owner: 'theowner', - ownerDisplayName: 'The Generous Owner', - name: 'the share name', - password: '' - }); - }); - it('sends share info with password to server on confirm', function() { - testShare = _.extend(testShare, {protected: 1}); - urlQueryStub.returns(testShare); - plugin.processIncomingShareFromUrl(); - expect(promptDialogStub.calledOnce).toEqual(true); - expect(confirmDialogStub.notCalled).toEqual(true); - promptDialogStub.getCall(0).args[2](true, 'thepassword'); - expect(fakeServer.requests.length).toEqual(1); - checkRequest({ - remote: 'http://example.com/owncloud', - token: 'abcdefg', - owner: 'theowner', - ownerDisplayName: 'The Generous Owner', - name: 'the share name', - password: 'thepassword' - }); - }); - it('does not send share info on cancel', function() { - urlQueryStub.returns(testShare); - plugin.processIncomingShareFromUrl(); - expect(promptDialogStub.notCalled).toEqual(true); - expect(confirmDialogStub.calledOnce).toEqual(true); - confirmDialogStub.getCall(0).args[2](false); - expect(fakeServer.requests.length).toEqual(0); - }); - }); - describe('show dialog for each share to confirm', function() { - var testShare; - - /** - * Call processSharesToConfirm() and make the fake server - * return the passed response. - * - * @param {Array} response list of shares to process - */ - function processShares(response) { - plugin.processSharesToConfirm(); - - expect(fakeServer.requests.length).toEqual(1); - - var req = fakeServer.requests[0]; - expect(req.method).toEqual('GET'); - expect(req.url).toEqual(OC.webroot + '/index.php/apps/files_sharing/api/externalShares'); - - req.respond( - 200, - {'Content-Type': 'application/json'}, - JSON.stringify(response) - ); - } - - beforeEach(function() { - testShare = { - id: 123, - remote: 'http://example.com/owncloud', - token: 'abcdefg', - owner: 'theowner', - ownerDisplayName: 'The Generous Owner', - name: 'the share name' - }; - }); - - it('does not show any dialog if no shares to confirm', function() { - processShares([]); - expect(confirmDialogStub.notCalled).toEqual(true); - expect(promptDialogStub.notCalled).toEqual(true); - }); - it('sends accept info to server on confirm', function() { - processShares([testShare]); - - expect(promptDialogStub.notCalled).toEqual(true); - expect(confirmDialogStub.calledOnce).toEqual(true); - - confirmDialogStub.getCall(0).args[2](true); - - expect(fakeServer.requests.length).toEqual(2); - - var request = fakeServer.requests[1]; - var query = OC.parseQueryString(request.requestBody); - expect(request.method).toEqual('POST'); - expect(query).toEqual({id: '123'}); - expect(request.url).toEqual( - OC.webroot + '/index.php/apps/files_sharing/api/externalShares' - ); - - expect(plugin.filesApp.fileList.reload.notCalled).toEqual(true); - request.respond( - 200, - {'Content-Type': 'application/json'}, - JSON.stringify({status: 'success'}) - ); - expect(plugin.filesApp.fileList.reload.calledOnce).toEqual(true); - }); - it('sends delete info to server on cancel', function() { - processShares([testShare]); - - expect(promptDialogStub.notCalled).toEqual(true); - expect(confirmDialogStub.calledOnce).toEqual(true); - - confirmDialogStub.getCall(0).args[2](false); - - expect(fakeServer.requests.length).toEqual(2); - - var request = fakeServer.requests[1]; - expect(request.method).toEqual('DELETE'); - expect(request.url).toEqual( - OC.webroot + '/index.php/apps/files_sharing/api/externalShares/123' - ); - - expect(plugin.filesApp.fileList.reload.notCalled).toEqual(true); - request.respond( - 200, - {'Content-Type': 'application/json'}, - JSON.stringify({status: 'success'}) - ); - expect(plugin.filesApp.fileList.reload.notCalled).toEqual(true); - }); - xit('shows another dialog when multiple shares need to be accepted', function() { - // TODO: enable this test when fixing multiple dialogs issue / confirm loop - var testShare2 = _.extend({}, testShare); - testShare2.id = 256; - processShares([testShare, testShare2]); - - // confirm first one - expect(confirmDialogStub.calledOnce).toEqual(true); - confirmDialogStub.getCall(0).args[2](true); - - // next dialog not shown yet - expect(confirmDialogStub.calledOnce); - - // respond to the first accept request - fakeServer.requests[1].respond( - 200, - {'Content-Type': 'application/json'}, - JSON.stringify({status: 'success'}) - ); - - // don't reload yet, there are other shares to confirm - expect(plugin.filesApp.fileList.reload.notCalled).toEqual(true); - - // cancel second share - expect(confirmDialogStub.calledTwice).toEqual(true); - confirmDialogStub.getCall(1).args[2](true); - - // reload only called at the very end - expect(plugin.filesApp.fileList.reload.calledOnce).toEqual(true); - }); - }); -}); diff --git a/apps/files_sharing/tests/js/publicAppSpec.js b/apps/files_sharing/tests/js/publicAppSpec.js deleted file mode 100644 index 58565744882..00000000000 --- a/apps/files_sharing/tests/js/publicAppSpec.js +++ /dev/null @@ -1,122 +0,0 @@ -/** -* ownCloud -* -* @author Vincent Petry -* @copyright 2015 Vincent Petry <pvince81@owncloud.com> -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 along with this library. If not, see <http://www.gnu.org/licenses/>. -* -*/ - -describe('OCA.Sharing.PublicApp tests', function() { - var App = OCA.Sharing.PublicApp; - var hostStub, protocolStub, webrootStub; - var $preview; - - beforeEach(function() { - protocolStub = sinon.stub(OC, 'getProtocol').returns('https'); - hostStub = sinon.stub(OC, 'getHost').returns('example.com:9876'); - webrootStub = sinon.stub(OC, 'getRootPath').returns('/owncloud'); - $preview = $('<div id="preview"></div>'); - $('#testArea').append($preview); - $preview.append( - '<div id="mimetype"></div>' + - '<div id="mimetypeIcon"></div>' + - '<input type="hidden" id="sharingToken" value="sh4tok"></input>' - ); - }); - - afterEach(function() { - protocolStub.restore(); - hostStub.restore(); - webrootStub.restore(); - }); - - describe('File list', function() { - // TODO: this should be moved to a separate file once the PublicFileList is extracted from public.js - beforeEach(function() { - $preview.append( - '<div id="app-content-files">' + - // init horrible parameters - '<input type="hidden" id="dir" value="/subdir"/>' + - '<input type="hidden" id="permissions" value="31"/>' + - // dummy controls - '<div id="controls">' + - ' <div class="actions creatable"></div>' + - ' <div class="notCreatable"></div>' + - '</div>' + - // uploader - '<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' + - // dummy table - // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + - '<thead><tr>' + - '<th id="headerName" class="hidden column-name">' + - '<input type="checkbox" id="select_all_files" class="select-all">' + - '<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' + - '<span class="selectedActions hidden">' + - '<a href class="download">Download</a>' + - '</th>' + - '<th class="hidden column-size"><a class="columntitle" data-sort="size"><span class="sort-indicator"></span></a></th>' + - '<th class="hidden column-mtime"><a class="columntitle" data-sort="mtime"><span class="sort-indicator"></span></a></th>' + - '</tr></thead>' + - '<tbody id="fileList"></tbody>' + - '<tfoot></tfoot>' + - '</table>' + - // TODO: move to handlebars template - '<div id="emptycontent"><h2>Empty content message</h2><p class="uploadmessage">Upload message</p></div>' + - '<div class="nofilterresults hidden"></div>' + - '</div>' - ); - - App.initialize($('#preview')); - }); - afterEach(function() { - App._initialized = false; - }); - - it('Uses public webdav endpoint', function() { - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('PROPFIND'); - expect(fakeServer.requests[0].url).toEqual('https://example.com:9876/owncloud/public.php/webdav/subdir'); - expect(fakeServer.requests[0].requestHeaders.Authorization).toEqual('Basic c2g0dG9rOm51bGw='); - }); - - describe('Download Url', function() { - var fileList; - - beforeEach(function() { - fileList = App.fileList; - }); - - it('returns correct download URL for single files', function() { - expect(fileList.getDownloadUrl('some file.txt')) - .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2Fsubdir&files=some%20file.txt'); - expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc')) - .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2Fanotherpath%2Fabc&files=some%20file.txt'); - fileList.changeDirectory('/'); - expect(fileList.getDownloadUrl('some file.txt')) - .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2F&files=some%20file.txt'); - }); - it('returns correct download URL for multiple files', function() { - expect(fileList.getDownloadUrl(['a b c.txt', 'd e f.txt'])) - .toEqual(OC.webroot + '/index.php/s/sh4tok/download?path=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D'); - }); - it('returns the correct ajax URL', function() { - expect(fileList.getAjaxUrl('test', {a:1, b:'x y'})) - .toEqual(OC.webroot + '/index.php/apps/files_sharing/ajax/test.php?a=1&b=x%20y&t=sh4tok'); - }); - }); - }); -}); diff --git a/apps/files_sharing/tests/js/shareSpec.js b/apps/files_sharing/tests/js/shareSpec.js deleted file mode 100644 index c34234bfe13..00000000000 --- a/apps/files_sharing/tests/js/shareSpec.js +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -describe('OCA.Sharing.Util tests', function() { - var fileList; - var testFiles; - - function getImageUrl($el) { - // might be slightly different cross-browser - var url = $el.css('background-image'); - var r = url.match(/url\(['"]?([^'")]*)['"]?\)/); - if (!r) { - return url; - } - return r[1]; - } - - beforeEach(function() { - var $content = $('<div id="content"></div>'); - $('#testArea').append($content); - // dummy file list - var $div = $( - '<div id="listContainer">' + - '<table id="filestable">' + - '<thead></thead>' + - '<tbody id="fileList"></tbody>' + - '</table>' + - '</div>'); - $('#content').append($div); - - var fileActions = new OCA.Files.FileActions(); - fileList = new OCA.Files.FileList( - $div, { - fileActions : fileActions - } - ); - OCA.Sharing.Util.attach(fileList); - - testFiles = [{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - shareOwner: 'User One', - isShareMountPoint: false, - shareTypes: [OC.Share.SHARE_TYPE_USER] - }]; - }); - afterEach(function() { - delete OCA.Sharing.sharesLoaded; - delete OC.Share.droppedDown; - fileList.destroy(); - fileList = null; - }); - - describe('Sharing data in table row', function() { - // TODO: test data-permissions, data-share-owner, etc - }); - describe('Share action icon', function() { - it('do not shows share text when not shared', function() { - var $action, $tr; - OC.Share.statuses = {}; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One', - path: '/subdir', - mimetype: 'httpd/unix-directory', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - shareTypes: [] - }]); - $tr = fileList.$el.find('tbody tr:first'); - $action = $tr.find('.action-share'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder.svg'); - }); - it('shows simple share text with share icon', function() { - var $action, $tr; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - shareTypes: [OC.Share.SHARE_TYPE_USER] - }]); - $tr = fileList.$el.find('tbody tr:first'); - $action = $tr.find('.action-share'); - expect($action.find('>span').text().trim()).toEqual('Shared'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg'); - }); - it('shows simple share text with public icon when shared with link', function() { - var $action, $tr; - OC.Share.statuses = {1: {link: true, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - shareTypes: [OC.Share.SHARE_TYPE_LINK] - }]); - $tr = fileList.$el.find('tbody tr:first'); - $action = $tr.find('.action-share'); - expect($action.find('>span').text().trim()).toEqual('Shared'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(false); - expect($action.find('.icon').hasClass('icon-public')).toEqual(true); - expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-public.svg'); - }); - it('shows owner name when owner is available', function() { - var $action, $tr; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - shareOwner: 'User One', - etag: 'abc', - shareTypes: [] - }]); - $tr = fileList.$el.find('tbody tr:first'); - $action = $tr.find('.action-share'); - expect($action.find('>span').text().trim()).toEqual('User One'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg'); - }); - it('shows recipients when recipients are available', function() { - var $action, $tr; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - recipientsDisplayName: 'User One, User Two', - etag: 'abc', - shareTypes: [OC.Share.SHARE_TYPE_USER] - }]); - $tr = fileList.$el.find('tbody tr:first'); - $action = $tr.find('.action-share'); - expect($action.find('>span').text().trim()).toEqual('Shared with User One, User Two'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg'); - }); - it('shows share action when shared with user who has no share permission', function() { - var $action, $tr; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_CREATE, - etag: 'abc', - shareOwner: 'User One' - }]); - $tr = fileList.$el.find('tbody tr:first'); - expect($tr.find('.action-share').length).toEqual(1); - }); - it('do not show share action when share exists but neither permission nor owner is available', function() { - var $action, $tr; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_CREATE, - etag: 'abc' - }]); - $tr = fileList.$el.find('tbody tr:first'); - expect($tr.find('.action-share').length).toEqual(0); - }); - }); - describe('Share action', function() { - var shareTab; - - function makeDummyShareItem(displayName) { - return { - share_with_displayname: displayName - }; - } - - beforeEach(function() { - // make it look like not the "All files" list - fileList.id = 'test'; - shareTab = fileList._detailsView._tabViews[0]; - }); - afterEach(function() { - shareTab = null; - }); - it('clicking share action opens sidebar and share tab', function() { - var showDetailsViewStub = sinon.stub(fileList, 'showDetailsView'); - - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc' - }]); - - var $tr = fileList.$el.find('tr:first'); - $tr.find('.action-share').click(); - - expect(showDetailsViewStub.calledOnce).toEqual(true); - expect(showDetailsViewStub.getCall(0).args[0]).toEqual('One.txt'); - expect(showDetailsViewStub.getCall(0).args[1]).toEqual('shareTabView'); - - showDetailsViewStub.restore(); - }); - it('adds share icon after sharing a non-shared file', function() { - var $action, $tr; - OC.Share.statuses = {}; - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc' - }]); - $action = fileList.$el.find('tbody tr:first .action-share'); - $tr = fileList.$el.find('tr:first'); - - $tr.find('.action-share').click(); - - // simulate updating shares - shareTab._dialog.model.set({ - shares: [ - {share_with_displayname: 'User One'}, - {share_with_displayname: 'User Two'}, - {share_with_displayname: 'Group One'}, - {share_with_displayname: 'Group Two'} - ] - }); - - expect($tr.attr('data-share-recipients')).toEqual('Group One, Group Two, User One, User Two'); - - expect($action.find('>span').text().trim()).toEqual('Shared with Group One, Group Two, User One, User Two'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - }); - it('updates share icon after updating shares of a file', function() { - var $action, $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc' - }]); - $action = fileList.$el.find('tbody tr:first .action-share'); - $tr = fileList.$el.find('tr:first'); - - $tr.find('.action-share').click(); - - // simulate updating shares - shareTab._dialog.model.set({ - shares: [ - {share_with_displayname: 'User One'}, - {share_with_displayname: 'User Two'}, - {share_with_displayname: 'User Three'} - ] - }); - - expect($tr.attr('data-share-recipients')).toEqual('User One, User Three, User Two'); - - expect($action.find('>span').text().trim()).toEqual('Shared with User One, User Three, User Two'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - }); - it('removes share icon after removing all shares from a file', function() { - var $action, $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - recipients: 'User One, User Two' - }]); - $action = fileList.$el.find('tbody tr:first .action-share'); - $tr = fileList.$el.find('tr:first'); - - $tr.find('.action-share').click(); - - // simulate updating shares - shareTab._dialog.model.set({ - shares: [] - }); - - expect($tr.attr('data-share-recipients')).not.toBeDefined(); - }); - it('keep share text after updating reshare', function() { - var $action, $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - shareOwner: 'User One' - }]); - $action = fileList.$el.find('tbody tr:first .action-share'); - $tr = fileList.$el.find('tr:first'); - - $tr.find('.action-share').click(); - - // simulate updating shares - shareTab._dialog.model.set({ - shares: [{share_with_displayname: 'User Two'}] - }); - - expect($tr.attr('data-share-recipients')).toEqual('User Two'); - - expect($action.find('>span').text().trim()).toEqual('User One'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - }); - it('keep share text after unsharing reshare', function() { - var $action, $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc', - shareOwner: 'User One', - recipients: 'User Two' - }]); - $action = fileList.$el.find('tbody tr:first .action-share'); - $tr = fileList.$el.find('tr:first'); - - $tr.find('.action-share').click(); - - // simulate updating shares - shareTab._dialog.model.set({ - shares: [] - }); - - expect($tr.attr('data-share-recipients')).not.toBeDefined(); - - expect($action.find('>span').text().trim()).toEqual('User One'); - expect($action.find('.icon').hasClass('icon-share')).toEqual(true); - expect($action.find('.icon').hasClass('icon-public')).toEqual(false); - }); - }); - describe('formatRecipients', function() { - it('returns a single recipient when one passed', function() { - expect(OCA.Sharing.Util.formatRecipients(['User one'])) - .toEqual('User one'); - }); - it('returns two recipients when two passed', function() { - expect(OCA.Sharing.Util.formatRecipients(['User one', 'User two'])) - .toEqual('User one, User two'); - }); - it('returns four recipients with plus when five passed', function() { - var recipients = [ - 'User one', - 'User two', - 'User three', - 'User four', - 'User five' - ]; - expect(OCA.Sharing.Util.formatRecipients(recipients)) - .toEqual('User four, User one, User three, User two, +1'); - }); - it('returns four recipients with plus when ten passed', function() { - var recipients = [ - 'User one', - 'User two', - 'User three', - 'User four', - 'User five', - 'User six', - 'User seven', - 'User eight', - 'User nine', - 'User ten' - ]; - expect(OCA.Sharing.Util.formatRecipients(recipients)) - .toEqual('User four, User one, User three, User two, +6'); - }); - it('returns four recipients with plus when four passed with counter', function() { - var recipients = [ - 'User one', - 'User two', - 'User three', - 'User four' - ]; - expect(OCA.Sharing.Util.formatRecipients(recipients, 10)) - .toEqual('User four, User one, User three, User two, +6'); - }); - }); - describe('Excluded lists', function() { - function createListThenAttach(listId) { - var fileActions = new OCA.Files.FileActions(); - fileList.destroy(); - fileList = new OCA.Files.FileList( - $('#listContainer'), { - id: listId, - fileActions: fileActions - } - ); - OCA.Sharing.Util.attach(fileList); - fileList.setFiles(testFiles); - return fileList; - } - - it('does not attach to trashbin or public file lists', function() { - createListThenAttach('trashbin'); - expect($('.action-share').length).toEqual(0); - expect($('[data-share-recipient]').length).toEqual(0); - createListThenAttach('files.public'); - expect($('.action-share').length).toEqual(0); - expect($('[data-share-recipient]').length).toEqual(0); - }); - }); - -}); diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js deleted file mode 100644 index 0b0676a19e6..00000000000 --- a/apps/files_sharing/tests/js/sharedfilelistSpec.js +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -describe('OCA.Sharing.FileList tests', function() { - var testFiles, alertStub, notificationStub, fileList; - - beforeEach(function() { - alertStub = sinon.stub(OC.dialogs, 'alert'); - notificationStub = sinon.stub(OC.Notification, 'show'); - - // init parameters and test table elements - $('#testArea').append( - '<div id="app-content-container">' + - // init horrible parameters - '<input type="hidden" id="dir" value="/"></input>' + - '<input type="hidden" id="permissions" value="31"></input>' + - // dummy controls - '<div id="controls">' + - ' <div class="actions creatable"></div>' + - ' <div class="notCreatable"></div>' + - '</div>' + - // dummy table - // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + - '<thead><tr>' + - '<th id="headerName" class="hidden column-name">' + - '<input type="checkbox" id="select_all_files" class="select-all">' + - '<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' + - '<span class="selectedActions hidden">' + - '</th>' + - '<th class="hidden column-mtime">' + - '<a class="columntitle" data-sort="mtime"><span class="sort-indicator"></span></a>' + - '</th>' + - '</tr></thead>' + - '<tbody id="fileList"></tbody>' + - '<tfoot></tfoot>' + - '</table>' + - '<div id="emptycontent">Empty content message</div>' + - '</div>' - ); - }); - afterEach(function() { - testFiles = undefined; - fileList.destroy(); - fileList = undefined; - - notificationStub.restore(); - alertStub.restore(); - }); - - describe('loading file list for incoming shares', function() { - var ocsResponse; - var ocsResponseRemote; - - beforeEach(function() { - fileList = new OCA.Sharing.FileList( - $('#app-content-container'), { - sharedWithUser: true - } - ); - OCA.Sharing.Util.attach(fileList); - - fileList.reload(); - - /* jshint camelcase: false */ - ocsResponse = { - ocs: { - meta: { - status: 'ok', - statuscode: 100, - message: null - }, - data: [{ - id: 7, - item_type: 'file', - item_source: 49, - item_target: '/49', - file_source: 49, - file_target: '/local path/local name.txt', - path: 'files/something shared.txt', - permissions: 31, - stime: 11111, - share_type: OC.Share.SHARE_TYPE_USER, - share_with: 'user1', - share_with_displayname: 'User One', - mimetype: 'text/plain', - uid_owner: 'user2', - displayname_owner: 'User Two' - }] - } - }; - - /* jshint camelcase: false */ - ocsResponseRemote = { - ocs: { - meta: { - status: 'ok', - statuscode: 100, - message: null - }, - data: [{ - id: 8, - remote: 'https://foo.bar/', - remote_id: 42, - share_token: 'abc', - name: '/a.txt', - owner: 'user3', - user: 'user1', - mountpoint: '/b.txt', - mountpoint_hash: 'def', - accepted: 1, - mimetype: 'text/plain', - mtime: 22222, - permissions: 31, - type: 'file', - file_id: 1337 - }] - } - }; - - }); - it('render file shares', function() { - expect(fakeServer.requests.length).toEqual(2); - expect(fakeServer.requests[0].url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=true' - ); - - expect(fakeServer.requests[1].url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'remote_shares?format=json' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - fakeServer.requests[1].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponseRemote) - ); - - var $rows = fileList.$el.find('tbody tr'); - expect($rows.length).toEqual(2); - - var $tr = $rows.eq(0); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('local name.txt'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-owner')).toEqual('User Two'); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/remote.php/webdav/local%20path/local%20name.txt' - ); - expect($tr.find('.nametext').text().trim()).toEqual('local name.txt'); - - $tr = $rows.eq(1); - expect($tr.attr('data-id')).toEqual('1337'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('b.txt'); - expect($tr.attr('data-path')).toEqual(''); - expect($tr.attr('data-size')).not.toBeDefined(); - expect(parseInt($tr.attr('data-permissions'), 10)) - .toEqual(OC.PERMISSION_ALL); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - expect($tr.attr('data-mtime')).toEqual('22222000'); - expect($tr.attr('data-share-owner')).toEqual('user3@foo.bar/'); - expect($tr.attr('data-share-id')).toEqual('8'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/remote.php/webdav/b.txt' - ); - expect($tr.find('.nametext').text().trim()).toEqual('b.txt'); - }); - it('render folder shares', function() { - /* jshint camelcase: false */ - ocsResponse.ocs.data[0] = _.extend(ocsResponse.ocs.data[0], { - item_type: 'folder', - file_target: '/local path/local name', - path: 'files/something shared', - }); - - ocsResponseRemote.ocs.data[0] = _.extend(ocsResponseRemote.ocs.data[0], { - type: 'dir', - mimetype: 'httpd/unix-directory', - name: '/a', - mountpoint: '/b' - }); - - expect(fakeServer.requests.length).toEqual(2); - expect(fakeServer.requests[0].url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=true' - ); - expect(fakeServer.requests[1].url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'remote_shares?format=json' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - fakeServer.requests[1].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponseRemote) - ); - - var $rows = fileList.$el.find('tbody tr'); - expect($rows.length).toEqual(2); - - var $tr = $rows.eq(0); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('dir'); - expect($tr.attr('data-file')).toEqual('local name'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-owner')).toEqual('User Two'); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/index.php/apps/files' + - '?dir=/local%20path/local%20name' - ); - expect($tr.find('.nametext').text().trim()).toEqual('local name'); - - $tr = $rows.eq(1); - expect($tr.attr('data-id')).toEqual('1337'); - expect($tr.attr('data-type')).toEqual('dir'); - expect($tr.attr('data-file')).toEqual('b'); - expect($tr.attr('data-path')).toEqual(''); - expect($tr.attr('data-size')).not.toBeDefined(); - expect(parseInt($tr.attr('data-permissions'), 10)) - .toEqual(OC.PERMISSION_ALL); // read and delete - expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); - expect($tr.attr('data-mtime')).toEqual('22222000'); - expect($tr.attr('data-share-owner')).toEqual('user3@foo.bar/'); - expect($tr.attr('data-share-id')).toEqual('8'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/index.php/apps/files' + - '?dir=/b' - ); - expect($tr.find('.nametext').text().trim()).toEqual('b'); - - }); - }); - describe('loading file list for outgoing shares', function() { - var ocsResponse; - - beforeEach(function() { - fileList = new OCA.Sharing.FileList( - $('#app-content-container'), { - sharedWithUser: false - } - ); - OCA.Sharing.Util.attach(fileList); - - fileList.reload(); - - /* jshint camelcase: false */ - ocsResponse = { - ocs: { - meta: { - status: 'ok', - statuscode: 100, - message: null - }, - data: [{ - id: 7, - item_type: 'file', - item_source: 49, - file_source: 49, - path: '/local path/local name.txt', - permissions: 27, - stime: 11111, - share_type: OC.Share.SHARE_TYPE_USER, - share_with: 'user2', - share_with_displayname: 'User Two', - mimetype: 'text/plain', - uid_owner: 'user1', - displayname_owner: 'User One' - }] - } - }; - }); - it('render file shares', function() { - var request; - - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=false' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - var $rows = fileList.$el.find('tbody tr'); - var $tr = $rows.eq(0); - expect($rows.length).toEqual(1); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('local name.txt'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-owner')).not.toBeDefined(); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/remote.php/webdav/local%20path/local%20name.txt' - ); - expect($tr.find('.nametext').text().trim()).toEqual('local name.txt'); - }); - it('render folder shares', function() { - var request; - /* jshint camelcase: false */ - ocsResponse.ocs.data[0] = _.extend(ocsResponse.ocs.data[0], { - item_type: 'folder', - path: '/local path/local name', - }); - - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=false' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - var $rows = fileList.$el.find('tbody tr'); - var $tr = $rows.eq(0); - expect($rows.length).toEqual(1); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('dir'); - expect($tr.attr('data-file')).toEqual('local name'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('httpd/unix-directory'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-owner')).not.toBeDefined(); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/index.php/apps/files' + - '?dir=/local%20path/local%20name' - ); - expect($tr.find('.nametext').text().trim()).toEqual('local name'); - }); - it('render link shares', function() { - /* jshint camelcase: false */ - var request; - ocsResponse.ocs.data[0] = { - id: 7, - item_type: 'file', - item_source: 49, - file_source: 49, - path: '/local path/local name.txt', - permissions: 1, - stime: 11111, - share_type: OC.Share.SHARE_TYPE_LINK, - share_with: null, - token: 'abc', - mimetype: 'text/plain', - uid_owner: 'user1', - displayname_owner: 'User One' - }; - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=false' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - var $rows = fileList.$el.find('tbody tr'); - var $tr = $rows.eq(0); - expect($rows.length).toEqual(1); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('local name.txt'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-owner')).not.toBeDefined(); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt' - ); - - expect($tr.find('.nametext').text().trim()).toEqual('local name.txt'); - }); - it('groups link shares with regular shares', function() { - /* jshint camelcase: false */ - var request; - // link share - ocsResponse.ocs.data.push({ - id: 8, - item_type: 'file', - item_source: 49, - file_source: 49, - path: '/local path/local name.txt', - permissions: 1, - stime: 11111, - share_type: OC.Share.SHARE_TYPE_LINK, - share_with: null, - token: 'abc', - mimetype: 'text/plain', - uid_owner: 'user1', - displayname_owner: 'User One' - }); - // another share of the same file - ocsResponse.ocs.data.push({ - id: 9, - item_type: 'file', - item_source: 49, - file_source: 49, - path: '/local path/local name.txt', - permissions: 27, - stime: 22222, - share_type: OC.Share.SHARE_TYPE_USER, - share_with: 'user3', - share_with_displayname: 'User Three', - mimetype: 'text/plain', - uid_owner: 'user1', - displayname_owner: 'User One' - }); - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=false' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - var $rows = fileList.$el.find('tbody tr'); - var $tr = $rows.eq(0); - expect($rows.length).toEqual(1); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('local name.txt'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - // always use the most recent stime - expect($tr.attr('data-mtime')).toEqual('22222000'); - expect($tr.attr('data-share-owner')).not.toBeDefined(); - expect($tr.attr('data-share-id')).toEqual('7,8,9'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt' - ); - expect($tr.find('.nametext').text().trim()).toEqual('local name.txt'); - }); - }); - describe('loading file list for link shares', function() { - var ocsResponse; - - beforeEach(function() { - fileList = new OCA.Sharing.FileList( - $('#app-content-container'), { - linksOnly: true - } - ); - OCA.Sharing.Util.attach(fileList); - - fileList.reload(); - - /* jshint camelcase: false */ - ocsResponse = { - ocs: { - meta: { - status: 'ok', - statuscode: 100, - message: null - }, - data: [{ - id: 7, - item_type: 'file', - item_source: 49, - file_source: 49, - path: '/local path/local name.txt', - permissions: 1, - stime: 11111, - share_type: OC.Share.SHARE_TYPE_LINK, - share_with: null, - token: 'abc', - mimetype: 'text/plain', - uid_owner: 'user1', - displayname_owner: 'User One' - }] - } - }; - }); - it('render only link shares', function() { - /* jshint camelcase: false */ - var request; - ocsResponse.ocs.data.push({ - // non-link share - id: 8, - item_type: 'file', - item_source: 49, - file_source: 49, - path: '/local path/local name.txt', - permissions: 27, - stime: 11111, - share_type: OC.Share.SHARE_TYPE_USER, - share_with: 'user2', - share_with_displayname: 'User Two', - mimetype: 'text/plain', - uid_owner: 'user1', - displayname_owner: 'User One' - }); - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=false' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - // only renders the link share entry - var $rows = fileList.$el.find('tbody tr'); - var $tr = $rows.eq(0); - expect($rows.length).toEqual(1); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('local name.txt'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-recipients')).not.toBeDefined(); - expect($tr.attr('data-share-owner')).not.toBeDefined(); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt' - ); - - expect($tr.find('.nametext').text().trim()).toEqual('local name.txt'); - }); - it('does not show virtual token recipient as recipient when password was set', function() { - /* jshint camelcase: false */ - var request; - // when a password is set, share_with contains an auth token - ocsResponse.ocs.data[0].share_with = 'abc01234/01234abc'; - ocsResponse.ocs.data[0].share_with_displayname = 'abc01234/01234abc'; - expect(fakeServer.requests.length).toEqual(1); - request = fakeServer.requests[0]; - expect(request.url).toEqual( - OC.linkToOCS('apps/files_sharing/api/v1') + - 'shares?format=json&shared_with_me=false' - ); - - fakeServer.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(ocsResponse) - ); - - // only renders the link share entry - var $rows = fileList.$el.find('tbody tr'); - var $tr = $rows.eq(0); - expect($rows.length).toEqual(1); - expect($tr.attr('data-id')).toEqual('49'); - expect($tr.attr('data-type')).toEqual('file'); - expect($tr.attr('data-file')).toEqual('local name.txt'); - expect($tr.attr('data-path')).toEqual('/local path'); - expect($tr.attr('data-size')).not.toBeDefined(); - expect($tr.attr('data-permissions')).toEqual('31'); // read and delete - expect($tr.attr('data-mime')).toEqual('text/plain'); - expect($tr.attr('data-mtime')).toEqual('11111000'); - expect($tr.attr('data-share-recipients')).not.toBeDefined(); - expect($tr.attr('data-share-owner')).not.toBeDefined(); - expect($tr.attr('data-share-id')).toEqual('7'); - expect($tr.find('a.name').attr('href')).toEqual( - OC.webroot + - '/remote.php/webdav/local%20path/local%20name.txt'); - - expect($tr.find('.nametext').text().trim()).toEqual('local name.txt'); - }); - }); - describe('setting share permissions for files', function () { - beforeEach(function () { - - var $content = $('<div id="content"></div>'); - $('#testArea').append($content); - // dummy file list - var $div = $( - '<div>' + - '<table id="filestable">' + - '<thead></thead>' + - '<tbody id="fileList"></tbody>' + - '</table>' + - '</div>'); - $('#content').append($div); - - fileList = new OCA.Files.FileList($div); - OCA.Sharing.Util.attach(fileList); - }); - - it('external storage root folder', function () { - var $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_READ, - etag: 'abc', - shareOwner: 'User One', - recipients: 'User Two', - mountType: 'external-root' - }]); - $tr = fileList.$el.find('tr:first'); - - expect(parseInt($tr.attr('data-share-permissions'), 10)).toEqual(OC.PERMISSION_ALL - OC.PERMISSION_SHARE); - }); - - it('external storage root folder reshare', function () { - var $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'dir', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_READ + OC.PERMISSION_SHARE, - etag: 'abc', - shareOwner: 'User One', - recipients: 'User Two', - mountType: 'external-root' - }]); - $tr = fileList.$el.find('tr:first'); - - expect(parseInt($tr.attr('data-share-permissions'), 10)).toEqual(OC.PERMISSION_ALL); - }); - - it('external storage root folder file', function () { - var $tr; - OC.Share.statuses = {1: {link: false, path: '/subdir'}}; - fileList.setFiles([{ - id: 1, - type: 'file', - name: 'One.txt', - path: '/subdir', - mimetype: 'text/plain', - size: 12, - permissions: OC.PERMISSION_READ, - etag: 'abc', - shareOwner: 'User One', - recipients: 'User Two', - mountType: 'external-root' - }]); - $tr = fileList.$el.find('tr:first'); - - expect(parseInt($tr.attr('data-share-permissions'), 10)) - .toEqual(OC.PERMISSION_ALL - OC.PERMISSION_SHARE - OC.PERMISSION_DELETE - OC.PERMISSION_CREATE); - }); - }); -}); diff --git a/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php b/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php deleted file mode 100644 index e80be772a92..00000000000 --- a/apps/files_sharing/tests/middleware/sharingcheckmiddleware.php +++ /dev/null @@ -1,287 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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\Middleware; -use OCP\AppFramework\Http\NotFoundResponse; -use OCP\Files\NotFoundException; -use OCP\AppFramework\Utility\IControllerMethodReflector; -use OCA\Files_Sharing\Exceptions\S2SException; -use OCP\AppFramework\Http\JSONResponse; - -/** - * @package OCA\Files_Sharing\Middleware\SharingCheckMiddleware - */ -class SharingCheckMiddlewareTest extends \Test\TestCase { - - /** @var \OCP\IConfig */ - private $config; - /** @var \OCP\App\IAppManager */ - private $appManager; - /** @var SharingCheckMiddleware */ - private $sharingCheckMiddleware; - /** @var \OCP\AppFramework\Controller */ - private $controllerMock; - /** @var IControllerMethodReflector */ - private $reflector; - - protected function setUp() { - $this->config = $this->getMockBuilder('\OCP\IConfig') - ->disableOriginalConstructor()->getMock(); - $this->appManager = $this->getMockBuilder('\OCP\App\IAppManager') - ->disableOriginalConstructor()->getMock(); - $this->controllerMock = $this->getMockBuilder('\OCP\AppFramework\Controller') - ->disableOriginalConstructor()->getMock(); - $this->reflector = $this->getMockBuilder('\OCP\AppFramework\Utility\IControllerMethodReflector') - ->disableOriginalConstructor()->getMock(); - - $this->sharingCheckMiddleware = new SharingCheckMiddleware( - 'files_sharing', - $this->config, - $this->appManager, - $this->reflector); - } - - public function testIsSharingEnabledWithAppEnabled() { - $this->appManager - ->expects($this->once()) - ->method('isEnabledForUser') - ->with('files_sharing') - ->will($this->returnValue(true)); - - $this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled')); - } - - public function testIsSharingEnabledWithAppDisabled() { - $this->appManager - ->expects($this->once()) - ->method('isEnabledForUser') - ->with('files_sharing') - ->will($this->returnValue(false)); - - $this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled')); - } - - public function testIsLinkSharingEnabledWithEverythinEnabled() { - $this->config - ->expects($this->at(0)) - ->method('getAppValue') - ->with('core', 'shareapi_enabled', 'yes') - ->will($this->returnValue('yes')); - - $this->config - ->expects($this->at(1)) - ->method('getAppValue') - ->with('core', 'shareapi_allow_links', 'yes') - ->will($this->returnValue('yes')); - - $this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled')); - } - - - public function testIsLinkSharingEnabledWithLinkSharingDisabled() { - $this->config - ->expects($this->at(0)) - ->method('getAppValue') - ->with('core', 'shareapi_enabled', 'yes') - ->will($this->returnValue('yes')); - - $this->config - ->expects($this->at(1)) - ->method('getAppValue') - ->with('core', 'shareapi_allow_links', 'yes') - ->will($this->returnValue('no')); - - $this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled')); - } - - public function testIsLinkSharingEnabledWithSharingAPIDisabled() { - $this->config - ->expects($this->once()) - ->method('getAppValue') - ->with('core', 'shareapi_enabled', 'yes') - ->will($this->returnValue('no')); - - $this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled')); - } - - public function externalSharesChecksDataProvider() { - - $data = []; - - foreach ([false, true] as $annIn) { - foreach ([false, true] as $annOut) { - foreach ([false, true] as $confIn) { - foreach ([false, true] as $confOut) { - - $res = true; - if (!$annIn && !$confIn) { - $res = false; - } elseif (!$annOut && !$confOut) { - $res = false; - } - - $d = [ - [ - ['NoIncomingFederatedSharingRequired', $annIn], - ['NoOutgoingFederatedSharingRequired', $annOut], - ], - [ - ['files_sharing', 'incoming_server2server_share_enabled', 'yes', $confIn ? 'yes' : 'no'], - ['files_sharing', 'outgoing_server2server_share_enabled', 'yes', $confOut ? 'yes' : 'no'], - ], - $res - ]; - - $data[] = $d; - } - } - } - } - - return $data; - } - - /** - * @dataProvider externalSharesChecksDataProvider - */ - public function testExternalSharesChecks($annotations, $config, $expectedResult) { - $this->reflector - ->expects($this->atLeastOnce()) - ->method('hasAnnotation') - ->will($this->returnValueMap($annotations)); - - $this->config - ->method('getAppValue') - ->will($this->returnValueMap($config)); - - $this->assertEquals($expectedResult, self::invokePrivate($this->sharingCheckMiddleware, 'externalSharesChecks')); - } - - /** - * @dataProvider externalSharesChecksDataProvider - */ - public function testBeforeControllerWithExternalShareControllerWithSharingEnabled($annotations, $config, $noException) { - $this->appManager - ->expects($this->once()) - ->method('isEnabledForUser') - ->with('files_sharing') - ->will($this->returnValue(true)); - - $this->reflector - ->expects($this->atLeastOnce()) - ->method('hasAnnotation') - ->will($this->returnValueMap($annotations)); - - $this->config - ->method('getAppValue') - ->will($this->returnValueMap($config)); - - $controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ExternalSharesController') - ->disableOriginalConstructor()->getMock(); - - $exceptionThrown = false; - - try { - $this->sharingCheckMiddleware->beforeController($controller, 'myMethod'); - } catch (\OCA\Files_Sharing\Exceptions\S2SException $exception) { - $exceptionThrown = true; - } - - $this->assertNotEquals($noException, $exceptionThrown); - } - - public function testBeforeControllerWithShareControllerWithSharingEnabled() { - $this->appManager - ->expects($this->once()) - ->method('isEnabledForUser') - ->with('files_sharing') - ->will($this->returnValue(true)); - - $this->config - ->expects($this->at(0)) - ->method('getAppValue') - ->with('core', 'shareapi_enabled', 'yes') - ->will($this->returnValue('yes')); - - $this->config - ->expects($this->at(1)) - ->method('getAppValue') - ->with('core', 'shareapi_allow_links', 'yes') - ->will($this->returnValue('yes')); - - $controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ShareController') - ->disableOriginalConstructor()->getMock(); - - $this->sharingCheckMiddleware->beforeController($controller, 'myMethod'); - } - - /** - * @expectedException \OCP\Files\NotFoundException - * @expectedExceptionMessage Link sharing is disabled - */ - public function testBeforeControllerWithShareControllerWithSharingEnabledAPIDisabled() { - $this->appManager - ->expects($this->once()) - ->method('isEnabledForUser') - ->with('files_sharing') - ->will($this->returnValue(true)); - - $controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ShareController') - ->disableOriginalConstructor()->getMock(); - - $this->sharingCheckMiddleware->beforeController($controller, 'myMethod'); - } - - /** - * @expectedException \OCP\Files\NotFoundException - * @expectedExceptionMessage Sharing is disabled. - */ - public function testBeforeControllerWithSharingDisabled() { - $this->appManager - ->expects($this->once()) - ->method('isEnabledForUser') - ->with('files_sharing') - ->will($this->returnValue(false)); - - $this->sharingCheckMiddleware->beforeController($this->controllerMock, 'myMethod'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage My Exception message - */ - public function testAfterExceptionWithRegularException() { - $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new \Exception('My Exception message')); - } - - public function testAfterExceptionWithNotFoundException() { - $this->assertEquals(new NotFoundResponse(), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new NotFoundException('My Exception message'))); - } - - public function testAfterExceptionWithS2SException() { - $this->assertEquals(new JSONResponse('My Exception message', 405), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new S2SException('My Exception message'))); - } - - -} diff --git a/apps/files_sharing/tests/migrationtest.php b/apps/files_sharing/tests/migrationtest.php deleted file mode 100644 index 82e6f47addb..00000000000 --- a/apps/files_sharing/tests/migrationtest.php +++ /dev/null @@ -1,351 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - - -use OCA\Files_Sharing\Tests\TestCase; -use OCA\Files_Sharing\Migration; - -/** - * Class MigrationTest - * - * @group DB - */ -class MigrationTest extends TestCase { - - /** @var \OCP\IDBConnection */ - private $connection; - - /** @var Migration */ - private $migration; - - private $table = 'share'; - - public function setUp() { - parent::setUp(); - - $this->connection = \OC::$server->getDatabaseConnection(); - $this->migration = new Migration($this->connection); - - $this->cleanDB(); - } - - public function tearDown() { - parent::tearDown(); - $this->cleanDB(); - } - - private function cleanDB() { - $query = $this->connection->getQueryBuilder(); - $query->delete($this->table)->execute(); - } - - public function addDummyValues() { - $query = $this->connection->getQueryBuilder(); - $query->insert($this->table) - ->values( - array( - 'share_type' => $query->createParameter('share_type'), - 'share_with' => $query->createParameter('share_with'), - 'uid_owner' => $query->createParameter('uid_owner'), - 'uid_initiator' => $query->createParameter('uid_initiator'), - 'parent' => $query->createParameter('parent'), - 'item_type' => $query->createParameter('item_type'), - 'item_source' => $query->createParameter('item_source'), - 'item_target' => $query->createParameter('item_target'), - 'file_source' => $query->createParameter('file_source'), - 'file_target' => $query->createParameter('file_target'), - 'permissions' => $query->createParameter('permissions'), - 'stime' => $query->createParameter('stime'), - ) - ); - // shared contact, shouldn't be modified - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_CONTACT) - ->setParameter('share_with', 'user1') - ->setParameter('uid_owner', 'owner1') - ->setParameter('uid_initiator', '') - ->setParameter('parent', null) - ->setParameter('item_type', 'contact') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', null) - ->setParameter('file_target', null) - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - // shared calendar, shouldn't be modified - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER) - ->setParameter('share_with', 'user1') - ->setParameter('uid_owner', 'owner1') - ->setParameter('uid_initiator', '') - ->setParameter('parent', null) - ->setParameter('item_type', 'calendar') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', null) - ->setParameter('file_target', null) - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - // single user share, shouldn't be modified - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER) - ->setParameter('share_with', 'user1') - ->setParameter('uid_owner', 'owner1') - ->setParameter('uid_initiator', '') - ->setParameter('parent', null) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foo') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - // single group share, shouldn't be modified - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_GROUP) - ->setParameter('share_with', 'group1') - ->setParameter('uid_owner', 'owner1') - ->setParameter('uid_initiator', '') - ->setParameter('parent', null) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foo') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - $parent = $query->getLastInsertId(); - // unique target for group share, shouldn't be modified - $query->setParameter('share_type', 2) - ->setParameter('share_with', 'group1') - ->setParameter('uid_owner', 'owner1') - ->setParameter('uid_initiator', '') - ->setParameter('parent', $parent) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foo renamed') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - // first user share, shouldn't be modified - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER) - ->setParameter('share_with', 'user1') - ->setParameter('uid_owner', 'owner2') - ->setParameter('uid_initiator', '') - ->setParameter('parent', null) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foobar') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - $parent = $query->getLastInsertId(); - // first re-share, should be attached to the first user share after migration - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER) - ->setParameter('share_with', 'user2') - ->setParameter('uid_owner', 'user1') - ->setParameter('uid_initiator', '') - ->setParameter('parent', $parent) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foobar') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - $parent = $query->getLastInsertId(); - // second re-share, should be attached to the first user share after migration - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER) - ->setParameter('share_with', 'user3') - ->setParameter('uid_owner', 'user2') - ->setParameter('uid_initiator', '') - ->setParameter('parent', $parent) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foobar') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - $parent = $query->getLastInsertId(); - // third re-share, should be attached to the first user share after migration - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_REMOTE) - ->setParameter('share_with', 'user@server.com') - ->setParameter('uid_owner', 'user3') - ->setParameter('uid_initiator', '') - ->setParameter('parent', $parent) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foobar') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - - // Link reshare should keep its parent - $query->setParameter('share_type', \OCP\Share::SHARE_TYPE_LINK) - ->setParameter('share_with', null) - ->setParameter('uid_owner', 'user3') - ->setParameter('uid_initiator', '') - ->setParameter('parent', $parent) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foobar') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - $this->assertSame(1, - $query->execute() - ); - } - - public function testRemoveReShares() { - $this->addDummyValues(); - $this->migration->removeReShares(); - $this->verifyResult(); - } - - public function verifyResult() { - $query = $this->connection->getQueryBuilder(); - $query->select('*')->from($this->table)->orderBy('id'); - $result = $query->execute()->fetchAll(); - $this->assertSame(10, count($result)); - - // shares which shouldn't be modified - for ($i = 0; $i < 4; $i++) { - $this->assertSame('owner1', $result[$i]['uid_owner']); - $this->assertEmpty($result[$i]['uid_initiator']); - $this->assertNull($result[$i]['parent']); - } - // group share with unique target - $this->assertSame('owner1', $result[4]['uid_owner']); - $this->assertEmpty($result[4]['uid_initiator']); - $this->assertNotEmpty($result[4]['parent']); - // initial user share which was re-shared - $this->assertSame('owner2', $result[5]['uid_owner']); - $this->assertEmpty($result[5]['uid_initiator']); - $this->assertNull($result[5]['parent']); - // flatted re-shares - for($i = 6; $i < 9; $i++) { - $this->assertSame('owner2', $result[$i]['uid_owner']); - $user = 'user' . ($i - 5); - $this->assertSame($user, $result[$i]['uid_initiator']); - $this->assertNull($result[$i]['parent']); - } - - /* - * The link share is flattend but has an owner to avoid invisible shares - * see: https://github.com/owncloud/core/pull/22317 - */ - $this->assertSame('owner2', $result[9]['uid_owner']); - $this->assertSame('user3', $result[9]['uid_initiator']); - $this->assertSame($result[7]['id'], $result[9]['parent']); - } - - public function test1001DeepReshares() { - $parent = null; - for ($i = 0; $i < 1001; $i++) { - $query = $this->connection->getQueryBuilder(); - $query->insert($this->table) - ->values( - [ - 'share_type' => $query->createParameter('share_type'), - 'share_with' => $query->createParameter('share_with'), - 'uid_owner' => $query->createParameter('uid_owner'), - 'uid_initiator' => $query->createParameter('uid_initiator'), - 'parent' => $query->createParameter('parent'), - 'item_type' => $query->createParameter('item_type'), - 'item_source' => $query->createParameter('item_source'), - 'item_target' => $query->createParameter('item_target'), - 'file_source' => $query->createParameter('file_source'), - 'file_target' => $query->createParameter('file_target'), - 'permissions' => $query->createParameter('permissions'), - 'stime' => $query->createParameter('stime'), - ] - ) - ->setParameter('share_type', \OCP\Share::SHARE_TYPE_USER) - ->setParameter('share_with', 'user'.($i+1)) - ->setParameter('uid_owner', 'user'.($i)) - ->setParameter('uid_initiator', null) - ->setParameter('parent', $parent) - ->setParameter('item_type', 'file') - ->setParameter('item_source', '2') - ->setParameter('item_target', '/2') - ->setParameter('file_source', 2) - ->setParameter('file_target', '/foobar') - ->setParameter('permissions', 31) - ->setParameter('stime', time()); - - $this->assertSame(1, $query->execute()); - $parent = $query->getLastInsertId(); - } - - $this->migration->removeReShares(); - $this->migration->updateInitiatorInfo(); - - $qb = $this->connection->getQueryBuilder(); - - $stmt = $qb->select('id', 'share_with', 'uid_owner', 'uid_initiator', 'parent') - ->from('share') - ->orderBy('id', 'asc') - ->execute(); - - $i = 0; - while($share = $stmt->fetch()) { - $this->assertEquals('user'.($i+1), $share['share_with']); - $this->assertEquals('user' . ($i), $share['uid_initiator']); - $this->assertEquals('user0', $share['uid_owner']); - $this->assertEquals(null, $share['parent']); - $i++; - } - $stmt->closeCursor(); - $this->assertEquals(1001, $i); - } -} diff --git a/apps/files_sharing/tests/permissions.php b/apps/files_sharing/tests/permissions.php deleted file mode 100644 index 43a57266851..00000000000 --- a/apps/files_sharing/tests/permissions.php +++ /dev/null @@ -1,161 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ -use OC\Files\Cache\Cache; -use OC\Files\Storage\Storage; -use OC\Files\View; - -/** - * Class Test_Files_Sharing_Permissions - * - * @group DB - */ -class Test_Files_Sharing_Permissions extends OCA\Files_sharing\Tests\TestCase { - - /** - * @var Storage - */ - private $sharedStorageRestrictedShare; - - /** - * @var Storage - */ - private $sharedCacheRestrictedShare; - - /** - * @var View - */ - private $secondView; - - /** - * @var Storage - */ - private $ownerStorage; - - /** - * @var Storage - */ - private $sharedStorage; - - /** - * @var Cache - */ - private $sharedCache; - - /** - * @var Cache - */ - private $ownerCache; - - protected function setUp() { - parent::setUp(); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // prepare user1's dir structure - $textData = "dummy file data\n"; - $this->view->mkdir('container'); - $this->view->mkdir('container/shareddir'); - $this->view->mkdir('container/shareddir/subdir'); - $this->view->mkdir('container/shareddirrestricted'); - $this->view->mkdir('container/shareddirrestricted/subdir'); - $this->view->file_put_contents('container/shareddir/textfile.txt', $textData); - $this->view->file_put_contents('container/shareddirrestricted/textfile1.txt', $textData); - - list($this->ownerStorage, $internalPath) = $this->view->resolvePath(''); - $this->ownerCache = $this->ownerStorage->getCache(); - $this->ownerStorage->getScanner()->scan(''); - - // share "shareddir" with user2 - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - $fileinfo2 = $this->view->getFileInfo('container/shareddirrestricted'); - \OCP\Share::shareItem('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 7); - - // login as user2 - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // retrieve the shared storage - $this->secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2); - list($this->sharedStorage, $internalPath) = $this->secondView->resolvePath('files/shareddir'); - list($this->sharedStorageRestrictedShare, $internalPath) = $this->secondView->resolvePath('files/shareddirrestricted'); - $this->sharedCache = $this->sharedStorage->getCache(); - $this->sharedCacheRestrictedShare = $this->sharedStorageRestrictedShare->getCache(); - } - - protected function tearDown() { - if ($this->sharedCache) { - $this->sharedCache->clear(); - } - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $fileinfo2 = $this->view->getFileInfo('container/shareddirrestricted'); - \OCP\Share::unshare('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - - $this->view->deleteAll('container'); - - $this->ownerCache->clear(); - - parent::tearDown(); - } - - /** - * Test that the permissions of shared directory are returned correctly - */ - function testGetPermissions() { - $sharedDirPerms = $this->sharedStorage->getPermissions('shareddir'); - $this->assertEquals(31, $sharedDirPerms); - $sharedDirPerms = $this->sharedStorage->getPermissions('shareddir/textfile.txt'); - $this->assertEquals(31, $sharedDirPerms); - $sharedDirRestrictedPerms = $this->sharedStorageRestrictedShare->getPermissions('shareddirrestricted'); - $this->assertEquals(7, $sharedDirRestrictedPerms); - $sharedDirRestrictedPerms = $this->sharedStorageRestrictedShare->getPermissions('shareddirrestricted/textfile.txt'); - $this->assertEquals(7, $sharedDirRestrictedPerms); - } - - /** - * Test that the permissions of shared directory are returned correctly - */ - function testGetDirectoryPermissions() { - $contents = $this->secondView->getDirectoryContent('files/shareddir'); - $this->assertEquals('subdir', $contents[0]['name']); - $this->assertEquals(31, $contents[0]['permissions']); - $this->assertEquals('textfile.txt', $contents[1]['name']); - // 27 is correct because create is reserved to folders only - requires more unit tests overall to ensure this - $this->assertEquals(27, $contents[1]['permissions']); - $contents = $this->secondView->getDirectoryContent('files/shareddirrestricted'); - $this->assertEquals('subdir', $contents[0]['name']); - $this->assertEquals(7, $contents[0]['permissions']); - $this->assertEquals('textfile1.txt', $contents[1]['name']); - // 3 is correct because create is reserved to folders only - $this->assertEquals(3, $contents[1]['permissions']); - } -} diff --git a/apps/files_sharing/tests/server2server.php b/apps/files_sharing/tests/server2server.php deleted file mode 100644 index 7714f274c6d..00000000000 --- a/apps/files_sharing/tests/server2server.php +++ /dev/null @@ -1,254 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -use OCA\Files_Sharing\Tests\TestCase; - -/** - * Class Test_Files_Sharing_Api - * - * @group DB - */ -class Test_Files_Sharing_S2S_OCS_API extends TestCase { - - const TEST_FOLDER_NAME = '/folder_share_api_test'; - - /** - * @var \OCP\IDBConnection - */ - private $connection; - - /** - * @var \OCA\Files_Sharing\API\Server2Server - */ - private $s2s; - - protected function setUp() { - parent::setUp(); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OCP\Share::registerBackend('test', 'Test_Share_Backend'); - - $config = $this->getMockBuilder('\OCP\IConfig') - ->disableOriginalConstructor()->getMock(); - $clientService = $this->getMock('\OCP\Http\Client\IClientService'); - $httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper') - ->setConstructorArgs([$config, $clientService]) - ->getMock(); - $httpHelperMock->expects($this->any())->method('post')->with($this->anything())->will($this->returnValue(true)); - - $this->registerHttpHelper($httpHelperMock); - - $this->s2s = new \OCA\Files_Sharing\API\Server2Server(); - - $this->connection = \OC::$server->getDatabaseConnection(); - } - - protected function tearDown() { - $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external`'); - $query->execute(); - - $this->restoreHttpHelper(); - - parent::tearDown(); - } - - /** - * Register an http helper mock for testing purposes. - * @param $httpHelper http helper mock - */ - private function registerHttpHelper($httpHelper) { - $this->oldHttpHelper = \OC::$server->query('HTTPHelper'); - \OC::$server->registerService('HTTPHelper', function ($c) use ($httpHelper) { - return $httpHelper; - }); - } - - /** - * Restore the original http helper - */ - private function restoreHttpHelper() { - $oldHttpHelper = $this->oldHttpHelper; - \OC::$server->registerService('HTTPHelper', function ($c) use ($oldHttpHelper) { - return $oldHttpHelper; - }); - } - - /** - * @medium - */ - function testCreateShare() { - // simulate a post request - $_POST['remote'] = 'localhost'; - $_POST['token'] = 'token'; - $_POST['name'] = 'name'; - $_POST['owner'] = 'owner'; - $_POST['shareWith'] = self::TEST_FILES_SHARING_API_USER2; - $_POST['remoteId'] = 1; - - $result = $this->s2s->createShare(null); - - $this->assertTrue($result->succeeded()); - - $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share_external` WHERE `remote_id` = ?'); - $result = $query->execute(array('1')); - $data = $result->fetchRow(); - - $this->assertSame('localhost', $data['remote']); - $this->assertSame('token', $data['share_token']); - $this->assertSame('/name', $data['name']); - $this->assertSame('owner', $data['owner']); - $this->assertSame(self::TEST_FILES_SHARING_API_USER2, $data['user']); - $this->assertSame(1, (int)$data['remote_id']); - $this->assertSame(0, (int)$data['accepted']); - } - - - function testDeclineShare() { - $dummy = \OCP\DB::prepare(' - INSERT INTO `*PREFIX*share` - (`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`, `share_with`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); - $dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token', 'foo@bar')); - - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertSame(1, count($data)); - - $_POST['token'] = 'token'; - $this->s2s->declineShare(array('id' => $data[0]['id'])); - - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertEmpty($data); - } - - function testDeclineShareMultiple() { - $dummy = \OCP\DB::prepare(' - INSERT INTO `*PREFIX*share` - (`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`, `share_with`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); - $dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token1', 'foo@bar')); - $dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token2', 'bar@bar')); - - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertCount(2, $data); - - $_POST['token'] = 'token1'; - $this->s2s->declineShare(array('id' => $data[0]['id'])); - - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertCount(1, $data); - $this->assertEquals('bar@bar', $data[0]['share_with']); - - $_POST['token'] = 'token2'; - $this->s2s->declineShare(array('id' => $data[0]['id'])); - - $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $verify->execute(); - $data = $result->fetchAll(); - $this->assertEmpty($data); - } - - /** - * @dataProvider dataTestDeleteUser - */ - function testDeleteUser($toDelete, $expected, $remainingUsers) { - $this->createDummyS2SShares(); - - $discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); - $manager = new OCA\Files_Sharing\External\Manager( - \OC::$server->getDatabaseConnection(), - \OC\Files\Filesystem::getMountManager(), - \OC\Files\Filesystem::getLoader(), - \OC::$server->getHTTPHelper(), - \OC::$server->getNotificationManager(), - $discoveryManager, - $toDelete - ); - - $manager->removeUserShares($toDelete); - - $query = $this->connection->prepare('SELECT `user` FROM `*PREFIX*share_external`'); - $query->execute(); - $result = $query->fetchAll(); - - foreach ($result as $r) { - $remainingShares[$r['user']] = isset($remainingShares[$r['user']]) ? $remainingShares[$r['user']] + 1 : 1; - } - - $this->assertSame($remainingUsers, count($remainingShares)); - - foreach ($expected as $key => $value) { - if ($key === $toDelete) { - $this->assertArrayNotHasKey($key, $remainingShares); - } else { - $this->assertSame($value, $remainingShares[$key]); - } - } - - } - - function dataTestDeleteUser() { - return array( - array('user1', array('user1' => 0, 'user2' => 3, 'user3' => 3), 2), - array('user2', array('user1' => 4, 'user2' => 0, 'user3' => 3), 2), - array('user3', array('user1' => 4, 'user2' => 3, 'user3' => 0), 2), - array('user4', array('user1' => 4, 'user2' => 3, 'user3' => 3), 3), - ); - } - - private function createDummyS2SShares() { - $query = $this->connection->prepare(' - INSERT INTO `*PREFIX*share_external` - (`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `remote_id`, `accepted`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); - - $users = array('user1', 'user2', 'user3'); - - for ($i = 0; $i < 10; $i++) { - $user = $users[$i%3]; - $query->execute(array('remote', 'token', 'password', 'name', 'owner', $user, 'mount point', $i, $i, 0)); - } - - $query = $this->connection->prepare('SELECT `id` FROM `*PREFIX*share_external`'); - $query->execute(); - $dummyEntries = $query->fetchAll(); - - $this->assertSame(10, count($dummyEntries)); - } - -} diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php deleted file mode 100644 index aad698bcdba..00000000000 --- a/apps/files_sharing/tests/share.php +++ /dev/null @@ -1,478 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -use OCA\Files\Share; - -/** - * Class Test_Files_Sharing - * - * @group DB - */ -class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase { - - const TEST_FOLDER_NAME = '/folder_share_api_test'; - - private static $tempStorage; - - protected function setUp() { - parent::setUp(); - - $this->folder = self::TEST_FOLDER_NAME; - $this->subfolder = '/subfolder_share_api_test'; - $this->subsubfolder = '/subsubfolder_share_api_test'; - - $this->filename = '/share-api-test.txt'; - - // save file with content - $this->view->file_put_contents($this->filename, $this->data); - $this->view->mkdir($this->folder); - $this->view->mkdir($this->folder . $this->subfolder); - $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); - $this->view->file_put_contents($this->folder.$this->filename, $this->data); - $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); - } - - protected function tearDown() { - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->view->unlink($this->filename); - $this->view->deleteAll($this->folder); - - self::$tempStorage = null; - - // clear database table - $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share`'); - $query->execute(); - - parent::tearDown(); - } - - public function testUnshareFromSelf() { - - \OC_Group::createGroup('testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - - $fileinfo = $this->view->getFileInfo($this->filename); - - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, 31); - - $this->assertTrue($result); - - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, - 'testGroup', 31); - - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - \OC\Files\Filesystem::unlink($this->filename); - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - // both group share and user share should be gone - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename)); - - // for user3 nothing should change - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - } - - /** - * if a file was shared as group share and as individual share they should be grouped - */ - public function testGroupingOfShares() { - - $fileinfo = $this->view->getFileInfo($this->filename); - - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, - \Test_Files_Sharing::TEST_FILES_SHARING_API_GROUP1, \OCP\Constants::PERMISSION_READ); - - $this->assertTrue($result); - - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_UPDATE); - - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $result = \OCP\Share::getItemSharedWith('file', null); - - $this->assertTrue(is_array($result)); - - // test should return exactly one shares created from testCreateShare() - $this->assertSame(1, count($result)); - - $share = reset($result); - $this->assertSame(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE, $share['permissions']); - - \OC\Files\Filesystem::rename($this->filename, $this->filename . '-renamed'); - - $result = \OCP\Share::getItemSharedWith('file', null); - - $this->assertTrue(is_array($result)); - - // test should return exactly one shares created from testCreateShare() - $this->assertSame(1, count($result)); - - $share = reset($result); - $this->assertSame(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE, $share['permissions']); - $this->assertSame($this->filename . '-renamed', $share['file_target']); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // unshare user share - $result = \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $result = \OCP\Share::getItemSharedWith('file', null); - - $this->assertTrue(is_array($result)); - - // test should return the remaining group share - $this->assertSame(1, count($result)); - - $share = reset($result); - // only the group share permissions should be available now - $this->assertSame(\OCP\Constants::PERMISSION_READ, $share['permissions']); - $this->assertSame($this->filename . '-renamed', $share['file_target']); - - } - - /** - * user1 share file to a group and to a user2 in the same group. Then user2 - * unshares the file from self. Afterwards user1 should no longer see the - * single user share to user2. If he re-shares the file to user2 the same target - * then the group share should be used to group the item - */ - public function testShareAndUnshareFromSelf() { - $fileinfo = $this->view->getFileInfo($this->filename); - - // share the file to group1 (user2 is a member of this group) and explicitely to user2 - \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1, \OCP\Constants::PERMISSION_ALL); - \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_ALL); - - // user1 should have to shared files - $shares = \OCP\Share::getItemsShared('file'); - $this->assertSame(2, count($shares)); - - // user2 should have two files "welcome.txt" and the shared file, - // both the group share and the single share of the same file should be - // grouped to one file - \Test_Files_Sharing::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $dirContent = \OC\Files\Filesystem::getDirectoryContent('/'); - $this->assertSame(2, count($dirContent)); - $this->verifyDirContent($dirContent, array('welcome.txt', ltrim($this->filename, '/'))); - - // now user2 deletes the share (= unshare from self) - \OC\Files\Filesystem::unlink($this->filename); - - // only welcome.txt should exists - $dirContent = \OC\Files\Filesystem::getDirectoryContent('/'); - $this->assertSame(1, count($dirContent)); - $this->verifyDirContent($dirContent, array('welcome.txt')); - - // login as user1... - \Test_Files_Sharing::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // ... now user1 should have only one shared file, the group share - $shares = \OCP\Share::getItemsShared('file'); - $this->assertSame(1, count($shares)); - - // user1 shares a gain the file directly to user2 - \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_ALL); - - // user2 should see again welcome.txt and the shared file - \Test_Files_Sharing::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $dirContent = \OC\Files\Filesystem::getDirectoryContent('/'); - $this->assertSame(2, count($dirContent)); - $this->verifyDirContent($dirContent, array('welcome.txt', ltrim($this->filename, '/'))); - - - } - - /** - * @param OC\Files\FileInfo[] $content - * @param string[] $expected - */ - public function verifyDirContent($content, $expected) { - foreach ($content as $c) { - if (!in_array($c['name'], $expected)) { - $this->assertTrue(false, "folder should only contain '" . implode(',', $expected) . "', found: " .$c['name']); - } - } - } - - public function testShareWithDifferentShareFolder() { - - $fileinfo = $this->view->getFileInfo($this->filename); - $folderinfo = $this->view->getFileInfo($this->folder); - - $fileShare = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($fileShare); - - \OCA\Files_Sharing\Helper::setShareFolder('/Shared/subfolder'); - - $folderShare = \OCP\Share::shareItem('folder', $folderinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($folderShare); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - $this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/subfolder/' . $this->folder)); - - //cleanup - \OC::$server->getConfig()->deleteSystemValue('share_folder'); - } - - public function testShareWithGroupUniqueName() { - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OC\Files\Filesystem::file_put_contents('test.txt', 'test'); - - $fileInfo = \OC\Files\Filesystem::getFileInfo('test.txt'); - - $this->assertTrue( - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, self::TEST_FILES_SHARING_API_GROUP1, 23) - ); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $items = \OCP\Share::getItemsSharedWith('file'); - $this->assertSame('/test.txt' ,$items[0]['file_target']); - $this->assertSame(23, $items[0]['permissions']); - - \OC\Files\Filesystem::rename('test.txt', 'new test.txt'); - - $items = \OCP\Share::getItemsSharedWith('file'); - $this->assertSame('/new test.txt' ,$items[0]['file_target']); - $this->assertSame(23, $items[0]['permissions']); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OCP\Share::setPermissions('file', $items[0]['item_source'], $items[0]['share_type'], $items[0]['share_with'], 3); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $items = \OCP\Share::getItemsSharedWith('file'); - - $this->assertSame('/new test.txt' ,$items[0]['file_target']); - $this->assertSame(3, $items[0]['permissions']); - } - - /** - * shared files should never have delete permissions - * @dataProvider dataProviderTestFileSharePermissions - */ - public function testFileSharePermissions($permission, $expectedPermissions) { - - $fileinfo = $this->view->getFileInfo($this->filename); - - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, $permission); - - $this->assertTrue($result); - - $result = \OCP\Share::getItemShared('file', null); - - $this->assertTrue(is_array($result)); - - // test should return exactly one shares created from testCreateShare() - $this->assertSame(1, count($result), 'more then one share found'); - - $share = reset($result); - $this->assertSame($expectedPermissions, $share['permissions']); - } - - public function dataProviderTestFileSharePermissions() { - $permission1 = \OCP\Constants::PERMISSION_ALL; - $permission3 = \OCP\Constants::PERMISSION_READ; - $permission4 = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE; - $permission5 = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_DELETE; - $permission6 = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; - - return array( - array($permission1, \OCP\Constants::PERMISSION_ALL & ~\OCP\Constants::PERMISSION_DELETE), - array($permission3, $permission3), - array($permission4, $permission4), - array($permission5, $permission3), - array($permission6, $permission4), - ); - } - - public function testFileOwner() { - - $fileinfo = $this->view->getFileInfo($this->filename); - - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_ALL); - - $this->assertTrue($result); - - $this->loginHelper(\Test_Files_Sharing::TEST_FILES_SHARING_API_USER2); - - $info = \OC\Files\Filesystem::getFileInfo($this->filename); - - $this->assertSame(\Test_Files_Sharing::TEST_FILES_SHARING_API_USER1, $info->getOwner()->getUID()); - } - - /** - * @dataProvider dataProviderGetUsersSharingFile - * - * @param string $groupName name of group to share with - * @param bool $includeOwner whether to include the owner in the result - * @param bool $includePaths whether to include paths in the result - * @param array $expectedResult expected result of the API call - */ - public function testGetUsersSharingFile($groupName, $includeOwner, $includePaths, $expectedResult) { - - $fileinfo = $this->view->getFileInfo($this->folder); - - $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, - $groupName, \OCP\Constants::PERMISSION_READ); - $this->assertTrue($result); - - // public share - $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, - null, \OCP\Constants::PERMISSION_READ); - $this->assertNotNull($result); // returns the token! - - // owner renames after sharing - $this->view->rename($this->folder, $this->folder . '_owner_renamed'); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $user2View->rename($this->folder, $this->folder . '_renamed'); - - $ownerPath = $this->folder . '_owner_renamed'; - $owner = self::TEST_FILES_SHARING_API_USER1; - - $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, $includeOwner, $includePaths); - - // sort users to make sure it matches - if ($includePaths) { - ksort($result); - } else { - sort($result['users']); - } - - $this->assertEquals( - $expectedResult, - $result - ); - } - - public function dataProviderGetUsersSharingFile() { - // note: "group" contains user1 (the owner), user2 and user3 - // and self::TEST_FILES_SHARING_API_GROUP1 contains only user2 - return [ - // share with group that contains owner - [ - 'group', - false, - false, - [ - 'users' => - [ - // because user1 was in group - self::TEST_FILES_SHARING_API_USER1, - self::TEST_FILES_SHARING_API_USER2, - self::TEST_FILES_SHARING_API_USER3, - ], - 'public' => true, - 'remote' => false, - ], - ], - // share with group that does not contain owner - [ - self::TEST_FILES_SHARING_API_GROUP1, - false, - false, - [ - 'users' => - [ - self::TEST_FILES_SHARING_API_USER2, - ], - 'public' => true, - 'remote' => false, - ], - ], - // share with group that does not contain owner, include owner - [ - self::TEST_FILES_SHARING_API_GROUP1, - true, - false, - [ - 'users' => - [ - self::TEST_FILES_SHARING_API_USER1, - self::TEST_FILES_SHARING_API_USER2, - ], - 'public' => true, - 'remote' => false, - ], - ], - // include paths, with owner - [ - 'group', - true, - true, - [ - self::TEST_FILES_SHARING_API_USER1 => self::TEST_FOLDER_NAME . '_owner_renamed', - self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME . '_renamed', - self::TEST_FILES_SHARING_API_USER3 => self::TEST_FOLDER_NAME, - ], - ], - // include paths, group without owner - [ - self::TEST_FILES_SHARING_API_GROUP1, - false, - true, - [ - self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME. '_renamed', - ], - ], - // include paths, include owner, group without owner - [ - self::TEST_FILES_SHARING_API_GROUP1, - true, - true, - [ - self::TEST_FILES_SHARING_API_USER1 => self::TEST_FOLDER_NAME . '_owner_renamed', - self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME . '_renamed', - ], - ], - ]; - } - -} diff --git a/apps/files_sharing/tests/sharedmount.php b/apps/files_sharing/tests/sharedmount.php deleted file mode 100644 index e01deeb60f4..00000000000 --- a/apps/files_sharing/tests/sharedmount.php +++ /dev/null @@ -1,466 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -/** - * Class Test_Files_Sharing_Api - * - * @group DB - */ -class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase { - - protected function setUp() { - parent::setUp(); - - $this->folder = '/folder_share_storage_test'; - - $this->filename = '/share-api-storage.txt'; - - - $this->view->mkdir($this->folder); - - // save file with content - $this->view->file_put_contents($this->filename, "root file"); - $this->view->file_put_contents($this->folder . $this->filename, "file in subfolder"); - } - - protected function tearDown() { - if ($this->view) { - $this->view->unlink($this->folder); - $this->view->unlink($this->filename); - } - - parent::tearDown(); - } - - /** - * test if the mount point moves up if the parent folder no longer exists - */ - function testShareMountLoseParentFolder() { - - // share to user - $fileinfo = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - $statement = "UPDATE `*PREFIX*share` SET `file_target` = ? where `share_with` = ?"; - $query = \OCP\DB::prepare($statement); - $arguments = array('/foo/bar' . $this->folder, self::TEST_FILES_SHARING_API_USER2); - $query->execute($arguments); - - $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $query->execute(); - - $shares = $result->fetchAll(); - - $this->assertSame(1, count($shares)); - - $share = reset($shares); - $this->assertSame('/foo/bar' . $this->folder, $share['file_target']); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // share should have moved up - - $query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); - $result = $query->execute(); - - $shares = $result->fetchAll(); - - $this->assertSame(1, count($shares)); - - $share = reset($shares); - $this->assertSame($this->folder, $share['file_target']); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2); - $this->view->unlink($this->folder); - } - - /** - * @medium - */ - function testDeleteParentOfMountPoint() { - - // share to user - $fileinfo = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $this->assertTrue($user2View->file_exists($this->folder)); - - // create a local folder - $result = $user2View->mkdir('localfolder'); - $this->assertTrue($result); - - // move mount point to local folder - $result = $user2View->rename($this->folder, '/localfolder/' . $this->folder); - $this->assertTrue($result); - - // mount point in the root folder should no longer exist - $this->assertFalse($user2View->is_dir($this->folder)); - - // delete the local folder - $result = $user2View->unlink('/localfolder'); - $this->assertTrue($result); - - //enforce reload of the mount points - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - //mount point should be back at the root - $this->assertTrue($user2View->is_dir($this->folder)); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->view->unlink($this->folder); - } - - function testMoveSharedFile() { - $fileinfo = $this->view->getFileInfo($this->filename); - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - \OC\Files\Filesystem::rename($this->filename, $this->filename . '_renamed'); - - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename . '_renamed')); - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename)); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename . '_renamed')); - - // rename back to original name - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - \OC\Files\Filesystem::rename($this->filename . '_renamed', $this->filename); - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename . '_renamed')); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - - //cleanup - \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2); - } - - /** - * share file with a group if a user renames the file the filename should not change - * for the other users - */ - function testMoveGroupShare () { - \OC_Group::createGroup('testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - - $fileinfo = $this->view->getFileInfo($this->filename); - $result = \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, - "testGroup", 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - - \OC\Files\Filesystem::rename($this->filename, "newFileName"); - - $this->assertTrue(\OC\Files\Filesystem::file_exists('newFileName')); - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename)); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - $this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName")); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename)); - $this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName")); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - } - - /** - * @dataProvider dataProviderTestStripUserFilesPath - * @param string $path - * @param string $expectedResult - * @param bool $exception if a exception is expected - */ - function testStripUserFilesPath($path, $expectedResult, $exception) { - $testClass = new DummyTestClassSharedMount(null, null); - try { - $result = $testClass->stripUserFilesPathDummy($path); - $this->assertSame($expectedResult, $result); - } catch (\Exception $e) { - if ($exception) { - $this->assertSame(10, $e->getCode()); - } else { - $this->assertTrue(false, "Exception catched, but expected: " . $expectedResult); - } - } - } - - function dataProviderTestStripUserFilesPath() { - return array( - array('/user/files/foo.txt', '/foo.txt', false), - array('/user/files/folder/foo.txt', '/folder/foo.txt', false), - array('/data/user/files/foo.txt', null, true), - array('/data/user/files/', null, true), - array('/files/foo.txt', null, true), - array('/foo.txt', null, true), - ); - } - - function dataPermissionMovedGroupShare() { - $data = []; - - $powerset = function($permissions) { - $results = [\OCP\Constants::PERMISSION_READ]; - - foreach ($permissions as $permission) { - foreach ($results as $combination) { - $results[] = $permission | $combination; - } - } - return $results; - }; - - //Generate file permissions - $permissions = [ - \OCP\Constants::PERMISSION_UPDATE, - \OCP\Constants::PERMISSION_CREATE, - \OCP\Constants::PERMISSION_SHARE, - ]; - - $allPermissions = $powerset($permissions); - - foreach ($allPermissions as $before) { - foreach ($allPermissions as $after) { - if ($before === $after) { continue; } - - $data[] = [ - 'file', - $before, - $after, - ]; - } - } - - //Generate folder permissions - $permissions = [ - \OCP\Constants::PERMISSION_UPDATE, - \OCP\Constants::PERMISSION_CREATE, - \OCP\Constants::PERMISSION_SHARE, - \OCP\Constants::PERMISSION_DELETE, - ]; - - $allPermissions = $powerset($permissions); - - foreach ($allPermissions as $before) { - foreach ($allPermissions as $after) { - if ($before === $after) { continue; } - - $data[] = [ - 'folder', - $before, - $after, - ]; - } - } - - return $data; - } - - - - /** - * moved mountpoints of a group share should keep the same permission as their parent group share. - * See #15253 - * - * @dataProvider dataPermissionMovedGroupShare - */ - function testPermissionMovedGroupShare($type, $beforePerm, $afterPerm) { - - if ($type === 'file') { - $path = $this->filename; - } else if ($type === 'folder') { - $path = $this->folder; - } - - \OC_Group::createGroup('testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - - // Share item with group - $fileinfo = $this->view->getFileInfo($path); - $this->assertTrue( - \OCP\Share::shareItem($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", $beforePerm) - ); - - // Login as user 2 and verify the item exists - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue(\OC\Files\Filesystem::file_exists($path)); - $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']); - $this->assertNotEmpty($result); - $this->assertEquals($beforePerm, $result['permissions']); - - // Now move the item forcing a new entry in the share table - \OC\Files\Filesystem::rename($path, "newPath"); - $this->assertTrue(\OC\Files\Filesystem::file_exists('newPath')); - $this->assertFalse(\OC\Files\Filesystem::file_exists($path)); - - // Login as user 1 again and change permissions - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->assertTrue( - \OCP\Share::setPermissions($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", $afterPerm) - ); - - // Login as user 3 and verify that the permissions are changed - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']); - $this->assertNotEmpty($result); - $this->assertEquals($afterPerm, $result['permissions']); - $groupShareId = $result['id']; - - // Login as user 2 and verify that the permissions are changed - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $result = \OCP\Share::getItemSharedWithBySource($type, $fileinfo['fileid']); - $this->assertNotEmpty($result); - $this->assertEquals($afterPerm, $result['permissions']); - $this->assertNotEquals($groupShareId, $result['id']); - - // Also verify in the DB - $statement = "SELECT `permissions` FROM `*PREFIX*share` WHERE `id`=?"; - $query = \OCP\DB::prepare($statement); - $result = $query->execute([$result['id']]); - $shares = $result->fetchAll(); - $this->assertCount(1, $shares); - $this->assertEquals($afterPerm, $shares[0]['permissions']); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OCP\Share::unshare($type, $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - } - - /** - * If the permissions on a group share are upgraded be sure to still respect - * removed shares by a member of that group - */ - function testPermissionUpgradeOnUserDeletedGroupShare() { - \OC_Group::createGroup('testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::addToGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - - $connection = \OC::$server->getDatabaseConnection(); - - // Share item with group - $fileinfo = $this->view->getFileInfo($this->folder); - $this->assertTrue( - \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", \OCP\Constants::PERMISSION_READ) - ); - - // Login as user 2 and verify the item exists - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->folder)); - $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']); - $this->assertNotEmpty($result); - $this->assertEquals(\OCP\Constants::PERMISSION_READ, $result['permissions']); - - // Delete the share - $this->assertTrue(\OC\Files\Filesystem::rmdir($this->folder)); - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->folder)); - - // Verify we do not get a share - $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']); - $this->assertEmpty($result); - - // Verify that the permission is correct in the DB - $qb = $connection->getQueryBuilder(); - $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('file_source', $qb->createParameter('fileSource'))) - ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('shareType'))) - ->setParameter(':fileSource', $fileinfo['fileid']) - ->setParameter(':shareType', 2); - $res = $qb->execute()->fetchAll(); - - $this->assertCount(1, $res); - $this->assertEquals(0, $res[0]['permissions']); - - // Login as user 1 again and change permissions - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->assertTrue( - \OCP\Share::setPermissions('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, "testGroup", \OCP\Constants::PERMISSION_ALL) - ); - - // Login as user 2 and verify - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertFalse(\OC\Files\Filesystem::file_exists($this->folder)); - $result = \OCP\Share::getItemSharedWithBySource('folder', $fileinfo['fileid']); - $this->assertEmpty($result); - - $connection = \OC::$server->getDatabaseConnection(); - $qb = $connection->getQueryBuilder(); - $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('file_source', $qb->createParameter('fileSource'))) - ->andWhere($qb->expr()->eq('share_type', $qb->createParameter('shareType'))) - ->setParameter(':fileSource', $fileinfo['fileid']) - ->setParameter(':shareType', 2); - $res = $qb->execute()->fetchAll(); - - $this->assertCount(1, $res); - $this->assertEquals(0, $res[0]['permissions']); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER1, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER2, 'testGroup'); - \OC_Group::removeFromGroup(self::TEST_FILES_SHARING_API_USER3, 'testGroup'); - } - -} - -class DummyTestClassSharedMount extends \OCA\Files_Sharing\SharedMount { - public function __construct($storage, $mountpoint, $arguments = null, $loader = null){ - // noop - } - - public function stripUserFilesPathDummy($path) { - return $this->stripUserFilesPath($path); - } -} diff --git a/apps/files_sharing/tests/sharedstorage.php b/apps/files_sharing/tests/sharedstorage.php deleted file mode 100644 index 63f4334103f..00000000000 --- a/apps/files_sharing/tests/sharedstorage.php +++ /dev/null @@ -1,488 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - -use OCA\Files\Share; - -/** - * Class Test_Files_Sharing_Api - * - * @group DB - */ -class Test_Files_Sharing_Storage extends OCA\Files_sharing\Tests\TestCase { - - protected function setUp() { - parent::setUp(); - \OCA\Files_Trashbin\Trashbin::registerHooks(); - $this->folder = '/folder_share_storage_test'; - - $this->filename = '/share-api-storage.txt'; - - - $this->view->mkdir($this->folder); - - // save file with content - $this->view->file_put_contents($this->filename, "root file"); - $this->view->file_put_contents($this->folder . $this->filename, "file in subfolder"); - } - - protected function tearDown() { - if ($this->view) { - $this->view->unlink($this->folder); - $this->view->unlink($this->filename); - } - - \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); - - parent::tearDown(); - } - - /** - * if the parent of the mount point is gone then the mount point should move up - * - * @medium - */ - function testParentOfMountPointIsGone() { - - // share to user - $fileinfo = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $this->assertTrue($user2View->file_exists($this->folder)); - - // create a local folder - $result = $user2View->mkdir('localfolder'); - $this->assertTrue($result); - - // move mount point to local folder - $result = $user2View->rename($this->folder, '/localfolder/' . $this->folder); - $this->assertTrue($result); - - // mount point in the root folder should no longer exist - $this->assertFalse($user2View->is_dir($this->folder)); - - // delete the local folder - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/localfolder'); - $storage->rmdir($internalPath); - - //enforce reload of the mount points - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - //mount point should be back at the root - $this->assertTrue($user2View->is_dir($this->folder)); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->view->unlink($this->folder); - } - - /** - * @medium - */ - function testRenamePartFile() { - - // share to user - $fileinfo = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - $this->assertTrue($user2View->file_exists($this->folder)); - - // create part file - $result = $user2View->file_put_contents($this->folder . '/foo.txt.part', 'some test data'); - - $this->assertTrue(is_int($result)); - // rename part file to real file - $result = $user2View->rename($this->folder . '/foo.txt.part', $this->folder . '/foo.txt'); - - $this->assertTrue($result); - - // check if the new file really exists - $this->assertTrue($user2View->file_exists($this->folder . '/foo.txt')); - - // check if the rename also affected the owner - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $this->assertTrue($this->view->file_exists($this->folder . '/foo.txt')); - - //cleanup - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - } - - public function testFilesize() { - - $fileinfoFolder = $this->view->getFileInfo($this->folder); - $fileinfoFile = $this->view->getFileInfo($this->filename); - - $folderSize = $this->view->filesize($this->folder); - $file1Size = $this->view->filesize($this->folder . $this->filename); - $file2Size = $this->view->filesize($this->filename); - - $result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($result); - - $result = \OCP\Share::shareItem('file', $fileinfoFile['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // compare file size between user1 and user2, should always be the same - $this->assertSame($folderSize, \OC\Files\Filesystem::filesize($this->folder)); - $this->assertSame($file1Size, \OC\Files\Filesystem::filesize($this->folder . $this->filename)); - $this->assertSame($file2Size, \OC\Files\Filesystem::filesize($this->filename)); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - $result = \OCP\Share::unshare('file', $fileinfoFile['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - - function testGetPermissions() { - $fileinfoFolder = $this->view->getFileInfo($this->folder); - - $result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 1); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $this->assertTrue(\OC\Files\Filesystem::is_dir($this->folder)); - - // for the share root we expect: - // the shared permissions (1) - // the delete permission (8), to enable unshare - $rootInfo = \OC\Files\Filesystem::getFileInfo($this->folder); - $this->assertSame(9, $rootInfo->getPermissions()); - - // for the file within the shared folder we expect: - // the shared permissions (1) - $subfileInfo = \OC\Files\Filesystem::getFileInfo($this->folder . $this->filename); - $this->assertSame(1, $subfileInfo->getPermissions()); - - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - - public function testFopenWithReadOnlyPermission() { - $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); - $fileinfoFolder = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - // part file should be forbidden - $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); - $this->assertFalse($handle); - - // regular file forbidden - $handle = $user2View->fopen($this->folder . '/test.txt', 'w'); - $this->assertFalse($handle); - - // rename forbidden - $this->assertFalse($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing2.txt')); - - // delete forbidden - $this->assertFalse($user2View->unlink($this->folder . '/existing.txt')); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - - public function testFopenWithCreateOnlyPermission() { - $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); - $fileinfoFolder = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - // create part file allowed - $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); - $this->assertNotFalse($handle); - fclose($handle); - - // create regular file allowed - $handle = $user2View->fopen($this->folder . '/test-create.txt', 'w'); - $this->assertNotFalse($handle); - fclose($handle); - - // rename file never allowed - $this->assertFalse($user2View->rename($this->folder . '/test-create.txt', $this->folder . '/newtarget.txt')); - $this->assertFalse($user2View->file_exists($this->folder . '/newtarget.txt')); - - // rename file not allowed if target exists - $this->assertFalse($user2View->rename($this->folder . '/newtarget.txt', $this->folder . '/existing.txt')); - - // overwriting file not allowed - $handle = $user2View->fopen($this->folder . '/existing.txt', 'w'); - $this->assertFalse($handle); - - // overwrite forbidden (no update permission) - $this->assertFalse($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/existing.txt')); - - // delete forbidden - $this->assertFalse($user2View->unlink($this->folder . '/existing.txt')); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - - public function testFopenWithUpdateOnlyPermission() { - $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); - $fileinfoFolder = $this->view->getFileInfo($this->folder); - - $result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - // create part file allowed - $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); - $this->assertNotFalse($handle); - fclose($handle); - - // create regular file not allowed - $handle = $user2View->fopen($this->folder . '/test-create.txt', 'w'); - $this->assertFalse($handle); - - // rename part file not allowed to non-existing file - $this->assertFalse($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/nonexist.txt')); - - // rename part file allowed to target existing file - $this->assertTrue($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/existing.txt')); - $this->assertTrue($user2View->file_exists($this->folder . '/existing.txt')); - - // rename regular file allowed - $this->assertTrue($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing-renamed.txt')); - $this->assertTrue($user2View->file_exists($this->folder . '/existing-renamed.txt')); - - // overwriting file directly is allowed - $handle = $user2View->fopen($this->folder . '/existing-renamed.txt', 'w'); - $this->assertNotFalse($handle); - fclose($handle); - - // delete forbidden - $this->assertFalse($user2View->unlink($this->folder . '/existing-renamed.txt')); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - - public function testFopenWithDeleteOnlyPermission() { - $this->view->file_put_contents($this->folder . '/existing.txt', 'foo'); - $fileinfoFolder = $this->view->getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_DELETE); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - // part file should be forbidden - $handle = $user2View->fopen($this->folder . '/test.txt.part', 'w'); - $this->assertFalse($handle); - - // regular file forbidden - $handle = $user2View->fopen($this->folder . '/test.txt', 'w'); - $this->assertFalse($handle); - - // rename forbidden - $this->assertFalse($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing2.txt')); - - // delete allowed - $this->assertTrue($user2View->unlink($this->folder . '/existing.txt')); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - - function testMountSharesOtherUser() { - $folderInfo = $this->view->getFileInfo($this->folder); - $fileInfo = $this->view->getFileInfo($this->filename); - $rootView = new \OC\Files\View(''); - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // share 2 different files with 2 different users - \OCP\Share::shareItem('folder', $folderInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER3, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . $this->folder)); - - $mountConfigManager = \OC::$server->getMountProviderCollection(); - $mounts = $mountConfigManager->getMountsForUser(\OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER3)); - array_walk($mounts, array(\OC\Files\Filesystem::getMountManager(), 'addMount')); - - $this->assertTrue($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER3 . '/files/' . $this->filename)); - - // make sure we didn't double setup shares for user 2 or mounted the shares for user 3 in user's 2 home - $this->assertFalse($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . $this->folder . ' (2)')); - $this->assertFalse($rootView->file_exists('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/' . $this->filename)); - - //cleanup - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->view->unlink($this->folder); - } - - public function testCopyFromStorage() { - $folderInfo = $this->view->getFileInfo($this->folder); - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // share 2 different files with 2 different users - \OCP\Share::shareItem('folder', $folderInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $view = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $this->assertTrue($view->file_exists($this->folder)); - - /** - * @var \OCP\Files\Storage $sharedStorage - */ - list($sharedStorage,) = $view->resolvePath($this->folder); - $this->assertTrue($sharedStorage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')); - - $sourceStorage = new \OC\Files\Storage\Temporary(array()); - $sourceStorage->file_put_contents('foo.txt', 'asd'); - - $sharedStorage->copyFromStorage($sourceStorage, 'foo.txt', 'bar.txt'); - $this->assertTrue($sharedStorage->file_exists('bar.txt')); - $this->assertEquals('asd', $sharedStorage->file_get_contents('bar.txt')); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->view->unlink($this->folder); - } - - public function testMoveFromStorage() { - $folderInfo = $this->view->getFileInfo($this->folder); - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // share 2 different files with 2 different users - \OCP\Share::shareItem('folder', $folderInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $view = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $this->assertTrue($view->file_exists($this->folder)); - - /** - * @var \OCP\Files\Storage $sharedStorage - */ - list($sharedStorage,) = $view->resolvePath($this->folder); - $this->assertTrue($sharedStorage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')); - - $sourceStorage = new \OC\Files\Storage\Temporary(array()); - $sourceStorage->file_put_contents('foo.txt', 'asd'); - - $sharedStorage->moveFromStorage($sourceStorage, 'foo.txt', 'bar.txt'); - $this->assertTrue($sharedStorage->file_exists('bar.txt')); - $this->assertEquals('asd', $sharedStorage->file_get_contents('bar.txt')); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->view->unlink($this->folder); - } - - public function testNameConflict() { - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $view1 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); - $view1->mkdir('foo'); - $folderInfo1 = $view1->getFileInfo('foo'); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - $view3 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files'); - $view3->mkdir('foo'); - $folderInfo2 = $view3->getFileInfo('foo'); - - // share a folder with the same name from two different users to the same user - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - \OCP\Share::shareItem('folder', $folderInfo1['fileid'], \OCP\Share::SHARE_TYPE_GROUP, - self::TEST_FILES_SHARING_API_GROUP1, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER3); - - \OCP\Share::shareItem('folder', $folderInfo2['fileid'], \OCP\Share::SHARE_TYPE_GROUP, - self::TEST_FILES_SHARING_API_GROUP1, 31); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - $view2 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - $this->assertTrue($view2->file_exists('/foo')); - $this->assertTrue($view2->file_exists('/foo (2)')); - - $mount = $view2->getMount('/foo'); - $this->assertInstanceOf('\OCA\Files_Sharing\SharedMount', $mount); - /** @var \OC\Files\Storage\Shared $storage */ - $storage = $mount->getStorage(); - - $source = $storage->getFile(''); - $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $source['uid_owner']); - } -} diff --git a/apps/files_sharing/tests/sizepropagation.php b/apps/files_sharing/tests/sizepropagation.php deleted file mode 100644 index 7b7884f3f96..00000000000 --- a/apps/files_sharing/tests/sizepropagation.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php -/** - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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; - -/** - * Class SizePropagation - * - * @group DB - * - * @package OCA\Files_sharing\Tests - */ -class SizePropagation extends TestCase { - - public function testSizePropagationWhenOwnerChangesFile() { - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $ownerView->mkdir('/sharedfolder/subfolder'); - $ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar'); - - $sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false); - $this->assertInstanceOf('\OC\Files\FileInfo', $sharedFolderInfo); - \OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31); - $ownerRootInfo = $ownerView->getFileInfo('', false); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt')); - $recipientRootInfo = $recipientView->getFileInfo('', false); - - // when file changed as owner - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar'); - - // size of recipient's root stays the same - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $newRecipientRootInfo = $recipientView->getFileInfo('', false); - $this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize()); - - // size of owner's root increases - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $newOwnerRootInfo = $ownerView->getFileInfo('', false); - $this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize()); - } - - public function testSizePropagationWhenRecipientChangesFile() { - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - $ownerView->mkdir('/sharedfolder/subfolder'); - $ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar'); - - $sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false); - $this->assertInstanceOf('\OC\Files\FileInfo', $sharedFolderInfo); - \OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31); - $ownerRootInfo = $ownerView->getFileInfo('', false); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt')); - $recipientRootInfo = $recipientView->getFileInfo('', false); - - // when file changed as recipient - $recipientView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar'); - - // size of recipient's root stays the same - $newRecipientRootInfo = $recipientView->getFileInfo('', false); - $this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize()); - - // size of owner's root increases - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $newOwnerRootInfo = $ownerView->getFileInfo('', false); - $this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize()); - } -} diff --git a/apps/files_sharing/tests/testcase.php b/apps/files_sharing/tests/testcase.php deleted file mode 100644 index ce0a8beeec8..00000000000 --- a/apps/files_sharing/tests/testcase.php +++ /dev/null @@ -1,204 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\Filesystem; -use OCA\Files\Share; -use OCA\Files_Sharing\Appinfo\Application; - -/** - * Class Test_Files_Sharing_Base - * - * @group DB - * - * Base class for sharing tests. - */ -abstract class TestCase extends \Test\TestCase { - - const TEST_FILES_SHARING_API_USER1 = "test-share-user1"; - const TEST_FILES_SHARING_API_USER2 = "test-share-user2"; - const TEST_FILES_SHARING_API_USER3 = "test-share-user3"; - const TEST_FILES_SHARING_API_USER4 = "test-share-user4"; - - const TEST_FILES_SHARING_API_GROUP1 = "test-share-group1"; - - public $filename; - public $data; - /** - * @var \OC\Files\View - */ - public $view; - public $folder; - public $subfolder; - - public static function setUpBeforeClass() { - parent::setUpBeforeClass(); - - $application = new Application(); - $application->registerMountProviders(); - - // reset backend - \OC_User::clearBackends(); - \OC_Group::clearBackends(); - - // clear share hooks - \OC_Hook::clear('OCP\\Share'); - \OC::registerShareHooks(); - - // create users - $backend = new \Test\Util\User\Dummy(); - \OC_User::useBackend($backend); - $backend->createUser(self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER1); - $backend->createUser(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER2); - $backend->createUser(self::TEST_FILES_SHARING_API_USER3, self::TEST_FILES_SHARING_API_USER3); - $backend->createUser(self::TEST_FILES_SHARING_API_USER4, self::TEST_FILES_SHARING_API_USER4); - - // create group - $groupBackend = new \OC_Group_Dummy(); - $groupBackend->createGroup(self::TEST_FILES_SHARING_API_GROUP1); - $groupBackend->createGroup('group'); - $groupBackend->createGroup('group1'); - $groupBackend->createGroup('group2'); - $groupBackend->createGroup('group3'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER1, 'group'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, 'group'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER3, 'group'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, 'group1'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER3, 'group2'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER4, 'group3'); - $groupBackend->addToGroup(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_GROUP1); - \OC_Group::useBackend($groupBackend); - - } - - protected function setUp() { - parent::setUp(); - - //login as user1 - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $this->data = 'foobar'; - $this->view = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files'); - } - - protected function tearDown() { - $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share`'); - $query->execute(); - - parent::tearDown(); - } - - public static function tearDownAfterClass() { - // cleanup users - $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER1); - if ($user !== null) { $user->delete(); } - $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER2); - if ($user !== null) { $user->delete(); } - $user = \OC::$server->getUserManager()->get(self::TEST_FILES_SHARING_API_USER3); - if ($user !== null) { $user->delete(); } - - // delete group - \OC_Group::deleteGroup(self::TEST_FILES_SHARING_API_GROUP1); - - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - Filesystem::tearDown(); - - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Database()); - - parent::tearDownAfterClass(); - } - - /** - * @param string $user - * @param bool $create - * @param bool $password - */ - protected static function loginHelper($user, $create = false, $password = false) { - - if ($password === false) { - $password = $user; - } - - if ($create) { - \OC::$server->getUserManager()->createUser($user, $password); - \OC_Group::createGroup('group'); - \OC_Group::addToGroup($user, 'group'); - } - - self::resetStorage(); - - \OC_Util::tearDownFS(); - \OC::$server->getUserSession()->setUser(null); - \OC\Files\Filesystem::tearDown(); - \OC::$server->getUserSession()->login($user, $password); - \OC::$server->getUserFolder($user); - - \OC_Util::setupFS($user); - } - - /** - * reset init status for the share storage - */ - protected static function resetStorage() { - $storage = new \ReflectionClass('\OC\Files\Storage\Shared'); - $isInitialized = $storage->getProperty('initialized'); - $isInitialized->setAccessible(true); - $isInitialized->setValue($storage, false); - $isInitialized->setAccessible(false); - } - - /** - * get some information from a given share - * @param int $shareID - * @return array with: item_source, share_type, share_with, item_type, permissions - */ - protected function getShareFromId($shareID) { - $sql = 'SELECT `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?'; - $args = array($shareID); - $query = \OCP\DB::prepare($sql); - $result = $query->execute($args); - - $share = Null; - - if ($result) { - $share = $result->fetchRow(); - } - - return $share; - - } - -} diff --git a/apps/files_sharing/tests/unsharechildren.php b/apps/files_sharing/tests/unsharechildren.php deleted file mode 100644 index 1968007be4e..00000000000 --- a/apps/files_sharing/tests/unsharechildren.php +++ /dev/null @@ -1,108 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @copyright Copyright (c) 2016, 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 OCA\Files\Share; - -/** - * Class UnshareChildren - * - * @group DB - * - * @package OCA\Files_sharing\Tests - */ -class UnshareChildren extends TestCase { - - protected $subsubfolder; - - const TEST_FOLDER_NAME = '/folder_share_api_test'; - - private static $tempStorage; - - protected function setUp() { - parent::setUp(); - - \OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren'); - - $this->folder = self::TEST_FOLDER_NAME; - $this->subfolder = '/subfolder_share_api_test'; - $this->subsubfolder = '/subsubfolder_share_api_test'; - - $this->filename = '/share-api-test'; - - // save file with content - $this->view->mkdir($this->folder); - $this->view->mkdir($this->folder . $this->subfolder); - $this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder); - $this->view->file_put_contents($this->folder . $this->filename, $this->data); - $this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data); - } - - protected function tearDown() { - if ($this->view) { - $this->view->deleteAll($this->folder); - } - - self::$tempStorage = null; - - parent::tearDown(); - } - - /** - * @medium - */ - function testUnshareChildren() { - - $fileInfo2 = \OC\Files\Filesystem::getFileInfo($this->folder); - - $result = \OCP\Share::shareItem('folder', $fileInfo2->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // one folder should be shared with the user - $sharedFolders = \OCP\Share::getItemsSharedWith('folder'); - $this->assertSame(1, count($sharedFolders)); - - // move shared folder to 'localDir' - \OC\Files\Filesystem::mkdir('localDir'); - $result = \OC\Files\Filesystem::rename($this->folder, '/localDir/' . $this->folder); - $this->assertTrue($result); - - \OC\Files\Filesystem::unlink('localDir'); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // after the parent directory was deleted the share should be unshared - $sharedFolders = \OCP\Share::getItemsSharedWith('folder'); - $this->assertTrue(empty($sharedFolders)); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - // the folder for the owner should still exists - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->folder)); - } -} diff --git a/apps/files_sharing/tests/updater.php b/apps/files_sharing/tests/updater.php deleted file mode 100644 index 67c1642cdd0..00000000000 --- a/apps/files_sharing/tests/updater.php +++ /dev/null @@ -1,218 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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/> - * - */ - - -/** - * Class Test_Files_Sharing_Updater - * - * @group DB - */ -class Test_Files_Sharing_Updater extends OCA\Files_Sharing\Tests\TestCase { - - const TEST_FOLDER_NAME = '/folder_share_updater_test'; - - public static function setUpBeforeClass() { - parent::setUpBeforeClass(); - \OCA\Files_Sharing\Helper::registerHooks(); - } - - protected function setUp() { - parent::setUp(); - - $this->folder = self::TEST_FOLDER_NAME; - - $this->filename = '/share-updater-test.txt'; - - // save file with content - $this->view->file_put_contents($this->filename, $this->data); - $this->view->mkdir($this->folder); - $this->view->file_put_contents($this->folder . '/' . $this->filename, $this->data); - } - - protected function tearDown() { - if ($this->view) { - $this->view->unlink($this->filename); - $this->view->deleteAll($this->folder); - } - - parent::tearDown(); - } - - /** - * test deletion of a folder which contains share mount points. Share mount - * points should be unshared before the folder gets deleted so - * that the mount point doesn't end up at the trash bin - */ - function testDeleteParentFolder() { - $status = \OC_App::isEnabled('files_trashbin'); - \OC_App::enable('files_trashbin'); - - \OCA\Files_Trashbin\Trashbin::registerHooks(); - - $fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder); - $this->assertTrue($fileinfo instanceof \OC\Files\FileInfo); - - \OCP\Share::shareItem('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - $view = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files'); - - // check if user2 can see the shared folder - $this->assertTrue($view->file_exists($this->folder)); - - $foldersShared = \OCP\Share::getItemsSharedWith('folder'); - $this->assertSame(1, count($foldersShared)); - - $view->mkdir("localFolder"); - $view->file_put_contents("localFolder/localFile.txt", "local file"); - - $view->rename($this->folder, 'localFolder/' . $this->folder); - - // share mount point should now be moved to the subfolder - $this->assertFalse($view->file_exists($this->folder)); - $this->assertTrue($view->file_exists('localFolder/' .$this->folder)); - - $view->unlink('localFolder'); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // shared folder should be unshared - $foldersShared = \OCP\Share::getItemsSharedWith('folder'); - $this->assertTrue(empty($foldersShared)); - - // trashbin should contain the local file but not the mount point - $rootView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2); - $trashContent = \OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_FILES_SHARING_API_USER2); - $this->assertSame(1, count($trashContent)); - $firstElement = reset($trashContent); - $timestamp = $firstElement['mtime']; - $this->assertTrue($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/localFile.txt')); - $this->assertFalse($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/' . $this->folder)); - - //cleanup - $rootView->deleteAll('files_trashin'); - - if ($status === false) { - \OC_App::disable('files_trashbin'); - } - - \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); - } - - public function shareFolderProvider() { - return [ - ['/'], - ['/my_shares'], - ]; - } - - /** - * if a file gets shared the etag for the recipients root should change - * - * @dataProvider shareFolderProvider - * - * @param string $shareFolder share folder to use - */ - public function testShareFile($shareFolder) { - $config = \OC::$server->getConfig(); - $oldShareFolder = $config->getSystemValue('share_folder'); - $config->setSystemValue('share_folder', $shareFolder); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $beforeShareRoot = \OC\Files\Filesystem::getFileInfo(''); - $etagBeforeShareRoot = $beforeShareRoot->getEtag(); - - \OC\Files\Filesystem::mkdir($shareFolder); - - $beforeShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder); - $etagBeforeShareDir = $beforeShareDir->getEtag(); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($result); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $afterShareRoot = \OC\Files\Filesystem::getFileInfo(''); - $etagAfterShareRoot = $afterShareRoot->getEtag(); - - $afterShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder); - $etagAfterShareDir = $afterShareDir->getEtag(); - - $this->assertTrue(is_string($etagBeforeShareRoot)); - $this->assertTrue(is_string($etagBeforeShareDir)); - $this->assertTrue(is_string($etagAfterShareRoot)); - $this->assertTrue(is_string($etagAfterShareDir)); - $this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot); - $this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir); - - // cleanup - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - - $config->setSystemValue('share_folder', $oldShareFolder); - } - - /** - * if a folder gets renamed all children mount points should be renamed too - */ - function testRename() { - - $fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder); - $result = \OCP\Share::shareItem('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, 31); - $this->assertTrue($result); - - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - // make sure that the shared folder exists - $this->assertTrue(\OC\Files\Filesystem::file_exists($this->folder)); - - \OC\Files\Filesystem::mkdir('oldTarget'); - \OC\Files\Filesystem::mkdir('oldTarget/subfolder'); - \OC\Files\Filesystem::mkdir('newTarget'); - - \OC\Files\Filesystem::rename($this->folder, 'oldTarget/subfolder/' . $this->folder); - - // re-login to make sure that the new mount points are initialized - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - \OC\Files\Filesystem::rename('/oldTarget', '/newTarget/oldTarget'); - - // re-login to make sure that the new mount points are initialized - $this->loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $this->assertTrue(\OC\Files\Filesystem::file_exists('/newTarget/oldTarget/subfolder/' . $this->folder)); - - // cleanup - $this->loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - } - -} |