From: Bjoern Schiessle Date: Fri, 18 Oct 2013 09:20:33 +0000 (+0200) Subject: ocs share api backport to stable5 X-Git-Tag: v5.0.13~29^2~4 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b5325dbe06e95a392e3e1aa67c68726d249d159a;p=nextcloud-server.git ocs share api backport to stable5 --- diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 9363a5431fa..5f73a0767eb 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -7,6 +7,7 @@ OC::$CLASSPATH['OC\Files\Cache\Shared_Cache'] = 'files_sharing/lib/cache.php'; OC::$CLASSPATH['OC\Files\Cache\Shared_Permissions'] = 'files_sharing/lib/permissions.php'; OC::$CLASSPATH['OC\Files\Cache\Shared_Updater'] = 'files_sharing/lib/updater.php'; OC::$CLASSPATH['OC\Files\Cache\Shared_Watcher'] = 'files_sharing/lib/watcher.php'; +OC::$CLASSPATH['OCA\Files\Share\Api'] = 'files_sharing/lib/api.php'; OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); OCP\Share::registerBackend('file', 'OC_Share_Backend_File'); OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file'); diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php new file mode 100644 index 00000000000..1936687e5e4 --- /dev/null +++ b/apps/files_sharing/appinfo/routes.php @@ -0,0 +1,27 @@ +. + * + */ + +namespace OCA\Files\Share; + +class Api { + + /** + * @brief get all shares + * + * @param array $params option 'file' to limit the result to a specific file/folder + * @return \OC_OCS_Result share information + */ + public static function getAllShares($params) { + // if a file is specified, get the share for this file + if (isset($_GET['path'])) { + $params['itemSource'] = self::getFileId($_GET['path']); + $params['path'] = $_GET['path']; + $params['itemType'] = self::getItemType($_GET['path']); + + if ( isset($_GET['reshares']) && $_GET['reshares'] !== 'false' ) { + $params['reshares'] = true; + } else { + $params['reshares'] = false; + } + + if (isset($_GET['subfiles']) && $_GET['subfiles'] !== 'false') { + return self::getSharesFromFolder($params); + } + return self::collectShares($params); + } + + $share = \OCP\Share::getItemShared('file', null); + + if ($share === false) { + return new \OC_OCS_Result(null, 404, 'could not get shares'); + } else { + return new \OC_OCS_Result($share); + } + + } + + /** + * @brief get share information for a given share + * + * @param array $params which contains a 'id' + * @return \OC_OCS_Result share information + */ + public static function getShare($params) { + + $s = self::getShareFromId($params['id']); + $params['itemSource'] = $s['item_source']; + $params['itemType'] = $s['item_type']; + $params['specificShare'] = true; + + return self::collectShares($params); + } + + /** + * @brief collect all share information, either of a specific share or all + * shares for a given path + * @param array $params + * @return \OC_OCS_Result + */ + private static function collectShares($params) { + + $itemSource = $params['itemSource']; + $itemType = $params['itemType']; + $getSpecificShare = isset($params['specificShare']) ? $params['specificShare'] : false; + + if ($itemSource !== null) { + $shares = \OCP\Share::getItemShared($itemType, $itemSource); + $receivedFrom = \OCP\Share::getItemSharedWithBySource($itemType, $itemSource); + // if a specific share was specified only return this one + if ($getSpecificShare === true) { + foreach ($shares as $share) { + if ($share['id'] === (int) $params['id']) { + $shares = array('element' => $share); + break; + } + } + } + + // include also reshares in the lists. This means that the result + // will contain every user with access to the file. + if (isset($params['reshares']) && $params['reshares'] === true) { + $shares = self::addReshares($shares, $itemSource); + } + + if ($receivedFrom) { + $shares['received_from'] = $receivedFrom['uid_owner']; + $shares['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']); + } + } else { + $shares = null; + } + + if ($shares === null || empty($shares)) { + return new \OC_OCS_Result(null, 404, 'share doesn\'t exist'); + } else { + return new \OC_OCS_Result($shares); + } + } + + /** + * @brief add reshares to a array of shares + * @param array $shares array of shares + * @param int $itemSource item source ID + * @return array new shares array which includes reshares + */ + private static function addReshares($shares, $itemSource) { + + // if there are no shares than there are also no reshares + $firstShare = reset($shares); + if ($firstShare) { + $path = $firstShare['path']; + } else { + return $shares; + } + + $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path` , `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`, `mail_send`'; + $getReshares = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` WHERE `*PREFIX*share`.`file_source` = ? AND `*PREFIX*share`.`item_type` IN (\'file\', \'folder\') AND `uid_owner` != ?'); + $reshares = $getReshares->execute(array($itemSource, \OCP\User::getUser()))->fetchAll(); + + foreach ($reshares as $key => $reshare) { + if (isset($reshare['share_with']) && $reshare['share_with'] !== '') { + $reshares[$key]['share_with_displayname'] = \OCP\User::getDisplayName($reshare['share_with']); + } + // add correct path to the result + $reshares[$key]['path'] = $path; + } + + return array_merge($shares, $reshares); + } + + /** + * @brief get share from all files in a given folder (non-recursive) + * @param array $params contains 'path' to the folder + * @return \OC_OCS_Result + */ + private static function getSharesFromFolder($params) { + $path = $params['path']; + $view = new \OC\Files\View('/'.\OCP\User::getUser().'/files'); + + if(!$view->is_dir($path)) { + return new \OC_OCS_Result(null, 404, "not a directory"); + } + + $content = $view->getDirectoryContent($path); + + $result = array(); + foreach ($content as $file) { + // workaround because folders are named 'dir' in this context + $itemType = $file['type'] === 'file' ? 'file' : 'folder'; + $share = \OCP\Share::getItemShared($itemType, $file['fileid']); + $receivedFrom = \OCP\Share::getItemSharedWithBySource($itemType, $file['fileid']); + if ($receivedFrom) { + $share['received_from'] = $receivedFrom['uid_owner']; + $share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']); + } + if ($share) { + $share['filename'] = $file['name']; + $result[] = $share; + } + } + + return new \OC_OCS_Result($result); + } + + /** + * @breif create a new share + * @param array $params + * @return \OC_OCS_Result + */ + public static function createShare($params) { + + $path = isset($_POST['path']) ? $_POST['path'] : null; + + if($path === null) { + return new \OC_OCS_Result(null, 400, "please specify a file or folder path"); + } + $itemSource = self::getFileId($path); + $itemType = self::getItemType($path); + + if($itemSource === null) { + return new \OC_OCS_Result(null, 404, "wrong path, file/folder doesn't exist."); + } + + $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; + $shareType = isset($_POST['shareType']) ? (int)$_POST['shareType'] : null; + + switch($shareType) { + case \OCP\Share::SHARE_TYPE_USER: + $permissions = isset($_POST['permissions']) ? (int)$_POST['permissions'] : 31; + break; + case \OCP\Share::SHARE_TYPE_GROUP: + $permissions = isset($_POST['permissions']) ? (int)$_POST['permissions'] : 31; + break; + case \OCP\Share::SHARE_TYPE_LINK: + //allow password protection + $shareWith = isset($_POST['password']) ? $_POST['password'] : null; + //check public link share + $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); + $encryptionEnabled = \OC_App::isEnabled('files_encryption'); + if(isset($_POST['publicUpload']) && + ($encryptionEnabled || $publicUploadEnabled !== 'yes')) { + return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator"); + } + $publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false'; + // read, create, update (7) if public upload is enabled or + // read (1) if public upload is disabled + $permissions = $publicUpload === 'true' ? 7 : 1; + break; + default: + return new \OC_OCS_Result(null, 404, "unknown share type"); + } + + try { + $token = \OCP\Share::shareItem( + $itemType, + $itemSource, + $shareType, + $shareWith, + $permissions + ); + } catch (\Exception $e) { + return new \OC_OCS_Result(null, 404, $e->getMessage()); + } + + if ($token) { + $data = array(); + $data['id'] = 'unknown'; + $shares = \OCP\Share::getItemShared($itemType, $itemSource); + if(is_string($token)) { //public link share + foreach ($shares as $share) { + if ($share['token'] === $token) { + $data['id'] = $share['id']; + break; + } + } + $url = \OCP\Util::linkToPublic('files&t='.$token); + $data['url'] = $url; // '&' gets encoded to $amp; + $data['token'] = $token; + + } else { + foreach ($shares as $share) { + if ($share['share_with'] === $shareWith && $share['share_type'] === $shareType) { + $data['id'] = $share['id']; + break; + } + } + } + return new \OC_OCS_Result($data); + } else { + return new \OC_OCS_Result(null, 404, "couldn't share file"); + } + } + + /** + * update shares, e.g. password, permissions, etc + * @param array $params shareId 'id' and the parameter we want to update + * currently supported: permissions, password, publicUpload + * @return \OC_OCS_Result + */ + public static function updateShare($params) { + + $share = self::getShareFromId($params['id']); + $itemSource = isset($share['item_source']) ? $share['item_source'] : null; + + if($itemSource === null) { + return new \OC_OCS_Result(null, 404, "wrong share Id, share doesn't exist."); + } + + try { + if(isset($params['_put']['permissions'])) { + return self::updatePermissions($share, $params); + } elseif (isset($params['_put']['password'])) { + return self::updatePassword($share, $params); + } elseif (isset($params['_put']['publicUpload'])) { + return self::updatePublicUpload($share, $params); + } + } catch (\Exception $e) { + return new \OC_OCS_Result(null, 400, $e->getMessage()); + } + + return new \OC_OCS_Result(null, 400, "Wrong or no update parameter given"); + + } + + /** + * @brief update permissions for a share + * @param array $share information about the share + * @param array $params contains 'permissions' + * @return \OC_OCS_Result + */ + private static function updatePermissions($share, $params) { + + $itemSource = $share['item_source']; + $itemType = $share['item_type']; + $shareWith = $share['share_with']; + $shareType = $share['share_type']; + $permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null; + + $publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); + $encryptionEnabled = \OC_App::isEnabled('files_encryption'); + $publicUploadEnabled = false; + if(!$encryptionEnabled && $publicUploadStatus === 'yes') { + $publicUploadEnabled = true; + } + + // only change permissions for public shares if public upload is enabled + // and we want to set permissions to 1 (read only) or 7 (allow upload) + if ( (int)$shareType === \OCP\Share::SHARE_TYPE_LINK ) { + if ($publicUploadEnabled === false || ($permissions !== 7 && $permissions !== 1)) { + return new \OC_OCS_Result(null, 400, "can't change permission for public link share"); + } + } + + try { + $return = \OCP\Share::setPermissions( + $itemType, + $itemSource, + $shareType, + $shareWith, + $permissions + ); + } catch (\Exception $e) { + return new \OC_OCS_Result(null, 404, $e->getMessage()); + } + + if ($return) { + return new \OC_OCS_Result(); + } else { + return new \OC_OCS_Result(null, 404, "couldn't set permissions"); + } + } + + /** + * @brief enable/disable public upload + * @param array $share information about the share + * @param array $params contains 'publicUpload' which can be 'yes' or 'no' + * @return \OC_OCS_Result + */ + private static function updatePublicUpload($share, $params) { + + $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); + $encryptionEnabled = \OC_App::isEnabled('files_encryption'); + if($encryptionEnabled || $publicUploadEnabled !== 'yes') { + return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator"); + } + + if ($share['item_type'] !== 'folder' || + (int)$share['share_type'] !== \OCP\Share::SHARE_TYPE_LINK ) { + return new \OC_OCS_Result(null, 404, "public upload is only possible for public shared folders"); + } + + // read, create, update (7) if public upload is enabled or + // read (1) if public upload is disabled + $params['_put']['permissions'] = $params['_put']['publicUpload'] === 'true' ? 7 : 1; + + return self::updatePermissions($share, $params); + + } + + /** + * @brief update password for public link share + * @param array $share information about the share + * @param type $params 'password' + * @return \OC_OCS_Result + */ + private static function updatePassword($share, $params) { + + $itemSource = $share['item_source']; + $itemType = $share['item_type']; + + if( (int)$share['share_type'] !== \OCP\Share::SHARE_TYPE_LINK) { + return new \OC_OCS_Result(null, 400, "password protection is only supported for public shares"); + } + + $shareWith = isset($params['_put']['password']) ? $params['_put']['password'] : null; + + if($shareWith === '') { + $shareWith = null; + } + + $items = \OCP\Share::getItemShared($itemType, $itemSource); + + $checkExists = false; + foreach ($items as $item) { + if($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { + $checkExists = true; + $permissions = $item['permissions']; + } + } + + if (!$checkExists) { + return new \OC_OCS_Result(null, 404, "share doesn't exists, can't change password"); + } + + $result = \OCP\Share::shareItem( + $itemType, + $itemSource, + \OCP\Share::SHARE_TYPE_LINK, + $shareWith, + $permissions + ); + if($result) { + return new \OC_OCS_Result(); + } + + return new \OC_OCS_Result(null, 404, "couldn't set password"); + } + + /** + * @brief unshare a file/folder + * @param array $params contains the shareID 'id' which should be unshared + * @return \OC_OCS_Result + */ + public static function deleteShare($params) { + + $share = self::getShareFromId($params['id']); + $itemSource = isset($share['item_source']) ? $share['item_source'] : null; + $itemType = isset($share['item_type']) ? $share['item_type'] : null;; + + if($itemSource === null) { + return new \OC_OCS_Result(null, 404, "wrong share ID, share doesn't exist."); + } + + $shareWith = isset($share['share_with']) ? $share['share_with'] : null; + $shareType = isset($share['share_type']) ? (int)$share['share_type'] : null; + + if( $shareType === \OCP\Share::SHARE_TYPE_LINK) { + $shareWith = null; + } + + try { + $return = \OCP\Share::unshare( + $itemType, + $itemSource, + $shareType, + $shareWith); + } catch (\Exception $e) { + return new \OC_OCS_Result(null, 404, $e->getMessage()); + } + + if ($return) { + return new \OC_OCS_Result(); + } else { + $msg = "Unshare Failed"; + return new \OC_OCS_Result(null, 404, $msg); + } + } + + /** + * @brief get file ID from a given path + * @param string $path + * @return string fileID or null + */ + private static function getFileId($path) { + + $view = new \OC\Files\View('/'.\OCP\User::getUser().'/files'); + $fileId = null; + $fileInfo = $view->getFileInfo($path); + if ($fileInfo) { + $fileId = $fileInfo['fileid']; + } + + return $fileId; + } + + /** + * @brief get itemType + * @param string $path + * @return string type 'file', 'folder' or null of file/folder doesn't exists + */ + private static function getItemType($path) { + $view = new \OC\Files\View('/'.\OCP\User::getUser().'/files'); + $itemType = null; + + if ($view->is_dir($path)) { + $itemType = "folder"; + } elseif ($view->is_file($path)) { + $itemType = "file"; + } + + return $itemType; + } + + /** + * @brief get some information from a given share + * @param int $shareID + * @return array with: item_source, share_type, share_with, item_type, permissions + */ + private static 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); + + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('files_sharing', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR); + return null; + } + if ($share = $result->fetchRow()) { + return $share; + } + + return null; + + } + +} diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php new file mode 100644 index 00000000000..44fc4d8b7b3 --- /dev/null +++ b/apps/files_sharing/tests/api.php @@ -0,0 +1,597 @@ + + * + * 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 . + * + */ + +require_once __DIR__ . '/../../../lib/base.php'; + +use OCA\Files\Share; + +/** + * Class Test_Files_Sharing_Api + */ +class Test_Files_Sharing_Api extends \PHPUnit_Framework_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"; + + public $stateFilesEncryption; + public $filename; + public $data; + /** + * @var OC_FilesystemView + */ + public $view; + public $folder; + + public static function setUpBeforeClass() { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); + + // clear share hooks + \OC_Hook::clear('OCP\\Share'); + \OC::registerShareHooks(); + \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); + + // create users + self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1, true); + self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, true); + self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, true); + + } + + function setUp() { + + //login as user1 + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); + + $this->data = 'foobar'; + $this->view = new \OC_FilesystemView('/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1 . '/files'); + + $this->folder = '/folder_share_api_test'; + + $this->filename = 'share-api-test.txt'; + + // remember files_encryption state + $this->stateFilesEncryption = \OC_App::isEnabled('files_encryption'); + + //we don't want to tests with app files_encryption enabled + \OC_App::disable('files_encryption'); + + + $this->assertTrue(!\OC_App::isEnabled('files_encryption')); + + // 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); + + } + + function tearDown() { + $this->view->unlink($this->filename); + $this->view->deleteAll($this->folder); + // reset app files_encryption + if ($this->stateFilesEncryption) { + \OC_App::enable('files_encryption'); + } else { + \OC_App::disable('files_encryption'); + } + } + + public static function tearDownAfterClass() { + + // cleanup users + \OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); + \OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + \OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3); + } + + /** + * @medium + */ + function testCreateShare() { + + // share to user + + // simulate a post request + $_POST['path'] = $this->filename; + $_POST['shareWith'] = \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2; + $_POST['shareType'] = \OCP\Share::SHARE_TYPE_USER; + + $result = Share\Api::createShare(array()); + + $this->assertTrue($result->succeeded()); + $data = $result->getData(); + + $share = $this->getShareFromId($data['id']); + + $items = \OCP\Share::getItemShared('file', $share['item_source']); + + $this->assertTrue(!empty($items)); + + // share link + + // simulate a post request + $_POST['path'] = $this->folder; + $_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK; + + $result = Share\Api::createShare(array()); + + // check if API call was successful + $this->assertTrue($result->succeeded()); + + $data = $result->getData(); + + // check if we have a token + $this->assertTrue(is_string($data['token'])); + + $share = $this->getShareFromId($data['id']); + + $items = \OCP\Share::getItemShared('file', $share['item_source']); + + $this->assertTrue(!empty($items)); + + $fileinfo = $this->view->getFileInfo($this->filename); + + \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + $fileinfo = $this->view->getFileInfo($this->folder); + + \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + + + + } + + /** + * @medium + * @depends testCreateShare + */ + function testGetAllShares() { + + $fileinfo = $this->view->getFileInfo($this->filename); + + \OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + $result = Share\Api::getAllShares(array()); + + $this->assertTrue($result->succeeded()); + + // test should return two shares created from testCreateShare() + $this->assertTrue(count($result->getData()) === 1); + + \OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + } + + /** + * @medium + * @depends testCreateShare + */ + function testGetShareFromSource() { + + $fileInfo = $this->view->getFileInfo($this->filename); + + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, + null, 1); + + $_GET['path'] = $this->filename; + + $result = Share\Api::getAllShares(array()); + + $this->assertTrue($result->succeeded()); + + // test should return one share created from testCreateShare() + $this->assertTrue(count($result->getData()) === 2); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + + } + + /** + * @medium + * @depends testCreateShare + */ + function testGetShareFromSourceWithReshares() { + + $fileInfo = $this->view->getFileInfo($this->filename); + + // share the file as user1 to user2 + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + // login as user2 and reshare the file to user3 + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, 31); + + // login as user1 again + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); + + $_GET['path'] = $this->filename; + + $result = Share\Api::getAllShares(array()); + + $this->assertTrue($result->succeeded()); + + // test should return one share + $this->assertTrue(count($result->getData()) === 1); + + // now also ask for the reshares + $_GET['reshares'] = 'true'; + + $result = Share\Api::getAllShares(array()); + + $this->assertTrue($result->succeeded()); + + // now we should get two shares, the initial share and the reshare + $this->assertTrue(count($result->getData()) === 2); + + // unshare files again + + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3); + + \Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + } + + /** + * @medium + * @depends testCreateShare + */ + function testGetShareFromId() { + + $fileInfo = $this->view->getFileInfo($this->filename); + + $result = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + // share was successful? + $this->assertTrue($result); + + // get item to determine share ID + $result = \OCP\Share::getItemShared('file', $fileInfo['fileid']); + + $this->assertEquals(1, count($result)); + + // get first element + $share = reset($result); + + // call getShare() with share ID + $params = array('id' => $share['id']); + $result = Share\Api::getShare($params); + + $this->assertTrue($result->succeeded()); + + // test should return one share created from testCreateShare() + $this->assertEquals(1, count($result->getData())); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + } + + /** + * @medium + */ + function testGetShareFromFolder() { + + $fileInfo1 = $this->view->getFileInfo($this->filename); + $fileInfo2 = $this->view->getFileInfo($this->folder.'/'.$this->filename); + + $result = \OCP\Share::shareItem('file', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + // share was successful? + $this->assertTrue($result); + + $result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, + null, 1); + + // share was successful? + $this->assertTrue(is_string($result)); + + $_GET['path'] = $this->folder; + $_GET['subfiles'] = 'true'; + + $result = Share\Api::getAllShares(array()); + + $this->assertTrue($result->succeeded()); + + // test should return one share within $this->folder + $this->assertTrue(count($result->getData()) === 1); + + \OCP\Share::unshare('file', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + + } + + /** + * @medium + */ + function testGetShareFromUnknownId() { + + $params = array('id' => 0); + + $result = Share\Api::getShare($params); + + $this->assertEquals(404, $result->getStatusCode()); + $meta = $result->getMeta(); + $this->assertEquals('share doesn\'t exist', $meta['message']); + + } + + /** + * @medium + * @depends testCreateShare + */ + function testUpdateShare() { + + $fileInfo = $this->view->getFileInfo($this->filename); + + $result = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + // share was successful? + $this->assertTrue($result); + + $result = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, + null, 1); + + // share was successful? + $this->assertTrue(is_string($result)); + + $items = \OCP\Share::getItemShared('file', null); + + // make sure that we found a link share and a user share + $this->assertEquals(count($items), 2); + + $linkShare = null; + $userShare = null; + + foreach ($items as $item) { + if ($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { + $linkShare = $item; + } + if ($item['share_type'] === \OCP\Share::SHARE_TYPE_USER) { + $userShare = $item; + } + } + + // make sure that we found a link share and a user share + $this->assertTrue(is_array($linkShare)); + $this->assertTrue(is_array($userShare)); + + // update permissions + + $this->assertEquals('31', $userShare['permissions']); + + $params = array(); + $params['id'] = $userShare['id']; + $params['_put'] = array(); + $params['_put']['permissions'] = 1; + + $result = Share\Api::updateShare($params); + + $meta = $result->getMeta(); + $this->assertTrue($result->succeeded(), $meta['message']); + + $items = \OCP\Share::getItemShared('file', $userShare['file_source']); + + $newUserShare = null; + foreach ($items as $item) { + if ($item['share_with'] === \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2) { + $newUserShare = $item; + break; + } + } + + $this->assertTrue(is_array($newUserShare)); + + $this->assertEquals('1', $newUserShare['permissions']); + + // update password for link share + + $this->assertTrue(empty($linkShare['share_with'])); + + $params = array(); + $params['id'] = $linkShare['id']; + $params['_put'] = array(); + $params['_put']['password'] = 'foo'; + + $result = Share\Api::updateShare($params); + + $this->assertTrue($result->succeeded()); + + $items = \OCP\Share::getItemShared('file', $linkShare['file_source']); + + $newLinkShare = null; + foreach ($items as $item) { + if ($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { + $newLinkShare = $item; + break; + } + } + + $this->assertTrue(is_array($newLinkShare)); + $this->assertTrue(!empty($newLinkShare['share_with'])); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + + } + + /** + * @medium + */ + function testUpdateShareUpload() { + + $fileInfo = $this->view->getFileInfo($this->folder); + + $result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, + null, 1); + + // share was successful? + $this->assertTrue(is_string($result)); + + $items = \OCP\Share::getItemShared('file', null); + + // make sure that we found a link share and a user share + $this->assertEquals(count($items), 1); + + $linkShare = null; + + foreach ($items as $item) { + if ($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { + $linkShare = $item; + } + } + + // make sure that we found a link share + $this->assertTrue(is_array($linkShare)); + + // update public upload + + $params = array(); + $params['id'] = $linkShare['id']; + $params['_put'] = array(); + $params['_put']['publicUpload'] = 'true'; + + $result = Share\Api::updateShare($params); + + $this->assertTrue($result->succeeded()); + + $items = \OCP\Share::getItemShared('file', $linkShare['file_source']); + + $updatedLinkShare = null; + foreach ($items as $item) { + if ($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { + $updatedLinkShare = $item; + break; + } + } + + $this->assertTrue(is_array($updatedLinkShare)); + $this->assertEquals(7, $updatedLinkShare['permissions']); + + // cleanup + + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + + } + + /** + * @medium + * @depends testCreateShare + */ + function testDeleteShare() { + + $fileInfo = $this->view->getFileInfo($this->filename); + + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, + null, 1); + + $items = \OCP\Share::getItemShared('file', null); + + $this->assertEquals(2, count($items)); + + foreach ($items as $item) { + $result = Share\Api::deleteShare(array('id' => $item['id'])); + + $this->assertTrue($result->succeeded()); + } + + $itemsAfterDelete = \OCP\Share::getItemShared('file', null); + + $this->assertTrue(empty($itemsAfterDelete)); + + } + + /** + * @param $user + * @param bool $create + * @param bool $password + */ + private static function loginHelper($user, $create = false, $password = false) { + if ($create) { + \OC_User::createUser($user, $user); + } + + if ($password === false) { + $password = $user; + } + + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($user); + \OC_User::setUserId($user); + + $params['uid'] = $user; + $params['password'] = $password; + } + + /** + * @brief get some information from a given share + * @param int $shareID + * @return array with: item_source, share_type, share_with, item_type, permissions + */ + private 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 && $result->numRows() > 0) { + $share = $result->fetchRow(); + } + + return $share; + + } + +}