diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index dde5d3c50af3..d673da09f70b 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -2,6 +2,7 @@
// Firefox and Konqueror tries to download application/json for me. --Arthur
OCP\JSON::setContentTypeHeader('text/plain');
+OCP\JSON::callCheck();
// If a directory token is sent along check if public upload is permitted.
// If not, check the login.
@@ -12,46 +13,48 @@
// The standard case, files are uploaded through logged in users :)
OCP\JSON::checkLoggedIn();
$dir = isset($_POST['dir']) ? $_POST['dir'] : "";
- if (!$dir || empty($dir) || $dir === false) {
- OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
+ if (!$dir) {
+ OCP\JSON::error(array('data' => array('message' => $l->t('Unable to set upload directory.'))));
die();
}
} else {
- $linkItem = OCP\Share::getShareByToken($_POST['dirToken']);
- if ($linkItem === false) {
- OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Invalid Token')))));
- die();
- }
-
- if (!($linkItem['permissions'] & OCP\PERMISSION_CREATE)) {
- OCP\JSON::checkLoggedIn();
- } else {
- // resolve reshares
- $rootLinkItem = OCP\Share::resolveReShare($linkItem);
-
- // Setup FS with owner
- OC_Util::tearDownFS();
- OC_Util::setupFS($rootLinkItem['uid_owner']);
-
- // The token defines the target directory (security reasons)
- $path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
- $dir = sprintf(
- "/%s/%s",
- $path,
- isset($_POST['subdir']) ? $_POST['subdir'] : ''
+ $shareManager = OCP\Share::getShareManager();
+ if ($shareManager) {
+ $filter = array(
+ 'shareTypeId' => 'link',
+ 'token' => $_POST['dirToken'],
);
-
- if (!$dir || empty($dir) || $dir === false) {
- OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
+ $share = $shareManager->getShares('file', $filter, 1);
+ if (empty($share)) {
+ // Try folder item type instead
+ $share = $shareManager->getShares('folder', $filter, 1);
+ }
+ if (!empty($share)) {
+ $share = reset($share);
+ if ($share->isCreatable()) {
+ OC_Util::tearDownFS();
+ OC_Util::setupFS($share->getItemOwner());
+ $path = \OC\Files\Filesystem::getPath($share->getItemSource());
+ $dir = sprintf(
+ "/%s/%s",
+ $path,
+ isset($_POST['subdir']) ? $_POST['subdir'] : ''
+ );
+ if (!$dir) {
+ OCP\JSON::error(array('data' => array('message' => $l->t('Unable to set upload directory.'))));
+ die();
+ }
+ }
+ } else {
+ OCP\JSON::error(array('data' => array('message' => $l->t('Invalid Token'))));
die();
}
+ } else {
+ OCP\JSON::error(array('data' => array('message' => $l->t('Unable to set upload directory.'))));
+ die();
}
}
-
-OCP\JSON::callCheck();
-
-
// get array with current storage stats (e.g. max file size)
$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index b8d686234939..27dff50f7621 100644
--- a/apps/files_encryption/lib/util.php
+++ b/apps/files_encryption/lib/util.php
@@ -1140,7 +1140,7 @@ public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId
if ($sharingEnabled) {
// Find out who, if anyone, is sharing the file
- $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true);
+ $result = $this->getUsersSharingFile($ownerPath, $owner, true);
$userIds = $result['users'];
if ($result['public']) {
$userIds[] = $this->publicShareKeyId;
@@ -1179,6 +1179,47 @@ public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId
}
+ /**
+ * @brief Find which users can access a shared item
+ * @param $path to the file
+ * @param $user owner of the file
+ * @param include owner to the list of users with access to the file
+ * @return array
+ * @note $path needs to be relative to user data dir, e.g. 'file.txt'
+ * not '/admin/data/file.txt'
+ */
+ public function getUsersSharingFile($path, $user, $includeOwner = false) {
+ $users = array();
+ $public = false;
+ $view = new \OC\Files\View('/' . $user . '/files/');
+ $meta = $view->getFileInfo(\OC\Files\Filesystem::normalizePath($path));
+ if ($meta !== false) {
+ $fileId = $meta['fileid'];
+ $shareManager = \OCP\Share::getShareManager();
+ if ($shareManager) {
+ $fetcher = new \OCA\Files\Share\FileShareFetcher($shareManager,
+ \OC_Group::getManager()
+ );
+ $shares = $fetcher->getById($fileId);
+ foreach ($shares as $share) {
+ if ($share->getShareTypeId() === 'link') {
+ $public = true;
+ break;
+ }
+ }
+ $users = $fetcher->getUsersSharedWith($shares);
+ if ($includeOwner) {
+ if (!in_array($user, $users)) {
+ $users[] = $user;
+ }
+ } else {
+ $users = array_diff($users, array($user));
+ }
+ }
+ }
+ return array('users' => $users, 'public' => $public);
+ }
+
private function getUserWithAccessToMountPoint($users, $groups) {
$result = array();
if (in_array('all', $users)) {
@@ -1605,7 +1646,7 @@ private function recoverFile($file, $privateKey) {
// Find out who, if anyone, is sharing the file
if ($sharingEnabled) {
- $result = \OCP\Share::getUsersSharingFile($file, $this->userId, true);
+ $result = $this->getUsersSharingFile($file, $this->userId, true);
$userIds = $result['users'];
$userIds[] = $this->recoveryKeyId;
if ($result['public']) {
diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php
index 6a29d2428dc0..74deb165850b 100755
--- a/apps/files_encryption/tests/share.php
+++ b/apps/files_encryption/tests/share.php
@@ -32,6 +32,7 @@
require_once __DIR__ . '/util.php';
use OCA\Encryption;
+use OCA\Files\Share\FileShare;
/**
* Class Test_Encryption_Share
@@ -55,6 +56,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
public $subfolder;
public $subsubfolder;
+ private static $usersSharingPolicy;
+ private static $linkSharingPolicy;
+
public static function setUpBeforeClass() {
// reset backend
\OC_User::clearBackends();
@@ -88,6 +92,11 @@ public static function setUpBeforeClass() {
\OC_Group::createGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
\OC_Group::addToGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
\OC_Group::addToGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+
+ self::$usersSharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+ self::$linkSharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', 'yes');
}
function setUp() {
@@ -125,6 +134,9 @@ public static function tearDownAfterClass() {
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', self::$usersSharingPolicy);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', self::$linkSharingPolicy);
}
/**
@@ -159,7 +171,15 @@ function testShareFile($withTeardown = true) {
\OC_FileProxy::$enabled = $proxyStatus;
// share the file
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('user');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $share->setPermissions(27);
+ $shareManager = \OCP\Share::getShareManager();
+ $share = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -186,7 +206,7 @@ function testShareFile($withTeardown = true) {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// unshare the file
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $shareManager->unshare($share);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -219,7 +239,15 @@ function testReShareFile($withTeardown = true) {
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename);
// share the file with user2
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('user');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+ $share->setPermissions(27);
+ $shareManager = \OCP\Share::getShareManager();
+ $share = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -245,8 +273,10 @@ function testReShareFile($withTeardown = true) {
// login as user1
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $parentShare = reset($shareManager->getParents($share));
+
// unshare the file with user2
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+ $shareManager->unshare($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -257,7 +287,7 @@ function testReShareFile($withTeardown = true) {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
// unshare the file with user1
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $shareManager->unshare($parentShare);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -314,7 +344,15 @@ function testShareFolder($withTeardown = true) {
\OC_FileProxy::$enabled = $proxyStatus;
// share the folder with user1
- \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('folder');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('user');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $share->setPermissions(OCP\PERMISSION_ALL);
+ $shareManager = \OCP\Share::getShareManager();
+ $share = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -343,7 +381,7 @@ function testShareFolder($withTeardown = true) {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// unshare the folder with user1
- \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $shareManager->unshare($share);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -390,7 +428,15 @@ function testReShareFolder($withTeardown = true) {
\OC_FileProxy::$enabled = $proxyStatus;
// share the file with user2
- \OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('folder');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('user');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+ $share->setPermissions(OCP\PERMISSION_ALL);
+ $shareManager = \OCP\Share::getShareManager();
+ $folderShare = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -421,7 +467,15 @@ function testReShareFolder($withTeardown = true) {
$this->assertTrue(is_array($fileInfo));
// share the file with user3
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('user');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
+ $share->setPermissions(27);
+ $shareManager = \OCP\Share::getShareManager();
+ $fileShare = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -449,7 +503,7 @@ function testReShareFolder($withTeardown = true) {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
// unshare the file with user3
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
+ $shareManager->unshare($fileShare);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -460,8 +514,10 @@ function testReShareFolder($withTeardown = true) {
// login as user1
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $parentShare = reset($shareManager->getParents($share));
+
// unshare the folder with user2
- \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+ $shareManager->unshare($folderShare);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -473,7 +529,7 @@ function testReShareFolder($withTeardown = true) {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// unshare the folder1 with user1
- \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ $shareManager->unshare($parentShare);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -522,7 +578,14 @@ function testPublicShareFile() {
\OC_FileProxy::$enabled = $proxyStatus;
// share the file
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('link');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+ $share->setPermissions(27);
+ $shareManager = \OCP\Share::getShareManager();
+ $share = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -551,7 +614,7 @@ function testPublicShareFile() {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// unshare the file
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
+ $shareManager->unshare($share);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -598,7 +661,15 @@ function testShareFileWithGroup() {
\OC_FileProxy::$enabled = $proxyStatus;
// share the file
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('group');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ $share->setPermissions(27);
+ $shareManager = \OCP\Share::getShareManager();
+ $share = $shareManager->share($share);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -625,7 +696,7 @@ function testShareFileWithGroup() {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// unshare the file
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ $this->shareManager->unshare($share);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -885,7 +956,15 @@ function testFailShareFile() {
// share the file
try {
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1, OCP\PERMISSION_ALL);
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource($fileInfo['fileid']);
+ $share->setShareTypeId('group');
+ $share->setShareOwner(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+ $share->setShareWith(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ $share->setPermissions(OCP\PERMISSION_ALL);
+ $shareManager = \OCP\Share::getShareManager();
+ $share = $shareManager->share($share);
} catch (Exception $e) {
$this->assertEquals(0, strpos($e->getMessage(), "Following users are not set up for encryption"));
}
@@ -917,7 +996,7 @@ function testFailShareFile() {
\OC_FileProxy::$enabled = $proxyStatus;
// unshare the file with user1
- \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ $shareManager->unshare($share);
// check if share key not exists
$this->assertFalse($this->view->file_exists(
diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php
index 895d446a3365..f9572b64546a 100644
--- a/apps/files_sharing/appinfo/app.php
+++ b/apps/files_sharing/appinfo/app.php
@@ -1,18 +1,73 @@
.
+ */
-OC::$CLASSPATH['OC_Share_Backend_File'] = 'files_sharing/lib/share/file.php';
-OC::$CLASSPATH['OC_Share_Backend_Folder'] = 'files_sharing/lib/share/folder.php';
+OC::$CLASSPATH['OCA\Files\Share\FileShare'] = 'files_sharing/lib/share/fileshare.php';
+OC::$CLASSPATH['OCA\Files\Share\FileShareBackend'] = 'files_sharing/lib/share/filesharebackend.php';
+OC::$CLASSPATH['OCA\Files\Share\FolderShareBackend'] = 'files_sharing/lib/share/foldersharebackend.php';
+OC::$CLASSPATH['OCA\Files\Share\FileShareFactory'] = 'files_sharing/lib/share/filesharefactory.php';
+OC::$CLASSPATH['OCA\Files\Share\FileTargetMachine'] = 'files_sharing/lib/share/filetargetmachine.php';
+OC::$CLASSPATH['OCA\Files\Share\FileShareFetcher'] = 'files_sharing/lib/share/filesharefetcher.php';
OC::$CLASSPATH['OC\Files\Storage\Shared'] = 'files_sharing/lib/sharedstorage.php';
-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';
-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');
-OCP\Util::addScript('files_sharing', 'share');
-\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Shared_Updater', 'writeHook');
-\OC_Hook::connect('OC_Filesystem', 'delete', '\OC\Files\Cache\Shared_Updater', 'deleteHook');
-\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Shared_Updater', 'renameHook');
-\OC_Hook::connect('OCP\Share', 'post_shared', '\OC\Files\Cache\Shared_Updater', 'shareHook');
-\OC_Hook::connect('OCP\Share', 'pre_unshare', '\OC\Files\Cache\Shared_Updater', 'shareHook');
+OC::$CLASSPATH['OC\Files\Cache\SharedCache'] = 'files_sharing/lib/cache.php';
+OC::$CLASSPATH['OC\Files\Cache\SharedPermissions'] = 'files_sharing/lib/permissions.php';
+OC::$CLASSPATH['OC\Files\Cache\SharedUpdater'] = 'files_sharing/lib/updater.php';
+OC::$CLASSPATH['OC\Files\Cache\SharedWatcher'] = 'files_sharing/lib/watcher.php';
+
+$shareManager = \OCP\Share::getShareManager();
+$timeMachine = new \OC\Share\TimeMachine();
+$fileShareFactory = new \OCA\Files\Share\FileShareFactory();
+$fileTargetMachine = new \OCA\Files\Share\FileTargetMachine();
+$userManager = \OC_User::getManager();
+$groupManager = \OC_Group::getManager();
+$tokenMachine = new \OC\Share\ShareType\TokenMachine();
+$hasher = new \PasswordHash(8, (CRYPT_BLOWFISH != 1));
+$fileShareTypes = array(
+ new \OC\Share\ShareType\User('file', $fileShareFactory, $fileTargetMachine, $userManager,
+ $groupManager
+ ),
+ new \OC\Share\ShareType\Group('file', $fileShareFactory, $fileTargetMachine, $groupManager,
+ $userManager
+ ),
+ new \OC\Share\ShareType\Link('file', $fileShareFactory, $fileTargetMachine, $userManager,
+ $tokenMachine, $hasher
+ ),
+);
+$folderShareTypes = array(
+ new \OC\Share\ShareType\User('folder', $fileShareFactory, $fileTargetMachine, $userManager,
+ $groupManager
+ ),
+ new \OC\Share\ShareType\Group('folder', $fileShareFactory, $fileTargetMachine, $groupManager,
+ $userManager
+ ),
+ new \OC\Share\ShareType\Link('folder', $fileShareFactory, $fileTargetMachine, $userManager,
+ $tokenMachine, $hasher
+ ),
+);
+$fileShareBackend = new \OCA\Files\Share\FileShareBackend($timeMachine, $fileShareTypes);
+$folderShareBackend = new \OCA\Files\Share\FolderShareBackend($timeMachine, $folderShareTypes);
+$shareManager->registerShareBackend($fileShareBackend);
+$shareManager->registerShareBackend($folderShareBackend);
+$sharedUpdater = new \OC\Files\Cache\SharedUpdater($shareManager,
+ new \OCA\Files\Share\FileShareFetcher($shareManager, $groupManager)
+);
+// TODO Wait for hook changes so we can use a closure to replace setup and pass in ShareManager
+\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
+\OCP\Util::addScript('files_sharing', 'share');
\ No newline at end of file
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 3be89a39fa0c..55a2a948e7f0 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -6,6 +6,7 @@ $(document).ready(function() {
$('#fileList').one('fileActionsReady',function(){
OC.Share.loadIcons('file');
+ OC.Share.loadIcons('folder');
});
FileActions.register('all', 'Share', OC.PERMISSION_READ, OC.imagePath('core', 'actions/share'), function(filename) {
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php
index 33cd14288998..9fa8f9329a9f 100644
--- a/apps/files_sharing/lib/cache.php
+++ b/apps/files_sharing/lib/cache.php
@@ -3,7 +3,7 @@
* ownCloud
*
* @author Michael Gapczynski
- * @copyright 2012 Michael Gapczynski mtgap@owncloud.com
+ * @copyright 2012-2013 Michael Gapczynski mtgap@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
@@ -21,51 +21,46 @@
namespace OC\Files\Cache;
+use OCA\Files\Share\FileShareFetcher;
+
/**
* Metadata cache for shared files
*
* don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead
*/
-class Shared_Cache extends Cache {
+class SharedCache extends Cache {
private $storage;
- private $files = array();
+ private $storageId;
+ private $fetcher;
- public function __construct($storage) {
+ /**
+ * The constructor
+ * @param \OC\Files\Storage\Shared $storage
+ * @param \OCA\Files\Share\FileShareFetcher $fetcher
+ */
+ public function __construct($storage, FileShareFetcher $fetcher) {
$this->storage = $storage;
+ $this->fetcher = $fetcher;
}
/**
- * @brief Get the source cache of a shared file or folder
+ * Get the source cache of a shared file or folder
* @param string $target Shared target file path
- * @return \OC\Files\Cache\Cache
+ * @return array Consisting of \OC\Files\Cache\Cache and the internal path
*/
- private function getSourceCache($target) {
- $source = \OC_Share_Backend_File::getSource($target);
- if (isset($source['path']) && isset($source['fileOwner'])) {
- \OC\Files\Filesystem::initMountPoints($source['fileOwner']);
- $mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
- if (is_array($mount)) {
- $fullPath = $mount[key($mount)]->getMountPoint().$source['path'];
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($fullPath);
- if ($storage) {
- $this->files[$target] = $internalPath;
- $cache = $storage->getCache();
- $this->storageId = $storage->getId();
- $this->numericId = $cache->getNumericStorageId();
- return $cache;
- }
- }
+ protected function getSourceCache($path) {
+ list ($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ $cache = $storage->getCache();
+ $this->storageId = $storage->getId();
+ return array($cache, $internalPath);
}
- return false;
+ return array(null, null);
}
public function getNumericStorageId() {
- if (isset($this->numericId)) {
- return $this->numericId;
- } else {
- return false;
- }
+ return null;
}
/**
@@ -75,32 +70,84 @@ public function getNumericStorageId() {
* @return array
*/
public function get($file) {
- if ($file == '') {
- $data = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT);
- $etag = \OCP\Config::getUserValue(\OCP\User::getUser(), 'files_sharing', 'etag');
+ if ($file === '' || $file === -1) {
+ $files = array();
+ $size = 0;
+ $mtime = 0;
+ $encrypted = false;
+ $unencryptedSize = 0;
+ $shares = $this->fetcher->getAll();
+ foreach ($shares as $share) {
+ $fileId = $share->getItemSource();
+ // Ignore duplicate shares
+ if (!isset($files[$fileId])) {
+ if ($share->getEncrypted()) {
+ $encrypted = true;
+ }
+ if ($share->getMtime() > $mtime) {
+ $mtime = $share->getMtime();
+ }
+ $size += $share->getSize();
+ $unencryptedSize += $share->getUnencryptedSize();
+ $files[$fileId] = true;
+ }
+ }
+ $etag = $this->fetcher->getETag();
if (!isset($etag)) {
$etag = $this->storage->getETag('');
- \OCP\Config::setUserValue(\OCP\User::getUser(), 'files_sharing', 'etag', $etag);
- }
- $data['etag'] = $etag;
- return $data;
- } else if (is_string($file)) {
- if ($cache = $this->getSourceCache($file)) {
- return $cache->get($this->files[$file]);
+ $this->fetcher->setETag($etag);
}
+ return array(
+ 'fileid' => -1,
+ 'storage' => null,
+ 'path' => '',
+ 'parent' => -1,
+ 'name' => 'Shared',
+ 'mimetype' => 'httpd/unix-directory',
+ 'mimepart' => 'httpd',
+ 'size' => $size,
+ 'mtime' => $mtime,
+ 'storage_mtime' => $mtime,
+ 'encrypted' => $encrypted,
+ 'unencrypted_size' => $unencryptedSize,
+ 'etag' => $etag,
+ );
} else {
- $query = \OC_DB::prepare(
- 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
- .' `size`, `mtime`, `encrypted`'
- .' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
- $result = $query->execute(array($file));
- $data = $result->fetchRow();
- $data['fileid'] = (int)$data['fileid'];
- $data['size'] = (int)$data['size'];
- $data['mtime'] = (int)$data['mtime'];
- $data['encrypted'] = (bool)$data['encrypted'];
- $data['mimetype'] = $this->getMimetype($data['mimetype']);
- $data['mimepart'] = $this->getMimetype($data['mimepart']);
+ $data = false;
+ if (is_string($file)) {
+ $shares = $this->fetcher->getByPath($file);
+ } else {
+ $shares = $this->fetcher->getById($file);
+ }
+ foreach ($shares as $share) {
+ // Check if we have an exact share for this path or id
+ if (is_string($file) && $share->getItemTarget() === $file
+ || is_int($file) && $share->getItemSource() === $file
+ ) {
+ $data = $share->getMetadata();
+ break;
+ }
+ }
+ if ($data) {
+ $data['mimetype'] = $this->getMimetype($data['mimetype']);
+ $data['mimepart'] = $this->getMimetype($data['mimepart']);
+ if ($data['storage_mtime'] === 0) {
+ $data['storage_mtime'] = $data['mtime'];
+ }
+ } else if (!empty($shares)) {
+ $share = reset($shares);
+ $folder = $share->getItemTarget();
+ if (is_string($file)) {
+ list($cache, $internalPath) = $this->getSourceCache($file);
+ $data = $cache->get($internalPath);
+ } else {
+ list($cache) = $this->getSourceCache($folder);
+ $data = $cache->get($file);
+ }
+ if ($data) {
+ $data['path'] = $folder.substr($data['path'], strlen($share->getPath()));
+ }
+ }
return $data;
}
return false;
@@ -113,19 +160,30 @@ public function get($file) {
* @return array
*/
public function getFolderContents($folder) {
- if ($folder == '') {
- $files = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS);
- foreach ($files as &$file) {
- $file['mimetype'] = $this->getMimetype($file['mimetype']);
- $file['mimepart'] = $this->getMimetype($file['mimepart']);
+ $files = array();
+ if ($folder === '') {
+ $shares = $this->fetcher->getAll();
+ foreach ($shares as $share) {
+ $fileId = $share->getItemSource();
+ // Ignore duplicate shares
+ if (!isset($files[$fileId])) {
+ $file = $share->getMetadata();
+ $file['mimetype'] = $this->getMimetype($file['mimetype']);
+ $file['mimepart'] = $this->getMimetype($file['mimepart']);
+ if ($file['storage_mtime'] === 0) {
+ $file['storage_mtime'] = $file['mtime'];
+ }
+ $files[$fileId] = $file;
+ }
}
- return $files;
+ $files = array_values($files);
} else {
- if ($cache = $this->getSourceCache($folder)) {
- return $cache->getFolderContents($this->files[$folder]);
+ list($cache, $internalPath) = $this->getSourceCache($folder);
+ if ($cache && $internalPath) {
+ $files = $cache->getFolderContents($internalPath);
}
}
- return false;
+ return $files;
}
/**
@@ -137,12 +195,17 @@ public function getFolderContents($folder) {
* @return int file id
*/
public function put($file, array $data) {
- if ($file === '' && isset($data['etag'])) {
- return \OCP\Config::setUserValue(\OCP\User::getUser(), 'files_sharing', 'etag', $data['etag']);
- } else if ($cache = $this->getSourceCache($file)) {
- return $cache->put($this->files[$file], $data);
+ if ($file === '') {
+ if (isset($data['etag'])) {
+ $this->fetcher->setETag($data['etag']);
+ }
+ } else {
+ list($cache, $internalPath) = $this->getSourceCache($file);
+ if ($cache && $internalPath) {
+ return $cache->put($internalPath, $data);
+ }
}
- return false;
+ return -1;
}
/**
@@ -152,8 +215,18 @@ public function put($file, array $data) {
* @return int
*/
public function getId($file) {
- if ($cache = $this->getSourceCache($file)) {
- return $cache->getId($this->files[$file]);
+ if ($file !== '') {
+ $shares = $this->fetcher->getByPath($file);
+ foreach ($shares as $share) {
+ // Check if we have an exact share for this path
+ if ($share->getItemTarget() === $file) {
+ return $share->getItemSource();
+ }
+ }
+ list($cache, $internalPath) = $this->getSourceCache($file);
+ if ($cache && $internalPath) {
+ return $cache->getId($internalPath);
+ }
}
return -1;
}
@@ -165,7 +238,7 @@ public function getId($file) {
* @return bool
*/
public function inCache($file) {
- if ($file == '') {
+ if ($file === '') {
return true;
}
return parent::inCache($file);
@@ -177,8 +250,9 @@ public function inCache($file) {
* @param string $file
*/
public function remove($file) {
- if ($cache = $this->getSourceCache($file)) {
- $cache->remove($this->files[$file]);
+ list($cache, $internalPath) = $this->getSourceCache($file);
+ if ($cache && $internalPath) {
+ return $cache->remove($internalPath);
}
}
@@ -189,10 +263,13 @@ public function remove($file) {
* @param string $target
*/
public function move($source, $target) {
- if ($cache = $this->getSourceCache($source)) {
- $file = \OC_Share_Backend_File::getSource($target);
- if ($file && isset($file['path'])) {
- $cache->move($this->files[$source], $file['path']);
+ list($cache, $oldInternalPath) = $this->getSourceCache($source);
+ if ($cache && $oldInternalPath) {
+ // Renaming/moving is only allowed within shared folders
+ if (dirname($target) !== '') {
+ list( , $newInternalPath) = $this->fetcher->resolvePath(dirname($target));
+ $newInternalPath .= '/'.basename($target);
+ $cache->move($oldInternalPath, $newInternalPath);
}
}
}
@@ -210,11 +287,12 @@ public function clear() {
* @return int, Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
*/
public function getStatus($file) {
- if ($file == '') {
+ if ($file === '') {
return self::COMPLETE;
}
- if ($cache = $this->getSourceCache($file)) {
- return $cache->getStatus($this->files[$file]);
+ list($cache, $internalPath) = $this->getSourceCache($file);
+ if ($cache && $internalPath) {
+ return $cache->getStatus($internalPath);
}
return self::NOT_FOUND;
}
@@ -226,31 +304,35 @@ public function getStatus($file) {
* @return array of file data
*/
public function search($pattern) {
- // TODO
+ $pattern = $this->normalize($pattern);
+ // Remove the '%' characters that were added for the LIKE query
+ $trimmedPattern = trim($pattern, '%');
+ return $this->searchCommon($pattern, 'search', function($share) use ($trimmedPattern) {
+ if (stripos($share->getItemTarget(), $trimmedPattern) !== false) {
+ return true;
+ }
+ return false;
+ });
}
/**
* search for files by mimetype
*
- * @param string $part1
- * @param string $part2
+ * @param string $mimetype
* @return array
*/
public function searchByMime($mimetype) {
- if (strpos($mimetype, '/')) {
- $where = '`mimetype` = ?';
- } else {
- $where = '`mimepart` = ?';
- }
- $mimetype = $this->getMimetypeId($mimetype);
- $ids = $this->getAll();
- $placeholders = join(',', array_fill(0, count($ids), '?'));
- $query = \OC_DB::prepare('
- SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`
- FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `fileid` IN (' . $placeholders . ')'
+ $mimetypeId = (int)$this->getMimetypeId($mimetype);
+ return $this->searchCommon($mimetype, 'searchByMime',
+ function($share) use ($mimetypeId) {
+ if ($share->getMimepart() === $mimetypeId
+ || $share->getMimetype() === $mimetypeId
+ ) {
+ return true;
+ }
+ return false;
+ }
);
- $result = $query->execute(array_merge(array($mimetype), $ids));
- return $result->fetchAll();
}
/**
@@ -260,8 +342,13 @@ public function searchByMime($mimetype) {
* @return int
*/
public function calculateFolderSize($path) {
- if ($cache = $this->getSourceCache($path)) {
- return $cache->calculateFolderSize($this->files[$path]);
+ if ($path === '') {
+ $data = $this->get('');
+ return $data['size'];
+ }
+ list($cache, $internalPath) = $this->getSourceCache($path);
+ if ($cache && $internalPath) {
+ return $cache->calculateFolderSize($internalPath);
}
return 0;
}
@@ -272,7 +359,20 @@ public function calculateFolderSize($path) {
* @return int[]
*/
public function getAll() {
- return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_GET_ALL);
+ $ids = array();
+ $shares = $this->fetcher->getAll();
+ $folderMimetypeId = (int)$this->getMimetypeId('httpd/unix-directory');
+ foreach ($shares as $share) {
+ $fileId = $share->getItemSource();
+ if (!isset($ids[$fileId])) {
+ $ids[$fileId] = $fileId;
+ if ($share->getMimetype() === $folderMimetypeId) {
+ $childrenIds = $this->getChildrenIds($fileId);
+ $ids = array_merge($ids, array_combine($childrenIds, $childrenIds));
+ }
+ }
+ }
+ return array_values($ids);
}
/**
@@ -288,4 +388,85 @@ public function getIncomplete() {
return false;
}
-}
+ /**
+ * Search all file shares and their children
+ * @param mixed $query The search query to pass to the method
+ * @param string $method The method to call inside a cache - 'search' or 'searchByMime'
+ * @param callable $callback A callable that returns true if the file share passed as an
+ * argument matches the search query, elsewise returns false
+ * @return array
+ */
+ protected function searchCommon($query, $method, $callback) {
+ $files = array();
+ $caches = array();
+ $folderMimetypeId = (int)$this->getMimetypeId('httpd/unix-directory');
+ $shares = $this->fetcher->getAll();
+ // Look through all file shares for matches
+ foreach ($shares as $share) {
+ $fileId = $share->getItemSource();
+ // Ignore duplicate shares
+ if (!isset($files[$fileId])) {
+ if ($callback($share)) {
+ $file = $share->getMetadata();
+ $file['mimetype'] = $this->getMimetype($file['mimetype']);
+ $file['mimepart'] = $this->getMimetype($file['mimepart']);
+ if ($file['storage_mtime'] === 0) {
+ $file['storage_mtime'] = $file['mtime'];
+ }
+ $files[$fileId] = $file;
+ }
+ $storageId = $share->getStorage();
+ if ($share->getMimetype() === $folderMimetypeId && !isset($caches[$storageId])) {
+ list($cache) = $this->getSourceCache($share->getItemTarget());
+ $caches[$storageId] = $cache;
+ }
+ }
+ }
+ $ids = $this->getAll();
+ // Look inside shared folders' caches for more results
+ foreach ($caches as $cache) {
+ $result = $cache->$method($query);
+ foreach ($result as $file) {
+ $fileId = (int)$file['fileid'];
+ // Ensure that the search result is a shared file
+ if (!isset($files[$fileId]) && in_array($fileId, $ids) !== false) {
+ // Find the shared folder this file is inside
+ foreach ($shares as $share) {
+ $path = $share->getPath();
+ if ((int)$file['storage'] === $share->getStorage()
+ && strpos($file['path'], $path) === 0
+ ) {
+ // Rebuild the path relative to the Shared folder
+ $folder = $share->getItemTarget();
+ $file['path'] = $folder.substr($file['path'], strlen($path));
+ $files[$fileId] = $file;
+ }
+ }
+ }
+ }
+ }
+ return array_values($files);
+ }
+
+ /**
+ * Get all children file ids for the specified file id
+ * @param int $fileId
+ * @return int[]
+ */
+ protected function getChildrenIds($fileId) {
+ $ids = array();
+ $folderMimetypeId = (int)$this->getMimetypeId('httpd/unix-directory');
+ $sql = 'SELECT `fileid`, `mimetype` FROM `*PREFIX*filecache` WHERE `parent` = ?';
+ $result = \OC_DB::executeAudited($sql, array($fileId));
+ $rows = $result->fetchAll();
+ foreach ($rows as $row) {
+ $fileId = (int)$row['fileid'];
+ $ids[] = $fileId;
+ if ((int)$row['mimetype'] === $folderMimetypeId) {
+ $ids = array_merge($ids, $this->getChildrenIds($fileId));
+ }
+ }
+ return $ids;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/permissions.php b/apps/files_sharing/lib/permissions.php
index e2978e12bfb1..e7ce00aa825e 100644
--- a/apps/files_sharing/lib/permissions.php
+++ b/apps/files_sharing/lib/permissions.php
@@ -1,26 +1,41 @@
.
-*/
+ * ownCloud
+ *
+ * @author Michael Gapczynski
+ * @copyright 2012-2013 Michael Gapczynski mtgap@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 .
+ */
+
namespace OC\Files\Cache;
-class Shared_Permissions extends Permissions {
+use OCA\Files\Share\FileShareFetcher;
+
+class SharedPermissions extends Permissions {
+
+ private $fetcher;
+
+ /**
+ * The constructor
+ * @param \OC\Files\Storage\Storage|string $storage
+ * @param \OCA\FilesSharing\Share\FileShareFetcher $fetcher
+ */
+ public function __construct($storage, FileShareFetcher $fetcher) {
+ parent::__construct($storage);
+ $this->fetcher = $fetcher;
+ }
/**
* get the permissions for a single file
@@ -30,16 +45,10 @@ class Shared_Permissions extends Permissions {
* @return int (-1 if file no permissions set)
*/
public function get($fileId, $user) {
- if ($fileId == -1) {
+ if ($fileId === -1) {
return \OCP\PERMISSION_READ;
}
- $source = \OCP\Share::getItemSharedWithBySource('file', $fileId, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE,
- null, true);
- if ($source) {
- return $source['permissions'];
- } else {
- return -1;
- }
+ return $this->fetcher->getPermissionsById($fileId);
}
/**
@@ -65,7 +74,7 @@ public function getMultiple($fileIds, $user) {
return array();
}
foreach ($fileIds as $fileId) {
- $filePermissions[$fileId] = self::get($fileId, $user);
+ $filePermissions[$fileId] = $this->get($fileId, $user);
}
return $filePermissions;
}
@@ -78,16 +87,17 @@ public function getMultiple($fileIds, $user) {
* @return int[]
*/
public function getDirectoryPermissions($parentId, $user) {
+ $filePermissions = array();
// Root of the Shared folder
if ($parentId === -1) {
- return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_PERMISSIONS);
- }
- $permissions = $this->get($parentId, $user);
- $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `parent` = ?');
- $result = $query->execute(array($parentId));
- $filePermissions = array();
- while ($row = $result->fetchRow()) {
- $filePermissions[$row['fileid']] = $permissions;
+ $filePermissions = $this->fetcher->getAllPermissions();
+ } else {
+ $permissions = $this->get($parentId, $user);
+ $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `parent` = ?';
+ $result = \OC_DB::executeAudited($sql, array($parentId));
+ while ($row = $result->fetchRow()) {
+ $filePermissions[$row['fileid']] = $permissions;
+ }
}
return $filePermissions;
}
diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php
deleted file mode 100644
index 07e7a4ca0c5c..000000000000
--- a/apps/files_sharing/lib/share/file.php
+++ /dev/null
@@ -1,179 +0,0 @@
-.
-*/
-
-class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
-
- const FORMAT_SHARED_STORAGE = 0;
- const FORMAT_GET_FOLDER_CONTENTS = 1;
- const FORMAT_FILE_APP_ROOT = 2;
- const FORMAT_OPENDIR = 3;
- const FORMAT_GET_ALL = 4;
- const FORMAT_PERMISSIONS = 5;
-
- private $path;
-
- public function isValidSource($itemSource, $uidOwner) {
- $query = \OC_DB::prepare('SELECT `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?');
- $result = $query->execute(array($itemSource));
- if ($row = $result->fetchRow()) {
- $this->path = $row['name'];
- return true;
- }
- return false;
- }
-
- public function getFilePath($itemSource, $uidOwner) {
- if (isset($this->path)) {
- $path = $this->path;
- $this->path = null;
- return $path;
- }
- return false;
- }
-
- public function generateTarget($filePath, $shareWith, $exclude = null) {
- $target = '/'.basename($filePath);
- if (isset($exclude)) {
- if ($pos = strrpos($target, '.')) {
- $name = substr($target, 0, $pos);
- $ext = substr($target, $pos);
- } else {
- $name = $target;
- $ext = '';
- }
- $i = 2;
- $append = '';
- while (in_array($name.$append.$ext, $exclude)) {
- $append = ' ('.$i.')';
- $i++;
- }
- $target = $name.$append.$ext;
- }
- return $target;
- }
-
- public function formatItems($items, $format, $parameters = null) {
- if ($format == self::FORMAT_SHARED_STORAGE) {
- // Only 1 item should come through for this format call
- return array(
- 'parent' => $items[key($items)]['parent'],
- 'path' => $items[key($items)]['path'],
- 'storage' => $items[key($items)]['storage'],
- 'permissions' => $items[key($items)]['permissions'],
- 'uid_owner' => $items[key($items)]['uid_owner']
- );
- } else if ($format == self::FORMAT_GET_FOLDER_CONTENTS) {
- $files = array();
- foreach ($items as $item) {
- $file = array();
- $file['fileid'] = $item['file_source'];
- $file['storage'] = $item['storage'];
- $file['path'] = $item['file_target'];
- $file['parent'] = $item['file_parent'];
- $file['name'] = basename($item['file_target']);
- $file['mimetype'] = $item['mimetype'];
- $file['mimepart'] = $item['mimepart'];
- $file['size'] = $item['size'];
- $file['mtime'] = $item['mtime'];
- $file['encrypted'] = $item['encrypted'];
- $file['etag'] = $item['etag'];
- $files[] = $file;
- }
- return $files;
- } else if ($format == self::FORMAT_FILE_APP_ROOT) {
- $mtime = 0;
- $size = 0;
- foreach ($items as $item) {
- if ($item['mtime'] > $mtime) {
- $mtime = $item['mtime'];
- }
- $size += (int)$item['size'];
- }
- return array(
- 'fileid' => -1,
- 'name' => 'Shared',
- 'mtime' => $mtime,
- 'mimetype' => 'httpd/unix-directory',
- 'size' => $size
- );
- } else if ($format == self::FORMAT_OPENDIR) {
- $files = array();
- foreach ($items as $item) {
- $files[] = basename($item['file_target']);
- }
- return $files;
- } else if ($format == self::FORMAT_GET_ALL) {
- $ids = array();
- foreach ($items as $item) {
- $ids[] = $item['file_source'];
- }
- return $ids;
- } else if ($format === self::FORMAT_PERMISSIONS) {
- $filePermissions = array();
- foreach ($items as $item) {
- $filePermissions[$item['file_source']] = $item['permissions'];
- }
- return $filePermissions;
- }
- return array();
- }
-
- public static function getSource($target) {
- if ($target == '') {
- return false;
- }
- $target = '/'.$target;
- $target = rtrim($target, '/');
- $pos = strpos($target, '/', 1);
- // Get shared folder name
- if ($pos !== false) {
- $folder = substr($target, 0, $pos);
- $source = \OCP\Share::getItemSharedWith('folder', $folder, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
- if ($source) {
- $source['path'] = $source['path'].substr($target, strlen($folder));
- }
- } else {
- $source = \OCP\Share::getItemSharedWith('file', $target, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
- }
- if ($source) {
- if (isset($source['parent'])) {
- $parent = $source['parent'];
- while (isset($parent)) {
- $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1);
- $item = $query->execute(array($parent))->fetchRow();
- if (isset($item['parent'])) {
- $parent = $item['parent'];
- } else {
- $fileOwner = $item['uid_owner'];
- break;
- }
- }
- } else {
- $fileOwner = $source['uid_owner'];
- }
- $source['fileOwner'] = $fileOwner;
- return $source;
- }
- \OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::ERROR);
- return false;
- }
-
-}
diff --git a/apps/files_sharing/lib/share/fileshare.php b/apps/files_sharing/lib/share/fileshare.php
new file mode 100644
index 000000000000..16413019d3de
--- /dev/null
+++ b/apps/files_sharing/lib/share/fileshare.php
@@ -0,0 +1,254 @@
+.
+ */
+
+namespace OCA\Files\Share;
+
+use OC\Share\Share;
+
+/**
+ * Data holder for shared files and folders
+ */
+class FileShare extends Share {
+
+ protected $storage;
+ protected $path;
+ protected $parent;
+ protected $name;
+ protected $mimetype;
+ protected $mimepart;
+ protected $size;
+ protected $mtime;
+ protected $storageMtime;
+ protected $encrypted;
+ protected $unencryptedSize;
+ protected $etag;
+
+ public function __construct() {
+ $this->addType('itemSource', 'int');
+ $this->addType('storage', 'int');
+ $this->addType('parent', 'int');
+ $this->addType('mimetype', 'int');
+ $this->addType('mimepart', 'int');
+ $this->addType('size', 'int');
+ $this->addType('mtime', 'int');
+ $this->addType('encrypted', 'bool');
+ $this->addType('unencryptedSize', 'int');
+ }
+
+ /**
+ * Get the numeric storage id
+ * @return int
+ */
+ public function getStorage() {
+ return $this->storage;
+ }
+
+ /**
+ * Set the numeric storage id
+ * @param int $storage
+ */
+ public function setStorage($storage) {
+ $this->storage = $storage;
+ }
+
+ /**
+ * Get the source file path
+ * @return string
+ */
+ public function getPath() {
+ return $this->path;
+ }
+
+ /**
+ * Set the source file path
+ * @param string $path
+ */
+ public function setPath($path) {
+ $this->path = $path;
+ }
+
+ /**
+ * Get the parent folder id, not to be confused with getParentIds for reshares
+ * @return int
+ */
+ public function getParent() {
+ return $this->parent;
+ }
+
+ /**
+ * Set the parent folder id, not to be confused with setParentIds for reshares
+ * @param int $parent
+ */
+ public function setParent($parent) {
+ $this->parent = $parent;
+ }
+
+ /**
+ * Get the mimetype id
+ * @return int
+ */
+ public function getMimetype() {
+ return $this->mimetype;
+ }
+
+ /**
+ * Set the mimetype id
+ * @param int $mimetype
+ */
+ public function setMimetype($mimetype) {
+ $this->mimetype = $mimetype;
+ }
+
+ /**
+ * Get the mimepart id
+ * @return int
+ */
+ public function getMimepart() {
+ return $this->mimepart;
+ }
+
+ /**
+ * Set the mimepart id
+ * @param int $mimepart
+ */
+ public function setMimepart($mimepart) {
+ $this->mimepart = $mimepart;
+ }
+
+ /**
+ * Get the file size
+ * @return int
+ */
+ public function getSize() {
+ return $this->size;
+ }
+
+ /**
+ * Set the file size
+ * @param int $size
+ */
+ public function setSize($size) {
+ $this->size = $size;
+ }
+
+ /**
+ * Get the mtime
+ * @return int
+ */
+ public function getMtime() {
+ return $this->mtime;
+ }
+
+ /**
+ * Set the mtime
+ * @param int $mtime
+ */
+ public function setMtime($mtime) {
+ $this->mtime = $mtime;
+ }
+
+ /**
+ * Get the storage mtime
+ * @return int
+ */
+ public function getStorageMtime() {
+ return $this->storageMtime;
+ }
+
+ /**
+ * Set the storage mtime
+ * @param int $storageMtime
+ */
+ public function setStorageMtime($storageMtime) {
+ $this->storageMtime = $storageMtime;
+ }
+
+ /**
+ * Get if the file is encrypted
+ * @return bool
+ */
+ public function getEncrypted() {
+ return $this->encrypted;
+ }
+
+ /**
+ * Set if the file is encrypted
+ * @param bool $encrypted
+ */
+ public function setEncrypted($encrypted) {
+ $this->encrypted = $encrypted;
+ }
+
+ /**
+ * Get the unencrypted file size
+ * @return int
+ */
+ public function getUnencryptedSize() {
+ return $this->unencryptedSize;
+ }
+
+ /**
+ * Set the unencrypted file size
+ * @param int $unencryptedSize
+ */
+ public function setUnencryptedSize($unencryptedSize) {
+ $this->unencryptedSize = $unencryptedSize;
+ }
+
+ /**
+ * Get the ETag
+ * @return string
+ */
+ public function getEtag() {
+ return $this->etag;
+ }
+
+ /**
+ * Set the ETag
+ * @param string $etag
+ */
+ public function setEtag($etag) {
+ $this->etag = $etag;
+ }
+
+ /**
+ * Get the metadata
+ * @return array
+ */
+ public function getMetadata() {
+ return array(
+ 'fileid' => $this->getItemSource(),
+ 'storage' => $this->getStorage(),
+ 'path' => $this->getItemTarget(),
+ 'parent' => $this->getParent(),
+ 'name' => basename($this->getItemTarget()),
+ 'mimetype' => $this->getMimetype(),
+ 'mimepart' => $this->getMimepart(),
+ 'size' => $this->getSize(),
+ 'mtime' => $this->getMtime(),
+ 'storage_mtime' => $this->getStorageMtime(),
+ 'encrypted' => $this->getEncrypted(),
+ 'unencrypted_size' => $this->getUnencryptedSize(),
+ 'etag' => $this->getEtag(),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/share/filesharebackend.php b/apps/files_sharing/lib/share/filesharebackend.php
new file mode 100644
index 000000000000..d8af85be2a76
--- /dev/null
+++ b/apps/files_sharing/lib/share/filesharebackend.php
@@ -0,0 +1,81 @@
+.
+ */
+
+namespace OCA\Files\Share;
+
+use OC\Share\Share;
+use OC\Share\ShareBackend;
+use OC\Share\Exception\InvalidItemException;
+use OC\Share\Exception\InvalidPermissionsException;
+use OC\Files\Filesystem;
+
+class FileShareBackend extends ShareBackend {
+
+ /**
+ * Get the identifier for the item type this backend handles, should be a singular noun
+ * @return string
+ */
+ public function getItemType() {
+ return 'file';
+ }
+
+ /**
+ * Get the plural form of getItemType, used for the RESTful API
+ * @return string
+ */
+ public function getItemTypePlural() {
+ return 'files';
+ }
+
+ /**
+ * Check if an item is valid for the share owner
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidItemException If the file does not exist or the share
+ * owner does not have access to the file
+ * @return bool
+ */
+ protected function isValidItem(Share $share) {
+ Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files');
+ $path = Filesystem::getPath((int)$share->getItemSource());
+ if (!isset($path)) {
+ throw new InvalidItemException('The file does not exist in the filesystem');
+ }
+ return true;
+ }
+
+ /**
+ * Check if a share's permissions are valid
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidPermissionsException If the permissions are not an
+ * integer or are not in the range of 1 to 31 or exceed the filesystem permissions
+ * @return bool
+ */
+ protected function areValidPermissions(Share $share) {
+ parent::areValidPermissions($share);
+ Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files');
+ $path = Filesystem::getPath((int)$share->getItemSource());
+ if ($share->getPermissions() & ~Filesystem::getPermissions($path)) {
+ throw new InvalidPermissionsException('The permissions are not valid for the file');
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/share/filesharefactory.php b/apps/files_sharing/lib/share/filesharefactory.php
new file mode 100644
index 000000000000..07788e38ed81
--- /dev/null
+++ b/apps/files_sharing/lib/share/filesharefactory.php
@@ -0,0 +1,79 @@
+.
+ */
+
+namespace OCA\Files\Share;
+
+use OC\Share\AdvancedShareFactory;
+
+/**
+ * Share factory for file shares, used by both file and folder backends
+ */
+class FileShareFactory extends AdvancedShareFactory {
+
+ protected $table;
+
+ public function __construct() {
+ $this->table = '`*PREFIX*filecache`';
+ }
+
+ /**
+ * Map a database row to a file share
+ * @param array $row A key => value array of share properties
+ * @return \OCA\Files\Share\FileShare
+ */
+ public function mapToShare($row) {
+ return FileShare::fromRow($row);
+ }
+
+ /**
+ * Get JOIN(s) to app table(s)
+ * @return string
+ */
+ public function getJoins() {
+ return 'JOIN '.$this->table.' ON '.
+ '`*PREFIX*shares`.`item_source` = '.$this->table.'.`fileid`';
+ }
+
+ /**
+ * Get app table column(s)
+ * @return string
+ */
+ public function getColumns() {
+ $columns = array(
+ 'storage',
+ 'path',
+ 'parent',
+ 'mimetype',
+ 'mimepart',
+ 'size',
+ 'mtime',
+ 'storage_mtime',
+ 'encrypted',
+ 'unencrypted_size',
+ 'etag',
+ );
+ foreach ($columns as &$column) {
+ $column = $this->table.'.`'.$column.'`';
+ }
+ return join(', ', $columns);
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/share/filesharefetcher.php b/apps/files_sharing/lib/share/filesharefetcher.php
new file mode 100644
index 000000000000..0e2838ffc66c
--- /dev/null
+++ b/apps/files_sharing/lib/share/filesharefetcher.php
@@ -0,0 +1,345 @@
+.
+ */
+
+namespace OCA\Files\Share;
+
+use OC\Share\ShareManager;
+use OC\Group\Manager;
+
+/**
+ * Class to retrieve file shares from the ShareManager
+ *
+ * These are helper methods used by the shared storage, cache, permissions, etc.
+ */
+class FileShareFetcher {
+
+ protected $shareManager;
+ protected $groupManager;
+ protected $uid;
+ protected $fileItemType;
+ protected $folderItemType;
+
+ /**
+ * The constructor
+ * @param \OC\Share\ShareManager $shareManager
+ * @param \OC\Group\Manager $groupManager
+ * @param string $uid (optional)
+ */
+ public function __construct(ShareManager $shareManager, Manager $groupManager, $uid = null) {
+ $this->shareManager = $shareManager;
+ $this->groupManager = $groupManager;
+ $this->setUID($uid);
+ $this->fileItemType = 'file';
+ $this->folderItemType = 'folder';
+ }
+
+ /**
+ * Get the UID of the user to retrieve shares for
+ * @return string | null
+ *
+ * If no UID is set, all file shares can be retrieved
+ *
+ */
+ public function getUID() {
+ return $this->uid;
+ }
+
+ /**
+ * Set the UID of the user to retrieve shares for
+ * @param string | null $uid
+ */
+ public function setUID($uid) {
+ $this->uid = $uid;
+ }
+
+ /**
+ * Get all files shares
+ * @return \OCA\Files\Share\FileShare[]
+ */
+ public function getAll() {
+ $filter = array();
+ $uid = $this->getUID();
+ if (isset($uid)) {
+ $filter['shareWith'] = $uid;
+ $filter['isShareWithUser'] = true;
+ }
+ $fileShares = $this->shareManager->getShares($this->fileItemType, $filter);
+ $folderShares = $this->shareManager->getShares($this->folderItemType, $filter);
+ return array_merge($fileShares, $folderShares);
+ }
+
+ /**
+ * Get all permissions of all shared files
+ * @return array With file ids as keys and permissions as values
+ */
+ public function getAllPermissions() {
+ return $this->getPermissions($this->getAll());
+ }
+
+ /**
+ * Get the ETag of the Shared folder for the user
+ * @return string
+ */
+ public function getETag() {
+ $uid = $this->getUID();
+ if (isset($uid)) {
+ return \OCP\Config::getUserValue($uid, 'files_sharing', 'etag');
+ }
+ }
+
+ /**
+ * Set the ETag of the Shared folder for the user
+ * @param string $etag
+ */
+ public function setETag($etag) {
+ $uid = $this->getUID();
+ if (isset($uid)) {
+ \OCP\Config::setUserValue($uid, 'files_sharing', 'etag', $etag);
+ }
+ }
+
+ /**
+ * Get all files shares specified by target path for the user
+ * @param string $path
+ * @return \OCA\Files\Share\FileShare[]
+ *
+ * The returned file shares may not be exact shares for the path, but parent folders
+ * Only works if a UID is set
+ *
+ */
+ public function getByPath($path) {
+ $shares = array();
+ $uid = $this->getUID();
+ if (isset($uid)) {
+ $filter = array(
+ 'shareWith' => $this->uid,
+ 'isShareWithUser' => true,
+ );
+ $path = rtrim($path, '/');
+ $pos = strpos($path, '/', 1);
+ // Get shared folder name
+ if ($pos !== false) {
+ $filter['itemTarget'] = substr($path, 0, $pos);
+ $shares = $this->shareManager->getShares($this->folderItemType, $filter);
+ } else {
+ $ext = pathinfo($path, PATHINFO_EXTENSION);
+ if ($ext === 'part') {
+ $path = substr($path, 0, -5);
+ }
+ $filter['itemTarget'] = $path;
+ // Try to guess file type
+ if (empty($ext)) {
+ $shares = $this->shareManager->getShares($this->folderItemType, $filter);
+ $itemType = $this->fileItemType;
+ } else {
+ $shares = $this->shareManager->getShares($this->fileItemType, $filter);
+ $itemType = $this->folderItemType;
+ }
+ if (empty($shares)) {
+ // Try the other item type
+ $shares = $this->shareManager->getShares($itemType, $filter);
+ }
+ }
+ }
+ return $shares;
+ }
+
+ /**
+ * Get all files shares specified by file id
+ * @param int $fileId
+ * @return \OCA\Files\Share\FileShare[]
+ *
+ * The returned file shares may not be exact shares for the file id, but parent folders
+ *
+ */
+ public function getById($fileId) {
+ $filter = array(
+ 'itemSource' => $fileId,
+ );
+ $uid = $this->getUID();
+ if (isset($uid)) {
+ $filter['shareWith'] = $uid;
+ $filter['isShareWithUser'] = true;
+ }
+ $shares = $this->shareManager->getShares($this->fileItemType, $filter);
+ if (empty($shares)) {
+ // Try folder item type instead
+ $shares = $this->shareManager->getShares($this->folderItemType, $filter);
+ }
+ return array_merge($shares, $this->getParentFolders($fileId));
+ }
+
+ /**
+ * Resolve a target path for the user to a storage and internal path
+ * @param string $path
+ * @return array Consisting of \OC\Files\Storage\Storage and the internal path
+ *
+ * Only works if a UID is set
+ *
+ */
+ public function resolvePath($path) {
+ $shares = $this->getByPath($path);
+ if (!empty($shares)) {
+ $share = reset($shares);
+ \OC\Files\Filesystem::initMountPoints($share->getItemOwner());
+ $mounts = \OC\Files\Filesystem::getMountByNumericId($share->getStorage());
+ if (!empty($mounts)) {
+ $internalPath = $share->getPath();
+ $path = rtrim($path, '/');
+ $pos = strpos($path, '/', 1);
+ // Get shared folder name
+ if ($pos !== false) {
+ $internalPath .= substr($path, $pos);
+ }
+ if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
+ $internalPath .= '.part';
+ }
+ $fullPath = reset($mounts)->getMountPoint().$internalPath;
+ return \OC\Files\Filesystem::resolvePath($fullPath);
+ }
+ }
+ return array(null, null);
+ }
+
+ /**
+ * Get permissions for a shared file specified by target path for the user
+ * @param string $path
+ * @return int
+ *
+ * Only works if a UID is set
+ *
+ */
+ public function getPermissionsByPath($path) {
+ $shares = $this->getByPath($path);
+ $permissions = $this->getPermissions($shares);
+ if (!empty($permissions)) {
+ return reset($permissions);
+ }
+ return 0;
+ }
+
+ /**
+ * Get permissions for a shared file specified by file id
+ * @param int $fileId
+ * @return int
+ */
+ public function getPermissionsById($fileId) {
+ $shares = $this->getById($fileId);
+ $permissions = $this->getPermissions($shares);
+ if (!empty($permissions)) {
+ return reset($permissions);
+ }
+ return 0;
+ }
+
+ /**
+ * Get all UIDs of files shares specified by target path for the user
+ * @param string $path
+ * @return array With UIDs as values
+ *
+ * Only works if a UID is set
+ *
+ */
+ public function getUsersSharedWithByPath($path) {
+ $shares = $this->getByPath($path);
+ return $this->getUsersSharedWith($shares);
+ }
+
+ /**
+ * Get all UIDs of files shares specified by file id
+ * @param int $fileId
+ * @return array With UIDs as values
+ */
+ public function getUsersSharedWithById($fileId) {
+ $shares = $this->getById($fileId);
+ return $this->getUsersSharedWith($shares);
+ }
+
+ /**
+ * Get all UIDs of an array of shares
+ * @param \OCA\Files\Share\FileShare[] $shares
+ * @return array With UIDs as values
+ */
+ public function getUsersSharedWith(array $shares) {
+ $uids = array();
+ foreach ($shares as $share) {
+ $shareTypeId = $share->getShareTypeId();
+ if ($shareTypeId === 'user') {
+ $uids[] = $share->getShareWith();
+ } else if ($shareTypeId === 'group') {
+ $group = $this->groupManager->get($share->getShareWith());
+ if ($group) {
+ foreach ($group->getUsers() as $user) {
+ $uids[] = $user->getUID();
+ }
+ }
+ }
+ }
+ return array_unique($uids);
+ }
+
+ /**
+ * Get all permissions of an array of shares
+ * @param \OCA\Files\Share\FileShare[] $shares
+ * @return array With file ids as keys and permissions as values
+ */
+ protected function getPermissions(array $shares) {
+ $files = array();
+ if (!empty($shares)) {
+ foreach ($shares as $share) {
+ $fileId = $share->getItemSource();
+ if (!isset($files[$fileId])) {
+ $files[$fileId] = $share->getPermissions();
+ } else {
+ // Combine permissions for duplicate shared files
+ $files[$fileId] |= $share->getPermissions();
+ }
+ }
+ }
+ return $files;
+ }
+
+ /**
+ * Get all shared parent folders
+ * @param int $fileId
+ * @return \OCA\Files\Share\FileShare[]
+ */
+ protected function getParentFolders($fileId) {
+ $shares = array();
+ $folderShareBackend = $this->shareManager->getShareBackend($this->folderItemType);
+ if ($folderShareBackend) {
+ $uid = $this->getUID();
+ if (isset($uid)) {
+ $filter['shareWith'] = $uid;
+ $filter['isShareWithUser'] = true;
+ }
+ $fileId = $folderShareBackend->getParentFolderId($fileId);
+ while ($fileId !== -1) {
+ $filter['itemSource'] = $fileId;
+ $folderShares = $this->shareManager->getShares($this->folderItemType, $filter);
+ $shares = array_merge($shares, $folderShares);
+ $fileId = $folderShareBackend->getParentFolderId($fileId);
+ }
+ }
+ return $shares;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/share/filetargetmachine.php b/apps/files_sharing/lib/share/filetargetmachine.php
new file mode 100644
index 000000000000..f47b97170f5e
--- /dev/null
+++ b/apps/files_sharing/lib/share/filetargetmachine.php
@@ -0,0 +1,46 @@
+.
+ */
+
+namespace OCA\Files\Share;
+
+use OC\Share\Share;
+use OC\Share\ItemTargetMachine;
+use OC\User\User;
+use OC\Files\Filesystem;
+
+class FileTargetMachine extends ItemTargetMachine {
+
+ /**
+ * Get a unique item target for the specified share and user
+ * @param \OC\Share\Share $share
+ * @param \OC\User\User $user
+ * @return string
+ *
+ * If $user is null, any item target is acceptable
+ *
+ */
+ public function getItemTarget(Share $share, User $user = null) {
+ Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files');
+ $path = Filesystem::getPath((int)$share->getItemSource());
+ return basename($path);
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/share/folder.php b/apps/files_sharing/lib/share/folder.php
deleted file mode 100644
index 4426beec6368..000000000000
--- a/apps/files_sharing/lib/share/folder.php
+++ /dev/null
@@ -1,51 +0,0 @@
-.
-*/
-
-class OC_Share_Backend_Folder extends OC_Share_Backend_File implements OCP\Share_Backend_Collection {
-
- public function getChildren($itemSource) {
- $children = array();
- $parents = array($itemSource);
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?');
- $result = $query->execute(array('httpd/unix-directory'));
- if ($row = $result->fetchRow()) {
- $mimetype = $row['id'];
- } else {
- $mimetype = -1;
- }
- while (!empty($parents)) {
- $parents = "'".implode("','", $parents)."'";
- $query = OC_DB::prepare('SELECT `fileid`, `name`, `mimetype` FROM `*PREFIX*filecache`'
- .' WHERE `parent` IN ('.$parents.')');
- $result = $query->execute();
- $parents = array();
- while ($file = $result->fetchRow()) {
- $children[] = array('source' => $file['fileid'], 'file_path' => $file['name']);
- // If a child folder is found look inside it
- if ($file['mimetype'] == $mimetype) {
- $parents[] = $file['fileid'];
- }
- }
- }
- return $children;
- }
-
-}
diff --git a/apps/files_sharing/lib/share/foldersharebackend.php b/apps/files_sharing/lib/share/foldersharebackend.php
new file mode 100644
index 000000000000..a9e2ec73edce
--- /dev/null
+++ b/apps/files_sharing/lib/share/foldersharebackend.php
@@ -0,0 +1,105 @@
+.
+ */
+
+namespace OCA\Files\Share;
+
+use OC\Share\Share;
+use OC\Share\ICollectionShareBackend;
+use OC\Share\TimeMachine;
+
+class FolderShareBackend extends FileShareBackend implements ICollectionShareBackend {
+
+ protected $table;
+
+ /**
+ * The constructor
+ * @param \OC\Share\TimeMachine $timeMachine The time() mock
+ * @param \OC\Share\ShareType\IShareType[] $shareTypes An array of share type objects that
+ * items can be shared through e.g. User, Group, Link
+ */
+ public function __construct(TimeMachine $timeMachine, array $shareTypes) {
+ parent::__construct($timeMachine, $shareTypes);
+ $this->table = '`*PREFIX*filecache`';
+ }
+
+ /**
+ * Get the identifier for the item type this backend handles, should be a singular noun
+ * @return string
+ */
+ public function getItemType() {
+ return 'folder';
+ }
+
+ /**
+ * Get the plural form of getItemType, used for the RESTful API
+ * @return string
+ */
+ public function getItemTypePlural() {
+ return 'folders';
+ }
+
+ /**
+ * Get the identifiers for the children item types of this backend
+ * @return array
+ */
+ public function getChildrenItemTypes() {
+ // Include 'folder' in the return because folders can be inside folders
+ return array('file', 'folder');
+ }
+
+ /**
+ * Search for shares of this collection item type that contain the child item source and
+ * shared with the share owner
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share[]
+ */
+ public function searchForParentCollections(Share $share) {
+ $parents = array();
+ $filter = array(
+ 'shareWith' => $share->getShareOwner(),
+ 'isShareWithUser' => true,
+ );
+ // Loop through parent folders and check if they are shared
+ $fileId = $this->getParentFolderId($share->getItemSource());
+ while ($fileId !== -1) {
+ $filter['itemSource'] = $fileId;
+ $parents = array_merge($parents, $this->getShares($filter));
+ $fileId = $this->getParentFolderId($fileId);
+ }
+ return $parents;
+ }
+
+ /**
+ * Get the file id of the parent folder for the specified file id
+ * @param int $fileId
+ * @return int
+ */
+ public function getParentFolderId($fileId) {
+ $sql = 'SELECT `parent` FROM '.$this->table.' WHERE `fileid` = ?';
+ $result = \OC_DB::executeAudited($sql, array($fileId));
+ $id = $result->fetchOne();
+ if ($id !== false) {
+ return (int)$id;
+ }
+ return -1;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index 7384b094cb04..5250f994912d 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -3,7 +3,7 @@
* ownCloud
*
* @author Michael Gapczynski
- * @copyright 2011 Michael Gapczynski mtgap@owncloud.com
+ * @copyright 2011-2013 Michael Gapczynski mtgap@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
@@ -22,162 +22,153 @@
namespace OC\Files\Storage;
+use OC\Files\Cache\SharedCache;
+use OC\Files\Cache\SharedPermissions;
+use OC\Files\Cache\SharedWatcher;
+use OCA\Files\Share\FileShareFetcher;
+
/**
* Convert target path to source path and pass the function call to the correct storage provider
*/
-class Shared extends \OC\Files\Storage\Common {
-
- private $sharedFolder;
- private $files = array();
-
- public function __construct($arguments) {
- $this->sharedFolder = $arguments['sharedFolder'];
- }
+class Shared extends Common {
- public function getId(){
- return 'shared::' . $this->sharedFolder;
- }
+ private $fetcher;
+ private $cache;
+ private $permissionsCache;
+ private $watcher;
/**
- * @brief Get the source file path, permissions, and owner for a shared file
- * @param string Shared target file path
- * @return Returns array with the keys path, permissions, and owner or false if not found
- */
- private function getFile($target) {
- if (!isset($this->files[$target])) {
- // Check for partial files
- if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
- $source = \OC_Share_Backend_File::getSource(substr($target, 0, -5));
- if ($source) {
- $source['path'] .= '.part';
- // All partial files have delete permission
- $source['permissions'] |= \OCP\PERMISSION_DELETE;
- }
- } else {
- $source = \OC_Share_Backend_File::getSource($target);
- }
- $this->files[$target] = $source;
- }
- return $this->files[$target];
+ * The constructor
+ * @param array $params Array with a FileShareFetcher
+ */
+ public function __construct($params) {
+ $this->fetcher = $params['fetcher'];
}
/**
- * @brief Get the source file path for a shared file
- * @param string Shared target file path
- * @return string source file path or false if not found
- */
- private function getSourcePath($target) {
- $source = $this->getFile($target);
- if ($source) {
- if (!isset($source['fullPath'])) {
- \OC\Files\Filesystem::initMountPoints($source['fileOwner']);
- $mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
- if (is_array($mount)) {
- $this->files[$target]['fullPath'] = $mount[key($mount)]->getMountPoint().$source['path'];
- } else {
- $this->files[$target]['fullPath'] = false;
- }
- }
- return $this->files[$target]['fullPath'];
+ * Mount this shared storage, called by the hook setup in files_sharing/appinfo/app.php
+ * @param array $params
+ */
+ public static function setup($params) {
+ if (isset($params['user']) && isset($params['user_dir'])) {
+ $shareManager = \OCP\Share::getShareManager();
+ $fetcher = new FileShareFetcher($shareManager, \OC_Group::getManager(),
+ $params['user']
+ );
+ \OC\Files\Filesystem::mount('\OC\Files\Storage\Shared', array('fetcher' => $fetcher),
+ $params['user_dir'].'/Shared/'
+ );
}
- return false;
}
- /**
- * @brief Get the permissions granted for a shared file
- * @param string Shared target file path
- * @return int CRUDS permissions granted or false if not found
- */
- public function getPermissions($target) {
- $source = $this->getFile($target);
- if ($source) {
- return $source['permissions'];
- }
- return false;
+ public function getId() {
+ return 'shared';
}
public function mkdir($path) {
- if ($path == '' || $path == '/' || !$this->isCreatable(dirname($path))) {
+ if ($path === '' || !$this->isCreatable(dirname($path))) {
return false;
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->mkdir($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->mkdir($internalPath);
+ }
}
return false;
}
public function rmdir($path) {
- if (($source = $this->getSourcePath($path)) && $this->isDeletable($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->rmdir($internalPath);
+ if ($this->isDeletable($path)) {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->rmdir($internalPath);
+ }
}
return false;
}
public function opendir($path) {
- if ($path == '' || $path == '/') {
- $files = \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_Folder::FORMAT_OPENDIR);
+ if ($path === '') {
+ $files = array();
+ $shares = $this->fetcher->getAll();
+ foreach ($shares as $share) {
+ $fileId = $share->getItemSource();
+ if (!isset($files[$fileId])) {
+ $files[$fileId] = basename($share->getItemTarget());
+ }
+ }
+ $files = array_values($files);
\OC\Files\Stream\Dir::register('shared', $files);
return opendir('fakedir://shared');
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->opendir($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->opendir($internalPath);
+ }
}
return false;
}
public function is_dir($path) {
- if ($path == '' || $path == '/') {
+ if ($path === '') {
return true;
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->is_dir($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->is_dir($internalPath);
+ }
}
return false;
}
public function is_file($path) {
- if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
return $storage->is_file($internalPath);
}
return false;
}
public function stat($path) {
- if ($path == '' || $path == '/') {
+ if ($path === '') {
$stat['size'] = $this->filesize($path);
$stat['mtime'] = $this->filemtime($path);
return $stat;
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->stat($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->mkdir($internalPath);
+ }
}
return false;
}
public function filetype($path) {
- if ($path == '' || $path == '/') {
+ if ($path === '') {
return 'dir';
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->filetype($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->filetype($internalPath);
+ }
}
return false;
}
public function filesize($path) {
- if ($path == '' || $path == '/' || $this->is_dir($path)) {
+ if ($path === '' || $this->is_dir($path)) {
return 0;
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->filesize($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->filesize($internalPath);
+ }
}
return false;
}
public function isCreatable($path) {
- if ($path == '') {
+ if ($path === '') {
return false;
}
return ($this->getPermissions($path) & \OCP\PERMISSION_CREATE);
@@ -188,39 +179,50 @@ public function isReadable($path) {
}
public function isUpdatable($path) {
- if ($path == '') {
+ if ($path === '') {
return false;
}
return ($this->getPermissions($path) & \OCP\PERMISSION_UPDATE);
}
public function isDeletable($path) {
- if ($path == '') {
+ if ($path === '') {
return true;
}
return ($this->getPermissions($path) & \OCP\PERMISSION_DELETE);
}
public function isSharable($path) {
- if ($path == '') {
+ if ($path === '') {
return false;
}
return ($this->getPermissions($path) & \OCP\PERMISSION_SHARE);
}
+ public function getPermissions($path) {
+ $permissions = $this->fetcher->getPermissionsByPath($path);
+ if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
+ // All partial files have delete permission
+ $permissions |= \OCP\PERMISSION_DELETE;
+ }
+ return $permissions;
+ }
+
public function file_exists($path) {
- if ($path == '' || $path == '/') {
+ if ($path === '') {
return true;
- } else if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->file_exists($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->file_exists($internalPath);
+ }
}
return false;
}
public function filemtime($path) {
- if ($path == '' || $path == '/') {
- $mtime = 0;
+ $mtime = 0;
+ if ($path === '') {
if ($dh = $this->opendir($path)) {
while (($filename = readdir($dh)) !== false) {
$tempmtime = $this->filemtime($filename);
@@ -229,62 +231,66 @@ public function filemtime($path) {
}
}
}
- return $mtime;
} else {
- $source = $this->getSourcePath($path);
- if ($source) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->filemtime($internalPath);
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ $mtime = $storage->filemtime($internalPath);
}
}
+ return $mtime;
}
public function file_get_contents($path) {
- $source = $this->getSourcePath($path);
- if ($source) {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
$info = array(
- 'target' => $this->sharedFolder.$path,
- 'source' => $source,
+ 'target' => '/Shared'.$path,
+ 'source' => $internalPath,
);
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
return $storage->file_get_contents($internalPath);
}
+ return null;
}
public function file_put_contents($path, $data) {
- if ($source = $this->getSourcePath($path)) {
- // Check if permission is granted
- if (($this->file_exists($path) && !$this->isUpdatable($path))
- || ($this->is_dir($path) && !$this->isCreatable($path))) {
- return false;
- }
+ $exists = $this->file_exists($path);
+ if ($exists && !$this->isUpdatable($path)) {
+ return false;
+ }
+ if (!$exists && !$this->isCreatable(dirname(path))) {
+ return false;
+ }
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
$info = array(
- 'target' => $this->sharedFolder.$path,
- 'source' => $source,
- );
+ 'target' => '/Shared'.$path,
+ 'source' => $internalPath,
+ );
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- $result = $storage->file_put_contents($internalPath, $data);
- return $result;
+ return $storage->file_put_contents($internalPath, $data);
}
return false;
}
public function unlink($path) {
// Delete the file if DELETE permission is granted
- if ($source = $this->getSourcePath($path)) {
- if ($this->isDeletable($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
+ if ($this->isDeletable($path)) {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
return $storage->unlink($internalPath);
- } else if (dirname($path) == '/' || dirname($path) == '.') {
+ } else if (dirname($path) === '/' || dirname($path) === '.') {
// Unshare the file from the user if in the root of the Shared folder
if ($this->is_dir($path)) {
$itemType = 'folder';
} else {
$itemType = 'file';
}
- return \OCP\Share::unshareFromSelf($itemType, $path);
+ $shareManager =\OCP\Share::getShareManager();
+ $shares = $this->fetcher->getByPath($path);
+ foreach ($shares as $share) {
+ $shareManager->unshare($share);
+ }
}
}
return false;
@@ -293,8 +299,8 @@ public function unlink($path) {
public function rename($path1, $path2) {
// Check for partial files
if (pathinfo($path1, PATHINFO_EXTENSION) === 'part') {
- if ($oldSource = $this->getSourcePath($path1)) {
- list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
+ list($storage, $oldInternalPath) = $this->fetcher->resolvePath($path1);
+ if ($storage && $oldInternalPath) {
$newInternalPath = substr($oldInternalPath, 0, -5);
return $storage->rename($oldInternalPath, $newInternalPath);
}
@@ -302,31 +308,31 @@ public function rename($path1, $path2) {
// Renaming/moving is only allowed within shared folders
$pos1 = strpos($path1, '/', 1);
$pos2 = strpos($path2, '/', 1);
- if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
- $newSource = $this->getSourcePath(dirname($path2)).'/'.basename($path2);
- if (dirname($path1) == dirname($path2)) {
- // Rename the file if UPDATE permission is granted
- if ($this->isUpdatable($path1)) {
- list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
- list( , $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
- return $storage->rename($oldInternalPath, $newInternalPath);
- }
- } else {
- // Move the file if DELETE and CREATE permissions are granted
- if ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
- // Get the root shared folder
- $folder1 = substr($path1, 0, $pos1);
- $folder2 = substr($path2, 0, $pos2);
- // Copy and unlink the file if it exists in a different shared folder
- if ($folder1 != $folder2) {
- if ($this->copy($path1, $path2)) {
- return $this->unlink($path1);
- }
- } else {
- list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
- list( , $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
+ if ($pos1 !== false && $pos2 !== false) {
+ list($storage, $oldInternalPath) = $this->fetcher->resolvePath($path1);
+ list( , $newInternalPath) = $this->fetcher->resolvePath(dirname($path2));
+ if ($storage && $oldInternalPath && $newInternalPath) {
+ $newInternalPath .= '/'.basename($path2);
+ if (dirname($path1) === dirname($path2)) {
+ // Rename the file if UPDATE permission is granted
+ if ($this->isUpdatable($path1)) {
return $storage->rename($oldInternalPath, $newInternalPath);
}
+ } else {
+ // Move the file if DELETE and CREATE permissions are granted
+ if ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
+ // Get the root shared folder
+ $folder1 = substr($path1, 0, $pos1);
+ $folder2 = substr($path2, 0, $pos2);
+ // Copy and unlink the file if it exists in a different shared folder
+ if ($folder1 != $folder2) {
+ if ($this->copy($path1, $path2)) {
+ return $this->unlink($path1);
+ }
+ } else {
+ return $storage->rename($oldInternalPath, $newInternalPath);
+ }
+ }
}
}
}
@@ -335,18 +341,15 @@ public function rename($path1, $path2) {
}
public function copy($path1, $path2) {
- // Copy the file if CREATE permission is granted
if ($this->isCreatable(dirname($path2))) {
- $source = $this->fopen($path1, 'r');
- $target = $this->fopen($path2, 'w');
- list ($count, $result) = \OC_Helper::streamCopy($source, $target);
- return $result;
+ parent::copy($path1, $path2);
}
return false;
}
public function fopen($path, $mode) {
- if ($source = $this->getSourcePath($path)) {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
switch ($mode) {
case 'r+':
case 'rb+':
@@ -362,112 +365,118 @@ public function fopen($path, $mode) {
case 'xb':
case 'a':
case 'ab':
- if (!$this->isUpdatable($path)) {
+ $exists = $this->file_exists($path);
+ if ($exists && !$this->isUpdatable($path)) {
+ return false;
+ }
+ if (!$exists && !$this->isCreatable(dirname(path))) {
return false;
}
}
$info = array(
- 'target' => $this->sharedFolder.$path,
- 'source' => $source,
+ 'target' => '/Shared'.$path,
+ 'source' => $internalPath,
'mode' => $mode,
);
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
return $storage->fopen($internalPath, $mode);
}
return false;
}
public function getMimeType($path) {
- if ($path == '' || $path == '/') {
+ if ($path === '') {
return 'httpd/unix-directory';
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->getMimeType($internalPath);
+ }
}
- if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->getMimeType($internalPath);
- }
- return false;
+ return null;
}
public function free_space($path) {
- if ($path == '') {
- return \OC\Files\SPACE_UNKNOWN;
- }
- $source = $this->getSourcePath($path);
- if ($source) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->free_space($internalPath);
+ if ($path !== '') {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->free_space($internalPath);
+ }
}
+ return \OC\Files\SPACE_UNKNOWN;
}
public function getLocalFile($path) {
- if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->getLocalFile($internalPath);
+ if ($path !== '') {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->getLocalFile($internalPath);
+ }
}
return false;
}
+
public function touch($path, $mtime = null) {
- if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->touch($internalPath, $mtime);
+ if ($path !== '') {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->touch($internalPath, $mtime);
+ }
}
return false;
}
- public static function setup($options) {
- if (!\OCP\User::isLoggedIn() || \OCP\User::getUser() != $options['user']
- || \OCP\Share::getItemsSharedWith('file')) {
- $user_dir = $options['user_dir'];
- \OC\Files\Filesystem::mount('\OC\Files\Storage\Shared',
- array('sharedFolder' => '/Shared'),
- $user_dir.'/Shared/');
- }
- }
-
public function hasUpdated($path, $time) {
- if ($path == '') {
- return false;
+ if ($path !== '') {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->hasUpdated($internalPath, $time);
+ }
}
- return $this->filemtime($path) > $time;
+ return false;
}
public function getCache($path = '') {
- return new \OC\Files\Cache\Shared_Cache($this);
- }
-
- public function getScanner($path = '') {
- return new \OC\Files\Cache\Scanner($this);
+ if (!isset($this->cache)) {
+ $this->cache = new SharedCache($this, $this->fetcher);
+ }
+ return $this->cache;
}
public function getPermissionsCache($path = '') {
- return new \OC\Files\Cache\Shared_Permissions($this);
+ if (!isset($this->permissionsCache)) {
+ $this->permissionsCache = new SharedPermissions($this, $this->fetcher);
+ }
+ return $this->permissionsCache;
}
public function getWatcher($path = '') {
- return new \OC\Files\Cache\Shared_Watcher($this);
+ if (!isset($this->watcher)) {
+ $this->watcher = new SharedWatcher($this);
+ }
+ return $this->watcher;
}
public function getOwner($path) {
- if ($path == '') {
- return false;
- }
- $source = $this->getFile($path);
- if ($source) {
- return $source['fileOwner'];
+ if ($path !== '') {
+ $shares = $this->fetcher->getByPath($path);
+ if (!empty($shares)) {
+ return reset($shares)->getItemOwner();
+ }
}
- return false;
+ return null;
}
public function getETag($path) {
- if ($path == '') {
+ if ($path === '') {
return parent::getETag($path);
- }
- if ($source = $this->getSourcePath($path)) {
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
- return $storage->getETag($internalPath);
+ } else {
+ list($storage, $internalPath) = $this->fetcher->resolvePath($path);
+ if ($storage && $internalPath) {
+ return $storage->getETag($internalPath);
+ }
}
return null;
}
-}
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/updater.php b/apps/files_sharing/lib/updater.php
index a43ab2e2a0a5..329f3a2df645 100644
--- a/apps/files_sharing/lib/updater.php
+++ b/apps/files_sharing/lib/updater.php
@@ -21,86 +21,113 @@
namespace OC\Files\Cache;
-class Shared_Updater {
+use OC\Share\Share;
+use OC\Share\ShareManager;
+use OCA\Files\Share\FileShareFetcher;
+use OC\Files\Filesystem;
+use OC\Files\Cache\Updater;
+
+/**
+ * Listens to filesystem hooks and share hooks to update ETags and remove deleted shares
+ */
+class SharedUpdater {
+
+ protected $shareManager;
+ protected $fetcher;
+ protected $fileItemType;
+ protected $folderItemType;
/**
- * Correct the parent folders' ETags for all users shared the file at $target
- *
- * @param string $target
- */
- static public function correctFolders($target) {
- $uid = \OCP\User::getUser();
- $uidOwner = \OC\Files\Filesystem::getOwner($target);
- $info = \OC\Files\Filesystem::getFileInfo($target);
- // Correct Shared folders of other users shared with
- $users = \OCP\Share::getUsersItemShared('file', $info['fileid'], $uidOwner, true);
- if (!empty($users)) {
- while (!empty($users)) {
- $reshareUsers = array();
- foreach ($users as $user) {
- if ( $user !== $uidOwner ) {
- $etag = \OC\Files\Filesystem::getETag('');
- \OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
- // Look for reshares
- $reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $info['fileid'], $user, true));
- }
- }
- $users = $reshareUsers;
- }
- // Correct folders of shared file owner
- $target = substr($target, 8);
- if ($uidOwner !== $uid && $source = \OC_Share_Backend_File::getSource($target)) {
- \OC\Files\Filesystem::initMountPoints($uidOwner);
- $source = '/'.$uidOwner.'/'.$source['path'];
- \OC\Files\Cache\Updater::correctFolder($source, $info['mtime']);
- }
- }
+ * The constructor
+ * @param \OC\Share\ShareManager $shareManager
+ * @param \OCA\Files\Share\FileShareFetcher $fetcher
+ */
+ public function __construct(ShareManager $shareManager, FileShareFetcher $fetcher) {
+ $this->shareManager = $shareManager;
+ $this->fetcher = $fetcher;
+ $this->fileItemType = 'file';
+ $this->folderItemType = 'folder';
+ \OCP\Util::connectHook('OC_Filesystem', 'post_write', $this, 'onWrite');
+ \OCP\Util::connectHook('OC_Filesystem', 'post_rename', $this, 'onRename');
+ \OCP\Util::connectHook('OC_Filesystem', 'post_delete', $this, 'onDelete');
+ $this->shareManager->listen('\OC\Share', 'postShare', array($this, 'onShare'));
}
/**
+ * Correct the parent folders' ETags
* @param array $params
*/
- static public function writeHook($params) {
- self::correctFolders($params['path']);
+ public function onWrite($params) {
+ $this->correctFolders($params['path']);
}
/**
+ * Correct the parent folders' ETags
* @param array $params
*/
- static public function renameHook($params) {
- self::correctFolders($params['newpath']);
- self::correctFolders(pathinfo($params['oldpath'], PATHINFO_DIRNAME));
+ public function onRename($params) {
+ $this->correctFolders($params['newpath']);
+ $this->correctFolders(dirname($params['oldpath']));
}
/**
+ * Correct the parent folders' ETags and unshare all shares of the file
* @param array $params
*/
- static public function deleteHook($params) {
- self::correctFolders($params['path']);
+ public function onDelete($params) {
+ $this->correctFolders($params['path']);
+ $data = Filesystem::getFileInfo($path);
+ if (isset($data['fileid']) && isset($data['mimetype'])) {
+ $fileId = $data['fileid'];
+ if ($data['mimetype'] === 'httpd/unix-directory') {
+ $itemType = $this->folderItemType;
+ } else {
+ $itemType = $this->fileItemType;
+ }
+ $this->shareManager->unshareItem($itemType, $fileId);
+ }
}
/**
- * @param array $params
+ * Correct the parent folders' ETags for all users the specified share was shared with
+ * @param \OC\Share\Share $share
*/
- static public function shareHook($params) {
- if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
- $uidOwner = \OCP\User::getUser();
- $users = \OCP\Share::getUsersItemShared($params['itemType'], $params['fileSource'], $uidOwner, true);
- if (!empty($users)) {
- while (!empty($users)) {
- $reshareUsers = array();
- foreach ($users as $user) {
- if ($user !== $uidOwner) {
- $etag = \OC\Files\Filesystem::getETag('');
- \OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
- // Look for reshares
- $reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $params['fileSource'], $user, true));
- }
- }
- $users = $reshareUsers;
+ public function onShare(Share $share) {
+ $itemType = $share->getItemType();
+ if ($itemType === $this->fileItemType || $itemType === $this->folderItemType) {
+ $eTag = Filesystem::getETag('');
+ $uids = $this->fetcher->getUsersSharedWith(array($share));
+ foreach ($uids as $uid) {
+ $this->fetcher->setUID($uid);
+ $this->fetcher->setETag($eTag);
+ }
+ }
+ }
+
+ /**
+ * Correct the parent folders' ETags for all users with access to the specified path
+ * @param string $path
+ */
+ protected function correctFolders($path) {
+ $data = Filesystem::getFileInfo($path);
+ if (isset($data['fileid'])) {
+ $fileId = $data['fileid'];
+ $itemOwner = Filesystem::getOwner($path);
+ $eTag = Filesystem::getETag('');
+ $this->fetcher->setUID(null);
+ $uids = $this->fetcher->getUsersSharedWithById($fileId);
+ foreach ($uids as $uid) {
+ if ($uid !== $itemOwner) {
+ $this->fetcher->setUID($uid);
+ $this->fetcher->setETag($eTag);
}
}
+ if ($itemOwner !== \OCP\User::getUser()) {
+ // Correct folders of file owner
+ Filesystem::init($itemOwner, '/'.$itemOwner.'/files');
+ Updater::correctFolder(Filesystem::getPath($fileId), $data['mtime']);
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/watcher.php b/apps/files_sharing/lib/watcher.php
index 6fdfc1db36d0..0c07e8a7392b 100644
--- a/apps/files_sharing/lib/watcher.php
+++ b/apps/files_sharing/lib/watcher.php
@@ -24,7 +24,7 @@
/**
* check the storage backends for updates and change the cache accordingly
*/
-class Shared_Watcher extends Watcher {
+class SharedWatcher extends Watcher {
/**
* check $path for updates
@@ -32,7 +32,7 @@ class Shared_Watcher extends Watcher {
* @param string $path
*/
public function checkUpdate($path) {
- if ($path != '') {
+ if ($path !== '') {
parent::checkUpdate($path);
}
}
@@ -43,7 +43,7 @@ public function checkUpdate($path) {
* @param string $path
*/
public function cleanFolder($path) {
- if ($path != '') {
+ if ($path !== '') {
parent::cleanFolder($path);
}
}
diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php
index e9fdf6e4c951..042b9c5653f4 100644
--- a/apps/files_sharing/public.php
+++ b/apps/files_sharing/public.php
@@ -1,245 +1,249 @@
.
+ */
+
// Load other apps for file previews
OC_App::loadApps();
-
-if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
- header('HTTP/1.0 404 Not Found');
- $tmpl = new OCP\Template('', '404', 'guest');
- $tmpl->printPage();
- exit();
-}
-
-function fileCmp($a, $b) {
- if ($a['type'] == 'dir' and $b['type'] != 'dir') {
- return -1;
- } elseif ($a['type'] != 'dir' and $b['type'] == 'dir') {
- return 1;
- } else {
- return strnatcasecmp($a['name'], $b['name']);
- }
-}
-
-if (isset($_GET['t'])) {
+if (isset($_GET['t']) && OCP\Config::getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes') {
$token = $_GET['t'];
- $linkItem = OCP\Share::getShareByToken($token);
- if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
- // seems to be a valid share
- $type = $linkItem['item_type'];
- $fileSource = $linkItem['file_source'];
- $shareOwner = $linkItem['uid_owner'];
- $path = null;
- $rootLinkItem = OCP\Share::resolveReShare($linkItem);
- $fileOwner = $rootLinkItem['uid_owner'];
- if (isset($fileOwner)) {
- OC_Util::tearDownFS();
- OC_Util::setupFS($fileOwner);
- $path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
+ $shareManager = OCP\Share::getShareManager();
+ if ($shareManager) {
+ $filter = array(
+ 'shareTypeId' => 'link',
+ 'token' => $token,
+ );
+ $share = $shareManager->getShares('file', $filter, 1);
+ if (empty($share)) {
+ // Try folder item type instead
+ $share = $shareManager->getShares('folder', $filter, 1);
}
- }
-}
-if (isset($path)) {
- if (!isset($linkItem['item_type'])) {
- OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR);
- header('HTTP/1.0 404 Not Found');
- $tmpl = new OCP\Template('', '404', 'guest');
- $tmpl->printPage();
- exit();
- }
- if (isset($linkItem['share_with'])) {
- // Authenticate share_with
- $url = OCP\Util::linkToPublic('files') . '&t=' . $token;
- if (isset($_GET['file'])) {
- $url .= '&file=' . urlencode($_GET['file']);
- } else {
- if (isset($_GET['dir'])) {
- $url .= '&dir=' . urlencode($_GET['dir']);
- }
- }
- if (isset($_POST['password'])) {
- $password = $_POST['password'];
- if ($linkItem['share_type'] == OCP\Share::SHARE_TYPE_LINK) {
- // Check Password
- $forcePortable = (CRYPT_BLOWFISH != 1);
- $hasher = new PasswordHash(8, $forcePortable);
- if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''),
- $linkItem['share_with']))) {
+ if (!empty($share)) {
+ $share = reset($share);
+ $password = $share->getPassword();
+ if (isset($password)) {
+ $url = OCP\Util::linkToPublic('files').'&t='.$token;
+ if (isset($_GET['file'])) {
+ $url .= '&file='.urlencode($_GET['file']);
+ } else {
+ if (isset($_GET['dir'])) {
+ $url .= '&dir='.urlencode($_GET['dir']);
+ }
+ }
+ if (isset($_POST['password'])) {
+ $forcePortable = (CRYPT_BLOWFISH != 1);
+ $hasher = new PasswordHash(8, $forcePortable);
+ $salt = OCP\Config::getSystemValue('passwordsalt', '');
+ if (!$hasher->CheckPassword($_POST['password'].$salt, $password)) {
+ // Prompt for password again
+ $tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
+ $tmpl->assign('URL', $url);
+ $tmpl->assign('wrongpw', true);
+ $tmpl->printPage();
+ exit();
+ } else {
+ // Save share id in session for future requests
+ OC::$session->set('public_link_authenticated', $share->getId());
+ }
+ // Check if share id is set in session
+ } else if (!OC::$session->exists('public_link_authenticated')
+ || OC::$session->get('public_link_authenticated') !== $share->getId()
+ ) {
+ // Prompt for password
$tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
$tmpl->assign('URL', $url);
- $tmpl->assign('wrongpw', true);
$tmpl->printPage();
exit();
- } else {
- // Save item id in session for future requests
- \OC::$session->set('public_link_authenticated', $linkItem['id']);
}
+ }
+ OC_Util::tearDownFS();
+ OC_Util::setupFS($share->getItemOwner());
+ $path = \OC\Files\Filesystem::getPath($share->getItemSource());
+ if (isset($_GET['path']) && \OC\Files\Filesystem::isReadable($path.$_GET['path'])) {
+ $getPath = \OC\Files\Filesystem::normalizePath($_GET['path']);
+ $path .= $getPath;
} else {
- OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type']
- .' for share id '.$linkItem['id'], \OCP\Util::ERROR);
- header('HTTP/1.0 404 Not Found');
- $tmpl = new OCP\Template('', '404', 'guest');
- $tmpl->printPage();
- exit();
+ $getPath = '';
}
-
- } else {
- // Check if item id is set in session
- if ( ! \OC::$session->exists('public_link_authenticated')
- || \OC::$session->get('public_link_authenticated') !== $linkItem['id']
- ) {
- // Prompt for password
- $tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest');
- $tmpl->assign('URL', $url);
- $tmpl->printPage();
+ $dir = dirname($path);
+ $file = basename($path);
+ if (isset($_GET['download'])) {
+ if (isset($_GET['files'])) {
+ $files = urldecode($_GET['files']);
+ $filesList = json_decode($files);
+ // in case we get only a single file
+ if ($filesList === NULL ) {
+ $filesList = array($files);
+ }
+ OC_Files::get($path, $filesList, $_SERVER['REQUEST_METHOD'] === 'HEAD');
+ } else {
+ OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] === 'HEAD');
+ }
exit();
- }
- }
- }
- $basePath = $path;
- if (isset($_GET['path']) && \OC\Files\Filesystem::isReadable($basePath . $_GET['path'])) {
- $getPath = \OC\Files\Filesystem::normalizePath($_GET['path']);
- $path .= $getPath;
- } else {
- $getPath = '';
- }
- $dir = dirname($path);
- $file = basename($path);
- // Download the file
- if (isset($_GET['download'])) {
- if (isset($_GET['files'])) { // download selected files
- $files = urldecode($_GET['files']);
- $files_list = json_decode($files);
- // in case we get only a single file
- if ($files_list === NULL ) {
- $files_list = array($files);
- }
- OC_Files::get($path, $files_list, $_SERVER['REQUEST_METHOD'] == 'HEAD');
- } else {
- OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD');
- }
- exit();
- } else {
- OCP\Util::addScript('files', 'file-upload');
- OCP\Util::addStyle('files_sharing', 'public');
- OCP\Util::addScript('files_sharing', 'public');
- OCP\Util::addScript('files', 'fileactions');
- OCP\Util::addScript('files', 'jquery.iframe-transport');
- OCP\Util::addScript('files', 'jquery.fileupload');
- $maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
- $tmpl = new OCP\Template('files_sharing', 'public', 'base');
- $tmpl->assign('uidOwner', $shareOwner);
- $tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner));
- $tmpl->assign('filename', $file);
- $tmpl->assign('directory_path', $linkItem['file_target']);
- $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path));
- $tmpl->assign('fileTarget', basename($linkItem['file_target']));
- $tmpl->assign('dirToken', $linkItem['token']);
- $allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE);
- if (\OCP\App::isEnabled('files_encryption')) {
- $allowPublicUploadEnabled = false;
- }
- if (OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
- $allowPublicUploadEnabled = false;
- }
- if ($linkItem['item_type'] !== 'folder') {
- $allowPublicUploadEnabled = false;
- }
- $tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled);
- $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
- $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
-
- $urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
- .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
- .(isset($_GET['file'])?'&file='.$_GET['file']:'');
- // Show file list
- if (\OC\Files\Filesystem::is_dir($path)) {
- $tmpl->assign('dir', $getPath);
-
- OCP\Util::addStyle('files', 'files');
- OCP\Util::addScript('files', 'files');
- OCP\Util::addScript('files', 'filelist');
- OCP\Util::addscript('files', 'keyboardshortcuts');
- $files = array();
- $rootLength = strlen($basePath) + 1;
- $totalSize = 0;
- foreach (\OC\Files\Filesystem::getDirectoryContent($path) as $i) {
- $totalSize += $i['size'];
- $i['date'] = OCP\Util::formatDate($i['mtime']);
- if ($i['type'] == 'file') {
- $fileinfo = pathinfo($i['name']);
- $i['basename'] = $fileinfo['filename'];
- if (!empty($fileinfo['extension'])) {
- $i['extension'] = '.' . $fileinfo['extension'];
+ } else {
+ // Display the file or folder
+ OCP\Util::addScript('files', 'file-upload');
+ OCP\Util::addStyle('files_sharing', 'public');
+ OCP\Util::addScript('files_sharing', 'public');
+ OCP\Util::addScript('files', 'fileactions');
+ OCP\Util::addScript('files', 'jquery.iframe-transport');
+ OCP\Util::addScript('files', 'jquery.fileupload');
+ $maxUploadFilesize = OCP\Util::maxUploadFilesize($path);
+ $tmpl = new OCP\Template('files_sharing', 'public', 'base');
+ $tmpl->assign('uidOwner', $share->getShareOwner());
+ $tmpl->assign('displayName', $share->getShareOwnerDisplayName());
+ $tmpl->assign('filename', $file);
+ $tmpl->assign('directory_path', $share->getItemTarget());
+ $tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path));
+ $tmpl->assign('fileTarget', $share->getItemTarget());
+ $tmpl->assign('dirToken', $token);
+ $allowPublicUploadEnabled = $share->isCreatable();
+ if (\OCP\App::isEnabled('files_encryption')
+ || OCP\Config::getAppValue('core', 'shareapi_allow_public_upload', 'yes')
+ === 'no' || $share->getItemType() !== 'folder'
+ ) {
+ $allowPublicUploadEnabled = false;
+ }
+ $tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled);
+ $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
+ $tmpl->assign('uploadMaxHumanFilesize',
+ OCP\Util::humanFileSize($maxUploadFilesize)
+ );
+ $urlLinkIdentifiers = (isset($token)?'&t='.$token:'')
+ .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
+ .(isset($_GET['file'])?'&file='.$_GET['file']:'');
+ // Show file list
+ if (\OC\Files\Filesystem::is_dir($path)) {
+ $tmpl->assign('dir', $getPath);
+ OCP\Util::addStyle('files', 'files');
+ OCP\Util::addScript('files', 'files');
+ OCP\Util::addScript('files', 'filelist');
+ OCP\Util::addscript('files', 'keyboardshortcuts');
+ $files = array();
+ $totalSize = 0;
+ foreach (\OC\Files\Filesystem::getDirectoryContent($path) as $i) {
+ $totalSize += $i['size'];
+ $i['date'] = OCP\Util::formatDate($i['mtime']);
+ if ($i['type'] == 'file') {
+ $fileinfo = pathinfo($i['name']);
+ $i['basename'] = $fileinfo['filename'];
+ if (!empty($fileinfo['extension'])) {
+ $i['extension'] = '.' . $fileinfo['extension'];
+ } else {
+ $i['extension'] = '';
+ }
+ }
+ $i['directory'] = $getPath;
+ $i['permissions'] = $share->getPermissions();
+ $files[] = $i;
+ }
+ usort($files, 'fileCmp');
+ // Make breadcrumb
+ $breadcrumb = array();
+ $pathtohere = '';
+ foreach (explode('/', $getPath) as $i) {
+ if ($i != '') {
+ $pathtohere .= '/' . $i;
+ $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i);
+ }
+ }
+ $list = new OCP\Template('files', 'part.list', '');
+ $list->assign('files', $files);
+ $list->assign('disableSharing', true);
+ $list->assign('baseURL',
+ OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&path='
+ );
+ $list->assign('downloadURL',
+ OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download&path='
+ );
+ $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '');
+ $breadcrumbNav->assign('breadcrumb', $breadcrumb);
+ $breadcrumbNav->assign('baseURL',
+ OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&path='
+ );
+ $maxUploadFilesize = OCP\Util::maxUploadFilesize($path);
+ $folder = new OCP\Template('files', 'index', '');
+ $folder->assign('fileList', $list->fetchPage());
+ $folder->assign('breadcrumb', $breadcrumbNav->fetchPage());
+ $folder->assign('dir', $getPath);
+ $folder->assign('isCreatable', false);
+ $folder->assign('permissions', OCP\PERMISSION_READ);
+ $folder->assign('isPublic',true);
+ $folder->assign('publicUploadEnabled', 'no');
+ $folder->assign('files', $files);
+ $folder->assign('uploadMaxFilesize', $maxUploadFilesize);
+ $folder->assign('uploadMaxHumanFilesize',
+ OCP\Util::humanFileSize($maxUploadFilesize)
+ );
+ $folder->assign('allowZipDownload',
+ intval(OCP\Config::getSystemValue('allowZipDownload', true))
+ );
+ $folder->assign('usedSpacePercent', 0);
+ $folder->assign('encryptedFiles', \OCP\Util::encryptedFiles());
+ $tmpl->assign('folder', $folder->fetchPage());
+ if (OCP\Config::getSystemValue('allowZipDownload', true)
+ && $totalSize <= OCP\Config::getSystemValue('maxZipInputSize',
+ OCP\Util::computerFileSize('800 MB'))
+ ) {
+ $allowZip = true;
} else {
- $i['extension'] = '';
+ $allowZip = false;
+ }
+ $tmpl->assign('allowZipDownload', intval($allowZip));
+ $tmpl->assign('downloadURL',
+ OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download&path='.
+ urlencode($getPath)
+ );
+ } else {
+ $tmpl->assign('dir', $dir);
+ // Show file preview if viewer is available
+ if ($share->getItemType() === 'file') {
+ $tmpl->assign('downloadURL',
+ OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download'
+ );
+ } else {
+ $tmpl->assign('downloadURL',
+ OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download&path='.
+ urlencode($getPath)
+ );
}
}
- $i['directory'] = $getPath;
- $i['permissions'] = OCP\PERMISSION_READ;
- $files[] = $i;
- }
- usort($files, "fileCmp");
-
- // Make breadcrumb
- $breadcrumb = array();
- $pathtohere = '';
- foreach (explode('/', $getPath) as $i) {
- if ($i != '') {
- $pathtohere .= '/' . $i;
- $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i);
- }
- }
- $list = new OCP\Template('files', 'part.list', '');
- $list->assign('files', $files);
- $list->assign('disableSharing', true);
- $list->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path=');
- $list->assign('downloadURL',
- OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=');
- $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '');
- $breadcrumbNav->assign('breadcrumb', $breadcrumb);
- $breadcrumbNav->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path=');
- $maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
- $folder = new OCP\Template('files', 'index', '');
- $folder->assign('fileList', $list->fetchPage());
- $folder->assign('breadcrumb', $breadcrumbNav->fetchPage());
- $folder->assign('dir', $getPath);
- $folder->assign('isCreatable', false);
- $folder->assign('permissions', OCP\PERMISSION_READ);
- $folder->assign('isPublic',true);
- $folder->assign('publicUploadEnabled', 'no');
- $folder->assign('files', $files);
- $folder->assign('uploadMaxFilesize', $maxUploadFilesize);
- $folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
- $folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
- $folder->assign('usedSpacePercent', 0);
- $tmpl->assign('folder', $folder->fetchPage());
- $allowZip = OCP\Config::getSystemValue('allowZipDownload', true)
- && $totalSize <= OCP\Config::getSystemValue('maxZipInputSize', OCP\Util::computerFileSize('800 MB'));
- $tmpl->assign('allowZipDownload', intval($allowZip));
- $tmpl->assign('downloadURL',
- OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=' . urlencode($getPath));
- } else {
- $tmpl->assign('dir', $dir);
-
- // Show file preview if viewer is available
- if ($type == 'file') {
- $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download');
- } else {
- $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files')
- .$urlLinkIdentifiers.'&download&path='.urlencode($getPath));
+ $tmpl->printPage();
}
+ exit();
}
- $tmpl->printPage();
}
- exit();
-} else {
- OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
}
-
$errorTemplate = new OCP\Template('files_sharing', 'part.404', '');
$errorContent = $errorTemplate->fetchPage();
-
header('HTTP/1.0 404 Not Found');
OCP\Util::addStyle('files_sharing', '404');
$tmpl = new OCP\Template('', '404', 'guest');
$tmpl->assign('content', $errorContent);
$tmpl->printPage();
+
+function fileCmp($a, $b) {
+ if ($a['type'] == 'dir' and $b['type'] != 'dir') {
+ return -1;
+ } elseif ($a['type'] != 'dir' and $b['type'] == 'dir') {
+ return 1;
+ } else {
+ return strnatcasecmp($a['name'], $b['name']);
+ }
+}
\ No newline at end of file
diff --git a/apps/files_sharing/tests/lib/cache.php b/apps/files_sharing/tests/lib/cache.php
new file mode 100644
index 000000000000..8684434de796
--- /dev/null
+++ b/apps/files_sharing/tests/lib/cache.php
@@ -0,0 +1,517 @@
+.
+ */
+
+namespace Test\Files\Cache;
+
+use OCA\Files\Share\FileShare;
+
+class TestSharedCache extends \OC\Files\Cache\SharedCache {
+
+ public function getMimetype($id) {
+ $mimetypes = array(
+ 1 => 'httpd',
+ 2 => 'httpd/unix-directory',
+ 3 => 'text',
+ 4 => 'text/plain',
+ );
+ if (isset($mimetypes[$id])) {
+ return $mimetypes[$id];
+ }
+ return null;
+ }
+
+}
+
+class SharedCache extends \PHPUnit_Framework_TestCase {
+
+ protected $storage;
+ protected $fetcher;
+ protected $cache;
+ protected $sourceStorage;
+ protected $sourceCache;
+
+ protected function setUp() {
+ $this->storage = $this->getMockBuilder('\OC\Files\Storage\Shared')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->fetcher = $this->getMockBuilder('\OCA\Files\Share\FileShareFetcher')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->cache = new TestSharedCache($this->storage, $this->fetcher);
+ $this->sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Local')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->sourceCache = $this->getMockBuilder('\OC\Files\Cache\Cache')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->sourceStorage->expects($this->any())
+ ->method('getCache')
+ ->will($this->returnValue($this->sourceCache));
+ }
+
+ protected function getTestShareFile() {
+ $share = new FileShare();
+ $share->setItemSource(23);
+ $share->setStorage(1);
+ $share->setItemTarget('foo.txt');
+ $share->setPath('files/foo.txt');
+ $share->setParent(2);
+ $share->setMimetype(4);
+ $share->setMimepart(3);
+ $share->setSize(342);
+ $share->setMtime(1377389543);
+ $share->setStorageMtime(1377389543);
+ $share->setEncrypted(false);
+ $share->setUnencryptedSize(342);
+ $share->setEtag('5203de5db60f6');
+ return $share;
+ }
+
+ protected function getTestShareFolder() {
+ $share = new FileShare();
+ $share->setItemSource(13);
+ $share->setStorage(1);
+ $share->setItemTarget('bar');
+ $share->setPath('files/foobar');
+ $share->setParent(2);
+ $share->setMimetype(2);
+ $share->setMimepart(1);
+ $share->setSize(123);
+ $share->setMtime(1377389567);
+ $share->setStorageMtime(1377389567);
+ $share->setEncrypted(false);
+ $share->setUnencryptedSize(123);
+ $share->setEtag('521618e9b8a59');
+ return $share;
+ }
+
+ public function testGetNumericStorageId() {
+ $this->assertNull($this->cache->getNumericStorageId());
+ }
+ public function testGetWithPath() {
+ $share = $this->getTestShareFile();
+ $data = $share->getMetadata();
+ $data['mimetype'] = 'text/plain';
+ $data['mimepart'] = 'text';
+ $data['storage_mtime'] = 1377389543;
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('foo.txt'))
+ ->will($this->returnValue(array($share)));
+ $this->assertEquals($data, $this->cache->get('foo.txt'));
+ }
+
+ public function testGetWithPathAndNotExactShare() {
+ $share = $this->getTestShareFolder();
+ $data = array(
+ 'fileid' => 26,
+ 'storage' => 1,
+ 'path' => 'files/foobar/bar.txt',
+ 'parent' => 13,
+ 'name' => 'bar.txt',
+ 'mimetype' => 'text/plain',
+ 'mimepart' => 'text',
+ 'size' => 42,
+ 'mtime' => 1377389567,
+ 'storage_mtime' => 1377389567,
+ 'encrypted' => false,
+ 'unencrypted_size' => 42,
+ 'etag' => '52150c666ec70',
+ );
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('bar/bar.txt'))
+ ->will($this->returnValue(array($share)));
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar/bar.txt'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar/bar.txt')));
+ $this->sourceCache->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo('files/foobar/bar.txt'))
+ ->will($this->returnValue($data));
+ $data['path'] = 'bar/bar.txt';
+ $this->assertEquals($data, $this->cache->get('bar/bar.txt'));
+ }
+
+ public function testGetWithId() {
+ $share = $this->getTestShareFile();
+ $share->setStorageMtime(0);
+ $data = $share->getMetadata();
+ $data['mimetype'] = 'text/plain';
+ $data['mimepart'] = 'text';
+ $data['storage_mtime'] = $share->getMtime();
+ $this->fetcher->expects($this->once())
+ ->method('getById')
+ ->with($this->equalTo(23))
+ ->will($this->returnValue(array($share)));
+ $this->assertEquals($data, $this->cache->get(23));
+ }
+
+ public function testGetWithIdAndNotExactShare() {
+ $share = $this->getTestShareFolder();
+ $data = array(
+ 'fileid' => 26,
+ 'storage' => 1,
+ 'path' => 'files/foobar/bar.txt',
+ 'parent' => 13,
+ 'name' => 'bar.txt',
+ 'mimetype' => 'text/plain',
+ 'mimepart' => 'text',
+ 'size' => 42,
+ 'mtime' => 1377389567,
+ 'storage_mtime' => 1377389567,
+ 'encrypted' => false,
+ 'unencrypted_size' => 42,
+ 'etag' => '52150c666ec70',
+ );
+ $this->fetcher->expects($this->once())
+ ->method('getById')
+ ->with($this->equalTo(26))
+ ->will($this->returnValue(array($share)));
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar')));
+ $this->sourceCache->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo(26))
+ ->will($this->returnValue($data));
+ $data['path'] = 'bar/bar.txt';
+ $this->assertEquals($data, $this->cache->get(26));
+ }
+
+ public function testGetWithRoot() {
+ $share1 = $this->getTestShareFile();
+ $share1->setEncrypted(true);
+ $share2 = $this->getTestShareFolder();
+ $data = array(
+ 'fileid' => -1,
+ 'storage' => null,
+ 'path' => '',
+ 'parent' => -1,
+ 'name' => 'Shared',
+ 'mimetype' => 'httpd/unix-directory',
+ 'mimepart' => 'httpd',
+ 'size' => 465,
+ 'mtime' => 1377389567,
+ 'storage_mtime' => 1377389567,
+ 'encrypted' => true,
+ 'unencrypted_size' => 465,
+ 'etag' => '52150a6bea09e',
+ );
+ $this->fetcher->expects($this->exactly(2))
+ ->method('getAll')
+ ->will($this->returnValue(array($share1, $share2)));
+ $this->fetcher->expects($this->exactly(2))
+ ->method('getETag')
+ ->will($this->returnValue('52150a6bea09e'));
+ $this->assertEquals($data, $this->cache->get(''));
+ $this->assertEquals($data, $this->cache->get(-1));
+ }
+
+ public function testGetWithRootAndNoETag() {
+ $share1 = $this->getTestShareFile();
+ $share2 = $this->getTestShareFolder();
+ $data = array(
+ 'fileid' => -1,
+ 'storage' => null,
+ 'path' => '',
+ 'parent' => -1,
+ 'name' => 'Shared',
+ 'mimetype' => 'httpd/unix-directory',
+ 'mimepart' => 'httpd',
+ 'size' => 465,
+ 'mtime' => 1377389567,
+ 'storage_mtime' => 1377389567,
+ 'encrypted' => false,
+ 'unencrypted_size' => 465,
+ 'etag' => '52150a6bea09e',
+ );
+ $this->fetcher->expects($this->once())
+ ->method('getAll')
+ ->will($this->returnValue(array($share1, $share2)));
+ $this->fetcher->expects($this->once())
+ ->method('getETag')
+ ->will($this->returnValue(null));
+ $this->storage->expects($this->once())
+ ->method('getETag')
+ ->with($this->equalTo(''))
+ ->will($this->returnValue('52150a6bea09e'));
+ $this->fetcher->expects($this->once())
+ ->method('setETag')
+ ->with($this->equalTo('52150a6bea09e'));
+ $this->assertEquals($data, $this->cache->get(''));
+ }
+
+ public function testGetWithNotFound() {
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('bar.txt'))
+ ->will($this->returnValue(array()));
+ $this->assertFalse($this->cache->get('bar.txt'));
+ }
+
+ public function testGetFolderContents() {
+ $files = array(
+ array(
+ 'fileid' => 26,
+ 'storage' => 1,
+ 'path' => 'files/foobar/bar.txt',
+ 'parent' => 13,
+ 'name' => 'bar.txt',
+ 'mimetype' => 'text/plain',
+ 'mimepart' => 'text',
+ 'size' => 42,
+ 'mtime' => 1377389567,
+ 'storage_mtime' => 1377389567,
+ 'encrypted' => false,
+ 'unencrypted_size' => 42,
+ 'etag' => '52150c666ec70',
+ ),
+ );
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar')));
+ $this->sourceCache->expects($this->once())
+ ->method('getFolderContents')
+ ->with($this->equalTo('files/foobar'))
+ ->will($this->returnValue($files));
+ $this->assertEquals($files, $this->cache->getFolderContents('bar'));
+ }
+
+ public function testGetFolderContentsWithRoot() {
+ $share1 = $this->getTestShareFile();
+ $share1->setStorageMtime(0);
+ $share2 = $this->getTestShareFolder();
+ $data1 = $share1->getMetadata();
+ $data1['mimetype'] = 'text/plain';
+ $data1['mimepart'] = 'text';
+ $data1['storage_mtime'] = $share1->getMtime();
+ $data2 = $share2->getMetadata();
+ $data2['mimetype'] = 'httpd/unix-directory';
+ $data2['mimepart'] = 'httpd';
+ $files = array($data1, $data2);
+ $this->fetcher->expects($this->once())
+ ->method('getAll')
+ ->will($this->returnValue(array($share1, $share2)));
+ $this->assertEquals($files, $this->cache->getFolderContents(''));
+ }
+
+ public function testPut() {
+ $data = array(
+ 'mtime' => 1377389567,
+ 'size' => 2802,
+ );
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('foo.txt'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foo.txt')));
+ $this->sourceCache->expects($this->once())
+ ->method('put')
+ ->with($this->equalTo('files/foo.txt'), $data)
+ ->will($this->returnValue(23));
+ $this->assertEquals(23, $this->cache->put('foo.txt', $data));
+ }
+
+ public function testPutWithNotFound() {
+ $data = array(
+ 'mtime' => 1377389321,
+ 'size' => 22,
+ );
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar.txt'))
+ ->will($this->returnValue(array(null, null)));
+ $this->sourceCache->expects($this->never())
+ ->method('put');
+ $this->assertEquals(-1, $this->cache->put('bar.txt', $data));
+ }
+
+ public function testPutWithRoot() {
+ $this->fetcher->expects($this->once())
+ ->method('setETag')
+ ->with($this->equalTo('52150a6bea09e'));
+ $this->assertEquals(-1, $this->cache->put('', array('etag' => '52150a6bea09e')));
+ }
+
+ public function testGetId() {
+ $share = $this->getTestShareFile();
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('foo.txt'))
+ ->will($this->returnValue(array($share)));
+ $this->assertEquals($share->getItemSource(), $this->cache->getId('foo.txt'));
+ }
+
+ public function testGetIdWithNotExactShare() {
+ $share = $this->getTestShareFolder();
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('bar/bar.txt'))
+ ->will($this->returnValue(array($share)));
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar/bar.txt'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar/bar.txt')));
+ $this->sourceCache->expects($this->once())
+ ->method('getId')
+ ->with($this->equalTo('files/foobar/bar.txt'))
+ ->will($this->returnValue(26));
+ $this->assertEquals(26, $this->cache->getId('bar/bar.txt'));
+ }
+
+ public function testGetIdWithNotFound() {
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('bar.txt'))
+ ->will($this->returnValue(array()));
+ $this->assertEquals(-1, $this->cache->getId('bar.txt'));
+ }
+
+ public function testGetIdWithRoot() {
+ $this->assertEquals(-1, $this->cache->getId(''));
+ }
+
+ public function testInCache() {
+ $share = $this->getTestShareFile();
+ $this->fetcher->expects($this->once())
+ ->method('getByPath')
+ ->with($this->equalTo('foo.txt'))
+ ->will($this->returnValue(array($share)));
+ $this->assertTrue($this->cache->inCache('foo.txt'));
+ }
+
+ public function testInCacheWithRoot() {
+ $this->assertTrue($this->cache->inCache(''));
+ }
+
+ public function testRemove() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('foo.txt'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foo.txt')));
+ $this->sourceCache->expects($this->once())
+ ->method('remove')
+ ->with($this->equalTo('files/foo.txt'));
+ $this->cache->remove('foo.txt');
+ }
+
+ public function testRemoveNotFound() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar.txt'))
+ ->will($this->returnValue(array(null, null)));
+ $this->sourceCache->expects($this->never())
+ ->method('remove');
+ $this->cache->remove('bar.txt');
+ }
+
+ public function testMove() {
+ $this->fetcher->expects($this->at(0))
+ ->method('resolvePath')
+ ->with($this->equalTo('bar/bar.txt'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar/bar.txt')));
+ $this->fetcher->expects($this->at(1))
+ ->method('resolvePath')
+ ->with($this->equalTo('bar'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar')));
+ $this->sourceCache->expects($this->once())
+ ->method('move')
+ ->with($this->equalTo('files/foobar/bar.txt'),
+ $this->equalTo('files/foobar/newbar.txt')
+ );
+ $this->cache->move('bar/bar.txt', 'bar/newbar.txt');
+ }
+
+ public function testMoveWithNotFound() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar.txt'))
+ ->will($this->returnValue(array(null, null)));
+ $this->sourceCache->expects($this->never())
+ ->method('move');
+ $this->cache->move('bar.txt', 'newbar.txt');
+ }
+
+ public function testGetStatus() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('foo.txt'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foo.txt')));
+ $this->sourceCache->expects($this->once())
+ ->method('getStatus')
+ ->with($this->equalTo('files/foo.txt'))
+ ->will($this->returnValue(\OC\Files\Cache\Cache::SHALLOW));
+ $this->assertEquals(\OC\Files\Cache\Cache::SHALLOW, $this->cache->getStatus('foo.txt'));
+ }
+
+ public function testGetStatusWithNotFound() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar.txt'))
+ ->will($this->returnValue(array(null, null)));
+ $this->sourceCache->expects($this->never())
+ ->method('getStatus');
+ $this->assertEquals(\OC\Files\Cache\Cache::NOT_FOUND, $this->cache->getStatus('bar.txt'));
+ }
+
+ public function testGetStatusWithRoot() {
+ $this->assertEquals(\OC\Files\Cache\Cache::COMPLETE, $this->cache->getStatus(''));
+ }
+
+ public function testCalculateFolderSize() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('bar'))
+ ->will($this->returnValue(array($this->sourceStorage, 'files/foobar')));
+ $this->sourceCache->expects($this->once())
+ ->method('calculateFolderSize')
+ ->with($this->equalTo('files/foobar'))
+ ->will($this->returnValue(79));
+ $this->assertEquals(79, $this->cache->calculateFolderSize('bar'));
+ }
+
+ public function testCalculateFolderSizeNotFound() {
+ $this->fetcher->expects($this->once())
+ ->method('resolvePath')
+ ->with($this->equalTo('foo'))
+ ->will($this->returnValue(array(null, null)));
+ $this->sourceCache->expects($this->never())
+ ->method('calculateFolderSize');
+ $this->assertEquals(0, $this->cache->calculateFolderSize('foo'));
+ }
+
+ public function testCalculateFolderSizeWithRoot() {
+ $share1 = $this->getTestShareFile();
+ $share2 = $this->getTestShareFolder();
+ $this->fetcher->expects($this->once())
+ ->method('getAll')
+ ->will($this->returnValue(array($share1, $share2)));
+ $this->assertEquals(465, $this->cache->calculateFolderSize(''));
+ }
+
+ public function testGetIncomplete() {
+ $this->assertFalse($this->cache->getIncomplete());
+ }
+
+}
\ No newline at end of file
diff --git a/apps/files_sharing/tests/lib/share/filesharefetcher.php b/apps/files_sharing/tests/lib/share/filesharefetcher.php
new file mode 100644
index 000000000000..a75e55bc236e
--- /dev/null
+++ b/apps/files_sharing/tests/lib/share/filesharefetcher.php
@@ -0,0 +1,394 @@
+.
+ */
+
+namespace Test\Share;
+
+use OCA\Files\Share\FileShare;
+
+class FileShareFetcher extends \PHPUnit_Framework_TestCase {
+
+ protected $matt;
+ protected $shareManager;
+ protected $groupManager;
+ protected $folderShareBackend;
+ protected $fetcher;
+
+ protected function setUp() {
+ $this->matt = 'MTRichards';
+ $this->shareManager = $this->getMockBuilder('\OC\Share\ShareManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->folderShareBackend = $this->getMockBuilder('\OCA\Files\Share\FolderShareBackend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->shareManager->expects($this->any())
+ ->method('getShareBackend')
+ ->with($this->equalTo('folder'))
+ ->will($this->returnValue($this->folderShareBackend));
+ $this->fetcher = new \OCA\Files\Share\FileShareFetcher($this->shareManager,
+ $this->groupManager, $this->matt
+ );
+ }
+
+ public function testGetAll() {
+ $share1 = new FileShare();
+ $share1->setItemType('file');
+ $share2 = new FileShare();
+ $share2->setItemType('folder');
+ $map = array(
+ array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true), null, null,
+ array($share1)
+ ),
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true), null,
+ null, array($share2)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $shares = $this->fetcher->getAll();
+ $this->assertCount(2, $shares);
+ $this->assertContains($share1, $shares);
+ $this->assertContains($share2, $shares);
+ }
+
+ public function testGetAllPermissions() {
+ $share1 = new FileShare();
+ $share1->setItemType('file');
+ $share1->setItemSource(79);
+ $share1->setPermissions(1);
+ $share2 = new FileShare();
+ $share2->setItemType('folder');
+ $share2->setItemSource(80);
+ $share2->setPermissions(27);
+ $share3 = new FileShare();
+ $share3->setItemType('folder');
+ $share3->setItemSource(80);
+ $share3->setPermissions(5);
+ $map = array(
+ array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true), null, null,
+ array($share1)
+ ),
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true), null,
+ null, array($share2, $share3)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $permissions = $this->fetcher->getAllPermissions();
+ $this->assertCount(2, $permissions);
+ $this->assertArrayHasKey(79, $permissions);
+ $this->assertEquals(1, $permissions[79]);
+ $this->assertArrayHasKey(80, $permissions);
+ $this->assertEquals(31, $permissions[80]);
+ }
+
+ public function testGetByPathWithFile() {
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemTarget('secrets.txt');
+ $map = array(
+ array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'secrets.txt'), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $shares = $this->fetcher->getByPath('secrets.txt');
+ $this->assertEquals(array($share), $shares);
+ }
+
+ public function testGetByPathWithFileWithoutExt() {
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemTarget('secrets');
+ $map = array(
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'secrets'), null, null, array()
+ ),
+ array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'secrets'), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $shares = $this->fetcher->getByPath('secrets');
+ $this->assertEquals(array($share), $shares);
+ }
+
+ public function testGetByPathWithFileAndPartExt() {
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemTarget('secrets.txt');
+ $map = array(
+ array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'secrets.txt'), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $shares = $this->fetcher->getByPath('secrets.txt.part');
+ $this->assertEquals(array($share), $shares);
+ }
+
+ public function testGetByPathWithFolder() {
+ $share = new FileShare();
+ $share->setItemType('folder');
+ $share->setItemTarget('reports');
+ $map = array(
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'reports'), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $shares = $this->fetcher->getByPath('reports/subfolder');
+ $this->assertEquals(array($share), $shares);
+ }
+
+ public function testGetByIdWithFile() {
+ $share = new FileShare();
+ $share->setItemType('file');
+ $share->setItemSource(79);
+ $map = array(
+ array('file', array('itemSource' => 79, 'shareWith' => $this->matt,
+ 'isShareWithUser' => true), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->folderShareBackend->expects($this->once())
+ ->method('getParentFolderId')
+ ->with($this->equalTo(79))
+ ->will($this->returnValue(-1));
+ $shares = $this->fetcher->getById(79);
+ $this->assertEquals(array($share), $shares);
+ }
+
+ public function testGetByIdWithFolder() {
+ $share = new FileShare();
+ $share->setItemType('folder');
+ $share->setItemSource(80);
+ $map = array(
+ array('file', array('itemSource' => 80, 'shareWith' => $this->matt,
+ 'isShareWithUser' => true), null, null, array()
+ ),
+ array('folder', array('itemSource' => 80, 'shareWith' => $this->matt,
+ 'isShareWithUser' => true), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->folderShareBackend->expects($this->once())
+ ->method('getParentFolderId')
+ ->with($this->equalTo(80))
+ ->will($this->returnValue(-1));
+ $shares = $this->fetcher->getById(80);
+ $this->assertEquals(array($share), $shares);
+ }
+
+ public function testGetByIdWithParentFolders() {
+ $share1 = new FileShare();
+ $share1->setItemType('file');
+ $share1->setItemSource(72);
+ $share2 = new FileShare();
+ $share2->setItemType('folder');
+ $share2->setItemSource(21);
+ $share3 = new FileShare();
+ $share3->setItemType('folder');
+ $share3->setItemSource(4);
+ $map = array(
+ array('file', array('itemSource' => 72, 'shareWith' => $this->matt,
+ 'isShareWithUser' => true), null, null, array($share1)
+ ),
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemSource' => 21), null, null, array($share2)
+ ),
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemSource' => 4), null, null, array($share3)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(3))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->folderShareBackend->expects($this->at(0))
+ ->method('getParentFolderId')
+ ->with($this->equalTo(72))
+ ->will($this->returnValue(21));
+ $this->folderShareBackend->expects($this->at(1))
+ ->method('getParentFolderId')
+ ->with($this->equalTo(21))
+ ->will($this->returnValue(4));
+ $this->folderShareBackend->expects($this->at(2))
+ ->method('getParentFolderId')
+ ->with($this->equalTo(4))
+ ->will($this->returnValue(-1));
+ $shares = $this->fetcher->getById(72);
+ $this->assertCount(3, $shares);
+ $this->assertContains($share1, $shares);
+ $this->assertContains($share2, $shares);
+ $this->assertContains($share3, $shares);
+ }
+
+ public function testGetPermissionsByPath() {
+ $share1 = new FileShare();
+ $share1->setItemType('folder');
+ $share1->setItemTarget('reports');
+ $share1->setPermissions(27);
+ $share2 = new FileShare();
+ $share2->setItemType('folder');
+ $share2->setItemTarget('reports');
+ $share2->setPermissions(5);
+ $map = array(
+ array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'reports'), null, null, array($share1, $share2)
+ ),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->assertEquals(31, $this->fetcher->getPermissionsByPath('reports/subfolder'));
+ }
+
+ public function testGetPermissionsByPathWithNoShares() {
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValue(array()));
+ $this->assertEquals(0, $this->fetcher->getPermissionsByPath('foo'));
+ }
+
+ public function testGetPermissionsById() {
+ $share1 = new FileShare();
+ $share1->setItemType('folder');
+ $share1->setItemSource(80);
+ $share1->setPermissions(27);
+ $share2 = new FileShare();
+ $share2->setItemType('folder');
+ $share2->setItemSource(80);
+ $share2->setPermissions(5);
+ $map = array(
+ array('file', array('itemSource' => 80, 'shareWith' => $this->matt,
+ 'isShareWithUser' => true), null, null, array()
+ ),
+ array('folder', array('itemSource' => 80, 'shareWith' => $this->matt,
+ 'isShareWithUser' => true), null, null, array($share1, $share2)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->folderShareBackend->expects($this->once())
+ ->method('getParentFolderId')
+ ->with($this->equalTo(80))
+ ->will($this->returnValue(-1));
+ $this->assertEquals(31, $this->fetcher->getPermissionsById(80));
+ }
+
+ public function testGetPermissionsByIdWithNoShares() {
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValue(array()));
+ $this->folderShareBackend->expects($this->once())
+ ->method('getParentFolderId')
+ ->will($this->returnValue(-1));
+ $this->assertEquals(0, $this->fetcher->getPermissionsById(1));
+ }
+
+ public function testGetUsersSharedWithByPath() {
+ $share = new FileShare();
+ $share->setShareTypeId('user');
+ $share->setShareWith($this->matt);
+ $share->setItemType('file');
+ $share->setItemTarget('secrets.txt');
+ $map = array(
+ array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true,
+ 'itemTarget' => 'secrets.txt'), null, null, array($share)
+ ),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $uids = $this->fetcher->getUsersSharedWithByPath('secrets.txt');
+ $this->assertCount(1, $uids);
+ $this->assertContains($this->matt, $uids);
+ }
+
+ public function testGetUsersSharedWithById() {
+ $share1 = new FileShare();
+ $share1->setShareTypeId('user');
+ $share1->setShareWith($this->matt);
+ $share1->setItemType('file');
+ $share1->setItemSource(79);
+ $share2 = new FileShare();
+ $share2->setShareTypeId('group');
+ $share2->setShareWith('group');
+ $share2->setItemType('file');
+ $share2->setItemSource(79);
+ $map = array(
+ array('file', array('itemSource' => 79), null, null, array($share1, $share2)),
+ );
+ $this->shareManager->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->folderShareBackend->expects($this->once())
+ ->method('getParentFolderId')
+ ->with($this->equalTo(79))
+ ->will($this->returnValue(-1));
+ $group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user1 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user1->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue($this->matt));
+ $user2 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user2->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('MTGap'));
+ $group->expects($this->once())
+ ->method('getUsers')
+ ->will($this->returnValue(array($user1, $user2)));
+ $this->groupManager->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo('group'))
+ ->will($this->returnValue($group));
+ $this->fetcher->setUID(null);
+ $uids = $this->fetcher->getUsersSharedWithById(79);
+ $this->assertCount(2, $uids);
+ $this->assertContains($this->matt, $uids);
+ $this->assertContains('MTGap', $uids);
+ }
+
+}
\ No newline at end of file
diff --git a/core/ajax/share.php b/core/ajax/share.php
index bdcb61284ecd..468b16e2733c 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -23,26 +23,34 @@
OCP\JSON::callCheck();
OC_App::loadApps();
+$shareManager = OCP\Share::getShareManager();
if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSource'])) {
switch ($_POST['action']) {
case 'share':
if (isset($_POST['shareType']) && isset($_POST['shareWith']) && isset($_POST['permissions'])) {
try {
- $shareType = (int)$_POST['shareType'];
+ $share = new \OC\Share\Share();
+ $shareType = $_POST['shareType'];
+ settype($shareType, 'int');
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ $share->setShareTypeId('user');
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ $share->setShareTypeId('group');
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ $share->setShareTypeId('link');
+ }
$shareWith = $_POST['shareWith'];
- if ($shareType === OCP\Share::SHARE_TYPE_LINK && $shareWith == '') {
+ if ($shareType === \OCP\Share::SHARE_TYPE_LINK && $shareWith === '') {
$shareWith = null;
}
-
- $token = OCP\Share::shareItem(
- $_POST['itemType'],
- $_POST['itemSource'],
- $shareType,
- $shareWith,
- $_POST['permissions']
- );
-
- if (is_string($token)) {
+ $share->setShareOwner(\OCP\User::getUser());
+ $share->setShareWith($shareWith);
+ $share->setItemType($_POST['itemType']);
+ $share->setItemSource($_POST['itemSource']);
+ $share->setPermissions((int)$_POST['permissions']);
+ $share = $shareManager->share($share);
+ $token = $share->getToken();
+ if (isset($token)) {
OC_JSON::success(array('data' => array('token' => $token)));
} else {
OC_JSON::success();
@@ -54,31 +62,85 @@
break;
case 'unshare':
if (isset($_POST['shareType']) && isset($_POST['shareWith'])) {
- if ((int)$_POST['shareType'] === OCP\Share::SHARE_TYPE_LINK && $_POST['shareWith'] == '') {
- $shareWith = null;
- } else {
- $shareWith = $_POST['shareWith'];
+ $shareType = $_POST['shareType'];
+ settype($shareType, 'int');
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ $shareType = 'user';
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ $shareType ='group';
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ $shareType = 'link';
+ }
+ $filter = array(
+ 'shareOwner' => \OCP\User::getUser(),
+ 'shareWith' => $_POST['shareWith'],
+ 'shareTypeId' => $shareType,
+ 'itemSource' => $_POST['itemSource'],
+ );
+ try {
+ $share = $shareManager->getShares($_POST['itemType'], $filter, 1);
+ if (!empty($share)) {
+ $share = reset($share);
+ $shareManager->unshare($share);
+ }
+ } catch (Exception $exception) {
+ OC_JSON::error();
}
- $return = OCP\Share::unshare($_POST['itemType'], $_POST['itemSource'], $_POST['shareType'], $shareWith);
- ($return) ? OC_JSON::success() : OC_JSON::error();
+ OC_JSON::success();
}
break;
case 'setPermissions':
if (isset($_POST['shareType']) && isset($_POST['shareWith']) && isset($_POST['permissions'])) {
- $return = OCP\Share::setPermissions(
- $_POST['itemType'],
- $_POST['itemSource'],
- $_POST['shareType'],
- $_POST['shareWith'],
- $_POST['permissions']
+ $shareType = $_POST['shareType'];
+ settype($shareType, 'int');
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ $shareType = 'user';
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ $shareType ='group';
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ $shareType = 'link';
+ }
+ $filter = array(
+ 'shareOwner' => \OCP\User::getUser(),
+ 'shareWith' => $_POST['shareWith'],
+ 'shareTypeId' => $shareType,
+ 'itemSource' => $_POST['itemSource'],
);
- ($return) ? OC_JSON::success() : OC_JSON::error();
+ try {
+ $share = $shareManager->getShares($_POST['itemType'], $filter, 1);
+ if (!empty($share)) {
+ $share = reset($share);
+ $share->setPermissions((int)$_POST['permissions']);
+ $shareManager->update($share);
+ }
+ } catch (Exception $exception) {
+ OC_JSON::error();
+ }
+ OC_JSON::success();
}
break;
case 'setExpirationDate':
if (isset($_POST['date'])) {
- $return = OCP\Share::setExpirationDate($_POST['itemType'], $_POST['itemSource'], $_POST['date']);
- ($return) ? OC_JSON::success() : OC_JSON::error();
+ if ($_POST['date'] === '') {
+ $time = null;
+ } else {
+ $date = new \DateTime($_POST['date']);
+ $time = $date->getTimeStamp();
+ }
+ $filter = array(
+ 'shareOwner' => \OCP\User::getUser(),
+ 'itemSource' => $_POST['itemSource'],
+ );
+ try {
+ $shares = $shareManager->getShares($_POST['itemType'], $filter);
+ foreach ($shares as $share) {
+ $share->setExpirationTime($time);
+ $shareManager->update($share);
+ }
+ } catch (Exception $exception) {
+ OC_JSON::error();
+ }
+ OC_JSON::success();
}
break;
case 'email':
@@ -126,8 +188,27 @@
switch ($_GET['fetch']) {
case 'getItemsSharedStatuses':
if (isset($_GET['itemType'])) {
- $return = OCP\Share::getItemsShared($_GET['itemType'], OCP\Share::FORMAT_STATUSES);
- is_array($return) ? OC_JSON::success(array('data' => $return)) : OC_JSON::error();
+ $statuses = array();
+ $filter = array(
+ 'shareOwner' => \OCP\User::getUser(),
+ );
+ try {
+ $shares = $shareManager->getShares($_GET['itemType'], $filter);
+ foreach ($shares as $share) {
+ if ($share->getShareTypeId() === 'link') {
+ $statuses[$share->getItemSource()]['link'] = true;
+ } else if (!isset($statuses[$share->getItemSource()])) {
+ $statuses[$share->getItemSource()]['link'] = false;
+ }
+ $itemType = $share->getItemType();
+ if ($itemType === 'file' || $itemType == 'folder') {
+ $statuses[$share->getItemSource()]['path'] = \OC\Files\Filesystem::getPath($share->getItemSource());
+ }
+ }
+ } catch (Exception $exception) {
+ OC_JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($exception->getMessage()))));
+ }
+ OC_JSON::success(array('data' => $statuses));
}
break;
case 'getItem':
@@ -136,104 +217,110 @@
&& isset($_GET['checkReshare'])
&& isset($_GET['checkShares'])) {
if ($_GET['checkReshare'] == 'true') {
- $reshare = OCP\Share::getItemSharedWithBySource(
- $_GET['itemType'],
- $_GET['itemSource'],
- OCP\Share::FORMAT_NONE,
- null,
- true
+ $reshare = array();
+ $filter = array(
+ 'shareWith' => \OCP\User::getUser(),
+ 'isShareWithUser' => true,
+ 'itemSource' => $_GET['itemSource'],
);
+ $result = $shareManager->getShares($_GET['itemType'], $filter);
+ $shares = array();
+ foreach ($result as $share) {
+ $shareTypeId = $share->getShareTypeId();
+ if ($shareTypeId === 'user') {
+ $shareTypeId = \OCP\Share::SHARE_TYPE_USER;
+ } else if ($shareTypeId === 'group') {
+ $shareTypeId = OCP\Share::SHARE_TYPE_GROUP;
+ } else if ($shareTypeId === 'link') {
+ $shareTypeId = OCP\Share::SHARE_TYPE_LINK;
+ }
+ $expiration = $share->getExpirationTime();
+ if (isset($expiration)) {
+ $expiration = date('d-m-Y', $share->getExpirationTime());
+ }
+ $reshare[$share->getId()] = array(
+ 'share_type' => $shareTypeId,
+ 'uid_owner' => $share->getShareOwner(),
+ 'share_with' => $share->getShareWith(),
+ 'permissions' => $share->getPermissions(),
+ 'share_with_displayname' => $share->getShareWithDisplayName(),
+ 'displayname_owner' => $share->getShareOwnerDisplayName(),
+ 'expiration' => $expiration,
+ );
+ }
} else {
- $reshare = false;
+ $reshare = array();
}
if ($_GET['checkShares'] == 'true') {
- $shares = OCP\Share::getItemShared(
- $_GET['itemType'],
- $_GET['itemSource'],
- OCP\Share::FORMAT_NONE,
- null,
- true
+ $filter = array(
+ 'shareOwner' => \OCP\User::getUser(),
+ 'itemSource' => $_GET['itemSource'],
);
+ $result = $shareManager->getShares($_GET['itemType'], $filter);
+ $shares = array();
+ foreach ($result as $share) {
+ $shareTypeId = $share->getShareTypeId();
+ if ($shareTypeId === 'user') {
+ $shareTypeId = \OCP\Share::SHARE_TYPE_USER;
+ } else if ($shareTypeId === 'group') {
+ $shareTypeId = OCP\Share::SHARE_TYPE_GROUP;
+ } else if ($shareTypeId === 'link') {
+ $shareTypeId = OCP\Share::SHARE_TYPE_LINK;
+ }
+ $expiration = $share->getExpirationTime();
+ if (isset($expiration)) {
+ $expiration = date('d-m-Y', $share->getExpirationTime());
+ }
+ $shares[$share->getId()] = array(
+ 'share_type' => $shareTypeId,
+ 'uid_owner' => $share->getShareOwner(),
+ 'share_with' => $share->getShareWith(),
+ 'permissions' => $share->getPermissions(),
+ 'share_with_displayname' => $share->getShareWithDisplayName(),
+ 'displayname_owner' => $share->getShareOwnerDisplayName(),
+ 'expiration' => $expiration,
+ );
+ }
} else {
- $shares = false;
+ $shares = array();
}
OC_JSON::success(array('data' => array('reshare' => $reshare, 'shares' => $shares)));
}
break;
case 'getShareWith':
if (isset($_GET['search'])) {
- $sharePolicy = OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
- $shareWith = array();
-// if (OC_App::isEnabled('contacts')) {
-// // TODO Add function to contacts to only get the 'fullname' column to improve performance
-// $ids = OC_Contacts_Addressbook::activeIds();
-// foreach ($ids as $id) {
-// $vcards = OC_Contacts_VCard::all($id);
-// foreach ($vcards as $vcard) {
-// $contact = $vcard['fullname'];
-// if (stripos($contact, $_GET['search']) !== false
-// && (!isset($_GET['itemShares'])
-// || !isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_CONTACT])
-// || !is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_CONTACT])
-// || !in_array($contact, $_GET['itemShares'][OCP\Share::SHARE_TYPE_CONTACT]))) {
-// $shareWith[] = array('label' => $contact, 'value' => array('shareType' => 5, 'shareWith' => $vcard['id']));
-// }
-// }
-// }
-// }
- if ($sharePolicy == 'groups_only') {
- $groups = OC_Group::getUserGroups(OC_User::getUser());
- } else {
- $groups = OC_Group::getGroups();
- }
- $count = 0;
- $users = array();
- $limit = 0;
- $offset = 0;
- while ($count < 15 && count($users) == $limit) {
- $limit = 15 - $count;
- if ($sharePolicy == 'groups_only') {
- $users = OC_Group::DisplayNamesInGroups($groups, $_GET['search'], $limit, $offset);
- } else {
- $users = OC_User::getDisplayNames($_GET['search'], $limit, $offset);
+ $shareWiths = array();
+ $shareOwner = \OCP\User::getUser();
+ $shareBackend = $shareManager->getShareBackend('file');
+ $shareTypes = $shareBackend->getShareTypes();
+ foreach ($shareTypes as $shareType) {
+ $shareTypeId = $shareType->getId();
+ if ($shareTypeId === 'user') {
+ $shareTypeId = \OCP\Share::SHARE_TYPE_USER;
+ } else if ($shareTypeId === 'group') {
+ $shareTypeId = OCP\Share::SHARE_TYPE_GROUP;
}
- $offset += $limit;
- foreach ($users as $uid => $displayName) {
- if ((!isset($_GET['itemShares'])
- || !is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_USER])
- || !in_array($uid, $_GET['itemShares'][OCP\Share::SHARE_TYPE_USER]))
- && $uid != OC_User::getUser()) {
- $shareWith[] = array(
- 'label' => $displayName,
- 'value' => array('shareType' => OCP\Share::SHARE_TYPE_USER,
- 'shareWith' => $uid)
- );
- $count++;
+ $result = $shareType->searchForPotentialShareWiths($shareOwner, $_GET['search'], 10, null);
+ foreach ($result as $shareWith) {
+ $shareWiths[] = array(
+ 'label' => $shareWith['shareWithDisplayName'],
+ 'value' => array(
+ 'shareType' => $shareTypeId,
+ 'shareWith' => $shareWith['shareWith'],
+ ),
+ );
+ if (isset($limit)) {
+ $limit--;
+ if ($limit === 0) {
+ break 2;
+ }
}
- }
- }
- $count = 0;
- foreach ($groups as $group) {
- if ($count < 15) {
- if (stripos($group, $_GET['search']) !== false
- && (!isset($_GET['itemShares'])
- || !isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])
- || !is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])
- || !in_array($group, $_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP]))) {
- $shareWith[] = array(
- 'label' => $group.' (group)',
- 'value' => array(
- 'shareType' => OCP\Share::SHARE_TYPE_GROUP,
- 'shareWith' => $group
- )
- );
- $count++;
+ if (isset($offset) && $offset > 0) {
+ $offset--;
}
- } else {
- break;
}
}
- OC_JSON::success(array('data' => $shareWith));
+ OC_JSON::success(array('data' => $shareWiths));
}
break;
}
diff --git a/core/js/share.js b/core/js/share.js
index 27c16f38b92d..a26aff86e3d4 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -257,7 +257,7 @@ OC.Share={
var shareWith = selected.item.value.shareWith;
$(this).val(shareWith);
// Default permissions are Edit (CRUD) and Share
- var permissions = OC.PERMISSION_ALL;
+ var permissions = 17;
OC.Share.share(itemType, itemSource, shareType, shareWith, permissions, function() {
OC.Share.addShareWith(shareType, shareWith, selected.item.label, permissions, possiblePermissions);
$('#shareWith').val('');
diff --git a/db_structure.xml b/db_structure.xml
index f926ab44cd40..55f753c5707f 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -857,6 +857,199 @@
+
+
+ *dbprefix*shares
+
+
+
+
+ id
+ integer
+ 0
+ true
+ 1
+ 4
+
+
+
+ share_type_id
+ text
+
+ true
+ 32
+
+
+
+ share_owner
+ text
+
+ true
+ 64
+
+
+
+ share_with
+ text
+
+ false
+ 64
+
+
+
+ item_type
+ text
+
+ true
+ 64
+
+
+
+ item_owner
+ text
+
+ true
+ 64
+
+
+
+ item_source
+ text
+
+ false
+ 64
+
+
+
+ item_target
+ text
+
+ false
+ 250
+
+
+
+ permissions
+ integer
+ 0
+ true
+ 1
+
+
+
+ share_time
+ integer
+ 0
+ true
+ 4
+
+
+
+ expiration_time
+ integer
+
+ false
+ 4
+
+
+
+
+
+
+
+
+ *dbprefix*shares_groups
+
+
+
+
+ id
+ integer
+ 0
+ true
+ 4
+
+
+
+ uid
+ text
+
+ true
+ 64
+
+
+
+ item_target
+ text
+
+ true
+ 250
+
+
+
+
+
+
+
+
+ *dbprefix*shares_links
+
+
+
+
+ id
+ integer
+ 0
+ true
+ 4
+
+
+
+ token
+ text
+
+ true
+ 250
+
+
+
+ password
+ text
+
+ false
+ 250
+
+
+
+
+
+
+
+
+ *dbprefix*shares_parents
+
+
+
+
+ id
+ integer
+ 0
+ true
+ 4
+
+
+
+ parent_id
+ integer
+ 0
+ true
+ 4
+
+
+
+
+
+
*dbprefix*jobs
diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php
index 39e36684b7ba..9dbe88e90567 100644
--- a/lib/files/cache/cache.php
+++ b/lib/files/cache/cache.php
@@ -104,8 +104,8 @@ public function get($file) {
$where = 'WHERE `storage` = ? AND `path_hash` = ?';
$params = array($this->getNumericStorageId(), md5($file));
} else { //file id
- $where = 'WHERE `fileid` = ?';
- $params = array($file);
+ $where = 'WHERE `storage` = ? AND `fileid` = ?';
+ $params = array($this->getNumericStorageId(), $file);
}
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
`storage_mtime`, `encrypted`, `unencrypted_size`, `etag`
@@ -119,9 +119,9 @@ public function get($file) {
$data = false;
}
- //merge partial data
- if (!$data and is_string($file)) {
- if (isset($this->partial[$file])) {
+ if (!$data) {
+ //merge partial data
+ if (is_string($file) && isset($this->partial[$file])) {
$data = $this->partial[$file];
}
} else {
diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php
index 10ec5c41d11e..ad784c56def3 100644
--- a/lib/files/filesystem.php
+++ b/lib/files/filesystem.php
@@ -588,6 +588,10 @@ static public function isSharable($path) {
return self::$defaultInstance->isSharable($path);
}
+ static public function getPermissions($path) {
+ return self::$defaultInstance->getPermissions($path);
+ }
+
static public function file_exists($path) {
return self::$defaultInstance->file_exists($path);
}
diff --git a/lib/files/mount/mount.php b/lib/files/mount/mount.php
index 0ce2f5975c71..e1dc7a984df6 100644
--- a/lib/files/mount/mount.php
+++ b/lib/files/mount/mount.php
@@ -119,7 +119,7 @@ public function getStorageId() {
* @return string
*/
public function getInternalPath($path) {
- if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) {
+ if ($this->mountPoint === $path or $this->mountPoint === $path . '/') {
$internalPath = '';
} else {
$internalPath = substr($path, strlen($this->mountPoint));
diff --git a/lib/files/view.php b/lib/files/view.php
index bb737f19ef82..8e43cdc0068b 100644
--- a/lib/files/view.php
+++ b/lib/files/view.php
@@ -230,6 +230,10 @@ public function isSharable($path) {
return $this->basicOperation('isSharable', $path);
}
+ public function getPermissions($path) {
+ return $this->basicOperation('getPermissions', $path);
+ }
+
public function file_exists($path) {
if ($path == '/') {
return true;
@@ -1026,23 +1030,26 @@ public function getETag($path) {
/**
* Get the path of a file by id, relative to the view
*
- * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
+ * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
*
* @param int $id
- * @return string
+ * @return string | null
*/
public function getPath($id) {
- list($storage, $internalPath) = Cache\Cache::getById($id);
- $mounts = Filesystem::getMountByStorageId($storage);
+ $mountManager = Filesystem::getMountManager();
+ $mounts = $mountManager->findIn($this->getRoot());
+ $mounts[] = $mountManager->find($this->getRoot());
foreach ($mounts as $mount) {
- /**
- * @var \OC\Files\Mount $mount
- */
- $fullPath = $mount->getMountPoint() . $internalPath;
- if (!is_null($path = $this->getRelativePath($fullPath))) {
- return $path;
+ $cache = $mount->getStorage()->getCache();
+ $data = $cache->get($id);
+ if ($data) {
+ $fullPath = $mount->getMountPoint() . $data['path'];
+ if (!is_null($path = $this->getRelativePath($fullPath))) {
+ return $path;
+ }
}
}
return null;
}
+
}
diff --git a/lib/public/share.php b/lib/public/share.php
index b38208bc67fc..268d2c725033 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -20,6 +20,9 @@
*/
namespace OCP;
+use OC\Share\ShareManager;
+use OC\Share\Controller\ShareDialogController;
+
/**
* This class provides the ability for apps to share their content between users.
* Apps must create a backend class that implements OCP\Share_Backend and register it with this class.
@@ -63,7 +66,124 @@ class Share {
private static $backendTypes = array();
private static $isResharingAllowed;
+ private static $shareManager;
+
+ /**
+ * Get the ShareManager
+ * @return \OC\Share\ShareManager | null
+ */
+ public static function getShareManager() {
+ if (!isset(self::$shareManager)) {
+ if (\OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes') === 'yes') {
+ self::$shareManager = new ShareManager();
+ \OC_Util::addScript('core', 'share');
+ \OC_Util::addStyle('core', 'share');
+ self::setupHooks();
+ } else {
+ self::$shareManager = null;
+ }
+ }
+ return self::$shareManager;
+ }
+
+ // /**
+ // * Get the ShareDialogController
+ // * @param mixed $params The parameters for the request
+ // * @return \OC\Share\Controller\ShareDialogController | null
+ // */
+ // public static function getShareDialogController($params) {
+ // \OC_JSON::callCheck();
+ // \OC_JSON::checkLoggedIn();
+ // $contents = json_decode(file_get_contents('php://input'), true);
+ // $contents = is_array($contents) ? $contents: array();
+ // $params = array_merge($params, $contents, $_GET, $_POST);
+ // $shareManager = self::getShareManager();
+ // if ($shareManager) {
+ // return new ShareDialogController($shareManager, new \OC\Log(), $params);
+ // }
+ // return null;
+ // }
+
+ /**
+ * Emit old hooks for backwards compatibility
+ */
+ public static function setupHooks() {
+ $shareManager = self::getShareManager();
+ if ($shareManager) {
+ $shareManager->listen('\OC\Share', 'preShare', function($share) {
+ \OC_Hook::emit('OCP\Share', 'pre_shared', self::getHookArray($share));
+ });
+ $shareManager->listen('\OC\Share', 'postShare', function($share) {
+ \OC_Hook::emit('OCP\Share', 'post_shared', self::getHookArray($share));
+ });
+ $shareManager->listen('\OC\Share', 'preUnshare', function($share) {
+ $params = self::getHookArray($share);
+ $params['itemParent'] = $params['parent'];
+ \OC_Hook::emit('OCP\Share', 'pre_unshare', $params);
+ });
+ $shareManager->listen('\OC\Share', 'postUnshare', function($share) {
+ $params = self::getHookArray($share);
+ $params['itemParent'] = $params['parent'];
+ \OC_Hook::emit('OCP\Share', 'post_unshare', $params);
+ });
+ $shareManager->listen('\OC\Share', 'postUpdate', function($share) {
+ $properties = $share->getUpdatedProperties();
+ if (isset($properties['permissions'])) {
+ $itemType = $share->getItemType();
+ if ($itemType === 'file' || $itemType === 'folder') {
+ $params = self::getHookArray($share);
+ $params['path'] = $share->getPath();
+ \OC_Hook::emit('OCP\Share', 'post_update_permissions', $params);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Get the share properties in an array as expected for the old hooks
+ * @param \OC\Share\Share $share
+ * @return array
+ */
+ public static function getHookArray($share) {
+ $itemTarget = $share->getItemTarget();
+ if ($share->getShareTypeId() === 'group') {
+ if (is_array($itemTarget)) {
+ $itemTarget = reset($itemTarget);
+ }
+ }
+ $shareType = null;
+ $shareTypeId = $share->getShareTypeId();
+ if ($shareTypeId === 'user') {
+ $shareType = self::SHARE_TYPE_USER;
+ } else if ($shareTypeId === 'group') {
+ $shareType = self::SHARE_TYPE_GROUP;
+ } else if ($shareTypeId === 'link') {
+ $shareType = self::SHARE_TYPE_LINK;
+ }
+ $parent = null;
+ $parentIds = $share->getParentIds();
+ if (is_array($parentIds)) {
+ $parent = reset($parentIds);
+ }
+ return array(
+ 'itemType' => $share->getItemType(),
+ 'itemSource' => $share->getItemSource(),
+ 'itemTarget' => $itemTarget,
+ 'parent' => $parent,
+ 'shareType' => $shareType,
+ 'shareWith' => $share->getShareWith(),
+ 'uidOwner' => $share->getShareOwner(),
+ 'permissions' => $share->getPermissions(),
+ 'fileSource' => $share->getItemSource(),
+ 'fileTarget' => $itemTarget,
+ 'id' => $share->getId(),
+ 'token' => $share->getToken(),
+ );
+ }
+
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Register a sharing backend class that implements OCP\Share_Backend for an item type
* @param string Item type
* @param string Backend class
@@ -94,6 +214,7 @@ public static function registerBackend($itemType, $class, $collectionOf = null,
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Check if the Share API is enabled
* @return Returns true if enabled or false
*
@@ -108,6 +229,7 @@ public static function isEnabled() {
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Prepare a path to be passed to DB as file_target
* @return string Prepared path
*/
@@ -125,6 +247,7 @@ public static function prepFileTarget( $path ) {
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Find which users can access a shared item
* @param $path to the file
* @param $user owner of the file
@@ -227,6 +350,7 @@ public static function getUsersSharingFile($path, $user, $includeOwner = false)
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Get the items of item type shared with the current user
* @param string Item type
* @param int Format (optional) Format type must be defined by the backend
@@ -240,6 +364,7 @@ public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Get the item of item type shared with the current user
* @param string Item type
* @param string Item target
@@ -253,6 +378,7 @@ public static function getItemSharedWith($itemType, $itemTarget, $format = self:
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Get the item of item type shared with the current user by source
* @param string Item type
* @param string Item source
@@ -266,6 +392,7 @@ public static function getItemSharedWithBySource($itemType, $itemSource, $format
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Get the item of item type shared by a link
* @param string Item type
* @param string Item source
@@ -278,6 +405,7 @@ public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief Get the item shared by a token
* @param string token
* @return Item
@@ -292,6 +420,7 @@ public static function getShareByToken($token) {
}
/**
+ * @deprecated As of version 2.0.0, replaced by ShareManager
* @brief resolves reshares down to the last real share
* @param $linkItem
* @return $fileOwner
@@ -454,9 +583,6 @@ public static function shareItem($itemType, $itemSource, $shareType, $shareWith,
$forcePortable = (CRYPT_BLOWFISH != 1);
$hasher = new \PasswordHash(8, $forcePortable);
$shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', ''));
- } else {
- // reuse the already set password
- $shareWith = $checkExists['share_with'];
}
// Generate token
@@ -1292,8 +1418,6 @@ private static function put($itemType, $itemSource, $shareType, $shareWith, $uid
if ($shareType == self::SHARE_TYPE_GROUP) {
$groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'],
$uidOwner, $suggestedItemTarget);
- $run = true;
- $error = '';
\OC_Hook::emit('OCP\Share', 'pre_shared', array(
'itemType' => $itemType,
'itemSource' => $itemSource,
@@ -1303,9 +1427,7 @@ private static function put($itemType, $itemSource, $shareType, $shareWith, $uid
'uidOwner' => $uidOwner,
'permissions' => $permissions,
'fileSource' => $fileSource,
- 'token' => $token,
- 'run' => &$run,
- 'error' => &$error
+ 'token' => $token
));
if ($run === false) {
@@ -1387,8 +1509,6 @@ private static function put($itemType, $itemSource, $shareType, $shareWith, $uid
} else {
$itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
$suggestedItemTarget);
- $run = true;
- $error = '';
\OC_Hook::emit('OCP\Share', 'pre_shared', array(
'itemType' => $itemType,
'itemSource' => $itemSource,
@@ -1398,9 +1518,7 @@ private static function put($itemType, $itemSource, $shareType, $shareWith, $uid
'uidOwner' => $uidOwner,
'permissions' => $permissions,
'fileSource' => $fileSource,
- 'token' => $token,
- 'run' => &$run,
- 'error' => &$error
+ 'token' => $token
));
if ($run === false) {
diff --git a/lib/share/advancedsharefactory.php b/lib/share/advancedsharefactory.php
new file mode 100644
index 000000000000..b1692e1f6cc0
--- /dev/null
+++ b/lib/share/advancedsharefactory.php
@@ -0,0 +1,49 @@
+.
+ */
+
+namespace OC\Share;
+
+/**
+ * An alternative to ShareFactory that can reduce the number of queries to create a Share entity
+ * Setups JOINs in the share queries to retrieve additional properties for the Share entity
+ * The columns specified in getColumns() will be returned in the $row passed to mapToShare($row)
+ */
+abstract class AdvancedShareFactory extends ShareFactory {
+
+ /**
+ * Get JOIN(s) to app table(s)
+ * @return string
+ *
+ * Example: JOIN `*PREFIX*table1` ON `*PREFIX*share`.`item_source` = `*PREFIX*table1`.`id`
+ *
+ */
+ abstract public function getJoins();
+
+ /**
+ * Get app table column(s)
+ * @return string
+ *
+ * Example: `*PREFIX*table1`.`id`, `*PREFIX*table1`.`name`
+ *
+ */
+ abstract public function getColumns();
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/invalidexpirationtimeexception.php b/lib/share/exception/invalidexpirationtimeexception.php
new file mode 100644
index 000000000000..c85538424862
--- /dev/null
+++ b/lib/share/exception/invalidexpirationtimeexception.php
@@ -0,0 +1,30 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class InvalidExpirationTimeException extends \Exception {
+
+ public function __construct($message) {
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/invaliditemexception.php b/lib/share/exception/invaliditemexception.php
new file mode 100644
index 000000000000..bb6abba2d73a
--- /dev/null
+++ b/lib/share/exception/invaliditemexception.php
@@ -0,0 +1,30 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class InvalidItemException extends \Exception {
+
+ public function __construct($message) {
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/invalidpermissionsexception.php b/lib/share/exception/invalidpermissionsexception.php
new file mode 100644
index 000000000000..e8edb6ea5550
--- /dev/null
+++ b/lib/share/exception/invalidpermissionsexception.php
@@ -0,0 +1,30 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class InvalidPermissionsException extends \Exception {
+
+ public function __construct($message) {
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/invalidshareexception.php b/lib/share/exception/invalidshareexception.php
new file mode 100644
index 000000000000..11c2eb424783
--- /dev/null
+++ b/lib/share/exception/invalidshareexception.php
@@ -0,0 +1,30 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class InvalidShareException extends \Exception {
+
+ public function __construct($message) {
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/multiplesharesreturnedexception.php b/lib/share/exception/multiplesharesreturnedexception.php
new file mode 100644
index 000000000000..6b5801e94047
--- /dev/null
+++ b/lib/share/exception/multiplesharesreturnedexception.php
@@ -0,0 +1,31 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class MultipleSharesReturnedException extends \Exception {
+
+ public function __construct($id) {
+ $message = 'Multiple shares were returned for the id '.$id;
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/sharebackenddoesnotexistexception.php b/lib/share/exception/sharebackenddoesnotexistexception.php
new file mode 100644
index 000000000000..afe54634cf60
--- /dev/null
+++ b/lib/share/exception/sharebackenddoesnotexistexception.php
@@ -0,0 +1,31 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class ShareBackendDoesNotExistException extends \Exception {
+
+ public function __construct($itemType) {
+ $message = 'A share backend does not exist for the item type '.$itemType;
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/sharedoesnotexistexception.php b/lib/share/exception/sharedoesnotexistexception.php
new file mode 100644
index 000000000000..a7da075dc27a
--- /dev/null
+++ b/lib/share/exception/sharedoesnotexistexception.php
@@ -0,0 +1,31 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class ShareDoesNotExistException extends \Exception {
+
+ public function __construct($id) {
+ $message = 'A share does not exist with the id '.$id;
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/exception/sharetypedoesnotexistexception.php b/lib/share/exception/sharetypedoesnotexistexception.php
new file mode 100644
index 000000000000..71e629609a27
--- /dev/null
+++ b/lib/share/exception/sharetypedoesnotexistexception.php
@@ -0,0 +1,31 @@
+.
+ */
+
+namespace OC\Share\Exception;
+
+class ShareTypeDoesNotExistException extends \Exception {
+
+ public function __construct($shareTypeId) {
+ $message = 'A share type does not exist with the id '.$shareTypeId;
+ parent::__construct($message);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/icollectionsharebackend.php b/lib/share/icollectionsharebackend.php
new file mode 100644
index 000000000000..874adc90844d
--- /dev/null
+++ b/lib/share/icollectionsharebackend.php
@@ -0,0 +1,56 @@
+.
+ */
+
+namespace OC\Share;
+
+use OC\Share\Share;
+
+/**
+ * This interface should be implemented if a share backend has content that can have children that
+ * are also shared using a different backend class e.g. folders
+ *
+ * Hooks available in scope \OC\Share:
+ * - preShare(\OC\Share\Share $share)
+ * - postShare(\OC\Share\Share $share)
+ * - preUnshare(\OC\Share\Share $share)
+ * - postUnshare(\OC\Share\Share $share)
+ * - preUpdate(\OC\Share\Share $share)
+ * - postUpdate(\OC\Share\Share $share)
+ *
+ * @version 2.0.0 BETA
+ */
+interface ICollectionShareBackend {
+
+ /**
+ * Get the identifiers for the children item types of this backend
+ * @return array
+ */
+ public function getChildrenItemTypes();
+
+ /**
+ * Search for shares of this collection item type that contain the child item source and
+ * shared with the share owner
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share[]
+ */
+ public function searchForParentCollections(Share $share);
+
+}
\ No newline at end of file
diff --git a/lib/share/itemtargetmachine.php b/lib/share/itemtargetmachine.php
new file mode 100644
index 000000000000..ace1bf592958
--- /dev/null
+++ b/lib/share/itemtargetmachine.php
@@ -0,0 +1,39 @@
+.
+ */
+
+namespace OC\Share;
+
+use OC\User\User;
+
+abstract class ItemTargetMachine {
+
+ /**
+ * Get a unique item target for the specified share and user
+ * @param \OC\Share\Share $share
+ * @param \OC\User\User $user
+ * @return string
+ *
+ * If $user is null, any item target is acceptable
+ *
+ */
+ abstract public function getItemTarget(Share $share, User $user = null);
+
+}
\ No newline at end of file
diff --git a/lib/share/share.php b/lib/share/share.php
new file mode 100644
index 000000000000..510ef073b4e5
--- /dev/null
+++ b/lib/share/share.php
@@ -0,0 +1,511 @@
+.
+ */
+
+namespace OC\Share;
+
+/**
+ * Data holder for shared items
+ * Extend this class to store additional properties
+ *
+ * Adapated from OCA\AppFramework\Db\Entity
+ * Only setters that call markPropertyUpdated are mutable properties
+ */
+class Share {
+
+ protected $id;
+ protected $parentIds = array();
+ protected $shareTypeId;
+ protected $shareOwner;
+ protected $shareOwnerDisplayName;
+ protected $shareWith;
+ protected $shareWithDisplayName;
+ protected $itemType;
+ protected $itemSource;
+ protected $itemTarget;
+ protected $itemOwner;
+ protected $permissions = 0;
+ protected $expirationTime;
+ protected $shareTime;
+ protected $token;
+ protected $password;
+
+ private $updatedProperties = array();
+ private $propertyTypes = array(
+ 'id' => 'int',
+ 'permissions' => 'int',
+ 'expirationTime' => 'int',
+ 'shareTime' => 'int'
+ );
+
+ /**
+ * Get the id
+ * @return int
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ * Set the id
+ * @param int $id
+ */
+ public function setId($id) {
+ $this->id = $id;
+ }
+
+ /**
+ * Get the references to parent shares
+ * @return array
+ */
+ public function getParentIds() {
+ return $this->parentIds;
+ }
+
+ /**
+ * Set the references to parent shares
+ * @param array $parentIds
+ */
+ public function setParentIds($parentIds) {
+ $this->parentIds = $parentIds;
+ $this->markPropertyUpdated('parentIds');
+ }
+
+ /**
+ * Add a reference to a parent share
+ * @param int $id
+ */
+ public function addParentId($id) {
+ $parentIds = $this->getParentIds();
+ $parentIds[] = $id;
+ $this->setParentIds($parentIds);
+ }
+
+ /**
+ * Remove a reference to a parent share
+ * @param int $id
+ */
+ public function removeParentId($id) {
+ $parentIds = $this->getParentIds();
+ $parentIds = array_diff($this->getParentIds(), array($id));
+ $this->setParentIds($parentIds);
+ }
+
+ /**
+ * Get the share type id
+ * @return string
+ */
+ public function getShareTypeId() {
+ return $this->shareTypeId;
+ }
+
+ /**
+ * Set the share type id
+ * @param string $shareTypeId
+ */
+ public function setShareTypeId($shareTypeId) {
+ $this->shareTypeId = $shareTypeId;
+ }
+
+ /**
+ * Get the share owner
+ * @return string
+ */
+ public function getShareOwner() {
+ return $this->shareOwner;
+ }
+
+ /**
+ * Set the share owner
+ * @param string $shareOwner
+ */
+ public function setShareOwner($shareOwner) {
+ $this->shareOwner = $shareOwner;
+ }
+
+ /**
+ * Get the share owner display name
+ * @return string
+ */
+ public function getShareOwnerDisplayName() {
+ return $this->shareOwnerDisplayName;
+ }
+
+ /**
+ * Set the share owner display name
+ * @param string $shareOwnerDisplayName
+ */
+ public function setShareOwnerDisplayName($shareOwnerDisplayName) {
+ $this->shareOwnerDisplayName = $shareOwnerDisplayName;
+ }
+
+ /**
+ * Get the share with
+ * @return string
+ */
+ public function getShareWith() {
+ return $this->shareWith;
+ }
+
+ /**
+ * Set the share with
+ * @param string $shareWith
+ */
+ public function setShareWith($shareWith) {
+ $this->shareWith = $shareWith;
+ }
+
+ /**
+ * Get the share with display name
+ * @return string
+ */
+ public function getShareWithDisplayName() {
+ return $this->shareWithDisplayName;
+ }
+
+ /**
+ * Set the share With display name
+ * @param string $shareWithDisplayName
+ */
+ public function setShareWithDisplayName($shareWithDisplayName) {
+ $this->shareWithDisplayName = $shareWithDisplayName;
+ }
+
+ /**
+ * Get the item type
+ * @return string
+ */
+ public function getItemType() {
+ return $this->itemType;
+ }
+
+ /**
+ * Set the item type
+ * @param string $itemType
+ */
+ public function setItemType($itemType) {
+ $this->itemType = $itemType;
+ }
+
+ /**
+ * Get the item source
+ * @return mixed
+ */
+ public function getItemSource() {
+ return $this->itemSource;
+ }
+
+ /**
+ * Set the item source
+ * @param mixed $itemSource
+ */
+ public function setItemSource($itemSource) {
+ $this->itemSource = $itemSource;
+ }
+
+ /**
+ * Get the item target
+ * @return string
+ */
+ public function getItemTarget() {
+ return $this->itemTarget;
+ }
+
+ /**
+ * Set the item target
+ * @param string $itemTarget
+ */
+ public function setItemTarget($itemTarget) {
+ $this->itemTarget = $itemTarget;
+ $this->markPropertyUpdated('itemTarget');
+ }
+
+ /**
+ * Get the item owner, may differ from share owner if this is a reshare
+ * @return string
+ */
+ public function getItemOwner() {
+ return $this->itemOwner;
+ }
+
+ /**
+ * Set the item owner
+ * @param string $itemOwner
+ */
+ public function setItemOwner($itemOwner) {
+ $this->itemOwner = $itemOwner;
+ }
+
+ /**
+ * Get the permissions
+ * @return int
+ */
+ public function getPermissions() {
+ return $this->permissions;
+ }
+
+ /**
+ * Set the permissions
+ * @param int $permissions
+ */
+ public function setPermissions($permissions) {
+ $this->permissions = $permissions;
+ $this->markPropertyUpdated('permissions');
+ }
+
+ /**
+ * Check if create permission is granted
+ * @return bool
+ */
+ public function isCreatable() {
+ return ($this->permissions & \OCP\PERMISSION_CREATE) !== 0;
+ }
+
+ /**
+ * Check if read permission is granted
+ * @return bool
+ */
+ public function isReadable() {
+ return ($this->permissions & \OCP\PERMISSION_READ) !== 0;
+ }
+
+ /**
+ * Check if update permission is granted
+ * @return bool
+ */
+ public function isUpdatable() {
+ return ($this->permissions & \OCP\PERMISSION_UPDATE) !== 0;
+ }
+
+ /**
+ * Check if delete permission is granted
+ * @return bool
+ */
+ public function isDeletable() {
+ return ($this->permissions & \OCP\PERMISSION_DELETE) !== 0;
+ }
+
+ /**
+ * Check if share permission is granted
+ * @return bool
+ */
+ public function isSharable() {
+ return ($this->permissions & \OCP\PERMISSION_SHARE) !== 0;
+ }
+
+ /**
+ * Get the expiration time
+ * @return int
+ */
+ public function getExpirationTime() {
+ return $this->expirationTime;
+ }
+
+ /**
+ * Set the expiration time
+ * @param int $expirationTime
+ */
+ public function setExpirationTime($expirationTime) {
+ $this->expirationTime = $expirationTime;
+ $this->markPropertyUpdated('expirationTime');
+ }
+
+ /**
+ * Get the share time
+ * @return int
+ */
+ public function getShareTime() {
+ return $this->shareTime;
+ }
+
+ /**
+ * Set the share time
+ * @param int $shareTime
+ */
+ public function setShareTime($shareTime) {
+ $this->shareTime = $shareTime;
+ }
+
+ /**
+ * Get the token, only for shares of the link share type
+ * @return string
+ */
+ public function getToken() {
+ return $this->token;
+ }
+
+ /**
+ * Set the token, only for shares of the link share type
+ * @param string $token
+ */
+ public function setToken($token) {
+ $this->token = $token;
+ }
+
+ /**
+ * Get the password, only for shares of the link share type
+ * @return string
+ */
+ public function getPassword() {
+ return $this->password;
+ }
+
+ /**
+ * Set the password, only for shares of the link share type
+ * @param string $password
+ */
+ public function setPassword($password) {
+ $this->password = $password;
+ $this->markPropertyUpdated('password');
+ }
+
+ /**
+ * Get all properties in an array
+ * @return array
+ */
+ public function toAPI() {
+ return array(
+ 'id' => $this->getId(),
+ 'parentIds' => $this->getParentIds(),
+ 'shareTypeId' => $this->getShareTypeId(),
+ 'shareOwner' => $this->getShareOwner(),
+ 'shareOwnerDisplayName' => $this->getShareOwnerDisplayName(),
+ 'shareWith' => $this->getShareWith(),
+ 'shareWithDisplayName' => $this->getShareWithDisplayName(),
+ 'itemType' => $this->getItemType(),
+ 'itemSource' => $this->getItemSource(),
+ 'itemTarget' => $this->getItemTarget(),
+ 'itemOwner' => $this->getItemOwner(),
+ 'permissions' => $this->getPermissions(),
+ 'expirationTime' => $this->getExpirationTime(),
+ 'shareTime' => $this->getShareTime(),
+ 'token' => $this->getToken(),
+ 'password' => $this->getPassword(),
+ );
+ }
+
+ /**
+ * Simple alternative constructor for building entities from a request
+ * @param array $params the array which was obtained via $this->params('key')
+ * in the controller
+ * @return Share
+ */
+ public static function fromParams(array $params) {
+ $instance = new static();
+ foreach ($params as $property => $value) {
+ $setter = 'set'.ucfirst($property);
+ if (method_exists($instance, $setter)) {
+ $instance->$setter($value);
+ }
+ }
+ return $instance;
+ }
+
+ /**
+ * Maps the keys of the row array to the attributes
+ * @param array $row the row to map onto the entity
+ */
+ public static function fromRow(array $row) {
+ $instance = new static();
+ foreach ($row as $column => $value) {
+ $property = $instance::columnToProperty($column);
+ $setter = 'set'.ucfirst($property);
+ if (method_exists($instance, $setter)) {
+ if (isset($value) && isset($instance->propertyTypes[$property])) {
+ settype($value, $instance->propertyTypes[$property]);
+ }
+ $instance->$setter($value);
+ }
+ }
+ return $instance;
+ }
+
+ /**
+ * Mark a property as updated
+ * @param string $property the name of the property
+ */
+ protected function markPropertyUpdated($property) {
+ $this->updatedProperties[$property] = true;
+ }
+
+ /**
+ * @return array array of updated fields for update query
+ */
+ public function getUpdatedProperties() {
+ return $this->updatedProperties;
+ }
+
+ /**
+ * Marks the entity as clean
+ */
+ public function resetUpdatedProperties() {
+ $this->updatedProperties = array();
+ }
+
+ /**
+ * Transform a database column name to a property
+ * @param string $columnName the name of the column
+ * @return string the property name
+ */
+ public static function columnToProperty($columnName) {
+ $columnName = trim($columnName, '`');
+ $parts = explode('_', $columnName);
+ $property = null;
+ foreach ($parts as $part) {
+ if ($property === null) {
+ $property = $part;
+ } else {
+ $property .= ucfirst($part);
+ }
+ }
+ return $property;
+ }
+
+ /**
+ * Transform a property to a database column name
+ * @param string $property the name of the property
+ * @return string the column name
+ */
+ public static function propertyToColumn($property) {
+ $parts = preg_split('/(?=[A-Z])/', $property);
+ $column = null;
+ foreach ($parts as $part) {
+ if ($column === null) {
+ $column = $part;
+ } else {
+ $column .= '_'.lcfirst($part);
+ }
+ }
+ return '`'.$column.'`';
+ }
+
+ /**
+ * Adds type information for a property so that its automatically casted to
+ * that value once its being returned from the database
+ * @param string $property the name of the attribute
+ * @param string $type the type which will be used to call settype()
+ */
+ protected function addType($property, $type) {
+ $this->propertyTypes[$property] = $type;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php
new file mode 100644
index 000000000000..6f39009ba72f
--- /dev/null
+++ b/lib/share/sharebackend.php
@@ -0,0 +1,292 @@
+.
+ */
+
+namespace OC\Share;
+
+use OC\Share\Share;
+use OC\Share\TimeMachine;
+use OC\Hooks\BasicEmitter;
+use OC\Share\Exception\InvalidShareException;
+use OC\Share\Exception\ShareTypeDoesNotExistException;
+use OC\Share\Exception\InvalidPermissionsException;
+use OC\Share\Exception\InvalidExpirationTimeException;
+
+/**
+ * Backend class that apps extend and register with the ShareManager to share content
+ *
+ * Hooks available in scope \OC\Share:
+ * - preShare(\OC\Share\Share $share)
+ * - postShare(\OC\Share\Share $share)
+ * - preUnshare(\OC\Share\Share $share)
+ * - postUnshare(\OC\Share\Share $share)
+ * - preUpdate(\OC\Share\Share $share)
+ * - postUpdate(\OC\Share\Share $share)
+ *
+ * @version 2.0.0 BETA
+ */
+abstract class ShareBackend extends BasicEmitter {
+
+ protected $timeMachine;
+ protected $shareTypes;
+
+ /**
+ * The constructor
+ * @param \OC\Share\TimeMachine $timeMachine The time() mock
+ * @param \OC\Share\ShareType\IShareType[] $shareTypes An array of share type objects that
+ * items can be shared through e.g. User, Group, Link
+ */
+ public function __construct(TimeMachine $timeMachine, array $shareTypes) {
+ $this->timeMachine = $timeMachine;
+ foreach ($shareTypes as $shareType) {
+ $this->shareTypes[$shareType->getId()] = $shareType;
+ }
+ }
+
+ /**
+ * Get the identifier for the item type this backend handles, should be a singular noun
+ * @return string
+ */
+ abstract public function getItemType();
+
+ /**
+ * Get the plural form of getItemType, used for the RESTful API
+ * @return string
+ */
+ abstract public function getItemTypePlural();
+
+ /**
+ * Check if an item is valid for the share owner
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidItemException If the item does not exist or the share
+ * owner does not have access to the item
+ * @return bool
+ */
+ abstract protected function isValidItem(Share $share);
+
+ /**
+ * Get all share types
+ * @return \OC\Share\ShareType\IShareType[]
+ */
+ public function getShareTypes() {
+ return $this->shareTypes;
+ }
+
+ /**
+ * Get share type by id
+ * @param string $shareTypeId
+ * @throws \OC\Share\Exception\ShareTypeDoesNotExistException
+ * @return \OC\Share\IShareType
+ */
+ public function getShareType($shareTypeId) {
+ if (isset($this->shareTypes[$shareTypeId])) {
+ return $this->shareTypes[$shareTypeId];
+ } else {
+ throw new ShareTypeDoesNotExistException($shareTypeId);
+ }
+ }
+
+ /**
+ * Share a share
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidItemException
+ * @throws \OC\Share\Exception\InvalidShareException
+ * @throws \OC\Share\Exception\InvalidPermissionsException
+ * @throws \OC\Share\Exception\InvalidExpirationTimeException
+ * @return \OC\Share\Share | bool
+ */
+ public function share(Share $share) {
+ if ($this->isValidItem($share)) {
+ // Don't share the same share again
+ $filter = array(
+ 'shareTypeId' => $share->getShareTypeId(),
+ 'shareOwner' => $share->getShareOwner(),
+ 'shareWith' => $share->getShareWith(),
+ 'itemSource' => $share->getItemSource(),
+ );
+ $exists = $this->getShares($filter, 1);
+ if (!empty($exists)) {
+ throw new InvalidShareException('The share already exists');
+ }
+ $shareType = $this->getShareType($share->getShareTypeId());
+ if ($shareType->isValidShare($share) && $this->areValidPermissions($share)
+ && $this->isValidExpirationTime($share)
+ ) {
+ $this->emit('\OC\Share', 'preShare', array($share));
+ $share->setShareTime($this->timeMachine->getTime());
+ $share = $shareType->share($share);
+ $this->emit('\OC\Share', 'postShare', array($share));
+ return $share;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Unshare a share
+ * @param \OC\Share\Share $share
+ */
+ public function unshare(Share $share) {
+ $shareType = $this->getShareType($share->getShareTypeId());
+ $this->emit('\OC\Share', 'preUnshare', array($share));
+ $shareType->unshare($share);
+ $this->emit('\OC\Share', 'postUnshare', array($share));
+ }
+
+ /**
+ * Update a share's properties in the database
+ * @param \OC\Share\Share $share
+ */
+ public function update(Share $share) {
+ $properties = $share->getUpdatedProperties();
+ if (!empty($properties)) {
+ if (isset($properties['permissions'])) {
+ $this->areValidPermissions($share);
+ }
+ if (isset($properties['expirationTime'])) {
+ $this->isValidExpirationTime($share);
+ }
+ $shareType = $this->getShareType($share->getShareTypeId());
+ $this->emit('\OC\Share', 'preUpdate', array($share));
+ foreach ($properties as $property => $updated) {
+ $setter = 'set'.ucfirst($property);
+ if (method_exists($shareType, $setter)) {
+ $shareType->$setter($share);
+ unset($properties[$property]);
+ }
+ }
+ if (!empty($properties)) {
+ $shareType->update($share);
+ }
+ $this->emit('\OC\Share', 'postUpdate', array($share));
+ }
+ }
+
+ /**
+ * Get the shares with the specified parameters
+ * @param array $filter (optional) A key => value array of share properties
+ * @param int $limit (optional)
+ * @param int $offset (optional)
+ * @return \OC\Share\Share[]
+ */
+ public function getShares($filter = array(), $limit = null, $offset = null) {
+ if (isset($filter['shareTypeId'])) {
+ $shareTypes = array($this->getShareType($filter['shareTypeId']));
+ unset($filter['shareTypeId']);
+ } else {
+ $shareTypes = $this->shareTypes;
+ }
+ $shares = array();
+ foreach ($shareTypes as $shareType) {
+ $result = $shareType->getShares($filter, $limit, $offset);
+ foreach ($result as $share) {
+ $shares[] = $share;
+ if (isset($limit)) {
+ $limit--;
+ if ($limit === 0) {
+ return $shares;
+ }
+ }
+ if (isset($offset) && $offset > 0) {
+ $offset--;
+ }
+ }
+ }
+ return $shares;
+ }
+
+ /**
+ * Check if a share is expired
+ * @param \OC\Share\Share $share
+ * @return bool
+ */
+ public function isExpired(Share $share) {
+ $time = $share->getExpirationTime();
+ $now = $this->timeMachine->getTime();
+ if (isset($time)) {
+ if ($time - $now < 0) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ // Check if the admin has set a default expiration time
+ $defaultTime = \OC_Appconfig::getValue('core', 'shareapi_expiration_time', 0);
+ if ($defaultTime > 0 && $defaultTime + $share->getShareTime() - $now < 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Check if a share's permissions are valid
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidPermissionsException If the permissions are not an
+ * integer or are not in the range of 1 to 31
+ * @return bool
+ *
+ * Permissions are defined by the CRUDS system, see lib/public/constants.php
+ * General information: wikipedia.org/wiki/Create,_read,_update_and_delete
+ *
+ * In ownCloud 'S' is defined as share permission
+ *
+ * You can use PHP's bitwise operators to manipulate the permissions
+ *
+ */
+ protected function areValidPermissions(Share $share) {
+ $permissions = $share->getPermissions();
+ if (!is_int($permissions)) {
+ throw new InvalidPermissionsException('The permissions are not an integer');
+ }
+ if ($permissions < 1 || $permissions > \OCP\PERMISSION_ALL) {
+ throw new InvalidPermissionsException(
+ 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL
+ );
+ }
+ return true;
+ }
+
+ /**
+ * Check if a share's expiration time is valid
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidExpirationTimeException If the expiration time is set and is
+ * not an integer or is not at least 1 hour in the future
+ * @return bool
+ *
+ * Expiration time is defined by a unix timestamp
+ * An expiration time of null implies the share will not expire
+ *
+ */
+ protected function isValidExpirationTime(Share $share) {
+ $time = $share->getExpirationTime();
+ if (isset($time) && !is_int($time)) {
+ throw new InvalidExpirationTimeException('The expiration time is not an integer');
+ }
+ if (isset($time) && $time < $this->timeMachine->getTime() + 3600) {
+ throw new InvalidExpirationTimeException(
+ 'The expiration time is not at least 1 hour in the future'
+ );
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharefactory.php b/lib/share/sharefactory.php
new file mode 100644
index 000000000000..7388dc99e41e
--- /dev/null
+++ b/lib/share/sharefactory.php
@@ -0,0 +1,38 @@
+.
+ */
+
+namespace OC\Share;
+
+/**
+ * Creates Share entities from the database
+ */
+class ShareFactory {
+
+ /**
+ * Map a database row to a Share entity
+ * @param array $row A key => value array of share properties
+ * @return Share
+ */
+ public function mapToShare($row) {
+ return Share::fromRow($row);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php
new file mode 100644
index 000000000000..aede75fb954d
--- /dev/null
+++ b/lib/share/sharemanager.php
@@ -0,0 +1,553 @@
+.
+ */
+
+namespace OC\Share;
+
+use OC\Share\Share;
+use OC\Share\ShareBackend;
+use OC\Share\CollectionShareBackend;
+use OC\Share\Exception\InvalidShareException;
+use OC\Share\Exception\ShareDoesNotExistException;
+use OC\Share\Exception\ShareBackendDoesNotExistException;
+use OC\Share\Exception\ShareTypeDoesNotExistException;
+use OC\Share\Exception\InvalidPermissionsException;
+use OC\Share\Exception\InvalidExpirationTimeException;
+use OC\Share\Exception\MultipleSharesReturnedException;
+use OC\Hooks\ForwardingEmitter;
+
+/**
+ * This is the gateway for sharing content between users in ownCloud, aka Share API
+ * Apps must create a share backend class that extends OC\Share\ShareBackend and register it here
+ *
+ * The ShareManager's primary purpose is to ensure consistency between shares and their reshares
+ *
+ * Hooks available in scope \OC\Share:
+ * - preShare(\OC\Share\Share $share)
+ * - postShare(\OC\Share\Share $share)
+ * - preUnshare(\OC\Share\Share $share)
+ * - postUnshare(\OC\Share\Share $share)
+ * - preUpdate(\OC\Share\Share $share)
+ * - postUpdate(\OC\Share\Share $share)
+ *
+ * @version 2.0.0 BETA
+ */
+class ShareManager extends ForwardingEmitter {
+
+ protected $shareBackends;
+
+ /**
+ * Register a share backend
+ * @param \OC\Share\ShareBackend $shareBackend
+ */
+ public function registerShareBackend(ShareBackend $shareBackend) {
+ $this->shareBackends[$shareBackend->getItemType()] = $shareBackend;
+ $this->forward($shareBackend);
+ }
+
+ /**
+ * Get all registered share backends
+ * @return \OC\Share\ShareBackend[]
+ */
+ public function getShareBackends() {
+ return $this->shareBackends;
+ }
+
+ /**
+ * Get a share backend by item type
+ * @param string $itemType
+ * @throws \OC\Share\Exception\ShareBackendDoesNotExistException
+ * @return \OC\Share\ShareBackend
+ */
+ public function getShareBackend($itemType) {
+ if (isset($this->shareBackends[$itemType])) {
+ return $this->shareBackends[$itemType];
+ } else {
+ throw new ShareBackendDoesNotExistException($itemType);
+ }
+ }
+
+ /**
+ * Share a share in the share backend
+ * @param Share $share
+ * @throws \OC\Share\Exception\InvalidItemException
+ * @throws \OC\Share\Exception\InvalidShareException
+ * @throws \OC\Share\Exception\InvalidPermissionsException
+ * @throws \OC\Share\Exception\InvalidExpirationTimeException
+ * @return \OC\Share\Share | bool
+ */
+ public function share(Share $share) {
+ $shareBackend = $this->getShareBackend($share->getItemType());
+ $parents = $this->searchForParents($share);
+ // See if the share is a reshare
+ if (!empty($parents)) {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ if ($resharing !== 'yes') {
+ throw new InvalidShareException('The admin has disabled resharing');
+ }
+ foreach ($parents as $parent) {
+ if ($parent->getShareTypeId() === $share->getShareTypeId()) {
+ if ($parent->getShareOwner() === $share->getShareWith()) {
+ throw new InvalidShareException(
+ 'The share can\'t reshare back to the share owner'
+ );
+ }
+ if ($parent->getShareWith() === $share->getShareWith()) {
+ throw new InvalidShareException(
+ 'The parent share has the same share with'
+ );
+ }
+ }
+ if ($parent->isSharable()) {
+ $share->addParentId($parent->getId());
+ }
+ }
+ $parentIds = $share->getParentIds();
+ if (empty($parentIds)) {
+ throw new InvalidShareException(
+ 'The parent shares don\'t allow resharing'
+ );
+ }
+ $share->setItemOwner(reset($parents)->getItemOwner());
+ $this->areValidPermissionsForParents($share);
+ $this->isValidExpirationTimeForParents($share);
+ } else {
+ $share->setItemOwner($share->getShareOwner());
+ }
+ $share = $shareBackend->share($share);
+ if ($share !== false && $share->isSharable()) {
+ $id = $share->getId();
+ // Add this share to existing reshares' parent ids
+ $reshares = $this->searchForReshares($share);
+ foreach ($reshares as $reshare) {
+ $reshare->addParentId($id);
+ $this->update($reshare);
+ }
+ }
+ return $share;
+ }
+
+ /**
+ * Unshare a share in the share backend
+ * @param \OC\Share\Share $share
+ */
+ public function unshare(Share $share) {
+ $shareBackend = $this->getShareBackend($share->getItemType());
+ if ($share->isSharable()) {
+ // Fake removing all permissions so reshares will be unshared or updated correctly
+ $fakeShare = clone $share;
+ $fakeShare->setPermissions(0);
+ $this->updateReshares($fakeShare, $share);
+ }
+ $shareBackend->unshare($share);
+ }
+
+ /**
+ * Update a share's properties in the share backend
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\ShareDoesNotExistException
+ * @throws \OC\Share\Exception\InvalidPermissionsException
+ * @throws \OC\Share\Exception\InvalidExpirationTimeException
+ *
+ * Updating permissions or expiration time will trigger an update of the respective property
+ * for all reshares to ensure consistency with the parent shares
+ *
+ */
+ public function update(Share $share) {
+ $itemType = $share->getItemType();
+ $properties = $share->getUpdatedProperties();
+ if (isset($properties['permissions'])) {
+ $this->areValidPermissionsForParents($share);
+ }
+ if (isset($properties['expirationTime'])) {
+ $this->isValidExpirationTimeForParents($share);
+ }
+ // Find the share in the backend to compare old/new properties for reshares' updates
+ $oldShare = $this->getShareById($share->getId(), $itemType, $share->getShareTypeId());
+ $shareBackend = $this->getShareBackend($itemType);
+ $shareBackend->update($share);
+ if (isset($properties['permissions']) || isset($properties['expirationTime'])) {
+ $this->updateReshares($share, $oldShare);
+ }
+ }
+
+ /**
+ * Get the shares with the specified parameters in the share backend
+ * @param string $itemType
+ * @param array $filter (optional) A key => value array of share properties
+ * @param int $limit (optional)
+ * @param int $offset (optional)
+ * @return \OC\Share\Share[]
+ */
+ public function getShares($itemType, $filter = array(), $limit = null, $offset = null) {
+ $shares = array();
+ $shareBackend = $this->getShareBackend($itemType);
+ $results = $shareBackend->getShares($filter, $limit, $offset);
+ $expired = 0;
+ foreach ($results as $share) {
+ if ($shareBackend->isExpired($share)) {
+ $this->unshare($share);
+ $expired++;
+ } else {
+ $shares[] = $share;
+ }
+ }
+ // If shares expired and a limit was requested, attempt to replace the shares
+ // Don't try if the number of results didn't match the limit since there are no more shares
+ if ($expired > 0 && isset($limit) && count($results) === $limit) {
+ if (isset($offset)) {
+ $offset += $limit - $expired;
+ } else {
+ $offset = $limit - $expired;
+ }
+ $expiredReplacements = $this->getShares($itemType, $filter, $expired, $offset);
+ $shares = array_merge($shares, $expiredReplacements);
+ }
+ return $shares;
+ }
+
+ /**
+ * Get a share by id
+ * @param int $id
+ * @param string $itemType (optional)
+ * @param string $shareTypeId (optional)
+ * @throws \OC\Share\Exception\ShareDoesNotExistException
+ * @return \OC\Share\Share
+ */
+ public function getShareById($id, $itemType = null, $shareTypeId = null) {
+ $share = array();
+ $filter = array('id' => $id);
+ if (isset($shareTypeId)) {
+ $filter['shareTypeId'] = $shareTypeId;
+ }
+ if (isset($itemType)) {
+ $share = $this->getShares($itemType, $filter, 1);
+ } else {
+ foreach ($this->getShareBackends() as $shareBackend) {
+ try {
+ $share = $this->getShares($shareBackend->getItemType(), $filter, 1);
+ if (!empty($share)) {
+ break;
+ }
+ } catch (ShareTypeDoesNotExistException $exception) {
+ // Do nothing
+ }
+ }
+ }
+ if (empty($share)) {
+ throw new ShareDoesNotExistException($id);
+ } else if (count($share) > 1) {
+ throw new MultipleSharesReturnedException($id);
+ } else {
+ return reset($share);
+ }
+ }
+
+ /**
+ * Unshare all shares of an item
+ * @param string $itemType
+ * @param any $itemSource
+ *
+ * Call this if an item is deleted by the item owner. However, this should not be called if
+ * the item owner is deleted because this is handled by the UserWatcher.
+ *
+ */
+ public function unshareItem($itemType, $itemSource) {
+ $filter = array(
+ 'itemSource' => $itemSource,
+ );
+ $shares = $this->getShares($itemType, $filter);
+ foreach ($shares as $share) {
+ $this->unshare($share);
+ }
+ }
+
+ /**
+ * Get all reshares of a share
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share[]
+ *
+ * It is possible for the reshares to be of a different item type if the share's item type
+ * is a collection
+ *
+ */
+ public function getReshares(Share $share) {
+ $itemType = $share->getItemType();
+ $filter = array(
+ 'parentId' => $share->getId(),
+ );
+ $reshares = $this->getShares($itemType, $filter);
+ $shareBackend = $this->getShareBackend($itemType);
+ if ($shareBackend instanceof ICollectionShareBackend) {
+ // Find reshares in children item types
+ foreach ($shareBackend->getChildrenItemTypes() as $childItemType) {
+ $childReshares = $this->getShares($childItemType, $filter);
+ $reshares = array_merge($reshares, $childReshares);
+ }
+ }
+ return $reshares;
+ }
+
+ /**
+ * Get all parents of a share
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\ShareDoesNotExistException
+ * @return \OC\Share\Share[]
+ *
+ * It is possible for the parents to be of a different item type if the shares's item type
+ * is a child item type in a collection
+ *
+ */
+ public function getParents(Share $share) {
+ $parents = array();
+ $parentIds = $share->getParentIds();
+ if (!empty($parentIds)) {
+ $itemType = $share->getItemType();
+ $parentItemTypes = array($itemType);
+ foreach ($this->getShareBackends() as $shareBackend) {
+ if ($shareBackend instanceof ICollectionShareBackend
+ && in_array($itemType, $shareBackend->getChildrenItemTypes())
+ && !in_array($shareBackend->getItemType(), $parentItemTypes)
+ ) {
+ $parentItemTypes[] = $shareBackend->getItemType();
+ }
+ }
+ foreach ($parentIds as $parentId) {
+ foreach ($parentItemTypes as $parentItemType) {
+ try {
+ $parents[] = $this->getShareById($parentId, $parentItemType);
+ break;
+ } catch (ShareDoesNotExistException $exception) {
+ if ($parentItemType === end($parentItemTypes)) {
+ throw $exception;
+ }
+ }
+ }
+ }
+ }
+ return $parents;
+ }
+
+ /**
+ * Search for reshares of a share
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share[]
+ *
+ * Call this to determine if the share has existing reshares because there is a duplicate share
+ *
+ * Use getReshares() for all other cases
+ *
+ */
+ protected function searchForReshares(Share $share) {
+ $reshares = array();
+ $id = $share->getId();
+ $filter = array(
+ 'shareOwner' => $share->getShareOwner(),
+ 'itemSource' => $share->getItemSource(),
+ );
+ $potentialDuplicates = $this->getShares($share->getItemType(), $filter);
+ foreach ($potentialDuplicates as $potentialDuplicate) {
+ if ($potentialDuplicate->getId() !== $id) {
+ $potentialReshares = $this->getReshares($potentialDuplicate);
+ foreach ($potentialReshares as $potentialReshare) {
+ $parents = $this->searchForParents($potentialReshare);
+ foreach ($parents as $parent) {
+ if ($parent->getId() === $id) {
+ $reshares[] = $potentialReshare;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return $reshares;
+ }
+
+ /**
+ * Search for parent shares of a share
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share[]
+ *
+ * Call this to determine if the share is a reshare and needs to set the parent ids property
+ *
+ * Use getParents() for all other cases
+ *
+ */
+ protected function searchForParents(Share $share) {
+ $itemType = $share->getItemType();
+ $filter = array(
+ 'shareWith' => $share->getShareOwner(),
+ 'isShareWithUser' => true,
+ 'itemSource' => $share->getItemSource(),
+ );
+ $parents = $this->getShares($itemType, $filter);
+ // Search in collections for parents in case children were reshared
+ foreach ($this->getShareBackends() as $shareBackend) {
+ if ($shareBackend instanceof ICollectionShareBackend
+ && in_array($itemType, $shareBackend->getChildrenItemTypes())
+ ) {
+ $collectionParents = $shareBackend->searchForParentCollections($share);
+ // Check if shares are expired, because this method call doesn't go through
+ // ShareManager's getShares method
+ foreach ($collectionParents as $share) {
+ if ($shareBackend->isExpired($share)) {
+ $this->unshare($share);
+ } else {
+ $parents[] = $share;
+ }
+ }
+ }
+ }
+ return $parents;
+ }
+
+ /**
+ * Get the total permissions of an array of shares
+ * @param \OC\Share\Share[] $shares
+ * @return int
+ */
+ protected function getTotalPermissions(array $shares) {
+ $totalPermissions = 0;
+ foreach ($shares as $share) {
+ $totalPermissions |= $share->getPermissions();
+ }
+ return $totalPermissions;
+ }
+
+ /**
+ * Get the latest expiration time of an array of shares
+ * @param \OC\Share\Share[] $shares
+ * @return int | null
+ */
+ protected function getLatestExpirationTime(array $shares) {
+ $latestTime = null;
+ foreach ($shares as $share) {
+ $time = $share->getExpirationTime();
+ if (!isset($time)) {
+ return null;
+ } else if (!isset($latestTime) || $time > $latestTime) {
+ $latestTime = $time;
+ }
+ }
+ return $latestTime;
+ }
+
+ /**
+ * Check if a share's permissions are valid with respect to the parent shares
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidPermissionsException
+ * @return bool
+ */
+ protected function areValidPermissionsForParents(Share $share) {
+ $parents = $this->getParents($share);
+ if (!empty($parents)) {
+ // Combine parent share's permissions to see if the share exceeds those permissions
+ $permissions = $share->getPermissions();
+ $parentPermissions = $this->getTotalPermissions($parents);
+ if ($permissions & ~$parentPermissions) {
+ throw new InvalidPermissionsException(
+ 'The permissions exceeds the parent shares\' permissions'
+ );
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check if a share's expiration time is valid with respect to the parent shares
+ * @param \OC\Share\Share $share
+ * @throws \OC\Share\Exception\InvalidExpirationTimeException
+ * @return bool
+ */
+ protected function isValidExpirationTimeForParents(Share $share) {
+ $parents = $this->getParents($share);
+ if (!empty($parents)) {
+ // Check if time is later than the latest parent share expiration time
+ $time = $share->getExpirationTime();
+ $latestParentTime = $this->getLatestExpirationTime($parents);
+ if (isset($latestParentTime) && (!isset($time) || $time > $latestParentTime)) {
+ throw new InvalidExpirationTimeException(
+ 'The expiration time exceeds the parent shares\' expiration times'
+ );
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Update the reshares of a share to ensure consistency of permissions and expiration time
+ * @param \OC\Share\Share $share
+ * @param \OC\Share\Share $oldShare
+ *
+ * The share has to be updated in the share backend before this is called
+ *
+ */
+ protected function updateReshares(Share $share, Share $oldShare) {
+ $id = $share->getId();
+ // Add this share to reshares' parent ids if share permission is added
+ if ($share->isSharable() && !$oldShare->isSharable()) {
+ $reshares = $this->searchForReshares($share);
+ foreach ($reshares as $reshare) {
+ $reshare->addParentId($id);
+ $this->update($reshare);
+ }
+ // There is no need to continue the update process if share permission was just added,
+ // because the reshares (if any) must have a different parent share that already
+ // dictated the possible permissions and expiration time
+ } else if ($oldShare->isSharable()) {
+ $reshares = $this->getReshares($share);
+ foreach ($reshares as $reshare) {
+ $parentIds = $reshare->getParentIds();
+ if (count($parentIds) === 1) {
+ if (!$share->isSharable()) {
+ // If the reshare has no other parents, it has to be unshared
+ $this->unshare($reshare);
+ continue;
+ }
+ $parents = array($share);
+ } else {
+ if (!$share->isSharable()) {
+ $reshare->removeParentId($id);
+ }
+ $parents = $this->getParents($reshare);
+ }
+ // Adjust permissions and expiration time as necessary for them to be valid
+ $parentPermissions = $this->getTotalPermissions($parents);
+ $latestParentTime = $this->getLatestExpirationTime($parents);
+ $resharePermissions = $reshare->getPermissions();
+ if (~$parentPermissions & $resharePermissions) {
+ $resharePermissions &= $parentPermissions;
+ $reshare->setPermissions($resharePermissions);
+ }
+ $reshareTime = $reshare->getExpirationTime();
+ if (isset($latestParentTime)
+ && (!isset($reshareTime) || $latestParentTime < $reshareTime)
+ ) {
+ $reshare->setExpirationTime($latestParentTime);
+ }
+ $properties = $reshare->getUpdatedProperties();
+ if (!empty($properties)) {
+ $this->update($reshare);
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/common.php b/lib/share/sharetype/common.php
new file mode 100644
index 000000000000..8e19f788c99a
--- /dev/null
+++ b/lib/share/sharetype/common.php
@@ -0,0 +1,199 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+use OC\Share\AdvancedShareFactory;
+
+abstract class Common implements IShareType {
+
+ protected $itemType;
+ protected $shareFactory;
+ protected $table;
+ protected $parentTable;
+
+ /**
+ * The constructor
+ * @param string $itemType
+ * @param ShareFactory $shareFactory
+ */
+ public function __construct($itemType, ShareFactory $shareFactory) {
+ $this->itemType = $itemType;
+ $this->shareFactory = $shareFactory;
+ $this->table = '`*PREFIX*shares`';
+ $this->parentsTable = '`*PREFIX*shares_parents`';
+ }
+
+ public function share(Share $share) {
+ $properties = array(
+ 'shareTypeId',
+ 'shareOwner',
+ 'shareWith',
+ 'itemType',
+ 'itemSource',
+ 'itemTarget',
+ 'itemOwner',
+ 'permissions',
+ 'expirationTime',
+ 'shareTime',
+ );
+ $columms = array();
+ $params = array();
+ // Retrieve share's properties to store in the database
+ foreach ($properties as $property) {
+ $columns[] = Share::propertyToColumn($property);
+ $getter = 'get'.ucfirst($property);
+ $params[] = $share->$getter();
+ }
+ $placeholders = join(',', array_fill(0, count($columns), '?'));
+ $columns = join(',', $columns);
+ $sql = 'INSERT INTO '.$this->table.' ('.$columns.') VALUES ('.$placeholders.')';
+ $result = \OC_DB::executeAudited($sql, $params);
+ $id = (int)\OC_DB::insertid();
+ $share->setId($id);
+ $share->resetUpdatedProperties();
+ $this->setParentIds($share);
+ return $share;
+ }
+
+ public function unshare(Share $share) {
+ $sql = 'DELETE FROM '.$this->table.' WHERE `id` = ?';
+ $params = array($share->getId());
+ \OC_DB::executeAudited($sql, $params);
+ $sql = 'DELETE FROM '.$this->parentsTable.' WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, $params);
+ }
+
+ public function update(Share $share) {
+ $columns = '';
+ $params = array();
+ $properties = $share->getUpdatedProperties();
+ foreach ($properties as $property => $updated) {
+ $columns .= Share::propertyToColumn($property).' = ?, ';
+ $getter = 'get'.ucfirst($property);
+ $params[] = $share->$getter();
+ }
+ $columns = rtrim($columns, ', ');
+ $params[] = $share->getId();
+ $sql = 'UPDATE '.$this->table.' SET '.$columns.' WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, $params);
+ }
+
+ /**
+ * Update the share's parent references in the database
+ * @param Share $share
+ */
+ public function setParentIds(Share $share) {
+ $id = $share->getId();
+ $parentIds = $share->getParentIds();
+ $cachedParentIds = $this->getParentIds($id);
+ // Compare current parent ids with those in the database
+ // to determine which need to be added and removed
+ $newParentIds = array_diff($parentIds, $cachedParentIds);
+ $oldParentIds = array_diff($cachedParentIds, $parentIds);
+ if (!empty($newParentIds)) {
+ $sql = 'INSERT INTO '.$this->parentsTable.' (`id`, `parent_id`) VALUES (?, ?)';
+ foreach ($newParentIds as $parentId) {
+ \OC_DB::executeAudited($sql, array($id, $parentId));
+ }
+ }
+ if (!empty($oldParentIds)) {
+ $sql = 'DELETE FROM '.$this->parentsTable.' WHERE `id` = ? AND `parent_id` = ?';
+ foreach ($oldParentIds as $parentId) {
+ \OC_DB::executeAudited($sql, array($id, $parentId));
+ }
+ }
+ }
+
+ public function getShares(array $filter, $limit, $offset) {
+ $defaults = array(
+ 'shareTypeId' => $this->getId(),
+ 'itemType' => $this->itemType,
+ );
+ unset($filter['isShareWithUser']);
+ $filter = array_merge($defaults, $filter);
+ $where = '';
+ $params = array();
+ // Build the WHERE clause
+ foreach ($filter as $property => $value) {
+ $column = Share::propertyToColumn($property);
+ if ($property === 'id') {
+ $column = $this->table.'.'.$column;
+ } else if ($property === 'parentId') {
+ $column = $this->parentsTable.'.'.$column;
+ }
+ $where .= $column.' = ? AND ';
+ $params[] = $value;
+ }
+ $where = rtrim($where, ' AND ');
+ $columns = $this->table.'.*';
+ $joins = '';
+ if (isset($filter['parentId'])) {
+ // LEFT JOIN with the parents table
+ $joins .= 'LEFT JOIN '.$this->parentsTable.' ON '.
+ $this->table.'.`id` = '.$this->parentsTable.'.`id`';
+ }
+ if ($this->shareFactory instanceof AdvancedShareFactory) {
+ // Add the JOINs for the app
+ $joins .= ' '.$this->shareFactory->getJoins();
+ $columns .= ', '.$this->shareFactory->getColumns();
+ }
+ $sql = 'SELECT '.$columns.' FROM '.$this->table.' '.$joins.' WHERE '.$where;
+ $query = \OC_DB::prepare($sql, $limit, $offset);
+ $result = \OC_DB::executeAudited($query, $params);
+ $shares = array();
+ while ($row = $result->fetchRow()) {
+ $share = $this->shareFactory->mapToShare($row);
+ // TODO Come up with an alternative so we don't have to do an additional query
+ $parentIds = $this->getParentIds($share->getId());
+ $share->setParentIds($parentIds);
+ $share->resetUpdatedProperties();
+ $shares[] = $share;
+ }
+ return $shares;
+ }
+
+ public function clear() {
+ $sql = 'DELETE FROM '.$this->table.' WHERE `share_type_id` = ?';
+ \OC_DB::executeAudited($sql, array($this->getId()));
+ $sql = 'DELETE FROM '.$this->parentsTable.' WHERE '.$this->parentsTable.'.`id` NOT IN '.
+ ' (SELECT `id` FROM '.$this->table.')';
+ \OC_DB::executeAudited($sql);
+ }
+
+ /**
+ * Get the parent ids for a share based on id
+ * @param int $id
+ * @return array
+ */
+ protected function getParentIds($id) {
+ $sql = 'SELECT `parent_id` FROM '.$this->parentsTable.' WHERE `id` = ?';
+ $result = \OC_DB::executeAudited($sql, array($id));
+ $parentIds = array();
+ while ($row = $result->fetchRow()) {
+ $parentIds[] = $row['parent_id'];
+ }
+ return $parentIds;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php
new file mode 100644
index 000000000000..d23f8b9eee60
--- /dev/null
+++ b/lib/share/sharetype/group.php
@@ -0,0 +1,319 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+use OC\Share\AdvancedShareFactory;
+use OC\Share\ItemTargetMachine;
+use OC\Share\Exception\InvalidShareException;
+use OC\Group\Manager as GroupManager;
+use OC\User\Manager as UserManager;
+
+/**
+ * Controller for shares between a user and a group
+ */
+class Group extends Common {
+
+ protected $itemTargetMachine;
+ protected $groupManager;
+ protected $userManager;
+ protected $groupTable;
+
+ /**
+ * The constructor
+ * @param string $itemType
+ * @param \OC\Share\ShareFactory $shareFactory
+ * @param \OC\Share\ItemTargetMachine $itemTargetMachine
+ * @param \OC\Group\Manager $groupManager
+ * @param \OC\User\Manager $userManager
+ */
+ public function __construct($itemType, ShareFactory $shareFactory,
+ ItemTargetMachine $itemTargetMachine, GroupManager $groupManager, UserManager $userManager
+ ) {
+ parent::__construct($itemType, $shareFactory);
+ $this->itemTargetMachine = $itemTargetMachine;
+ $this->groupManager = $groupManager;
+ $this->userManager = $userManager;
+ $this->groupsTable = '`*PREFIX*shares_groups`';
+ }
+
+ public function getId() {
+ return 'group';
+ }
+
+ public function isValidShare(Share $share) {
+ $shareOwner = $share->getShareOwner();
+ $shareWith = $share->getShareWith();
+ if (!$this->userManager->userExists($shareOwner)) {
+ throw new InvalidShareException('The share owner does not exist');
+ }
+ if (!$this->groupManager->groupExists($shareWith)) {
+ throw new InvalidShareException('The group shared with does not exist');
+ }
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ if ($sharingPolicy === 'groups_only') {
+ $group = $this->groupManager->get($shareWith);
+ $shareOwnerUser = $this->userManager->get($shareOwner);
+ if (!$group->inGroup($shareOwnerUser)) {
+ throw new InvalidShareException(
+ 'The share owner is not in the group shared with as required by '.
+ 'the groups only sharing policy set by the admin'
+ );
+ }
+ }
+ return true;
+ }
+
+ public function share(Share $share) {
+ $groupItemTarget = $this->itemTargetMachine->getItemTarget($share);
+ $share->setItemTarget($groupItemTarget);
+ $share = parent::share($share);
+ if ($share) {
+ $shareOwner = $share->getShareOwner();
+ $userItemTargets = array();
+ $group = $this->groupManager->get($share->getShareWith());
+ foreach ($group->getUsers() as $user) {
+ $uid = $user->getUID();
+ if ($uid !== $shareOwner) {
+ $userItemTarget = $this->itemTargetMachine->getItemTarget($share, $user);
+ if ($userItemTarget !== $groupItemTarget) {
+ $userItemTargets[$uid] = $userItemTarget;
+ }
+ }
+ }
+ $itemTargets = array($share->getItemTarget());
+ $itemTargets['users'] = $userItemTargets;
+ $share->setItemTarget($itemTargets);
+ if (!empty($userItemTargets)) {
+ $this->setItemTarget($share);
+ }
+ $share = $this->setShareDisplayNames($share);
+ }
+ return $share;
+ }
+
+ /**
+ * Update the share's item targets in the database
+ * @param \OC\Share\Share $share
+ *
+ * Group shares can have different item targets for users in the group
+ * and are stored in a separate table
+ *
+ */
+ public function setItemTarget(Share $share) {
+ $id = $share->getId();
+ $itemTargets = $share->getItemTarget();
+ if (is_array($itemTargets)) {
+ $groupItemTarget = reset($itemTargets);
+ } else {
+ $groupItemTarget = $itemTargets;
+ }
+ if (isset($itemTargets['users'])) {
+ $userItemTargets = $itemTargets['users'];
+ } else {
+ $userItemTargets = array();
+ }
+ $sql = 'UPDATE '.$this->table.' SET `item_target` = ? WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, array($groupItemTarget, $id));
+ $cachedItemTargets = $this->getUserItemTargets($id);
+ // Compare current item targets with those in the database
+ // to determine which need to be added and removed
+ $newItemTargets = array_diff_assoc($userItemTargets, $cachedItemTargets);
+ $oldItemTargets = array_diff_assoc($cachedItemTargets, $userItemTargets);
+ if (!empty($newItemTargets)) {
+ $sql = 'INSERT INTO '.$this->groupsTable.' (`id`, `uid`, `item_target`)
+ VALUES (?, ?, ?)';
+ foreach ($newItemTargets as $uid => $itemTarget) {
+ \OC_DB::executeAudited($sql, array($id, $uid, $itemTarget));
+ }
+ }
+ if (!empty($oldItemTargets)) {
+ $sql = 'DELETE FROM '.$this->groupsTable.' WHERE `id` = ? AND `uid` = ? AND '.
+ '`item_target` = ?';
+ foreach ($oldItemTargets as $uid => $itemTarget) {
+ \OC_DB::executeAudited($sql, array($id, $uid, $itemTarget));
+ }
+ }
+ }
+
+ public function getShares(array $filter, $limit, $offset) {
+ $shares = array();
+ $isShareWithUser = false;
+ // The isShareWithUser parameter allows the shareWith parameter to be a user rather than
+ // a group in the filter
+ if (!isset($filter['isShareWithUser']) || $filter['isShareWithUser'] === false) {
+ unset($filter['isShareWithUser']);
+ $shares = parent::getShares($filter, $limit, $offset);
+ } else {
+ unset($filter['isShareWithUser']);
+ $isShareWithUser = true;
+ $defaults = array(
+ 'shareTypeId' => $this->getId(),
+ 'itemType' => $this->itemType,
+ );
+ $filter = array_merge($defaults, $filter);
+ $where = '';
+ $params = array();
+ // Build the WHERE clause
+ foreach ($filter as $property => $value) {
+ $column = Share::propertyToColumn($property);
+ if ($property === 'shareWith') {
+ $groups = array();
+ $shareWithUser = $this->userManager->get($value);
+ if ($shareWithUser) {
+ $groups = $this->groupManager->getUserGroups($shareWithUser);
+ }
+ if (empty($groups)) {
+ // The user has no groups, no group shares are possible
+ return array();
+ } else {
+ // Find shares with the user's groups, but exclude the shares they own
+ foreach ($groups as $group) {
+ $params[] = $group->getGID();
+ }
+ $placeholders = join(',', array_fill(0, count($groups), '?'));
+ $where .= $column.' IN ('.$placeholders.') AND `share_owner` != ? AND ';
+ $params[] = $value;
+ }
+ } else {
+ if ($property === 'id') {
+ $column = $this->table.'.'.$column;
+ } else if ($property === 'parentId') {
+ $column = $this->parentsTable.'.'.$column;
+ }
+ $where .= $column.' = ? AND ';
+ $params[] = $value;
+ }
+ }
+ $where = rtrim($where, ' AND ');
+ $columns = $this->table.'.*';
+ $joins = '';
+ if (isset($filter['parentId'])) {
+ // LEFT JOIN with the parents table
+ $joins .= 'LEFT JOIN '.$this->parentsTable.' ON '.
+ $this->table.'.`id` = '.$this->parentsTable.'.`id`';
+ }
+ if ($this->shareFactory instanceof AdvancedShareFactory) {
+ // Add the JOINs for the app
+ $joins .= $this->shareFactory->getJoins();
+ $columns .= ', '.$this->shareFactory->getColumns();
+ }
+ $sql = 'SELECT '.$columns.' FROM '.$this->table.' '.$joins.' WHERE '.$where;
+ $query = \OC_DB::prepare($sql, $limit, $offset);
+ $result = \OC_DB::executeAudited($query, $params);
+ while ($row = $result->fetchRow()) {
+ $share = $this->shareFactory->mapToShare($row);
+ $parentIds = $this->getParentIds($share->getId());
+ $share->setParentIds($parentIds);
+ $share->resetUpdatedProperties();
+ $shares[] = $share;
+ }
+ }
+ foreach ($shares as &$share) {
+ $userItemTargets = $this->getUserItemTargets($share->getId());
+ if (!empty($userItemTargets)) {
+ if ($isShareWithUser && isset($userItemTargets[$filter['shareWith']])) {
+ $share->setItemTarget($userItemTargets[$filter['shareWith']]);
+ } else {
+ $itemTargets = array($share->getItemTarget());
+ $itemTargets['users'] = $userItemTargets;
+ $share->setItemTarget($itemTargets);
+ }
+ }
+ $share = $this->setShareDisplayNames($share);
+ }
+ return $shares;
+ }
+
+ public function clear() {
+ parent::clear();
+ $sql = 'DELETE FROM '.$this->groupsTable.' WHERE '.$this->groupsTable.'.`id` NOT IN '.
+ ' (SELECT `id` FROM '.$this->table.')';
+ \OC_DB::executeAudited($sql);
+ }
+
+ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset) {
+ $shareWiths = array();
+ $groups = array();
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ if ($sharingPolicy === 'groups_only') {
+ $shareOwnerUser = $this->userManager->get($shareOwner);
+ if ($shareOwnerUser) {
+ $groups = $this->groupManager->search($pattern);
+ $userGroups = $this->groupManager->getUserGroups($shareOwnerUser);
+ $groups = array_uintersect($groups, $userGroups, function($group1, $group2) {
+ return strcmp($group1->getGID(), $group2->getGID());
+ });
+ $groups = array_slice($groups, $offset, $limit);
+ }
+ } else {
+ $groups = $this->groupManager->search($pattern, $limit, $offset);
+ }
+ foreach ($groups as $group) {
+ $shareWiths[] = array(
+ 'shareWith' => $group->getGID(),
+ 'shareWithDisplayName' => $group->getGID().' (group)',
+ );
+ }
+ return $shareWiths;
+ }
+
+ /**
+ * Get the item target machine
+ * @return \OC\Share\ItemTargetMachine
+ */
+ public function getItemTargetMachine() {
+ return $this->itemTargetMachine;
+ }
+
+ /**
+ * Get the unique item targets for the users of a group share specified by the id
+ * @param int $id
+ * @return array
+ */
+ protected function getUserItemTargets($id) {
+ $sql = 'SELECT `uid`, `item_target` FROM '.$this->groupsTable.' WHERE `id` = ?';
+ $result = \OC_DB::executeAudited($sql, array($id));
+ $itemTargets = array();
+ while ($row = $result->fetchRow()) {
+ $itemTargets[$row['uid']] = $row['item_target'];
+ }
+ return $itemTargets;
+ }
+
+ /**
+ * Set the display names for the share owner and share with
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share
+ */
+ protected function setShareDisplayNames(Share $share) {
+ $shareOwnerUser = $this->userManager->get($share->getShareOwner());
+ if ($shareOwnerUser) {
+ $share->setShareOwnerDisplayName($shareOwnerUser->getDisplayName());
+ }
+ $share->setShareWithDisplayName($share->getShareWith(). ' (group)');
+ $share->resetUpdatedProperties();
+ return $share;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/groupwatcher.php b/lib/share/sharetype/groupwatcher.php
new file mode 100644
index 000000000000..d6f24f2bdd14
--- /dev/null
+++ b/lib/share/sharetype/groupwatcher.php
@@ -0,0 +1,163 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+use OC\Share\ShareManager;
+use OC\Share\Exception\InvalidShareException;
+use OC\Share\Exception\ShareTypeDoesNotExistException;
+use OC\Group\Manager;
+
+/**
+ * Listen to group events that require updating shares
+ */
+class GroupWatcher {
+
+ private $shareManager;
+
+ public function __construct(ShareManager $shareManager, Manager $groupManager) {
+ $this->shareManager = $shareManager;
+ $groupManager->listen('\OC\Group', 'postDelete', array($this, 'onGroupDeleted'));
+ $groupManager->listen('\OC\Group', 'postAddUser', array($this, 'onUserAddedToGroup'));
+ $groupManager->listen('\OC\Group', 'postRemoveUser',
+ array($this, 'onUserRemovedFromGroup')
+ );
+ }
+
+ /**
+ * Unshare all shares to the deleted group
+ * @param \OC\Group\Group $group
+ */
+ public function onGroupDeleted(\OC\Group\Group $group) {
+ $shares = $this->getGroupShares($group);
+ foreach ($shares as $share) {
+ $this->shareManager->unshare($share);
+ }
+ foreach ($group->getUsers() as $user) {
+ $this->revalidateShares($user);
+ }
+ }
+
+ /**
+ * Check if the added user requires unique item targets for the group shares
+ * @param \OC\Group\Group $group
+ * @param \OC\User\User $user
+ */
+ public function onUserAddedToGroup(\OC\Group\Group $group, \OC\User\User $user) {
+ $shares = $this->getGroupShares($group);
+ foreach ($shares as $share) {
+ $shareBackend = $this->shareManager->getShareBackend($share->getItemType());
+ $shareType = $shareBackend->getShareType($share->getShareTypeId());
+ $itemTargetMachine = $shareType->getItemTargetMachine();
+ $itemTargets = $share->getItemTarget();
+ $groupItemTarget = reset($itemTargets);
+ $userItemTarget = $itemTargetMachine->getItemTarget($share, $user);
+ if ($userItemTarget !== $groupItemTarget) {
+ $itemTargets['users'][$user->getUID()] = $userItemTarget;
+ $share->setItemTarget($itemTargets);
+ $this->shareManager->update($share);
+ }
+ }
+ }
+
+ /**
+ * Unshare all reshares of the group share that were reshared by the removed user
+ * @param \OC\Group\Group $group
+ * @param \OC\User\User $user
+ */
+ public function onUserRemovedFromGroup(\OC\Group\Group $group, \OC\User\User $user) {
+ $uid = $user->getUID();
+ $shares = $this->getGroupShares($group);
+ foreach ($shares as $share) {
+ $reshares = $this->shareManager->getReshares($share);
+ foreach ($reshares as $reshare) {
+ if ($reshare->getShareOwner() === $uid) {
+ $this->shareManager->unshare($reshare);
+ }
+ }
+ $itemTargets = $share->getItemTarget();
+ // Remove unique item target if set for removed user
+ if (isset($itemTargets['user'][$uid])) {
+ unset($itemTargets['user'][$uid]);
+ $share->setItemTarget($itemTargets);
+ $this->shareManager->update($share);
+ }
+ }
+ $this->revalidateShares($user);
+ }
+
+ /**
+ * Get all group shares
+ * @param \OC\Group\Group $group
+ * @return \OC\Share\Share[]
+ */
+ protected function getGroupShares(\OC\Group\Group $group) {
+ $gid = $group->getGID();
+ $shares = array();
+ $filter = array(
+ 'shareTypeId' => 'group',
+ 'shareWith' => $gid,
+ );
+ $shareBackends = $this->shareManager->getShareBackends();
+ foreach ($shareBackends as $shareBackend) {
+ try {
+ $itemType = $shareBackend->getItemType();
+ $shares = array_merge($shares, $this->shareManager->getShares($itemType, $filter));
+ } catch (ShareTypeDoesNotExistException $exception) {
+ // Do nothing
+ }
+ }
+ return $shares;
+ }
+
+ /**
+ * Revalidate the sharing conditions for a user's shares if the groups only policy is set
+ * @param \OC\User\User $user
+ */
+ protected function revalidateShares(\OC\User\User $user) {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ if ($sharingPolicy === 'groups_only') {
+ $uid = $user->getUID();
+ $filter = array(
+ 'shareTypeId' => 'user',
+ 'shareOwner' => $uid,
+ );
+ $shareBackends = $this->shareManager->getShareBackends();
+ foreach ($shareBackends as $shareBackend) {
+ try {
+ $shareType = $shareBackend->getShareType('user');
+ $itemType = $shareBackend->getItemType();
+ $shares = $this->shareManager->getShares($itemType, $filter);
+ foreach ($shares as $share) {
+ try {
+ $shareType->isValidShare($share);
+ } catch (InvalidShareException $exception) {
+ $this->shareManager->unshare($share);
+ }
+ }
+ } catch (ShareTypeDoesNotExistException $exception) {
+ // Do nothing
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/isharetype.php b/lib/share/sharetype/isharetype.php
new file mode 100644
index 000000000000..c2d660870725
--- /dev/null
+++ b/lib/share/sharetype/isharetype.php
@@ -0,0 +1,88 @@
+.
+*/
+
+namespace OC\Share\ShareType;
+
+use OC\Share\Share;
+
+/**
+ * Interface for a controller of shares
+ */
+interface IShareType {
+
+ /**
+ * Get the identifier for this share type
+ * @return string id
+ */
+ public function getId();
+
+ /**
+ * Check if this share is valid for this share type
+ * @param \OC\Share\Share $share
+ * @return bool
+ * @throws \OC\Share\Exception\InvalidShareException
+ */
+ public function isValidShare(Share $share);
+
+ /**
+ * Insert the share into the database
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share
+ */
+ public function share(Share $share);
+
+ /**
+ * Remove the share from the database
+ * @param \OC\Share\Share $share
+ */
+ public function unshare(Share $share);
+
+ /**
+ * Update the share's properties in the database
+ * @param \OC\Share\Share $share
+ */
+ public function update(Share $share);
+
+ /**
+ * Get the shares with the specified parameters for this share type
+ * @param array $filter A key => value array of share properties
+ * @param int $limit
+ * @param int $offset
+ * @return \OC\Share\Share[]
+ */
+ public function getShares(array $filter, $limit, $offset);
+
+ /**
+ * Remove all shares of this share type in the database
+ */
+ public function clear();
+
+ /**
+ * Search for potential people of this share type to share with based on the given pattern
+ * @param string $shareOwner
+ * @param string $pattern
+ * @param int $limit
+ * @param int $offset
+ * @return array
+ */
+ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset);
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php
new file mode 100644
index 000000000000..feaf67649331
--- /dev/null
+++ b/lib/share/sharetype/link.php
@@ -0,0 +1,209 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+use OC\Share\AdvancedShareFactory;
+use OC\Share\ItemTargetMachine;
+use OC\Share\Exception\InvalidShareException;
+use OC\User\Manager;
+use PasswordHash;
+
+/**
+ * Controller for shares between a user and the public via a link
+ */
+class Link extends Common {
+
+ protected $itemTargetMachine;
+ protected $userManager;
+ protected $tokenMachine;
+ protected $hasher;
+ protected $linkTable;
+
+ const TOKEN_LENGTH = 32;
+
+ /**
+ * The constructor
+ * @param string $itemType
+ * @param \OC\Share\ShareFactory $shareFactory
+ * @param \OC\Share\ItemTargetMachine $itemTargetMachine
+ * @param \OC\User\Manager $userManager
+ * @param \OC\Share\ShareType\TokenMachine $tokenMachine
+ * @param \PasswordHash $hasher
+ */
+ public function __construct($itemType, ShareFactory $shareFactory,
+ ItemTargetMachine $itemTargetMachine, Manager $userManager, TokenMachine $tokenMachine,
+ PasswordHash $hasher
+ ) {
+ parent::__construct($itemType, $shareFactory);
+ $this->itemTargetMachine = $itemTargetMachine;
+ $this->userManager = $userManager;
+ $this->tokenMachine = $tokenMachine;
+ $this->hasher = $hasher;
+ $this->linksTable = '`*PREFIX*shares_links`';
+ }
+
+ public function getId() {
+ return 'link';
+ }
+
+ public function isValidShare(Share $share) {
+ $shareOwner = $share->getShareOwner();
+ if (!$this->userManager->userExists($shareOwner)) {
+ throw new InvalidShareException('The share owner does not exist');
+ }
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes');
+ if ($sharingPolicy !== 'yes') {
+ throw new InvalidShareException('The admin has disabled sharing via links');
+ }
+ return true;
+ }
+
+ public function share(Share $share) {
+ $share->setItemTarget($this->itemTargetMachine->getItemTarget($share));
+ $share = parent::share($share);
+ if ($share) {
+ $token = $this->tokenMachine->getToken(self::TOKEN_LENGTH);
+ $password = $this->hashPassword($share->getPassword());
+ $sql = 'INSERT INTO '.$this->linksTable.' (`id`, `token`, `password`)'.
+ 'VALUES (?, ?, ?)';
+ \OC_DB::executeAudited($sql, array($share->getId(), $token, $password));
+ $share->setToken($token);
+ $share->setPassword($password);
+ $share = $this->setShareDisplayName($share);
+ }
+ return $share;
+ }
+
+ public function unshare(Share $share) {
+ parent::unshare($share);
+ $sql = 'DELETE FROM '.$this->linksTable.' WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, array($share->getId()));
+ }
+
+ /**
+ * Update the share's password for the link in the database
+ * @param \OC\Share\Share $share
+ */
+ public function setPassword(Share $share) {
+ $password = $this->hashPassword($share->getPassword());
+ $sql = 'UPDATE '.$this->linksTable.' SET `password` = ? WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, array($password, $share->getId()));
+ }
+
+ public function getShares(array $filter, $limit, $offset) {
+ if (isset($filter['shareWith'])) {
+ // Links are not associated with a person
+ return array();
+ } else {
+ $defaults = array(
+ 'shareTypeId' => $this->getId(),
+ 'itemType' => $this->itemType,
+ );
+ $filter = array_merge($defaults, $filter);
+ $where = '';
+ $params = array();
+ // Build the WHERE clause
+ foreach ($filter as $property => $value) {
+ $column = Share::propertyToColumn($property);
+ if ($property === 'id') {
+ $column = $this->table.'.'.$column;
+ } else if ($property === 'parentId') {
+ $column = $this->parentsTable.'.'.$column;
+ } else if ($property === 'token' || $property === 'password') {
+ $column = $this->linksTable.'.'.$column;
+ }
+ $where .= $column.' = ? AND ';
+ $params[] = $value;
+ }
+ $where = rtrim($where, ' AND ');
+ $columns = $this->table.'.*';
+ // JOIN with the links table
+ $joins = 'JOIN '.$this->linksTable.' ON '.
+ $this->table.'.`id` = '.$this->linksTable.'.`id`';
+ $columns .= ', '.$this->linksTable.'.*';
+ if (isset($filter['parentId'])) {
+ // LEFT JOIN with the parents table
+ $joins .= ' LEFT JOIN '.$this->parentsTable.' ON '.
+ $this->table.'.`id` = '.$this->parentsTable.'.`id`';
+ }
+ if ($this->shareFactory instanceof AdvancedShareFactory) {
+ // Add the JOINs for the app
+ $joins .= ' '.$this->shareFactory->getJoins();
+ $columns .= ', '.$this->shareFactory->getColumns();
+ }
+ $sql = 'SELECT '.$columns.' FROM '.$this->table.' '.$joins.' WHERE '.$where;
+ $query = \OC_DB::prepare($sql, $limit, $offset);
+ $result = \OC_DB::executeAudited($query, $params);
+ $shares = array();
+ while ($row = $result->fetchRow()) {
+ $share = $this->shareFactory->mapToShare($row);
+ $parentIds = $this->getParentIds($share->getId());
+ $share->setParentIds($parentIds);
+ $share = $this->setShareDisplayName($share);
+ $shares[] = $share;
+ }
+ return $shares;
+ }
+ }
+
+ public function clear() {
+ parent::clear();
+ $sql = 'DELETE FROM '.$this->linksTable.' WHERE '.$this->linksTable.'.`id` NOT IN '.
+ ' (SELECT `id` FROM '.$this->table.')';
+ \OC_DB::executeAudited($sql);
+ }
+
+ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset) {
+ // Links are not associated with a person
+ return array();
+ }
+
+ /**
+ * Hash the link password to store in the database
+ * @param string|null $password
+ * @return string|null
+ */
+ protected function hashPassword($password) {
+ if (isset($password)) {
+ $salt = \OC_Config::getValue('passwordsalt', '');
+ $password = $this->hasher->HashPassword($password.$salt);
+ }
+ return $password;
+ }
+
+ /**
+ * Set the display name for the share owner
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share
+ */
+ protected function setShareDisplayName(Share $share) {
+ $shareOwnerUser = $this->userManager->get($share->getShareOwner());
+ if ($shareOwnerUser) {
+ $share->setShareOwnerDisplayName($shareOwnerUser->getDisplayName());
+ }
+ $share->resetUpdatedProperties();
+ return $share;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/tokenmachine.php b/lib/share/sharetype/tokenmachine.php
new file mode 100644
index 000000000000..2442c1575d40
--- /dev/null
+++ b/lib/share/sharetype/tokenmachine.php
@@ -0,0 +1,33 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+/**
+ * Temporary class - waiting for an injectable Util
+ */
+class TokenMachine {
+
+ public function getToken($length) {
+ return \OC_Util::generate_random_bytes($length);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/user.php b/lib/share/sharetype/user.php
new file mode 100644
index 000000000000..304d1d27b830
--- /dev/null
+++ b/lib/share/sharetype/user.php
@@ -0,0 +1,167 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+use OC\Share\ItemTargetMachine;
+use OC\Share\Exception\InvalidShareException;
+use OC\User\Manager as UserManager;
+use OC\Group\Manager as GroupManager;
+
+/**
+ * Controller for shares between two users
+ */
+class User extends Common {
+
+ protected $itemTargetMachine;
+ protected $userManager;
+ protected $groupManager;
+
+ /**
+ * The constructor
+ * @param string $itemType
+ * @param \OC\Share\ShareFactory $shareFactory
+ * @param \OC\Share\ItemTargetMachine $itemTargetMachine
+ * @param \OC\User\Manager $userManager
+ * @param \OC\Group\Manager $groupManager
+ */
+ public function __construct($itemType, ShareFactory $shareFactory,
+ ItemTargetMachine $itemTargetMachine, UserManager $userManager, GroupManager $groupManager
+ ) {
+ parent::__construct($itemType, $shareFactory);
+ $this->itemTargetMachine = $itemTargetMachine;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ }
+
+ public function getId() {
+ return 'user';
+ }
+
+ public function isValidShare(Share $share) {
+ $shareOwner = $share->getShareOwner();
+ $shareWith = $share->getShareWith();
+ if ($shareOwner === $shareWith) {
+ throw new InvalidShareException('The share owner is the user shared with');
+ }
+ if (!$this->userManager->userExists($shareOwner)) {
+ throw new InvalidShareException('The share owner does not exist');
+ }
+ if (!$this->userManager->userExists($shareWith)) {
+ throw new InvalidShareException('The user shared with does not exist');
+ }
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ if ($sharingPolicy === 'groups_only') {
+ $shareOwnerUser = $this->userManager->get($shareOwner);
+ $shareWithUser = $this->userManager->get($shareWith);
+ $groups = $this->groupManager->getUserGroups($shareOwnerUser);
+ foreach ($groups as $group) {
+ if ($group->inGroup($shareWithUser)) {
+ return true;
+ }
+ }
+ throw new InvalidShareException(
+ 'The share owner is not in any groups of the user shared with as required by '.
+ 'the groups only sharing policy set by the admin'
+ );
+ }
+ return true;
+ }
+
+ public function share(Share $share) {
+ $user = $this->userManager->get($share->getShareWith());
+ $share->setItemTarget($this->itemTargetMachine->getItemTarget($share, $user));
+ $share = parent::share($share);
+ if ($share) {
+ $share = $this->setShareDisplayNames($share);
+ }
+ return $share;
+ }
+
+ public function getShares(array $filter, $limit, $offset) {
+ $shares = parent::getShares($filter, $limit, $offset);
+ foreach ($shares as &$share) {
+ $share = $this->setShareDisplayNames($share);
+ }
+ return $shares;
+ }
+
+ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset) {
+ $shareWiths = array();
+ $users = array();
+ $fakeLimit = $limit;
+ if (isset($fakeLimit)) {
+ // Just in case the share owner shows up in the list of users
+ $fakeLimit++;
+ if (isset($offset)) {
+ // Using the offset in the user manager and group calls may cause unexpected
+ // returns because this function filters the users. The limit and offset are
+ // applied manually after all possible users are retrieved and filtered
+ $fakeLimit += $offset;
+ }
+ }
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ if ($sharingPolicy === 'groups_only') {
+ $shareOwnerUser = $this->userManager->get($shareOwner);
+ if ($shareOwnerUser) {
+ $groups = $this->groupManager->getUserGroups($shareOwnerUser);
+ foreach ($groups as $group) {
+ $result = $group->searchDisplayName($pattern, $fakeLimit, null);
+ $users = array_merge($users, $result);
+ }
+ }
+ } else {
+ $users = $this->userManager->searchDisplayName($pattern, $fakeLimit, null);
+ }
+ foreach ($users as $user) {
+ $uid = $user->getUID();
+ if ($uid !== $shareOwner && !isset($shareWiths[$uid])) {
+ $shareWiths[$uid] = array(
+ 'shareWith' => $uid,
+ 'shareWithDisplayName' => $user->getDisplayName(),
+ );
+ }
+ }
+ $shareWiths = array_slice($shareWiths, $offset, $limit);
+ return array_values($shareWiths);
+ }
+
+ /**
+ * Set the display names for the share owner and share with
+ * @param \OC\Share\Share $share
+ * @return \OC\Share\Share
+ */
+ protected function setShareDisplayNames(Share $share) {
+ $shareOwnerUser = $this->userManager->get($share->getShareOwner());
+ if ($shareOwnerUser) {
+ $share->setShareOwnerDisplayName($shareOwnerUser->getDisplayName());
+ }
+ $shareWithUser = $this->userManager->get($share->getShareWith());
+ if ($shareWithUser) {
+ $share->setShareWithDisplayName($shareWithUser->getDisplayName());
+ }
+ $share->resetUpdatedProperties();
+ return $share;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/sharetype/userwatcher.php b/lib/share/sharetype/userwatcher.php
new file mode 100644
index 000000000000..0ef9bc255082
--- /dev/null
+++ b/lib/share/sharetype/userwatcher.php
@@ -0,0 +1,71 @@
+.
+ */
+
+namespace OC\Share\ShareType;
+
+use OC\Share\ShareManager;
+use OC\Share\Exception\ShareTypeDoesNotExistException;
+use OC\User\Manager;
+
+/**
+ * Listen to user events that require updating shares
+ */
+class UserWatcher {
+
+ private $shareManager;
+
+ public function __construct(ShareManager $shareManager, Manager $userManager) {
+ $this->shareManager = $shareManager;
+ $userManager->listen('\OC\User', 'postDelete', array($this, 'onUserDeleted'));
+ }
+
+ /**
+ * Unshare all shares to and owned by the deleted user
+ * @param \OC\User\User $user
+ */
+ public function onUserDeleted(\OC\User\User $user) {
+ $uid = $user->getUID();
+ $shares = array();
+ $filterShareOwner = array(
+ 'shareOwner' => $uid,
+ );
+ $filterShareWith = array(
+ 'shareTypeId' => 'user',
+ 'shareWith' => $uid,
+ );
+ $shareBackends = $this->shareManager->getShareBackends();
+ foreach ($shareBackends as $shareBackend) {
+ $itemType = $shareBackend->getItemType();
+ $shareOwnerShares = $this->shareManager->getShares($itemType, $filterShareOwner);
+ $shares = array_merge($shares, $shareOwnerShares);
+ try {
+ $shareWithShares = $this->shareManager->getShares($itemType, $filterShareWith);
+ $shares = array_merge($shares, $shareWithShares);
+ } catch (ShareTypeDoesNotExistException $exception) {
+ // Do nothing
+ }
+ }
+ foreach ($shares as $share) {
+ $this->shareManager->unshare($share);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/timemachine.php b/lib/share/timemachine.php
new file mode 100644
index 000000000000..b2d8b4930437
--- /dev/null
+++ b/lib/share/timemachine.php
@@ -0,0 +1,37 @@
+.
+ */
+
+namespace OC\Share;
+
+/**
+ * Mock calls to time()
+ */
+class TimeMachine {
+
+ /**
+ * Get time()
+ * @return int
+ */
+ public function getTime() {
+ return time();
+ }
+
+}
\ No newline at end of file
diff --git a/lib/share/updater.php b/lib/share/updater.php
new file mode 100644
index 000000000000..56070dfb4eb2
--- /dev/null
+++ b/lib/share/updater.php
@@ -0,0 +1,230 @@
+.
+ */
+
+namespace OC\Share;
+
+use OC\Log;
+use DateTime;
+use Exception;
+
+/**
+ * Update old shares to Share API 2.0.0
+ */
+class Updater {
+
+ private $shareManager;
+ private $logger;
+ private $shareTypeGroupUserUnique = 2;
+ private $updatedShares;
+
+ /**
+ * The constructor
+ * @param \OC\Share\ShareManager $shareManager
+ * @param \OC\Log $logger
+ */
+ public function __construct(ShareManager $shareManager, Log $logger) {
+ $this->shareManager = $shareManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Update all shares
+ */
+ public function updateAll() {
+ $version = \OC_Appconfig::getValue('core', 'shareAPIVersion', '1.0.0');
+ if ($version === '1.0.0') {
+ $this->logger->notice('Started update of shares to Share API 2');
+ $sql = 'SELECT `id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_type`, '.
+ '`item_source`, `file_source`, `permissions`, `stime`, `expiration`, `token` '.
+ 'FROM `*PREFIX*share`';
+ $result = \OC_DB::executeAudited($sql);
+ while ($row = $result->fetchRow()) {
+ $this->updateShare($row);
+ }
+ $this->logger->notice('Finished update of shares to Share API 2');
+ \OC_Appconfig::setValue('core', 'shareAPIVersion', '2.0.0');
+ }
+ }
+
+ /**
+ * Update the share specified by the $row
+ * @param array $row
+ * @return \OC\Share\Share | false
+ */
+ protected function updateShare($row) {
+ $id = $row['id'];
+ if (!isset($this->updatedShares[$id])) {
+ $share = $this->getShareFromRow($row);
+ if ($share) {
+ // Ensure all parent shares are already updated
+ $latestParentTime = false;
+ $parentRows = $this->searchForParents($row);
+ foreach ($parentRows as $parentRow) {
+ $parent = $this->updateShare($parentRow);
+ if ($parent) {
+ // Find the latest parent expiration time
+ $time = $parent->getExpirationTime();
+ if (!isset($time)) {
+ $latestParentTime = null;
+ } else if ($latestParentTime === false
+ || (isset($latestParentTime) && $time > $latestParentTime)
+ ) {
+ $latestParentTime = $time;
+ }
+ }
+ }
+ if ($latestParentTime !== false) {
+ $time = $share->getExpirationTime();
+ // Truncate expiration time as necessary
+ if (!isset($time) || $latestParentTime < $time) {
+ $share->setExpirationTime($latestParentTime);
+ }
+ }
+ try {
+ $token = $share->getToken();
+ $password = $share->getPassword();
+ $share = $this->shareManager->share($share);
+ $this->updatedShares[$id] = $share;
+ if (isset($token)) {
+ // Reuse old token and password
+ $sql = 'UPDATE `*PREFIX*shares_links` SET `token` = ?, `password` = ? '.
+ 'WHERE `id` = ?';
+ \OC_DB::executeAudited($sql, array($token, $password, $share->getId()));
+ }
+ } catch (Exception $exception) {
+ $this->logger->error('Unable to update share with id: '.$id.' '.
+ 'because of an exception: '.$exception->getMessage(),
+ array('app' => 'core')
+ );
+ $this->updatedShares[$id] = false;
+ }
+ } else {
+ $this->updatedShares[$id] = false;
+ }
+ }
+ return $this->updatedShares[$id];
+ }
+
+ /**
+ * Translate an old database row to a share
+ * @param array $row
+ * @return \OC\Share\Share | null
+ */
+ protected function getShareFromRow($row) {
+ $id = $row['id'];
+ unset($row['id']);
+ unset($row['parent']);
+ settype($row['share_type'], 'int');
+ // The group user unique target shares can be ignored because the unique targets
+ // are handled by the group share type
+ if ($row['share_type'] !== $this->shareTypeGroupUserUnique) {
+ if ($row['share_type'] === \OCP\Share::SHARE_TYPE_USER) {
+ $row['share_type_id'] = 'user';
+ } else if ($row['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
+ $row['share_type_id'] = 'group';
+ } else if ($row['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
+ $row['share_type_id'] = 'link';
+ if (isset($row['share_with'])) {
+ $row['password'] = $row['share_with'];
+ unset($row['share_with']);
+ }
+ } else {
+ $this->logger->error('Unable to update share with id: '.$id.' '.
+ 'because the share type is unknown', array('app' => 'core')
+ );
+ return null;
+ }
+ unset($row['share_type']);
+ $row['share_owner'] = $row['uid_owner'];
+ unset($row['uid_owner']);
+ if (isset($row['file_source'])) {
+ $row['item_source'] = $row['file_source'];
+ }
+ unset($row['file_source']);
+ settype($row['permissions'], 'int');
+ if ($row['item_type'] === 'file') {
+ // Remove Create permission from files
+ $row['permissions'] &= ~4;
+ }
+ $row['share_time'] = $row['stime'];
+ unset($row['stime']);
+ settype($row['share_time'], 'int');
+ if (isset($row['expiration'])) {
+ $date = new DateTime($row['expiration']);
+ $row['expiration_time'] = $date->getTimeStamp();
+ }
+ unset($row['expiration']);
+ return Share::fromRow($row);
+ }
+ return null;
+ }
+
+ /**
+ * Search for parent shares of a share
+ * @param array $row
+ * @return array
+ */
+ protected function searchForParents($row) {
+ $parentRows = array();
+ if (isset($row['parent'])) {
+ $sql = 'SELECT `id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_type`, '.
+ '`item_source`, `file_source`, `permissions`, `stime`, `expiration`, `token` '.
+ 'FROM `*PREFIX*share` WHERE `id` = ?';
+ $parentRow = \OC_DB::executeAudited($sql, array($row['parent']), 1)->fetchRow();
+ if ($parentRow) {
+ $parentRows[] = $parentRow;
+ // Look for shares similar to parent
+ $sql = 'SELECT `id`, `parent`, `share_type`, `share_with`, `uid_owner`, '.
+ '`item_type`, `item_source`, `file_source`, `permissions`, `stime`, '.
+ '`expiration`, `token` FROM `*PREFIX*share`';
+ $params = array();
+ if ($parentRow['item_type'] === 'file') {
+ $sql .= ' WHERE `item_type` IN (?, ?)';
+ $params[] = 'file';
+ $params[] = 'folder';
+ } else {
+ $sql .= ' WHERE `item_type` = ?';
+ $params[] = $parentRow['item_type'];
+ }
+ // A trick for reshared files inside shared folders is that the item_source
+ // is always the file id of the shared folder, thanks to bad programming
+ $sql .= ' AND `item_source` = ?';
+ $params[] = $parentRow['item_source'];
+ $sql .= ' AND `share_type` IN (?, ?)';
+ $params[] = \OCP\Share::SHARE_TYPE_USER;
+ $params[] = \OCP\Share::SHARE_TYPE_GROUP;
+ $user = $row['uid_owner'];
+ $userAndGroups = array_merge(array($user), \OC_Group::getUserGroups($user));
+ $placeholders = join(',', array_fill(0, count($userAndGroups), '?'));
+ $sql .= ' AND `share_with` IN ('.$placeholders.')';
+ $params = array_merge($params, $userAndGroups);
+ $sql .= ' AND `id` != ?';
+ $params[] = $row['parent'];
+ $result = \OC_DB::executeAudited($sql, $params);
+ while ($row = $result->fetchRow()) {
+ $parentRows[] = $row;
+ }
+ }
+ }
+ return $parentRows;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/updater.php b/lib/updater.php
index df7332a96a97..6fb26bb5544c 100644
--- a/lib/updater.php
+++ b/lib/updater.php
@@ -115,6 +115,15 @@ public function upgrade() {
\OC_App::checkAppsRequirements();
// load all apps to also upgrade enabled apps
\OC_App::loadApps();
+ try {
+ $shareManager = \OCP\Share::getShareManager();
+ if ($shareManager) {
+ $updater = new \OC\Share\Updater($shareManager, $this->log);
+ $updater->updateAll();
+ }
+ } catch (\Exception $exception) {
+ $this->emit('\OC\Updater', 'failure', array($exception->getMessage()));
+ }
\OC_Config::setValue('maintenance', false);
$this->emit('\OC\Updater', 'maintenanceEnd');
}
diff --git a/lib/util.php b/lib/util.php
index e03667b07944..6195178701b5 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -98,7 +98,7 @@ public static function tearDownFS() {
public static function getVersion() {
// hint: We only can count up. Reset minor/patchlevel when
// updating major/minor version number.
- return array(5, 80, 05);
+ return array(5, 80, 07);
}
/**
diff --git a/tests/lib/share/backend.php b/tests/lib/share/backend.php
deleted file mode 100644
index 2f6c84678ffc..000000000000
--- a/tests/lib/share/backend.php
+++ /dev/null
@@ -1,71 +0,0 @@
-.
-*/
-
-OC::$CLASSPATH['OCP\Share_Backend']='lib/public/share.php';
-
-class Test_Share_Backend implements OCP\Share_Backend {
-
- const FORMAT_SOURCE = 0;
- const FORMAT_TARGET = 1;
- const FORMAT_PERMISSIONS = 2;
-
- private $testItem1 = 'test.txt';
- private $testItem2 = 'share.txt';
-
- public function isValidSource($itemSource, $uidOwner) {
- if ($itemSource == $this->testItem1 || $itemSource == $this->testItem2) {
- return true;
- }
- }
-
- public function generateTarget($itemSource, $shareWith, $exclude = null) {
- // Always make target be test.txt to cause conflicts
- $target = 'test.txt';
- if (isset($exclude)) {
- $pos = strrpos($target, '.');
- $name = substr($target, 0, $pos);
- $ext = substr($target, $pos);
- $append = '';
- $i = 1;
- while (in_array($name.$append.$ext, $exclude)) {
- $append = $i;
- $i++;
- }
- $target = $name.$append.$ext;
- }
- return $target;
- }
-
- public function formatItems($items, $format, $parameters = null) {
- $testItems = array();
- foreach ($items as $item) {
- if ($format == self::FORMAT_SOURCE) {
- $testItems[] = $item['item_source'];
- } else if ($format == self::FORMAT_TARGET) {
- $testItems[] = $item['item_target'];
- } else if ($format == self::FORMAT_PERMISSIONS) {
- $testItems[] = $item['permissions'];
- }
- }
- return $testItems;
- }
-
-}
diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php
index e7d441a7e780..57bf79786dbc 100644
--- a/tests/lib/share/share.php
+++ b/tests/lib/share/share.php
@@ -1,413 +1,208 @@
.
+ * ownCloud
+ *
+ * @author Alessandro Cosentino
+ * @author Bernhard Posselt
+ * @author Michael Gapczynski
+ * @copyright 2012 Alessandro Cosentino cosenal@gmail.com
+ * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
+ * @copyright 2013 Michael Gapczynski mtgap@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 .
+ *
*/
-class Test_Share extends PHPUnit_Framework_TestCase {
-
- protected $itemType;
- protected $userBackend;
- protected $user1;
- protected $user2;
- protected $groupBackend;
- protected $group1;
- protected $group2;
- protected $resharing;
-
- public function setUp() {
- OC_User::clearBackends();
- OC_User::useBackend('dummy');
- $this->user1 = uniqid('user1_');
- $this->user2 = uniqid('user2_');
- $this->user3 = uniqid('user3_');
- $this->user4 = uniqid('user4_');
- OC_User::createUser($this->user1, 'pass');
- OC_User::createUser($this->user2, 'pass');
- OC_User::createUser($this->user3, 'pass');
- OC_User::createUser($this->user4, 'pass');
- OC_User::setUserId($this->user1);
- OC_Group::clearBackends();
- OC_Group::useBackend(new OC_Group_Dummy);
- $this->group1 = uniqid('group_');
- $this->group2 = uniqid('group_');
- OC_Group::createGroup($this->group1);
- OC_Group::createGroup($this->group2);
- OC_Group::addToGroup($this->user1, $this->group1);
- OC_Group::addToGroup($this->user2, $this->group1);
- OC_Group::addToGroup($this->user3, $this->group1);
- OC_Group::addToGroup($this->user2, $this->group2);
- OC_Group::addToGroup($this->user4, $this->group2);
- OCP\Share::registerBackend('test', 'Test_Share_Backend');
- OC_Hook::clear('OCP\\Share');
- OC::registerShareHooks();
- $this->resharing = OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
- OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+namespace Test\Share;
+
+use OC\Share\Share;
+
+class ShareTest extends \PHPUnit_Framework_TestCase {
+
+ public function testToAPI() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setParentIds(array(2, 3));
+ $share->setShareTypeId('link');
+ $share->setShareOwner('MTGap');
+ $share->setShareOwnerDisplayName('Michael Gapczynski');
+ $share->setItemType('test');
+ $share->setItemSource(21);
+ $share->setItemTarget('Test');
+ $share->setItemOwner('MTGap');
+ $share->setPermissions(31);
+ $share->setExpirationTime(1370884025);
+ $share->setShareTime(1370883025);
+ $share->setToken('3akdsfj32as23kjsdf');
+ $share->setPassword('4AJak34jkDajl4aa42Jmkapw');
+ $this->assertEquals(array(
+ 'id' => 1,
+ 'parentIds' => array(2, 3),
+ 'shareTypeId' => 'link',
+ 'shareOwner' => 'MTGap',
+ 'shareOwnerDisplayName' => 'Michael Gapczynski',
+ 'shareWith' => null,
+ 'shareWithDisplayName' => null,
+ 'itemType' => 'test',
+ 'itemSource' => 21,
+ 'itemTarget' => 'Test',
+ 'itemOwner' => 'MTGap',
+ 'permissions' => 31,
+ 'expirationTime' => 1370884025,
+ 'shareTime' => 1370883025,
+ 'token' => '3akdsfj32as23kjsdf',
+ 'password' => '4AJak34jkDajl4aa42Jmkapw',
+ ), $share->toAPI());
}
- public function tearDown() {
- $query = OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `item_type` = ?');
- $query->execute(array('test'));
- OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $this->resharing);
- }
-
- public function testShareInvalidShareType() {
- $message = 'Share type foobar is not valid for test.txt';
- try {
- OCP\Share::shareItem('test', 'test.txt', 'foobar', $this->user2, OCP\PERMISSION_READ);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- }
+ public function testIsCreatable() {
+ $share = new Share();
+ $share->setPermissions(\OCP\PERMISSION_CREATE);
+ $this->assertTrue($share->isCreatable());
- public function testInvalidItemType() {
- $message = 'Sharing backend for foobar not found';
- try {
- OCP\Share::shareItem('foobar', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- try {
- OCP\Share::getItemsSharedWith('foobar');
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- try {
- OCP\Share::getItemSharedWith('foobar', 'test.txt');
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- try {
- OCP\Share::getItemSharedWithBySource('foobar', 'test.txt');
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- try {
- OCP\Share::getItemShared('foobar', 'test.txt');
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- try {
- OCP\Share::unshare('foobar', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- try {
- OCP\Share::setPermissions('foobar', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_UPDATE);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
+ $share->setPermissions(\OCP\PERMISSION_READ);
+ $this->assertFalse($share->isCreatable());
}
- public function testShareWithUser() {
- // Invalid shares
- $message = 'Sharing test.txt failed, because the user '.$this->user1.' is the item owner';
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user1, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- $message = 'Sharing test.txt failed, because the user foobar does not exist';
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, 'foobar', OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- $message = 'Sharing foobar failed, because the sharing backend for test could not find its source';
- try {
- OCP\Share::shareItem('test', 'foobar', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
-
- // Valid share
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ));
- $this->assertEquals(array('test.txt'), OCP\Share::getItemShared('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
-
- // Attempt to share again
- OC_User::setUserId($this->user1);
- $message = 'Sharing test.txt failed, because this item is already shared with '.$this->user2;
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
-
- // Attempt to share back
- OC_User::setUserId($this->user2);
- $message = 'Sharing test.txt failed, because the user '.$this->user1.' is the original sharer';
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user1, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
-
- // Unshare
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2));
-
- // Attempt reshare without share permission
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ));
- OC_User::setUserId($this->user2);
- $message = 'Sharing test.txt failed, because resharing is not allowed';
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user3, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
-
- // Owner grants share and update permission
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::setPermissions('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE | OCP\PERMISSION_SHARE));
-
- // Attempt reshare with escalated permissions
- OC_User::setUserId($this->user2);
- $message = 'Sharing test.txt failed, because the permissions exceed permissions granted to '.$this->user2;
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user3, OCP\PERMISSION_READ | OCP\PERMISSION_DELETE);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
-
- // Valid reshare
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user3, OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE));
- $this->assertEquals(array('test.txt'), OCP\Share::getItemShared('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
- OC_User::setUserId($this->user3);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
-
- // Attempt to escalate permissions
- OC_User::setUserId($this->user2);
- $message = 'Setting permissions for test.txt failed, because the permissions exceed permissions granted to '.$this->user2;
- try {
- OCP\Share::setPermissions('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user3, OCP\PERMISSION_READ | OCP\PERMISSION_DELETE);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
-
- // Remove update permission
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::setPermissions('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ | OCP\PERMISSION_SHARE));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_SHARE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
- OC_User::setUserId($this->user3);
- $this->assertEquals(array(OCP\PERMISSION_READ), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
-
- // Remove share permission
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::setPermissions('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array(OCP\PERMISSION_READ), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
- OC_User::setUserId($this->user3);
- $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt'));
-
- // Reshare again, and then have owner unshare
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::setPermissions('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ | OCP\PERMISSION_SHARE));
- OC_User::setUserId($this->user2);
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user3, OCP\PERMISSION_READ));
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2));
- OC_User::setUserId($this->user2);
- $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt'));
- OC_User::setUserId($this->user3);
- $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt'));
+ public function testIsReadable() {
+ $share = new Share();
+ $share->setPermissions(\OCP\PERMISSION_READ);
+ $this->assertTrue($share->isReadable());
- // Attempt target conflict
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ));
- OC_User::setUserId($this->user3);
- $this->assertTrue(OCP\Share::shareItem('test', 'share.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ));
-
- OC_User::setUserId($this->user2);
- $to_test = OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET);
- $this->assertEquals(2, count($to_test));
- $this->assertTrue(in_array('test.txt', $to_test));
- $this->assertTrue(in_array('test1.txt', $to_test));
-
- // Remove user
- OC_User::setUserId($this->user1);
- OC_User::deleteUser($this->user1);
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test1.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ $share->setPermissions(0);
+ $this->assertFalse($share->isReadable());
}
- public function testShareWithGroup() {
- // Invalid shares
- $message = 'Sharing test.txt failed, because the group foobar does not exist';
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, 'foobar', OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- $policy = OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
- OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
- $message = 'Sharing test.txt failed, because '.$this->user1.' is not a member of the group '.$this->group2;
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group2, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
- OC_Appconfig::setValue('core', 'shareapi_share_policy', $policy);
+ public function testIsUpdatable() {
+ $share = new Share();
+ $share->setPermissions(\OCP\PERMISSION_UPDATE);
+ $this->assertTrue($share->isUpdatable());
- // Valid share
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1, OCP\PERMISSION_READ));
- $this->assertEquals(array('test.txt'), OCP\Share::getItemShared('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
- OC_User::setUserId($this->user3);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE));
-
- // Attempt to share again
- OC_User::setUserId($this->user1);
- $message = 'Sharing test.txt failed, because this item is already shared with '.$this->group1;
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
+ $share->setPermissions(\OCP\PERMISSION_READ);
+ $this->assertFalse($share->isUpdatable());
+ }
- // Attempt to share back to owner of group share
- OC_User::setUserId($this->user2);
- $message = 'Sharing test.txt failed, because the user '.$this->user1.' is the original sharer';
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user1, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
+ public function testIsDeletable() {
+ $share = new Share();
+ $share->setPermissions(\OCP\PERMISSION_DELETE);
+ $this->assertTrue($share->isDeletable());
- // Attempt to share back to group
- $message = 'Sharing test.txt failed, because this item is already shared with '.$this->group1;
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
+ $share->setPermissions(\OCP\PERMISSION_READ);
+ $this->assertFalse($share->isDeletable());
+ }
- // Attempt to share back to member of group
- $message ='Sharing test.txt failed, because this item is already shared with '.$this->user3;
- try {
- OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user3, OCP\PERMISSION_READ);
- $this->fail('Exception was expected: '.$message);
- } catch (Exception $exception) {
- $this->assertEquals($message, $exception->getMessage());
- }
+ public function testIsSharable() {
+ $share = new Share();
+ $share->setPermissions(\OCP\PERMISSION_SHARE);
+ $this->assertTrue($share->isSharable());
- // Unshare
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1));
+ $share->setPermissions(\OCP\PERMISSION_READ);
+ $this->assertFalse($share->isSharable());
+ }
- // Valid share with same person - user then group
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ | OCP\PERMISSION_DELETE | OCP\PERMISSION_SHARE));
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1, OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE | OCP\PERMISSION_DELETE | OCP\PERMISSION_SHARE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
- OC_User::setUserId($this->user3);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
+ public function testAddParentId() {
+ $share = new Share();
+ $share->addParentId(1);
+ $this->assertEquals(array(1), $share->getParentIds());
+ $this->assertContains('parentIds', $share->getUpdatedProperties());
+ $share->addParentId(3);
+ $this->assertEquals(array(1, 3), $share->getParentIds());
+ $this->assertContains('parentIds', $share->getUpdatedProperties());
+ }
- // Valid reshare
- OC_User::setUserId($this->user2);
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user4, OCP\PERMISSION_READ));
- OC_User::setUserId($this->user4);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ public function testRemoveParentId() {
+ $share = new Share();
+ $share->setParentIds(array(1, 3));
+ $share->removeParentId(3);
+ $this->assertEquals(array(1), $share->getParentIds());
+ $this->assertContains('parentIds', $share->getUpdatedProperties());
+ }
- // Unshare from user only
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
- OC_User::setUserId($this->user4);
- $this->assertEquals(array(), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ public function testFromParams() {
+ $params = array(
+ 'shareTypeId' => 'group',
+ 'shareOwner' => 'MTGap',
+ 'shareWith' => 'friends',
+ 'itemType' => 'test',
+ 'itemSource' => 23,
+ );
+ $share = Share::fromParams($params);
+ $this->assertEquals($params['shareTypeId'], $share->getShareTypeId());
+ $this->assertEquals($params['shareOwner'], $share->getShareOwner());
+ $this->assertEquals($params['shareWith'], $share->getShareWith());
+ $this->assertEquals($params['itemType'], $share->getItemType());
+ $this->assertEquals($params['itemSource'], $share->getItemSource());
+ $this->assertTrue($share instanceof Share);
+ }
- // Valid share with same person - group then user
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user2, OCP\PERMISSION_READ | OCP\PERMISSION_DELETE));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE | OCP\PERMISSION_DELETE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
+ public function testFromRow() {
+ $row = array(
+ 'id' => '1',
+ 'shareTypeId' => 'group',
+ 'shareOwner' => 'MTGap',
+ 'shareWith' => 'friends',
+ 'itemType' => 'test',
+ 'itemSource' => '23',
+ );
+ $share = Share::fromRow($row);
+ $this->assertEquals(1, $share->getId());
+ $this->assertEquals($row['shareTypeId'], $share->getShareTypeId());
+ $this->assertEquals($row['shareOwner'], $share->getShareOwner());
+ $this->assertEquals($row['shareWith'], $share->getShareWith());
+ $this->assertEquals($row['itemType'], $share->getItemType());
+ $this->assertEquals($row['itemSource'], $share->getItemSource());
+ $this->assertTrue($share instanceof Share);
+ }
- // Unshare from group only
- OC_User::setUserId($this->user1);
- $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array(OCP\PERMISSION_READ | OCP\PERMISSION_DELETE), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_PERMISSIONS));
+ public function testGetSetId() {
+ $id = 3;
+ $share = new Share();
+ $share->setId($id);
+ $this->assertEquals($id, $share->getId());
+ }
- // Attempt user specific target conflict
- OC_User::setUserId($this->user3);
- $this->assertTrue(OCP\Share::shareItem('test', 'share.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1, OCP\PERMISSION_READ | OCP\PERMISSION_SHARE));
- OC_User::setUserId($this->user2);
- $to_test = OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET);
- $this->assertEquals(2, count($to_test));
- $this->assertTrue(in_array('test.txt', $to_test));
- $this->assertTrue(in_array('test1.txt', $to_test));
+ public function testSetterMarksPropertyUpdated() {
+ $share = new Share();
+ $share->setParentIds(array(1, 3));
+ $this->assertContains('parentIds', $share->getUpdatedProperties());
+ }
- // Valid reshare
- $this->assertTrue(OCP\Share::shareItem('test', 'share.txt', OCP\Share::SHARE_TYPE_USER, $this->user4, OCP\PERMISSION_READ | OCP\PERMISSION_SHARE));
- OC_User::setUserId($this->user4);
- $this->assertEquals(array('test1.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ public function testResetUpdatedProperties() {
+ $share = new Share();
+ $share->setParentIds(array(1, 3));
+ $share->resetUpdatedProperties();
+ $this->assertEmpty($share->getUpdatedProperties());
+ }
- // Remove user from group
- OC_Group::removeFromGroup($this->user2, $this->group1);
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
- OC_User::setUserId($this->user4);
- $this->assertEquals(array(), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ public function testColumnToPropertyNoReplacement() {
+ $column = 'my';
+ $this->assertEquals('my', Share::columnToProperty($column));
+ }
- // Add user to group
- OC_Group::addToGroup($this->user4, $this->group1);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ public function testColumnToProperty() {
+ $column = 'my_property';
+ $this->assertEquals('myProperty', Share::columnToProperty($column));
+ }
- // Unshare from self
- $this->assertTrue(OCP\Share::unshareFromSelf('test', 'test.txt'));
- $this->assertEquals(array(), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
- OC_User::setUserId($this->user2);
- $this->assertEquals(array('test.txt'), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
+ public function testPropertyToColumnNoReplacement() {
+ $property = 'my';
+ $this->assertEquals('`my`', Share::propertyToColumn($property));
+ }
- // Remove group
- OC_Group::deleteGroup($this->group1);
- OC_User::setUserId($this->user4);
- $this->assertEquals(array(), OCP\Share::getItemsSharedWith('test', Test_Share_Backend::FORMAT_TARGET));
- OC_User::setUserId($this->user3);
- $this->assertEquals(array(), OCP\Share::getItemsShared('test'));
+ public function testPropertyToColumn() {
+ $property = 'myProperty';
+ $this->assertEquals('`my_property`', Share::propertyToColumn($property));
}
-}
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php
new file mode 100644
index 000000000000..0f5a9f6041c3
--- /dev/null
+++ b/tests/lib/share/sharebackend.php
@@ -0,0 +1,571 @@
+.
+ */
+
+namespace Test\Share;
+
+use OC\Share\Share;
+
+class TestShareBackend extends \OC\Share\ShareBackend {
+
+ private $isValidItem;
+ private $events;
+
+ public function getItemType() {
+ return 'test';
+ }
+
+ public function getItemTypePlural() {
+ return 'tests';
+ }
+
+ protected function isValidItem(Share $share) {
+ if ($this->isValidItem === false) {
+ throw new \OC\Share\Exception\InvalidItemException(
+ 'The item does not exist'
+ );
+ } else {
+ return true;
+ }
+ }
+
+ public function setIsValidItem($isValidItem) {
+ $this->isValidItem = $isValidItem;
+ }
+
+ public function pAreValidPermissions(Share $share) {
+ return parent::areValidPermissions($share);
+ }
+
+ public function pIsValidExpirationTime(Share $share) {
+ return parent::isValidExpirationTime($share);
+ }
+
+ protected function emit($scope, $method, $arguments = array()) {
+ // Store the emitted events so they can be retrieved later for assertions
+ $this->events[] = array($scope, $method, $arguments);
+ }
+
+ public function getEvents() {
+ return $this->events;
+ }
+
+}
+
+class ShareBackend extends \PHPUnit_Framework_TestCase {
+
+ protected $timeMachine;
+ protected $user;
+ protected $group;
+ protected $link;
+ protected $shareBackend;
+
+ protected function setUp() {
+ $this->timeMachine = $this->getMockBuilder('\OC\Share\TimeMachine')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->timeMachine->expects($this->any())
+ ->method('getTime')
+ ->will($this->returnValue(1370797580));
+ $this->user = $this->getMockBuilder('\OC\Share\ShareType\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->user->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('user'));
+ $this->group = $this->getMockBuilder('\OC\Share\ShareType\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->group->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('group'));
+ $this->link = $this->getMockBuilder('\OC\Share\ShareType\Link')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->link->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('link'));
+ $this->shareBackend = new TestShareBackend($this->timeMachine,
+ array($this->user, $this->group, $this->link)
+ );
+ }
+
+ /**
+ * Get a fake valid item source for testing isValidItem
+ * @param Share $share
+ * @return any
+ */
+ protected function getValidItemSource(Share $share) {
+ $this->shareBackend->setIsValidItem(true);
+ return 1;
+ }
+
+ protected function getExpectedItemTarget(Share $share) {}
+
+ public function testGetShareTypes() {
+ $shareTypes = $this->shareBackend->getShareTypes();
+ $this->assertCount(3, $shareTypes);
+ $this->assertArrayHasKey('user', $shareTypes);
+ $this->assertEquals($this->user, $shareTypes['user']);
+ $this->assertArrayHasKey('group', $shareTypes);
+ $this->assertEquals($this->group, $shareTypes['group']);
+ $this->assertArrayHasKey('link', $shareTypes);
+ $this->assertEquals($this->link, $shareTypes['link']);
+ }
+
+ public function testGetShareType() {
+ $this->assertEquals($this->group, $this->shareBackend->getShareType('group'));
+ }
+
+ public function testGetShareTypeDoesNotExist() {
+ $this->setExpectedException('\OC\Share\Exception\ShareTypeDoesNotExistException',
+ 'A share type does not exist with the id foo'
+ );
+ $this->shareBackend->getShareType('foo');
+ }
+
+ public function testShare() {
+ $mtgap = 'MTGap';
+ $icewind = 'Icewind';
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($mtgap);
+ $share->setShareWith($icewind);
+ $share->setItemOwner($mtgap);
+ $share->setPermissions(31);
+ $item = $this->getValidItemSource($share);
+ $share->setItemSource($item);
+ $share->resetUpdatedProperties();
+ $sharedShare = clone $share;
+ $sharedShare->setShareTime(1370797580);
+ $userMap = array(
+ array(array('shareOwner' => $mtgap, 'shareWith' => $icewind, 'itemSource' => $item),
+ 1, null, array()
+ )
+ );
+ $this->user->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($userMap));
+ $this->group->expects($this->never())
+ ->method('getShares');
+ $this->link->expects($this->never())
+ ->method('getShares');
+ $this->user->expects($this->once())
+ ->method('isValidShare')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue(true));
+ $this->user->expects($this->once())
+ ->method('share')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue($share));
+ $this->user->expects($this->never())
+ ->method('update');
+ $this->user->expects($this->never())
+ ->method('setParentIds');
+ $this->group->expects($this->never())
+ ->method('update');
+ $this->group->expects($this->never())
+ ->method('setParentIds');
+ $this->link->expects($this->never())
+ ->method('update');
+ $this->link->expects($this->never())
+ ->method('setParentIds');
+ $share = $this->shareBackend->share($share);
+ $this->assertEquals($sharedShare, $share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertContains(array('\OC\Share', 'preShare', array($share)), $events);
+ $this->assertContains(array('\OC\Share', 'postShare', array($sharedShare)), $events);
+ }
+
+ public function testShareWithInvalidItem() {
+ $this->shareBackend->setIsValidItem(false);
+
+ $share = new Share();
+ $this->setExpectedException('\OC\Share\Exception\InvalidItemException',
+ 'The item does not exist'
+ );
+ $this->shareBackend->share($share);
+ }
+
+ public function testShareAgain() {
+ $butonic = 'butonic';
+ $bartv = 'bartv';
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($butonic);
+ $share->setShareWith($bartv);
+ $share->setItemOwner($butonic);
+ $item = $this->getValidItemSource($share);
+ $share->setItemSource($item);
+ $map = array(
+ array(array('shareOwner' => $butonic, 'shareWith' => $bartv, 'itemSource' => $item),
+ 1, null, array($share)
+ )
+ );
+ $this->user->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share already exists'
+ );
+ $this->shareBackend->share($share);
+ }
+
+ public function testShareWithInvalidShare() {
+ $mtgap = 'MTGap';
+ $icewind = 'Icewind';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($mtgap);
+ $share->setShareWith($icewind);
+ $share->setItemOwner($mtgap);
+ $share->setPermissions(31);
+ $item = $this->getValidItemSource($share);
+ $share->setItemSource($item);
+ $userMap = array(
+ array(array('shareOwner' => $mtgap, 'shareWith' => $icewind, 'itemSource' => $item),
+ 1, null, array()
+ ),
+ );
+ $this->user->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($userMap));
+ $this->group->expects($this->never())
+ ->method('getShares');
+ $this->link->expects($this->never())
+ ->method('getShares');
+ $this->user->expects($this->once())
+ ->method('isValidShare')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue(false));
+ $this->assertFalse($this->shareBackend->share($share));
+ }
+
+ public function testUnshare() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setShareTypeId('user');
+ $this->user->expects($this->once())
+ ->method('unshare')
+ ->with($this->equalTo($share));
+ $this->shareBackend->unshare($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertContains(array('\OC\Share', 'preUnshare', array($share)), $events);
+ $this->assertContains(array('\OC\Share', 'postUnshare', array($share)), $events);
+ }
+
+ public function testUpdate() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setShareTypeId('user');
+ $share->resetUpdatedProperties();
+ $share->setItemTarget('New Test Item');
+ $this->user->expects($this->once())
+ ->method('update')
+ ->with($this->equalTo($share));
+ $this->shareBackend->update($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertContains(array('\OC\Share', 'preUpdate', array($share)), $events);
+ $this->assertContains(array('\OC\Share', 'postUpdate', array($share)), $events);
+ }
+
+ public function testUpdateWithCustomUpdateMethod() {
+ $share = new Share();
+ $share->setId(3);
+ $share->setShareTypeId('user');
+ $share->resetUpdatedProperties();
+ $share->setParentIds(array(1, 2));
+ $this->user->expects($this->never())
+ ->method('update');
+ $this->user->expects($this->once())
+ ->method('setParentIds')
+ ->with($this->equalTo($share));
+ $this->shareBackend->update($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertContains(array('\OC\Share', 'preUpdate', array($share)), $events);
+ $this->assertContains(array('\OC\Share', 'postUpdate', array($share)), $events);
+ }
+
+ public function testUpdateWithNoChanges() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setShareTypeId('link');
+ $share->resetUpdatedProperties();
+ $this->link->expects($this->never())
+ ->method('update');
+ $this->shareBackend->update($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertEmpty($events);
+ }
+
+ public function testUpdateWithValidPermissionsAndExpirationTime() {
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->resetUpdatedProperties();
+ $share->setPermissions(1);
+ $share->setExpirationTime(1370801180);
+ $this->user->expects($this->once())
+ ->method('update');
+ $this->shareBackend->update($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertContains(array('\OC\Share', 'preUpdate', array($share)), $events);
+ $this->assertContains(array('\OC\Share', 'postUpdate', array($share)), $events);
+ }
+
+ public function testUpdateWithInvalidPermissions() {
+ $share = new Share();
+ $share->setShareTypeId('link');
+ $share->resetUpdatedProperties();
+ $share->setPermissions(0);
+ $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException',
+ 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL
+ );
+ $this->shareBackend->update($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertEmpty($events);
+ }
+
+ public function testUpdateWithInvalidExpirationTime() {
+ $share = new Share();
+ $share->setShareTypeId('link');
+ $share->resetUpdatedProperties();
+ // 59 minutes 59 seconds in the future
+ $share->setExpirationTime(1370801179);
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time is not at least 1 hour in the future'
+ );
+ $this->shareBackend->update($share);
+ $events = $this->shareBackend->getEvents();
+ $this->assertEmpty($events);
+ }
+
+ public function testGetShares() {
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setShareTypeId('user');
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->setShareTypeId('group');
+ $userMap = array(
+ array(array(), null, null, array($share1))
+ );
+ $this->user->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($userMap));
+ $groupMap = array(
+ array(array(), null, null, array($share2))
+ );
+ $this->group->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($groupMap));
+ $linkMap = array(
+ array(array(), null, null, array())
+ );
+ $this->link->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($linkMap));
+ $shares = $this->shareBackend->getShares();
+ $this->assertCount(2, $shares);
+ $this->assertContains($share1, $shares);
+ $this->assertContains($share2, $shares);
+ }
+
+ public function testGetSharesWithFilter() {
+ $item = 1;
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setShareTypeId('user');
+ $share1->setItemSource($item);
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->setShareTypeId('group');
+ $share2->setItemSource($item);
+ $userMap = array(
+ array(array('itemSource' => $item), null, null, array($share1)),
+ array(array('id' => 2), null, null, array())
+ );
+ $this->user->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($userMap));
+ $groupMap = array(
+ array(array('itemSource' => $item), null, null, array($share2)),
+ array(array('id' => 2), null, null, array($share2))
+ );
+ $this->group->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($groupMap));
+ $linkMap = array(
+ array(array('itemSource' => $item), null, null, array()),
+ array(array('id' => 2), null, null, array())
+ );
+ $this->link->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($linkMap));
+ $shares = $this->shareBackend->getShares(array('itemSource' => $item));
+ $this->assertCount(2, $shares);
+ $this->assertContains($share1, $shares);
+ $this->assertContains($share2, $shares);
+
+ $share = $this->shareBackend->getShares(array('id' => 2));
+ $this->assertCount(1, $share);
+ $this->assertContains($share2, $share);
+ }
+
+ public function testGetSharesWithShareTypeId() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setShareTypeId('link');
+ $linkMap = array(
+ array(array(), null, null, array($share))
+ );
+ $this->user->expects($this->never())
+ ->method('getShares');
+ $this->group->expects($this->never())
+ ->method('getShares');
+ $this->link->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($linkMap));
+ $shares = $this->shareBackend->getShares(array('shareTypeId' => 'link'));
+ $this->assertCount(1, $shares);
+ $this->assertContains($share, $shares);
+ }
+
+ public function testGetSharesWithLimitOffset() {
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->setShareTypeId('user');
+ $share3 = new Share();
+ $share3->setId(3);
+ $share3->setShareTypeId('user');
+ $share4 = new Share();
+ $share4->setId(4);
+ $share4->setShareTypeId('group');
+ $userMap = array(
+ array(array(), 3, 1, array($share2, $share3)),
+ );
+ $this->user->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($userMap));
+ $groupMap = array(
+ array(array(), 1, 0, array($share4)),
+ );
+ $this->group->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($groupMap));
+ $this->link->expects($this->never())
+ ->method('getShares');
+ $shares = $this->shareBackend->getShares(array(), 3, 1);
+ $this->assertCount(3, $shares);
+ $this->assertContains($share2, $shares);
+ $this->assertContains($share3, $shares);
+ $this->assertContains($share4, $shares);
+ }
+
+ public function testIsExpired() {
+ // No expiration time
+ $share = new Share();
+ $this->assertFalse($this->shareBackend->isExpired($share));
+
+ // 1 second in the past
+ $share->setExpirationTime(1370797579);
+ $this->assertTrue($this->shareBackend->isExpired($share));
+
+ // 1 second in the future
+ $share->setExpirationTime(1370797581);
+ $this->assertFalse($this->shareBackend->isExpired($share));
+
+ // Default expiration time set for 2 hours from share time
+ $share->setExpirationTime(null);
+ $defaultTime = \OC_Appconfig::getValue('core', 'shareapi_expiration_time', 0);
+ \OC_Appconfig::setValue('core', 'shareapi_expiration_time', 7200);
+ // 1 hour 59 minutes 59 seconds in the past
+ $share->setShareTime(1370790381);
+ $this->assertFalse($this->shareBackend->isExpired($share));
+
+ // 2 hours 1 second in the past
+ $share->setShareTime(1370790379);
+ $this->assertTrue($this->shareBackend->isExpired($share));
+ \OC_Appconfig::setValue('core', 'shareapi_expiration_time', $defaultTime);
+ }
+
+ public function testAreValidPermissions() {
+ $share = new Share();
+ $share->setPermissions(31);
+ $this->assertTrue($this->shareBackend->pAreValidPermissions($share));
+ }
+
+ public function testAreValidPermissionsWithString() {
+ $share = new Share();
+ $share->setPermissions('31');
+ $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException',
+ 'The permissions are not an integer'
+ );
+ $this->shareBackend->pAreValidPermissions($share);
+ }
+
+ public function testAreValidPermissionsWithZero() {
+ $share = new Share();
+ $share->setPermissions(0);
+ $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException',
+ 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL
+ );
+ $this->shareBackend->pAreValidPermissions($share);
+ }
+
+ public function testAreValidPermissionsWithOneMoreThanAll() {
+ $share = new Share();
+ $share->setPermissions(\OCP\PERMISSION_ALL + 1);
+ $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException',
+ 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL
+ );
+ $this->shareBackend->pAreValidPermissions($share);
+ }
+
+ public function testIsValidExpirationTime() {
+ // No expiration time
+ $share = new Share();
+ $this->assertTrue($this->shareBackend->pIsValidExpirationTime($share));
+
+ // 1 hour in the future
+ $share->setExpirationTime(1370801180);
+ $this->assertTrue($this->shareBackend->pIsValidExpirationTime($share));
+ }
+
+ public function testIsValidExpirationTimeWithString() {
+ $share = new Share();
+ $share->setExpirationTime('1370797580');
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time is not an integer'
+ );
+ $this->shareBackend->pIsValidExpirationTime($share);
+ }
+
+ public function testIsValidExpirationTimeNot1HourInTheFuture() {
+ $share = new Share();
+ // 59 minutes 59 seconds in the future
+ $share->setExpirationTime(1370801179);
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time is not at least 1 hour in the future'
+ );
+ $this->shareBackend->pIsValidExpirationTime($share);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php
new file mode 100644
index 000000000000..8968c51296b1
--- /dev/null
+++ b/tests/lib/share/sharemanager.php
@@ -0,0 +1,1981 @@
+.
+ */
+
+namespace Test\Share;
+
+use OC\Share\Share;
+use OC\Share\Exception\ShareTypeDoesNotExistException;
+
+class TestShareManager extends \OC\Share\ShareManager {
+
+ public function pAreValidPermissionsForParents(Share $share) {
+ return parent::areValidPermissionsForParents($share);
+ }
+
+ public function pIsValidExpirationTimeForParents(Share $share) {
+ return parent::isValidExpirationTimeForParents($share);
+ }
+
+}
+
+abstract class CollectionShareBackend extends \OC\Share\ShareBackend
+ implements \OC\Share\ICollectionShareBackend {
+
+}
+
+class ShareManager extends \PHPUnit_Framework_TestCase {
+
+ private $shareBackend;
+ private $collectionShareBackend;
+ private $shareManager;
+ private $areCollectionsEnabled;
+
+ /**
+ * In some of the tests we need to clone shares to mock the share stored in the database and to
+ * confirm that the property was updated correctly
+ */
+
+ protected function setUp() {
+ // Found workaround for mocks of abstract classes with concrete functions here:
+ // https://github.com/sebastianbergmann/phpunit-mock-objects/issues/95
+ $this->shareBackend = $this->getMockBuilder('\OC\Share\ShareBackend')
+ ->disableOriginalConstructor()
+ ->setMethods(get_class_methods('\OC\Share\ShareBackend'))
+ ->getMockForAbstractClass();
+ $this->shareBackend->expects($this->any())
+ ->method('getItemType')
+ ->will($this->returnValue('test'));
+ $this->shareBackend->expects($this->any())
+ ->method('getItemTypePlural')
+ ->will($this->returnValue('tests'));
+ $this->shareBackend->expects($this->any())
+ ->method('isValidItem')
+ ->will($this->returnValue(true));
+ $this->areCollectionsEnabled = false;
+ $this->collectionShareBackend = $this->getMockBuilder('\Test\Share\CollectionShareBackend')
+ ->disableOriginalConstructor()
+ ->setMethods(get_class_methods('\Test\Share\CollectionShareBackend'))
+ ->getMockForAbstractClass();
+ $this->collectionShareBackend->expects($this->any())
+ ->method('getItemType')
+ ->will($this->returnValue('testCollection'));
+ $this->collectionShareBackend->expects($this->any())
+ ->method('getItemTypePlural')
+ ->will($this->returnValue('testCollections'));
+ $this->collectionShareBackend->expects($this->any())
+ ->method('isValidItem')
+ ->will($this->returnValue(true));
+ $this->collectionShareBackend->expects($this->any())
+ ->method('getChildrenItemTypes')
+ ->will($this->returnCallback(array($this, 'getChildrenItemTypesMock')));
+ $this->shareManager = new TestShareManager();
+ $this->shareManager->registerShareBackend($this->shareBackend);
+ $this->shareManager->registerShareBackend($this->collectionShareBackend);
+ }
+
+ public function getChildrenItemTypesMock() {
+ if ($this->areCollectionsEnabled) {
+ return array('test');
+ } else {
+ return array();
+ }
+ }
+
+ public function testGetShareBackends() {
+ $backends = $this->shareManager->getShareBackends();
+ $this->assertCount(2, $backends);
+ $this->assertArrayHasKey('test', $backends);
+ $this->assertEquals($this->shareBackend, $backends['test']);
+ $this->assertArrayHasKey('testCollection', $backends);
+ $this->assertEquals($this->collectionShareBackend, $backends['testCollection']);
+ }
+
+ public function testGetShareBackend() {
+ $this->setExpectedException('\OC\Share\Exception\ShareBackendDoesNotExistException',
+ 'A share backend does not exist for the item type foo'
+ );
+ $this->shareManager->getShareBackend('foo');
+ }
+
+ public function testShareWithOneParent() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ $jancborchardt = 'jancborchardt';
+ $danimo = 'danimo';
+ $dragotin = 'dragotin';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($danimo);
+ $share->setShareWith($dragotin);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $share->resetUpdatedProperties();
+ $sharedShare = clone $share;
+ $sharedShare->setItemOwner($jancborchardt);
+ $sharedShare->addParentId(1);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('user');
+ $parent->setShareOwner($jancborchardt);
+ $parent->setShareWith($danimo);
+ $parent->setItemOwner($jancborchardt);
+ $parent->setItemType('test');
+ $parent->setItemSource($item);
+ $parent->setPermissions(31);
+ $map = array(
+ array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array($parent)
+ ),
+ array(array('id' => 1), 1, null, array($parent)),
+ array(array('shareOwner' => $danimo, 'itemSource' => $item), null, null,
+ array($share)
+ ),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->once())
+ ->method('share')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue($share));
+ $share = $this->shareManager->share($share);
+ $this->assertEquals($sharedShare, $share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithOneParentAndResharingDisabled() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'no');
+
+ $mtgap = 'MTGap';
+ $blizzz = 'Blizzz';
+ $schiesbn = 'schiesbn';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($blizzz);
+ $share->setShareWith($schiesbn);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('user');
+ $parent->setShareOwner($mtgap);
+ $parent->setShareWith($blizzz);
+ $parent->setItemOwner($mtgap);
+ $parent->setItemType('test');
+ $parent->setItemSource($item);
+ $parent->setPermissions(31);
+ $map = array(
+ array(array('shareWith' => $blizzz, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array($parent)
+ ),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->never())
+ ->method('share');
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The admin has disabled resharing'
+ );
+ $this->shareManager->share($share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithOneParentWithoutSharePermission() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ $mtgap = 'MTGap';
+ $blizzz = 'Blizzz';
+ $schiesbn = 'schiesbn';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($blizzz);
+ $share->setShareWith($schiesbn);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('user');
+ $parent->setShareOwner($mtgap);
+ $parent->setShareWith($blizzz);
+ $parent->setItemOwner($mtgap);
+ $parent->setItemType('test');
+ $parent->setItemSource($item);
+ $parent->setPermissions(15);
+ $map = array(
+ array(array('shareWith' => $blizzz, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array($parent)
+ ),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->never())
+ ->method('share');
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The parent shares don\'t allow resharing'
+ );
+ $this->shareManager->share($share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithOneParentAndReshareBackToOwner() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ $danimo = 'danimo';
+ $dragotin = 'dragotin';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($danimo);
+ $share->setShareWith($dragotin);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('user');
+ $parent->setShareOwner($dragotin);
+ $parent->setShareWith($danimo);
+ $parent->setItemOwner($dragotin);
+ $parent->setItemType('test');
+ $parent->setItemSource($item);
+ $parent->setPermissions(31);
+ $map = array(
+ array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array($parent)
+ ),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share can\'t reshare back to the share owner'
+ );
+ $this->shareManager->share($share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithOneParentAndReshareWithSamePeople() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ $jancborchardt = 'jancborchardt';
+ $danimo = 'danimo';
+ $group = 'group';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('group');
+ $share->setShareOwner($danimo);
+ $share->setShareWith($group);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('group');
+ $parent->setShareOwner($jancborchardt);
+ $parent->setShareWith($group);
+ $parent->setItemOwner($jancborchardt);
+ $parent->setItemType('test');
+ $parent->setItemSource($item);
+ $parent->setPermissions(31);
+ $map = array(
+ array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array($parent)
+ ),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The parent share has the same share with'
+ );
+ $this->shareManager->share($share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithTwoParents() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ $mtgap = 'MTGap';
+ $group = 'group';
+ $anybodyelse = 'AnybodyElse';
+ $georgehrke = 'georgehrke';
+ $item = 1;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($anybodyelse);
+ $share->setShareWith($georgehrke);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $share->resetUpdatedProperties();
+ $sharedShare = clone $share;
+ $sharedShare->setItemOwner($mtgap);
+ $sharedShare->setParentIds(array(1, 2));
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setShareOwner($mtgap);
+ $parent1->setShareWith($anybodyelse);
+ $parent1->setItemOwner($mtgap);
+ $parent1->setItemType('test');
+ $parent1->setItemSource($item);
+ $parent1->setPermissions(31);
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setShareTypeId('group');
+ $parent2->setShareOwner($mtgap);
+ $parent2->setShareWith($group);
+ $parent2->setItemOwner($mtgap);
+ $parent2->setItemType('test');
+ $parent2->setItemSource($item);
+ $parent2->setPermissions(31);
+ $map = array(
+ array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true,
+ 'itemSource' => $item), null, null, array($parent1, $parent2)
+ ),
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ array(array('shareOwner' => $anybodyelse, 'itemSource' => $item), null, null,
+ array($share)
+ ),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->once())
+ ->method('share')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue($share));
+ $this->shareBackend->expects($this->never())
+ ->method('update');
+ $share->resetUpdatedProperties();
+ $share = $this->shareManager->share($share);
+ $this->assertEquals($sharedShare, $share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithExistingReshares() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ $mtgap = 'MTGap';
+ $group = 'group';
+ $anybodyelse = 'AnybodyElse';
+ $georgehrke = 'georgehrke';
+ $item = 1;
+ $share = new Share();
+ $share->setId(3);
+ $share->setShareTypeId('user');
+ $share->setShareOwner($mtgap);
+ $share->setShareWith($anybodyelse);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $share->setExpirationTime(1370884027);
+ $share->resetUpdatedProperties();
+ $sharedShare = clone $share;
+ $sharedShare->setItemOwner($mtgap);
+ $duplicate = new Share();
+ $duplicate->setId(1);
+ $duplicate->setShareTypeId('group');
+ $duplicate->setShareOwner($mtgap);
+ $duplicate->setShareWith($group);
+ $duplicate->setItemOwner($mtgap);
+ $duplicate->setItemType('test');
+ $duplicate->setItemSource($item);
+ $duplicate->setPermissions(31);
+ $duplicate->setExpirationTime(1370884026);
+ $reshare = new Share();
+ $reshare->setId(2);
+ $reshare->setShareTypeId('user');
+ $reshare->setShareOwner($anybodyelse);
+ $reshare->setShareWith($georgehrke);
+ $reshare->setItemType('test');
+ $reshare->setItemSource($item);
+ $reshare->setPermissions(31);
+ $reshare->setExpirationTime(1370884026);
+ $reshare->addParentId(1);
+ $reshare->resetUpdatedProperties();
+ $updatedReshare = clone $reshare;
+ $updatedReshare->addParentId(3);
+ $map = array(
+ array(array('shareWith' => $mtgap, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array()),
+ array(array('shareOwner' => $mtgap, 'itemSource' => $item), null, null,
+ array($share, $duplicate)
+ ),
+ array(array('parentId' => 1), null, null, array($reshare)),
+ array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true,
+ 'itemSource' => $item), null, null, array($duplicate, $share)
+ ),
+ array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare)),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->once())
+ ->method('share')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue($share));
+ $this->shareBackend->expects($this->once())
+ ->method('update')
+ ->with($this->equalTo($reshare));
+ $share->resetUpdatedProperties();
+ $share = $this->shareManager->share($share);
+ $this->assertEquals($sharedShare, $share);
+ $this->assertEquals($updatedReshare, $reshare);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareWithOneParentInCollection() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+ $this->areCollectionsEnabled = true;
+
+ $jancborchardt = 'jancborchardt';
+ $danimo = 'danimo';
+ $dragotin = 'dragotin';
+ $group = 'group';
+ $item = 1;
+ $collectionItem = 2;
+ $share = new Share();
+ $share->setShareTypeId('user');
+ $share->setShareOwner($danimo);
+ $share->setShareWith($dragotin);
+ $share->setItemType('test');
+ $share->setItemSource($item);
+ $share->setPermissions(31);
+ $share->resetUpdatedProperties();
+ $sharedShare = clone $share;
+ $sharedShare->setItemOwner($jancborchardt);
+ $sharedShare->addParentId(1);
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setShareOwner($jancborchardt);
+ $parent1->setShareWith($danimo);
+ $parent1->setItemOwner($jancborchardt);
+ $parent1->setItemType('testCollection');
+ $parent1->setItemSource($collectionItem);
+ $parent1->setPermissions(31);
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setShareTypeId('user');
+ $parent2->setShareOwner($jancborchardt);
+ $parent2->setShareWith($group);
+ $parent2->setItemOwner($jancborchardt);
+ $parent2->setItemType('testCollection');
+ $parent2->setItemSource($collectionItem);
+ $parent2->setPermissions(31);
+ $sharesMap = array(
+ array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item),
+ null, null, array()),
+ array(array('id' => 1), 1, null, array()),
+ array(array('shareOwner' => $danimo, 'itemSource' => $item), null, null,
+ array($share)
+ ),
+ array(array('parentId' => 2), null, null, array()),
+ );
+ $collectionMap = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ array(array('parentId' => 2), null, null, array()),
+ );
+ $childMap = array(
+ array($share, array($parent1, $parent2)),
+ );
+ $expiredMap = array(
+ array($parent1, false),
+ array($parent2, true),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($sharesMap));
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('searchForParentCollections')
+ ->will($this->returnValueMap($childMap));
+ $this->collectionShareBackend->expects($this->any())
+ ->method('isExpired')
+ ->will($this->returnValueMap($expiredMap));
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($collectionMap));
+ $this->shareBackend->expects($this->once())
+ ->method('share')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue($share));
+ $share = $this->shareManager->share($share);
+ $this->assertEquals($sharedShare, $share);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testShareCollectionWithExistingReshares() {
+ $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+ $this->areCollectionsEnabled = true;
+
+ $mtgap = 'MTGap';
+ $group = 'group';
+ $anybodyelse = 'AnybodyElse';
+ $georgehrke = 'georgehrke';
+ $dragotin = 'dragotin';
+ $item = 1;
+ $collectionItem = 2;
+ $share = new Share();
+ $share->setId(5);
+ $share->setShareTypeId('user');
+ $share->setShareOwner($mtgap);
+ $share->setShareWith($anybodyelse);
+ $share->setItemType('testCollection');
+ $share->setItemSource($collectionItem);
+ $share->setPermissions(31);
+ $share->setExpirationTime(1370884027);
+ $share->resetUpdatedProperties();
+ $sharedShare = clone $share;
+ $sharedShare->setItemOwner($mtgap);
+ $duplicate = new Share();
+ $duplicate->setId(1);
+ $duplicate->setShareTypeId('group');
+ $duplicate->setShareOwner($mtgap);
+ $duplicate->setShareWith($group);
+ $duplicate->setItemOwner($mtgap);
+ $duplicate->setItemType('testCollection');
+ $duplicate->setItemSource($collectionItem);
+ $duplicate->setPermissions(31);
+ $duplicate->setExpirationTime(1370884026);
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('user');
+ $reshare1->setShareOwner($anybodyelse);
+ $reshare1->setShareWith($georgehrke);
+ $reshare1->setItemType('test');
+ $reshare1->setItemSource($item);
+ $reshare1->setPermissions(31);
+ $reshare1->setExpirationTime(1370884026);
+ $reshare1->addParentId(1);
+ $reshare1->resetUpdatedProperties();
+ $updatedReshare1 = clone $reshare1;
+ $updatedReshare1->addParentId(5);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('link');
+ $reshare2->setShareOwner($anybodyelse);
+ $reshare2->setItemType('testCollection');
+ $reshare2->setItemSource($collectionItem);
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(1370884020);
+ $reshare2->addParentId(1);
+ $reshare2->resetUpdatedProperties();
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->addParentId(5);
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('link');
+ $reshare3->setShareOwner($dragotin);
+ $reshare3->setItemType('testCollection');
+ $reshare3->setItemSource($collectionItem);
+ $reshare3->setPermissions(31);
+ $reshare3->setExpirationTime(1370884020);
+ $reshare3->addParentId(1);
+ $reshare3->resetUpdatedProperties();
+ $updatedReshare3 = clone $reshare3;
+ $collectionMap = array(
+ array(array('shareWith' => $mtgap, 'isShareWithUser' => true,
+ 'itemSource' => $collectionItem), null, null, array()
+ ),
+ array(array('shareOwner' => $mtgap, 'itemSource' => $collectionItem), null, null,
+ array($share, $duplicate)
+ ),
+ array(array('parentId' => 1), null, null, array($reshare2, $reshare3)),
+ array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true,
+ 'itemSource' => $collectionItem), null, null, array($duplicate, $share)
+ ),
+ array(array('shareWith' => $dragotin, 'isShareWithUser' => true,
+ 'itemSource' => $collectionItem), null, null, array($duplicate)
+ ),
+ array(array('id' => 3, 'shareTypeId' => 'link'), 1, null, array($reshare2)),
+ );
+ $sharesMap = array(
+ array(array('parentId' => 1), null, null, array($reshare1)),
+ array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true,
+ 'itemSource' => $item), null, null, array()
+ ),
+ array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare1)),
+ );
+ $childMap = array(
+ array($reshare1, array($duplicate, $share)),
+ );
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($collectionMap));
+ $this->collectionShareBackend->expects($this->once())
+ ->method('share')
+ ->with($this->equalTo($share))
+ ->will($this->returnValue($share));
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('searchForParentCollections')
+ ->will($this->returnValueMap($childMap));
+ $this->collectionShareBackend->expects($this->once())
+ ->method('update')
+ ->with($this->equalTo($reshare2));
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($sharesMap));
+ $this->shareBackend->expects($this->once())
+ ->method('update')
+ ->with($this->equalTo($reshare1));
+ $share = $this->shareManager->share($share);
+ $this->assertEquals($sharedShare, $share);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ $this->assertEquals($updatedReshare3, $reshare3);
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing);
+ }
+
+ public function testUnshareWithReshares() {
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('group');
+ $parent->setItemType('test');
+ $parent->setPermissions(31);
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('user');
+ $reshare1->setItemType('test');
+ $reshare1->addParentId(1);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('link');
+ $reshare2->setItemType('test');
+ $reshare2->addParentId(1);
+ $map = array(
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('parentId' => 3), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(3))
+ ->method('unshare');
+ $this->shareBackend->expects($this->never())
+ ->method('update');
+ $this->shareManager->unshare($parent);
+ }
+
+ public function testUnshareWithResharesAndTwoParents() {
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setItemType('test');
+ $parent1->setPermissions(31);
+ $parent1->setExpirationTime(1370884027);
+ $parent1->resetUpdatedProperties();
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('test');
+ $parent2->setPermissions(21);
+ $parent2->setExpirationTime(1370884026);
+ $parent2->resetUpdatedProperties();
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $oldReshare1 = clone $reshare1;
+ $updatedReshare1 = clone $reshare1;
+ $updatedReshare1->setPermissions(17);
+ $updatedReshare1->removeParentId(1);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(1370884027);
+ $reshare2->resetUpdatedProperties();
+ $oldReshare2 = clone $reshare2;
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->setPermissions(21);
+ $updatedReshare2->setExpirationTime(1370884026);
+ $updatedReshare2->removeParentId(1);
+ $map = array(
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 5), 1, null, array($parent2)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($oldReshare1)),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($oldReshare2)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('parentId' => 3), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(2))
+ ->method('update');
+ $this->shareBackend->expects($this->once())
+ ->method('unshare')
+ ->with($this->equalTo($parent1));
+ $this->shareManager->unshare($parent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ }
+
+ public function testUnshareWithResharesAndTwoParentsAndOneParentDoesNotExpire() {
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setItemType('test');
+ $parent1->setPermissions(31);
+ $parent1->setExpirationTime(null);
+ $parent1->resetUpdatedProperties();
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('test');
+ $parent2->setPermissions(21);
+ $parent2->resetUpdatedProperties();
+ $parent2->setExpirationTime(1370884027);
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $oldReshare1 = clone $reshare1;
+ $updatedReshare1 = clone $reshare1;
+ $updatedReshare1->setPermissions(17);
+ $updatedReshare1->removeParentId(1);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(null);
+ $reshare2->resetUpdatedProperties();
+ $oldReshare2 = clone $reshare2;
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->setPermissions(21);
+ $updatedReshare2->setExpirationTime(1370884027);
+ $updatedReshare2->removeParentId(1);
+ $map = array(
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 5), 1, null, array($parent2)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($oldReshare1)),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($oldReshare2)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('parentId' => 3), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(2))
+ ->method('update');
+ $this->shareBackend->expects($this->once())
+ ->method('unshare')
+ ->with($this->equalTo($parent1));
+ $this->shareManager->unshare($parent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ }
+
+ public function testUnshareCollectionWithResharesAndDifferentParents() {
+ $this->areCollectionsEnabled = true;
+ $item = 1;
+ $collectionItem = 2;
+
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setItemType('testCollection');
+ $parent1->setItemSource($collectionItem);
+ $parent1->setPermissions(31);
+ $parent1->setExpirationTime(1370884027);
+ $parent1->resetUpdatedProperties();
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('testCollection');
+ $parent2->setItemSource($collectionItem);
+ $parent2->setPermissions(21);
+ $parent2->setExpirationTime(1370884026);
+ $parent2->resetUpdatedProperties();
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('user');
+ $reshare1->setItemType('test');
+ $reshare1->setItemSource($item);
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $oldReshare1 = clone $reshare1;
+ $updatedReshare1 = clone $reshare1;
+ $updatedReshare1->setPermissions(17);
+ $updatedReshare1->removeParentId(1);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('link');
+ $reshare2->setItemType('testCollection');
+ $reshare2->setItemSource($collectionItem);
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(1370884027);
+ $reshare2->resetUpdatedProperties();
+ $oldReshare2 = clone $reshare2;
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->setPermissions(21);
+ $updatedReshare2->setExpirationTime(1370884026);
+ $updatedReshare2->removeParentId(1);
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('link');
+ $reshare3->setItemType('testCollection');
+ $reshare3->setItemSource($collectionItem);
+ $reshare3->setPermissions(31);
+ $reshare3->setExpirationTime(1370884020);
+ $reshare3->addParentId(1);
+ $reshare3->resetUpdatedProperties();
+ $sharesMap = array(
+ array(array('parentId' => 1), null, null, array($reshare1)),
+ array(array('id' => 5), 1, null, array()),
+ array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($oldReshare1)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('parentId' => 3), null, null, array()),
+ array(array('parentId' => 4), null, null, array()),
+ );
+ $collectionMap = array(
+ array(array('parentId' => 1), null, null, array($reshare2, $reshare3)),
+ array(array('id' => 5), 1, null, array($parent2)),
+ array(array('id' => 3, 'shareTypeId' => 'link'), 1, null, array($oldReshare2)),
+ array(array('id' => 4, 'shareTypeId' => 'link'), 1, null, array($reshare3)),
+ array(array('parentId' => 3), null, null, array()),
+ array(array('parentId' => 4), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($sharesMap));
+ $this->shareBackend->expects($this->once())
+ ->method('update');
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($collectionMap));
+ $this->collectionShareBackend->expects($this->once())
+ ->method('update');
+ $this->collectionShareBackend->expects($this->exactly(2))
+ ->method('unshare');
+ $this->shareManager->unshare($parent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ }
+
+ public function testUpdateWithShareDoesNotExist() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setShareTypeId('group');
+ $share->setItemType('test');
+ $share->resetUpdatedProperties();
+ $share->setExpirationTime(1370884024);
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'group'), 1, null, array()),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException',
+ 'A share does not exist with the id 1'
+ );
+ $this->shareManager->update($share);
+ }
+
+ public function testUpdateResharesWithOneParent() {
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('user');
+ $parent->setItemType('test');
+ $parent->setPermissions(31);
+ $parent->setExpirationTime(null);
+ $parent->resetUpdatedProperties();
+ $updatedParent = clone $parent;
+ $updatedParent->setPermissions(19);
+ $updatedParent->setExpirationTime(1370884025);
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->addParentId(1);
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $oldReshare1 = clone $reshare1;
+ $updatedReshare1 = clone $reshare1;
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->addParentId(1);
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(null);
+ $reshare2->resetUpdatedProperties();
+ $oldReshare2 = clone $reshare2;
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->setPermissions(19);
+ $updatedReshare2->setExpirationTime(1370884025);
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setItemType('test');
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(15);
+ $reshare3->setExpirationTime(1370884026);
+ $reshare3->resetUpdatedProperties();
+ $oldReshare3 = clone $reshare3;
+ $updatedReshare3 = clone $reshare3;
+ $updatedReshare3->setPermissions(3);
+ $updatedReshare3->setExpirationTime(1370884025);
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'user'), 1, null, array($parent)),
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 1), 1, null, array($parent)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($oldReshare1)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($oldReshare2)),
+ array(array('parentId' => 3), null, null, array($reshare3)),
+ array(array('id' => 3), 1, null, array($reshare2)),
+ array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($oldReshare3)),
+ array(array('parentId' => 4), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(3))
+ ->method('update');
+ $this->shareManager->update($updatedParent);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ $this->assertEquals($updatedReshare3, $reshare3);
+ }
+
+ public function testUpdateResharesWithOneParentAndSharePermissionRemoved() {
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setShareTypeId('user');
+ $parent->setItemType('test');
+ $parent->setPermissions(31);
+ $parent->resetUpdatedProperties();
+ $updatedParent = clone $parent;
+ $updatedParent->setPermissions(15);
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->addParentId(1);
+ $reshare1->setPermissions(19);
+ $reshare1->resetUpdatedProperties();
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->addParentId(1);
+ $reshare2->setPermissions(31);
+ $reshare2->resetUpdatedProperties();
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setItemType('test');
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(15);
+ $reshare3->resetUpdatedProperties();
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'user'), 1, null, array($parent)),
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 1), 1, null, array($parent)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($reshare1)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($reshare2)),
+ array(array('parentId' => 3), null, null, array($reshare3)),
+ array(array('id' => 3), 1, null, array($reshare2)),
+ array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($reshare3)),
+ array(array('parentId' => 4), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->once())
+ ->method('update');
+ $this->shareBackend->expects($this->exactly(3))
+ ->method('unshare');
+ $this->shareManager->update($updatedParent);
+ }
+
+ public function testUpdateResharesWithTwoParents() {
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setItemType('test');
+ $parent1->setPermissions(31);
+ $parent1->setExpirationTime(1370884027);
+ $parent1->resetUpdatedProperties();
+ $updatedParent1 = clone $parent1;
+ $updatedParent1->setPermissions(19);
+ $updatedParent1->setExpirationTime(1370884025);
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('test');
+ $parent2->setPermissions(21);
+ $parent2->setExpirationTime(1370884026);
+ $parent2->resetUpdatedProperties();
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $oldReshare1 = clone $reshare1;
+ $updatedReshare1 = clone $reshare1;
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(1370884027);
+ $reshare2->resetUpdatedProperties();
+ $oldReshare2 = clone $reshare2;
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->setPermissions(23);
+ $updatedReshare2->setExpirationTime(1370884026);
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setItemType('test');
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(15);
+ $reshare3->setExpirationTime(1370884026);
+ $reshare3->resetUpdatedProperties();
+ $oldReshare3 = clone $reshare3;
+ $updatedReshare3 = clone $reshare3;
+ $updatedReshare3->setPermissions(7);
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'user'), 1, null, array($parent1)),
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 1), 1, null, array($updatedParent1)),
+ array(array('id' => 5), 1, null, array($parent2)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($oldReshare1)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($oldReshare2)),
+ array(array('parentId' => 3), null, null, array($reshare3)),
+ array(array('id' => 3), 1, null, array($reshare2)),
+ array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($oldReshare3)),
+ array(array('parentId' => 4), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(3))
+ ->method('update');
+ $this->shareManager->update($updatedParent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ $this->assertEquals($updatedReshare3, $reshare3);
+ }
+
+ public function testUpdateResharesWithTwoParentsAndSharePermissionRemoved() {
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setItemType('test');
+ $parent1->setPermissions(31);
+ $parent1->setExpirationTime(1370884027);
+ $parent1->resetUpdatedProperties();
+ $updatedParent1 = clone $parent1;
+ $updatedParent1->setPermissions(3);
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('test');
+ $parent2->setPermissions(21);
+ $parent2->setExpirationTime(1370884026);
+ $parent2->resetUpdatedProperties();
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $oldReshare1 = clone $reshare1;
+ $updatedReshare1 = clone $reshare1;
+ $updatedReshare1->setPermissions(17);
+ $updatedReshare1->removeParentId(1);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(1370884027);
+ $reshare2->resetUpdatedProperties();
+ $oldReshare2 = clone $reshare2;
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->setPermissions(21);
+ $updatedReshare2->setExpirationTime(1370884026);
+ $updatedReshare2->removeParentId(1);
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setItemType('test');
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(15);
+ $reshare3->setExpirationTime(1370884027);
+ $reshare3->resetUpdatedProperties();
+ $oldReshare3 = clone $reshare3;
+ $updatedReshare3 = clone $reshare3;
+ $updatedReshare3->setPermissions(5);
+ $updatedReshare3->setExpirationTime(1370884026);
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'user'), 1, null, array($parent1)),
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 1), 1, null, array($updatedParent1)),
+ array(array('id' => 5), 1, null, array($updatedParent2)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($oldReshare1)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($oldReshare2)),
+ array(array('parentId' => 3), null, null, array($reshare3)),
+ array(array('id' => 3), 1, null, array($updatedReshare2)),
+ array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($oldReshare3)),
+ array(array('parentId' => 4), null, null, array()),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(4))
+ ->method('update');
+ $this->shareManager->update($updatedParent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ $this->assertEquals($updatedReshare3, $reshare3);
+ }
+
+ public function testUpdateResharesWithSharePermissionAdded() {
+ $tanghus = 'tanghus';
+ $DeepDiver = 'DeepDiver';
+ $tpn = 'tpn';
+ $zimba12 = 'zimba12';
+ $group1 = 'group1';
+ $group2 = 'group2';
+ $item = 1;
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setShareOwner($tanghus);
+ $parent1->setShareWith($DeepDiver);
+ $parent1->setItemType('test');
+ $parent1->setItemSource($item);
+ $parent1->setPermissions(15);
+ $parent1->setExpirationTime(null);
+ $parent1->resetUpdatedProperties();
+ $updatedParent1 = clone $parent1;
+ $updatedParent1->setPermissions(31);
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setShareOwner($tanghus);
+ $parent2->setShareWith($group1);
+ $parent2->setItemType('test');
+ $parent2->setItemSource($item);
+ $parent2->setPermissions(21);
+ $parent2->setExpirationTime(1370884020);
+ $parent2->resetUpdatedProperties();
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setShareOwner($DeepDiver);
+ $reshare1->setItemType('test');
+ $reshare1->setItemSource($item);
+ $reshare1->addParentId(5);
+ $reshare1->setPermissions(17);
+ $reshare1->setExpirationTime(1370884019);
+ $reshare1->resetUpdatedProperties();
+ $updatedReshare1 = clone $reshare1;
+ $updatedReshare1->addParentId(1);
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setShareOwner($DeepDiver);
+ $reshare2->setShareWith($group2);
+ $reshare2->setItemType('test');
+ $reshare2->setItemSource($item);
+ $reshare2->addParentId(5);
+ $reshare2->setPermissions(21);
+ $reshare2->setExpirationTime(1370884020);
+ $reshare2->resetUpdatedProperties();
+ $updatedReshare2 = clone $reshare2;
+ $updatedReshare2->addParentId(1);
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setShareOwner($tpn);
+ $reshare3->setShareWith($zimba12);
+ $reshare3->setItemType('test');
+ $reshare3->setItemSource($item);
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(5);
+ $reshare3->setExpirationTime(1370884020);
+ $reshare3->resetUpdatedProperties();
+ $updatedReshare3 = clone $reshare3;
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'user'), 1, null, array($parent1)),
+ array(array('shareOwner' => $tanghus, 'itemSource' => $item), null, null,
+ array($parent1, $parent2)
+ ),
+ array(array('parentId' => 5), null, null, array($reshare1, $reshare2)),
+ array(array('shareWith' => $DeepDiver, 'isShareWithUser' => true,
+ 'itemSource' => $item), null, null, array($parent1, $parent2)
+ ),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($reshare1)),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($reshare2)),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->exactly(3))
+ ->method('update');
+ $this->shareManager->update($updatedParent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ $this->assertEquals($updatedReshare3, $reshare3);
+ }
+
+ public function testUpdateResharesTwoParentsAndOneParentDoesNotExpire() {
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setShareTypeId('user');
+ $parent1->setItemType('test');
+ $parent1->setPermissions(31);
+ $parent1->setExpirationTime(1370884027);
+ $parent1->resetUpdatedProperties();
+ $updatedParent1 = clone $parent1;
+ $updatedParent1->setExpirationTime(1370884025);
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('test');
+ $parent2->setPermissions(21);
+ $parent2->setExpirationTime(null);
+ $updatedParent2 = clone $parent2;
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(19);
+ $reshare1->setExpirationTime(1370884024);
+ $reshare1->resetUpdatedProperties();
+ $updatedReshare1 = clone $reshare1;
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(31);
+ $reshare2->setExpirationTime(null);
+ $reshare2->resetUpdatedProperties();
+ $updatedReshare2 = clone $reshare2;
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setItemType('test');
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(15);
+ $reshare3->setExpirationTime(1370884028);
+ $reshare3->resetUpdatedProperties();
+ $updatedReshare3 = clone $reshare3;
+ $map = array(
+ array(array('id' => 1, 'shareTypeId' => 'user'), 1, null, array($parent1)),
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 5), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->once())
+ ->method('update');
+ $this->shareManager->update($updatedParent1);
+ $this->assertEquals($updatedParent2, $parent2);
+ $this->assertEquals($updatedReshare1, $reshare1);
+ $this->assertEquals($updatedReshare2, $reshare2);
+ $this->assertEquals($updatedReshare3, $reshare3);
+ }
+
+ public function testGetSharesWithExpiredShare() {
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setItemType('test');
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->setItemType('test');
+ $share3 = new Share();
+ $share3->setId(3);
+ $share3->setItemType('test');
+ $map = array(
+ array(array(), null, null, array($share1, $share2, $share3)),
+ array(array('parentId' => 2), null, null, array()),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->at(2))
+ ->method('isExpired')
+ ->will($this->returnValue(true));
+ $this->shareBackend->expects($this->once())
+ ->method('unshare')
+ ->with($this->equalTo($share2));
+ $shares = $this->shareManager->getShares('test');
+ $this->assertEquals(2, count($shares));
+ $this->assertContains($share1, $shares);
+ $this->assertContains($share3, $shares);
+ }
+
+ public function testGetSharesWithExpiredSharesAndLimit() {
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setItemType('test');
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->setItemType('test');
+ $share3 = new Share();
+ $share3->setId(3);
+ $share3->setItemType('test');
+ $share4 = new Share();
+ $share4->setId(4);
+ $share4->setItemType('test');
+ $map = array(
+ array(array(), 3, null, array($share1, $share2, $share3)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array(), 1, 2, array($share4)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->at(2))
+ ->method('isExpired')
+ ->will($this->returnValue(true));
+ $this->shareBackend->expects($this->once())
+ ->method('unshare')
+ ->with($this->equalTo($share2));
+ $shares = $this->shareManager->getShares('test', array(), 3);
+ $this->assertCount(3, $shares);
+ $this->assertContains($share1, $shares);
+ $this->assertContains($share3, $shares);
+ $this->assertContains($share4, $shares);
+ }
+
+ public function testGetSharesWithExpiredSharesAndLimitOffset() {
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->setItemType('test');
+ $share3 = new Share();
+ $share3->setId(3);
+ $share3->setItemType('test');
+ $share4 = new Share();
+ $share4->setId(4);
+ $share4->setItemType('test');
+ $share5 = new Share();
+ $share5->setId(5);
+ $share5->setItemType('test');
+ $map = array(
+ array(array(), 3, 1, array($share2, $share3, $share4)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array(), 1, 3, array($share5)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->at(1))
+ ->method('isExpired')
+ ->will($this->returnValue(true));
+ $this->shareBackend->expects($this->once())
+ ->method('unshare')
+ ->with($this->equalTo($share2));
+ $shares = $this->shareManager->getShares('test', array(), 3, 1);
+ $this->assertCount(3, $shares);
+ $this->assertContains($share3, $shares);
+ $this->assertContains($share4, $shares);
+ $this->assertContains($share5, $shares);
+ }
+
+ public function testGetShareById() {
+ $share = new Share();
+ $share->setId(1);
+ $share->setItemType('testCollection');
+ $share->setShareTypeId('link');
+ $collectionMap = array(
+ array(array('id' => 1, 'shareTypeId' => 'link'), 1, null, array($share)),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->throwException(new ShareTypeDoesNotExistException(
+ 'No share type found matching id'
+ )));
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($collectionMap));
+ $this->assertEquals($share, $this->shareManager->getShareById(1, null, 'link'));
+ }
+
+ public function testGetShareByIdWithMultipleSharesReturned() {
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setItemType('test');
+ $share2 = new Share();
+ $share2->setId(1);
+ $share2->setItemType('test');
+ $map = array(
+ array(array('id' => 1), 1, null, array($share1, $share2)),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\MultipleSharesReturnedException',
+ 'Multiple shares were returned for the id 1'
+ );
+ $this->shareManager->getShareById(1, 'test');
+ }
+
+ public function testUnshareItem() {
+ $item = 1;
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent1->setShareTypeId('user');
+ $parent1->setItemSource($item);
+ $parent1->setPermissions(31);
+ $parent1->resetUpdatedProperties();
+ $parent2 = new Share();
+ $parent2->setId(5);
+ $parent2->setShareTypeId('group');
+ $parent2->setItemType('test');
+ $parent2->setItemSource($item);
+ $parent2->setPermissions(21);
+ $reshare1 = new Share();
+ $reshare1->setId(2);
+ $reshare1->setShareTypeId('link');
+ $reshare1->setItemType('test');
+ $reshare1->setItemSource($item);
+ $reshare1->setParentIds(array(1, 5));
+ $reshare1->setPermissions(17);
+ $reshare1->resetUpdatedProperties();
+ $reshare2 = new Share();
+ $reshare2->setId(3);
+ $reshare2->setShareTypeId('group');
+ $reshare2->setItemType('test');
+ $reshare2->setItemSource($item);
+ $reshare2->setParentIds(array(1, 5));
+ $reshare2->setPermissions(21);
+ $reshare2->resetUpdatedProperties();
+ $reshare3 = new Share();
+ $reshare3->setId(4);
+ $reshare3->setShareTypeId('user');
+ $reshare3->setItemType('test');
+ $reshare3->setItemSource($item);
+ $reshare3->addParentId(3);
+ $reshare3->setPermissions(5);
+ $reshare3->resetUpdatedProperties();
+ $map = array(
+ array(array('itemSource' => $item), null, null,
+ array($parent1, $parent2, $reshare1, $reshare2, $reshare3)
+ ),
+ array(array('parentId' => 1), null, null, array($reshare1, $reshare2)),
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 5), 1, null, array($parent2)),
+ array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($reshare1)),
+ array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($reshare2)),
+ array(array('parentId' => 5), null, null, array($reshare1, $reshare2)),
+ array(array('parentId' => 2), null, null, array()),
+ array(array('parentId' => 3), null, null, array($reshare3)),
+ array(array('id' => 5), 1, null, array($reshare2)),
+ array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($reshare3)),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareBackend->expects($this->any())
+ ->method('unshare');
+ $this->shareManager->unshareItem('test', $item);
+ }
+
+ public function testGetReshares() {
+ $share1 = new Share();
+ $share1->setItemType('test');
+ $share2 = new Share();
+ $share2->setItemType('test');
+ $share3 = new Share();
+ $share3->setItemType('test');
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $share1->addParentId(1);
+ $share2->addParentId(1);
+ $share3->addParentId(1);
+ $map = array(
+ array(array('parentId' => 1), null, null, array($share1, $share2, $share3)),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $reshares = $this->shareManager->getReshares($parent);
+ $this->assertCount(3, $reshares);
+ $this->assertContains($share1, $reshares);
+ $this->assertContains($share2, $reshares);
+ $this->assertContains($share3, $reshares);
+ }
+
+ public function testGetResharesWithNoReshares() {
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $map = array(
+ array(array('parentId' => 1), null, null, array()),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->assertEmpty($this->shareManager->getReshares($parent));
+ }
+
+ public function testGetResharesInCollection() {
+ $this->areCollectionsEnabled = true;
+
+ $share1 = new Share();
+ $share1->setItemType('test');
+ $share2 = new Share();
+ $share2->setItemType('testCollection');
+ $share3 = new Share();
+ $share3->setItemType('test');
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('testCollection');
+ $share1->addParentId(1);
+ $share2->addParentId(1);
+ $share3->addParentId(1);
+ $shareMap = array(
+ array(array('parentId' => 1), null, null, array($share1, $share3)),
+ );
+ $collectionMap = array(
+ array(array('parentId' => 1), null, null, array($share2)),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($shareMap));
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($collectionMap));
+ $reshares = $this->shareManager->getReshares($parent);
+ $this->assertCount(3, $reshares);
+ $this->assertContains($share1, $reshares);
+ $this->assertContains($share2, $reshares);
+ $this->assertContains($share3, $reshares);
+ }
+
+ public function testGetParents() {
+ $share = new Share();
+ $share->setItemType('test');
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('test');
+ $parent3 = new Share();
+ $parent3->setId(3);
+ $parent3->setItemType('test');
+ $share->setParentIds(array(1, 2, 3));
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ array(array('id' => 3), 1, null, array($parent3)),
+ );
+ $this->shareBackend->expects($this->exactly(3))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $parents = $this->shareManager->getParents($share);
+ $this->assertCount(3, $parents);
+ $this->assertContains($parent1, $parents);
+ $this->assertContains($parent2, $parents);
+ $this->assertContains($parent3, $parents);
+ }
+
+ public function testGetParentsInCollection() {
+ $this->areCollectionsEnabled = true;
+
+ $share = new Share();
+ $share->setItemType('test');
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('testCollection');
+ $share->setParentIds(array(1, 2));
+ $sharesMap = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array()),
+ );
+ $collectionMap = array(
+ array(array('id' => 1), 1, null, array()),
+ array(array('id' => 2), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($sharesMap));
+ $this->collectionShareBackend->expects($this->atLeastOnce())
+ ->method('getShares')
+ ->will($this->returnValueMap($collectionMap));
+ $parents = $this->shareManager->getParents($share);
+ $this->assertCount(2, $parents);
+ $this->assertContains($parent1, $parents);
+ $this->assertContains($parent2, $parents);
+ }
+
+ public function testGetParentsWithNoParents() {
+ $share = new Share();
+ $this->shareBackend->expects($this->never())
+ ->method('getShares');
+ $this->collectionShareBackend->expects($this->never())
+ ->method('getShares');
+ $this->assertEmpty($this->shareManager->getParents($share));
+ }
+
+ public function testGetParentsWithNotExistingParent() {
+ $share = new Share();
+ $share->setItemType('test');
+ $share->addParentId(1);
+ $map = array(
+ array(array('id' => 1), 1, null, array()),
+ );
+ $this->shareBackend->expects($this->once())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException',
+ 'A share does not exist with the id 1'
+ );
+ $this->shareManager->getParents($share);
+ }
+
+ public function testAreValidPermissionsWithOneParent() {
+ // Share and parent have all permissions
+ $share = new Share();
+ $share->setItemType('test');
+ $share->setPermissions(31);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $parent->setPermissions(31);
+ $share->addParentId(1);
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share));
+
+ // Share permissions are only Read and parent permissions are only Read, Update, and Share
+ $share->setPermissions(1);
+ $parent->setPermissions(19);
+ $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share));
+ }
+
+ public function testAreValidPermissionsWithOneParentAndShareExceedsPermissions() {
+ // Share has all permissions and parent permissions are only Read, Update, and Share
+ $share = new Share();
+ $share->setItemType('test');
+ $share->setPermissions(31);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $parent->setPermissions(19);
+ $share->addParentId(1);
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException',
+ 'The permissions exceeds the parent shares\' permissions'
+ );
+ $this->shareManager->pAreValidPermissionsForParents($share);
+ }
+
+ public function testAreValidPermissionsWithTwoParents() {
+ // Share has all permissions, 1 parent has only Read, Update, and Share
+ // The other parent has only Read, Create, Delete, and Share
+ $share = new Share();
+ $share->setItemType('test');
+ $share->setPermissions(31);
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent1->setPermissions(19);
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('test');
+ $parent2->setPermissions(29);
+ $share->setParentIds(array(1, 2));
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share));
+
+ // Share and parent remove Create permission
+ $share->setPermissions(27);
+ $parent2->setPermissions(25);
+ $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share));
+ }
+
+ public function testAreValidPermissionsWithTwoParentsAndShareExceedsPermissions() {
+ // Share has all permissions, 1 parent has only Read, Update, and Share
+ // The other parent has only Read, Delete, and Share
+ $share = new Share();
+ $share->setItemType('test');
+ $share->setPermissions(31);
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent1->setPermissions(19);
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('test');
+ $parent2->setPermissions(25);
+ $share->setParentIds(array(1, 2));
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException',
+ 'The permissions exceeds the parent shares\' permissions'
+ );
+ $this->shareManager->pAreValidPermissionsForParents($share);
+ }
+
+ public function testIsValidExpirationTimeWithOneParent() {
+ // Share and parent have no expiration time
+ $share = new Share();
+ $share->setItemType('test');
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $share->addParentId(1);
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+
+ // Share expires 1 second before parent
+ $share->setExpirationTime(1370884024);
+ $parent->setExpirationTime(1370884025);
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+ }
+
+ public function testIsValidExpirationTimeWithOneParentExpiresAndShareDoesNotExpire() {
+ // Parent expires, share has no expiration time
+ $share = new Share();
+ $share->setItemType('test');
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $parent->setExpirationTime(1370884025);
+ $share->addParentId(1);
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time exceeds the parent shares\' expiration times'
+ );
+ $this->shareManager->pIsValidExpirationTimeForParents($share);
+ }
+
+ public function testIsValidExpirationTimeWithOneParentExpiresAndShareExpiresAfter() {
+ // Share expires 1 second after parent
+ $share = new Share();
+ $share->setItemType('test');
+ $share->setExpirationTime(1370884026);
+ $parent = new Share();
+ $parent->setId(1);
+ $parent->setItemType('test');
+ $parent->setExpirationTime(1370884025);
+ $share->addParentId(1);
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time exceeds the parent shares\' expiration times'
+ );
+ $this->shareManager->pIsValidExpirationTimeForParents($share);
+ }
+
+ public function testIsValidExpirationTimeWithTwoParents() {
+ // Share and parents have no expiration time
+ $share = new Share();
+ $share->setItemType('test');
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('test');
+ $share->setParentIds(array(1, 2));
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+
+ // 1 parent expires, the other parent and share have no expiration time
+ $parent1->setExpirationTime(1370884025);
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+
+ // Share expires 1 second after 1 parent, the other parent has no expiration time
+ $share->setExpirationTime(1370884026);
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+
+ // 1 parent expires 1 second before share, the other parent expires 1 second after share
+ $parent2->setExpirationTime(1370884027);
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+
+ // Share expires 1 second before both parents
+ $share->setExpirationTime(1370884024);
+ $parent2->setExpirationTime(1370884025);
+ $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share));
+ }
+
+ public function testIsValidExpirationTimeWithTwoParentsExpireAndShareDoesNotExpire() {
+ // Both parents expire, and share has no expiration time
+ $share = new Share();
+ $share->setItemType('test');
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent1->setExpirationTime(1370884025);
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('test');
+ $parent2->setExpirationTime(1370884026);
+ $share->setParentIds(array(1, 2));
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time exceeds the parent shares\' expiration times'
+ );
+ $this->shareManager->pIsValidExpirationTimeForParents($share);
+ }
+
+ public function testIsValidExpirationTimeWithTwoParentsExpireAndShareExpiresAfter() {
+ // Both parents expire before share
+ $share = new Share();
+ $share->setItemType('test');
+ $share->setExpirationTime(1370884026);
+ $parent1 = new Share();
+ $parent1->setId(1);
+ $parent1->setItemType('test');
+ $parent1->setExpirationTime(1370884024);
+ $parent2 = new Share();
+ $parent2->setId(2);
+ $parent2->setItemType('test');
+ $parent2->setExpirationTime(1370884025);
+ $share->setParentIds(array(1, 2));
+ $map = array(
+ array(array('id' => 1), 1, null, array($parent1)),
+ array(array('id' => 2), 1, null, array($parent2)),
+ );
+ $this->shareBackend->expects($this->any())
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException',
+ 'The expiration time exceeds the parent shares\' expiration times'
+ );
+ $this->shareManager->pIsValidExpirationTimeForParents($share);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php
new file mode 100644
index 000000000000..17771d45bd26
--- /dev/null
+++ b/tests/lib/share/sharetype/group.php
@@ -0,0 +1,676 @@
+.
+ */
+
+namespace Test\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+
+class TestGroup extends \OC\Share\ShareType\Group {
+
+ public function getId() {
+ return 'testgroup';
+ }
+
+}
+
+class Group extends ShareType {
+
+ private $itemTargetMachine;
+ private $groupManager;
+ private $userManager;
+ private $mtgap;
+ private $mtgapDisplay;
+ private $karlitschek;
+ private $karlitschekDisplay;
+ private $icewind;
+ private $icewindDisplay;
+ private $group1;
+ private $group1Display;
+ private $group2;
+ private $group2Display;
+
+ protected function setUp() {
+ $this->mtgap = 'MTGap';
+ $this->mtgapDisplay = 'Michael Gapczynski';
+ $this->karlitschek = 'karlitschek';
+ $this->karlitschekDisplay = 'Frank Karlitschek';
+ $this->icewind = 'Icewind';
+ $this->icewindDisplay = 'Robin Appelman';
+ $this->group1 = 'group1';
+ $this->group2 = 'group2';
+ $this->group1Display = 'group1 (group)';
+ $this->group2Display = 'group2 (group)';
+ $this->itemTargetMachine = $this->getMockBuilder('\OC\Share\ItemTargetMachine')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager = $this->getMockBuilder('\OC\User\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->instance = new TestGroup('test', new ShareFactory(), $this->itemTargetMachine,
+ $this->groupManager, $this->userManager
+ );
+ }
+
+ protected function getTestShare($version) {
+ $share = new Share();
+ $share->setShareTypeId($this->instance->getId());
+ $share->setItemType('test');
+ $share->setItemSource('23');
+ $share->setPermissions(31);
+ $share->setShareTime(1370797580);
+ $mtgapUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mtgapUser->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue($this->mtgap));
+ $mtgapUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->mtgapDisplay));
+ $karlitschekUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $karlitschekUser->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue($this->karlitschek));
+ $karlitschekUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->karlitschekDisplay));
+ $icewindUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $icewindUser->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue($this->icewind));
+ $icewindUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->icewindDisplay));
+ $userMap = array(
+ array($this->mtgap, $mtgapUser),
+ array($this->karlitschek, $karlitschekUser),
+ array($this->icewind, $icewindUser),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('get')
+ ->will($this->returnValueMap($userMap));
+ $group1Group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1Group->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue($this->group1Display));
+ $group1Group->expects($this->any())
+ ->method('getUsers')
+ ->will($this->returnValue(array($mtgapUser, $karlitschekUser)));
+ $group2Group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2Group->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue($this->group2Display));
+ $group2Group->expects($this->any())
+ ->method('getUsers')
+ ->will($this->returnValue(array($mtgapUser, $karlitschekUser, $icewindUser)));
+ $groupMap = array(
+ array($this->group1, $group1Group),
+ array($this->group2, $group2Group),
+ );
+ $this->groupManager->expects($this->any())
+ ->method('get')
+ ->will($this->returnValueMap($groupMap));
+ switch ($version) {
+ case 1:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareWith($this->group1);
+ $this->itemTargetMachine->expects($this->at(1))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($karlitschekUser))
+ ->will($this->returnValue('Frank\'s Target'));
+ break;
+ case 2:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareWith($this->group2);
+ $this->itemTargetMachine->expects($this->at(1))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($karlitschekUser))
+ ->will($this->returnValue('Frank\'s Target'));
+ $this->itemTargetMachine->expects($this->at(2))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($icewindUser))
+ ->will($this->returnValue('Robin\'s Target'));
+ break;
+ case 3:
+ $share->setShareOwner($this->icewind);
+ $share->setItemOwner($this->icewind);
+ $share->setShareWith($this->group1);
+ $this->itemTargetMachine->expects($this->at(1))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($mtgapUser))
+ ->will($this->returnValue('Michael\'s Target'));
+ $this->itemTargetMachine->expects($this->at(2))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($karlitschekUser))
+ ->will($this->returnValue('Frank\'s Target'));
+ break;
+ case 4:
+ $share->setShareOwner($this->karlitschek);
+ $share->setItemOwner($this->karlitschek);
+ $share->setShareWith($this->group2);
+ $this->itemTargetMachine->expects($this->at(1))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($mtgapUser))
+ ->will($this->returnValue('Michael\'s Target'));
+ $this->itemTargetMachine->expects($this->at(2))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo($icewindUser))
+ ->will($this->returnValue('Robin\'s Target'));
+ break;
+ }
+ $this->itemTargetMachine->expects($this->at(0))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share), $this->equalTo(null))
+ ->will($this->returnValue('Group Target'));
+ return $share;
+ }
+
+ protected function getSharedTestShare($version) {
+ $share = new Share();
+ $share->setShareTypeId($this->instance->getId());
+ $share->setItemType('test');
+ $share->setItemSource('23');
+ $share->setPermissions(31);
+ $share->setShareTime(1370797580);
+ switch ($version) {
+ case 1:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareOwnerDisplayName($this->mtgapDisplay);
+ $share->setShareWith($this->group1);
+ $share->setShareWithDisplayName($this->group1Display);
+ $share->setItemTarget(array('Group Target', 'users' => array(
+ $this->karlitschek => 'Frank\'s Target'
+ )
+ ));
+ break;
+ case 2:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareOwnerDisplayName($this->mtgapDisplay);
+ $share->setShareWith($this->group2);
+ $share->setShareWithDisplayName($this->group2Display);
+ $share->setItemTarget(array('Group Target', 'users' => array(
+ $this->karlitschek => 'Frank\'s Target',
+ $this->icewind => 'Robin\'s Target',
+ )
+ ));
+ break;
+ case 3:
+ $share->setShareOwner($this->icewind);
+ $share->setItemOwner($this->icewind);
+ $share->setShareOwnerDisplayName($this->icewindDisplay);
+ $share->setShareWith($this->group1);
+ $share->setShareWithDisplayName($this->group1Display);
+ $share->setItemTarget(array('Group Target', 'users' => array(
+ $this->mtgap => 'Michael\'s Target',
+ $this->karlitschek => 'Frank\'s Target',
+ )
+ ));
+ break;
+ case 4:
+ $share->setShareOwner($this->karlitschek);
+ $share->setItemOwner($this->karlitschek);
+ $share->setShareOwnerDisplayName($this->karlitschekDisplay);
+ $share->setShareWith($this->group2);
+ $share->setShareWithDisplayName($this->group2Display);
+ $share->setItemTarget(array('Group Target', 'users' => array(
+ $this->mtgap => 'Michael\'s Target',
+ $this->icewind => 'Robin\'s Target',
+ )
+ ));
+ break;
+ }
+ return $share;
+ }
+
+ public function testIsValidShare() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $jancborchardt = 'jancborchardt';
+ $designers = 'designers';
+ $share = new Share();
+ $share->setShareOwner($jancborchardt);
+ $share->setShareWith($designers);
+ $map = array(
+ array($jancborchardt, true),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->once())
+ ->method('groupExists')
+ ->with($this->equalTo($designers))
+ ->will($this->returnValue(true));
+ $this->assertTrue($this->instance->isValidShare($share));
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testIsValidShareWithShareOwnerDoesNotExist() {
+ $bar = 'bar';
+ $designers = 'designers';
+ $share = new Share();
+ $share->setShareOwner($bar);
+ $share->setShareWith($designers);
+ $map = array(
+ array($bar, false),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->any())
+ ->method('groupExists')
+ ->with($this->equalTo($designers))
+ ->will($this->returnValue(true));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share owner does not exist'
+ );
+ $this->instance->isValidShare($share);
+ }
+
+ public function testIsValidShareWithShareWithDoesNotExist() {
+ $jakobsack = 'jakobsack';
+ $share = new Share();
+ $share->setShareOwner($jakobsack);
+ $share->setShareWith('foo');
+ $map = array(
+ array($jakobsack, true),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->once())
+ ->method('groupExists')
+ ->with($this->equalTo('foo'))
+ ->will($this->returnValue(false));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The group shared with does not exist'
+ );
+ $this->instance->isValidShare($share);
+ }
+
+ public function testIsValidShareWithGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $jancborchardt = 'jancborchardt';
+ $designers = 'designers';
+ $share = new Share();
+ $share->setShareOwner($jancborchardt);
+ $share->setShareWith($designers);
+ $map = array(
+ array($jancborchardt, true),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->once())
+ ->method('groupExists')
+ ->with($this->equalTo($designers))
+ ->will($this->returnValue(true));
+ $group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo($designers))
+ ->will($this->returnValue($group));
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($jancborchardt)
+ ->will($this->returnValue($shareOwnerUser));
+ $group->expects($this->once())
+ ->method('inGroup')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(true));
+ $this->assertTrue($this->instance->isValidShare($share));
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testIsValidShareWithShareOwnerNotInGroupAndGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $jancborchardt = 'jancborchardt';
+ $designers = 'designers';
+ $share = new Share();
+ $share->setShareOwner($jancborchardt);
+ $share->setShareWith($designers);
+ $map = array(
+ array($jancborchardt, true),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->once())
+ ->method('groupExists')
+ ->with($this->equalTo($designers))
+ ->will($this->returnValue(true));
+ $group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo($designers))
+ ->will($this->returnValue($group));
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($jancborchardt)
+ ->will($this->returnValue($shareOwnerUser));
+ $group->expects($this->once())
+ ->method('inGroup')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(false));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share owner is not in the group shared with as required by '.
+ 'the groups only sharing policy set by the admin'
+ );
+ $this->instance->isValidShare($share);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSetItemTarget() {
+ $share = $this->getTestShare(3);
+ $share = $this->instance->share($share);
+ $itemTargets = array(
+ 'Group Item Target',
+ 'users' => array(
+ 'tpn' => 'tpn\'s Target',
+ 'bartv' => 'bartv\'s Target',
+ ),
+ );
+ $share->setItemTarget($itemTargets);
+ $this->instance->setItemTarget($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+
+ $itemTargets = array(
+ 'New Group Item Target',
+ 'users' => array(
+ 'tpn' => 'tpn\'s New Target',
+ ),
+ );
+ $share->setItemTarget($itemTargets);
+ $this->instance->setItemTarget($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+
+ $share->setItemTarget('Group Item Target');
+ $this->instance->setItemTarget($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ }
+
+ public function testGetSharesWithShareWithFilter() {
+ $this->setupTestShares();
+ $group1 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue($this->group1));
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->will($this->returnValue(array($group1)));
+ $filter = array(
+ 'shareWith' => $this->icewind,
+ 'isShareWithUser' => true,
+ );
+ $shares = $this->instance->getShares($filter, null, null);
+ $this->assertCount(1, $shares);
+ $this->assertContains($this->share1, $shares, '', false, false);
+ }
+
+ public function testGetSharesWithShareWithFilterAndNoGroups() {
+ $this->setupTestShares();
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->will($this->returnValue(array()));
+ $filter = array(
+ 'shareWith' => $this->mtgap,
+ 'isShareWithUser' => true,
+ );
+ $this->assertEmpty($this->instance->getShares($filter, null, null));
+ }
+
+ public function testSearchForPotentialShareWiths() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $group1 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup1'));
+ $group2 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup2'));
+ $group3 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group3->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup3'));
+ $map = array(
+ array('foo', null, null, array($group1, $group2, $group3)),
+ );
+ $this->groupManager->expects($this->once())
+ ->method('search')
+ ->will($this->returnValueMap($map));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', null, null);
+ $this->assertCount(3, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup1',
+ 'shareWithDisplayName' => 'foogroup1 (group)'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup2',
+ 'shareWithDisplayName' => 'foogroup2 (group)'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup3',
+ 'shareWithDisplayName' => 'foogroup3 (group)'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSearchForPotentialShareWithsWithLimitOffset() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $group2 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup2'));
+ $group3 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group3->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup3'));
+ $map = array(
+ array('foo', 3, 1, array($group2, $group3)),
+ );
+ $this->groupManager->expects($this->once())
+ ->method('search')
+ ->will($this->returnValueMap($map));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1);
+ $this->assertCount(2, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup2',
+ 'shareWithDisplayName' => 'foogroup2 (group)'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup3',
+ 'shareWithDisplayName' => 'foogroup3 (group)'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSearchForPotentialShareWithsWithGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->with($this->equalTo('user2'))
+ ->will($this->returnValue($shareOwnerUser));
+ $group1 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup1'));
+ $group2 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup2'));
+ $group3 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group3->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup3'));
+ $group4 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group4->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup4'));
+ $map = array(
+ array('foo', null, null, array($group1, $group2, $group3, $group4)),
+ );
+ $this->groupManager->expects($this->once())
+ ->method('search')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(array($group1, $group2, $group4)));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', null, null);
+ $this->assertCount(3, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup1',
+ 'shareWithDisplayName' => 'foogroup1 (group)'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup2',
+ 'shareWithDisplayName' => 'foogroup2 (group)'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup4',
+ 'shareWithDisplayName' => 'foogroup4 (group)'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSearchForPotentialShareWithsWithLimitOffsetAndGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->with($this->equalTo('user2'))
+ ->will($this->returnValue($shareOwnerUser));
+ $group1 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup1'));
+ $group2 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup2'));
+ $group3 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group3->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup3'));
+ $group4 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group4->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('foogroup4'));
+ $map = array(
+ array('foo', null, null, array($group1, $group2, $group3, $group4)),
+ );
+ $this->groupManager->expects($this->once())
+ ->method('search')
+ ->will($this->returnValueMap($map));
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(array($group1, $group2, $group4)));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1);
+ $this->assertCount(2, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup2',
+ 'shareWithDisplayName' => 'foogroup2 (group)'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'foogroup4',
+ 'shareWithDisplayName' => 'foogroup4 (group)'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testGetItemTargetMachine() {
+ $this->assertEquals($this->itemTargetMachine, $this->instance->getItemTargetMachine());
+ }
+
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharetype/groupwatcher.php b/tests/lib/share/sharetype/groupwatcher.php
new file mode 100644
index 000000000000..3618a4ab8a09
--- /dev/null
+++ b/tests/lib/share/sharetype/groupwatcher.php
@@ -0,0 +1,431 @@
+.
+ */
+
+namespace Test\Share;
+
+use OC\Share\Share;
+use OC\Share\Exception\InvalidShareException;
+use OC\User\User;
+
+class GroupWatcher extends \PHPUnit_Framework_TestCase {
+
+ private $shareManager;
+ private $shareBackend1;
+ private $shareBackend2;
+ private $user1;
+ private $user2;
+ private $group;
+
+ protected function setUp() {
+ $this->shareManager = $this->getMockBuilder('\OC\Share\ShareManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->shareBackend1 = $this->getMockBuilder('\OC\Share\ShareBackend')
+ ->disableOriginalConstructor()
+ ->setMethods(get_class_methods('\OC\Share\ShareBackend'))
+ ->getMockForAbstractClass();
+ $this->shareBackend1->expects($this->any())
+ ->method('getItemType')
+ ->will($this->returnValue('test1'));
+ $this->shareBackend2 = $this->getMockBuilder('\OC\Share\ShareBackend')
+ ->disableOriginalConstructor()
+ ->setMethods(get_class_methods('\OC\Share\ShareBackend'))
+ ->getMockForAbstractClass();
+ $this->shareBackend2->expects($this->any())
+ ->method('getItemType')
+ ->will($this->returnValue('test2'));
+ $this->shareManager->expects($this->any())
+ ->method('getShareBackends')
+ ->will($this->returnValue(array(
+ 'test1' => $this->shareBackend1,
+ 'test2' => $this->shareBackend2,
+ )));
+ $this->shareManager->expects($this->any())
+ ->method('getShareBackend')
+ ->will($this->returnValueMap(array(
+ array('test1', $this->shareBackend1),
+ array('test2', $this->shareBackend2),
+ )));
+ $this->user1 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->user1->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('MTGap'));
+ $this->user2 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->user2->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('bantu'));
+ $this->group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->group->expects($this->any())
+ ->method('getGID')
+ ->will($this->returnValue('friends'));
+ $this->group->expects($this->any())
+ ->method('getUsers')
+ ->will($this->returnValue(array($this->user1, $this->user2)));
+ }
+
+ public function testOnGroupDeleted() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $mtgap = 'MTGap';
+ $group = 'friends';
+ $share1 = new Share();
+ $share1->setShareTypeId('group');
+ $share1->setShareOwner($mtgap);
+ $share1->setShareWith($group);
+ $share1->setItemType('test1');
+ $share2 = new Share();
+ $share2->setShareTypeId('group');
+ $share2->setShareOwner($mtgap);
+ $share2->setShareWith($group);
+ $share2->setItemType('test2');
+ $map = array(
+ array('test1', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share1)
+ ),
+ array('test2', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share2)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->exactly(2))
+ ->method('unshare');
+ $groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $groupManager->expects($this->atLeastOnce())
+ ->method('listen')
+ ->will($this->returnCallBack(array($this, 'listenPostDelete')));
+ $groupWatcher = new \OC\Share\ShareType\GroupWatcher($this->shareManager, $groupManager);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testOnGroupDeletedWithGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $mtgap = 'MTGap';
+ $bantu = 'bantu';
+ $group = 'friends';
+ $share1 = new Share();
+ $share1->setShareTypeId('group');
+ $share1->setShareOwner($mtgap);
+ $share1->setShareWith($group);
+ $share1->setItemType('test1');
+ $share2 = new Share();
+ $share2->setShareTypeId('group');
+ $share2->setShareOwner($mtgap);
+ $share2->setShareWith($group);
+ $share2->setItemType('test2');
+ $share3 = new Share();
+ $share3->setShareTypeId('user');
+ $share3->setShareOwner($bantu);
+ $share3->setShareWith($mtgap);
+ $share3->setItemType('test2');
+ $map = array(
+ array('test1', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share1)
+ ),
+ array('test2', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share2)
+ ),
+ array('test1', array('shareTypeId' => 'user', 'shareOwner' => $mtgap), null, null,
+ array()
+ ),
+ array('test2', array('shareTypeId' => 'user', 'shareOwner' => $mtgap), null, null,
+ array()
+ ),
+ array('test1', array('shareTypeId' => 'user', 'shareOwner' => $bantu), null, null,
+ array()
+ ),
+ array('test2', array('shareTypeId' => 'user', 'shareOwner' => $bantu), null, null,
+ array($share3)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(6))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->exactly(3))
+ ->method('unshare');
+ $shareType = $this->getMockBuilder('\OC\Share\ShareType\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $shareType->expects($this->once())
+ ->method('isValidShare')
+ ->with($this->equalTo($share3))
+ ->will($this->throwException(new InvalidShareException(
+ 'The share owner is not in any groups of the user shared with as required by '.
+ 'the groups only sharing policy set by the admin'
+ )));
+ $this->shareBackend1->expects($this->any())
+ ->method('getShareType')
+ ->with($this->equalTo('user'))
+ ->will($this->returnValue($shareType));
+ $this->shareBackend2->expects($this->any())
+ ->method('getShareType')
+ ->with($this->equalTo('user'))
+ ->will($this->returnValue($shareType));
+ $groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $groupManager->expects($this->atLeastOnce())
+ ->method('listen')
+ ->will($this->returnCallBack(array($this, 'listenPostDelete')));
+ $groupWatcher = new \OC\Share\ShareType\GroupWatcher($this->shareManager, $groupManager);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function listenPostDelete($scope, $method, $callback) {
+ if ($method === 'postDelete') {
+ $this->assertEquals('\OC\Group', $scope);
+ // Fake PublicEmitter's emit
+ call_user_func_array($callback, array($this->group));
+ }
+ }
+
+ public function testOnUserAddedToGroup() {
+ $mtgap = 'MTGap';
+ $bantu = 'bantu';
+ $group = 'friends';
+ $share1 = new Share();
+ $share1->setShareTypeId('group');
+ $share1->setShareOwner($mtgap);
+ $share1->setShareWith($group);
+ $share1->setItemType('test1');
+ $share1->setItemTarget(array('Group Target'));
+ $share2 = new Share();
+ $share2->setShareTypeId('group');
+ $share2->setShareOwner($mtgap);
+ $share2->setShareWith($group);
+ $share2->setItemType('test2');
+ $share2->setItemTarget(array('Group Target'));
+ $map = array(
+ array('test1', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share1)
+ ),
+ array('test2', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share2)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $itemTargetMachine = $this->getMockBuilder('\OC\Share\ItemTargetMachine')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $itemTargetMachine->expects($this->at(0))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share1), $this->equalTo($this->user2))
+ ->will($this->returnValue('Andreas\' Target 1'));
+ $itemTargetMachine->expects($this->at(1))
+ ->method('getItemTarget')
+ ->with($this->equalTo($share2), $this->equalTo($this->user2))
+ ->will($this->returnValue('Andreas\' Target 2'));
+ $shareType = $this->getMockBuilder('\OC\Share\ShareType\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $shareType->expects($this->any())
+ ->method('getItemTargetMachine')
+ ->will($this->returnValue($itemTargetMachine));
+ $this->shareBackend1->expects($this->any())
+ ->method('getShareType')
+ ->with($this->equalTo('group'))
+ ->will($this->returnValue($shareType));
+ $this->shareBackend2->expects($this->any())
+ ->method('getShareType')
+ ->with($this->equalTo('group'))
+ ->will($this->returnValue($shareType));
+ $updatedShare1 = clone $share1;
+ $updatedShare1->setItemTarget(array('Group Target', 'users' => array(
+ $bantu => 'Andreas\' Target 1'
+ )
+ ));
+ $updatedShare2 = clone $share2;
+ $updatedShare2->setItemTarget(array('Group Target', 'users' => array(
+ $bantu => 'Andreas\' Target 2'
+ )
+ ));
+ // I had to manually counted the indices... this could break easily
+ $this->shareManager->expects($this->at(4))
+ ->method('update')
+ ->with($this->equalTo($updatedShare1));
+ $this->shareManager->expects($this->at(6))
+ ->method('update')
+ ->with($this->equalTo($updatedShare2));
+ $groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $groupManager->expects($this->atLeastOnce())
+ ->method('listen')
+ ->will($this->returnCallBack(array($this, 'listenPostAddUser')));
+ $groupWatcher = new \OC\Share\ShareType\GroupWatcher($this->shareManager, $groupManager);
+ }
+
+ public function listenPostAddUser($scope, $method, $callback) {
+ if ($method === 'postAddUser') {
+ $this->assertEquals('\OC\Group', $scope);
+ // Fake PublicEmitter's emit
+ call_user_func_array($callback, array($this->group, $this->user2));
+ }
+ }
+
+ public function testOnUserRemovedFromGroup() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $mtgap = 'MTGap';
+ $bantu = 'bantu';
+ $group = 'friends';
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setShareTypeId('group');
+ $share1->setShareOwner($mtgap);
+ $share1->setShareWith($group);
+ $share1->setItemType('test1');
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->addParentId(1);
+ $share2->setShareTypeId('link');
+ $share2->setShareOwner($bantu);
+ $share2->setItemType('test1');
+ $map = array(
+ array('test1', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share1)
+ ),
+ array('test2', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array()
+ ),
+ );
+ $this->shareManager->expects($this->exactly(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->once())
+ ->method('getReshares')
+ ->with($this->equalTo($share1))
+ ->will($this->returnValue(array($share2)));
+ $this->shareManager->expects($this->once())
+ ->method('unshare');
+ $groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $groupManager->expects($this->atLeastOnce())
+ ->method('listen')
+ ->will($this->returnCallBack(array($this, 'listenPostRemoveUser')));
+ $groupWatcher = new \OC\Share\ShareType\GroupWatcher($this->shareManager, $groupManager);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testOnUserRemovedFromGroupWithGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $mtgap = 'MTGap';
+ $bantu = 'bantu';
+ $group = 'friends';
+ $share1 = new Share();
+ $share1->setId(1);
+ $share1->setShareTypeId('group');
+ $share1->setShareOwner($mtgap);
+ $share1->setShareWith($group);
+ $share1->setItemType('test1');
+ $share2 = new Share();
+ $share2->setId(2);
+ $share2->addParentId(1);
+ $share2->setShareTypeId('link');
+ $share2->setShareOwner($bantu);
+ $share2->setItemType('test1');
+ $share3 = new Share();
+ $share3->setShareTypeId('user');
+ $share3->setShareOwner($bantu);
+ $share3->setShareWith($mtgap);
+ $share3->setItemType('test2');
+ $map = array(
+ array('test1', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array($share1)
+ ),
+ array('test2', array('shareTypeId' => 'group', 'shareWith' => $group), null, null,
+ array()
+ ),
+ array('test1', array('shareTypeId' => 'user', 'shareOwner' => $bantu), null, null,
+ array()
+ ),
+ array('test2', array('shareTypeId' => 'user', 'shareOwner' => $bantu), null, null,
+ array($share3)
+ ),
+ );
+ $this->shareManager->expects($this->exactly(4))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->once())
+ ->method('getReshares')
+ ->with($this->equalTo($share1))
+ ->will($this->returnValue(array($share2)));
+ $this->shareManager->expects($this->exactly(2))
+ ->method('unshare');
+ $shareType = $this->getMockBuilder('\OC\Share\ShareType\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $shareType->expects($this->once())
+ ->method('isValidShare')
+ ->with($this->equalTo($share3))
+ ->will($this->throwException(new InvalidShareException(
+ 'The share owner is not in any groups of the user shared with as required by '.
+ 'the groups only sharing policy set by the admin'
+ )));
+ $this->shareBackend1->expects($this->any())
+ ->method('getShareType')
+ ->with($this->equalTo('user'))
+ ->will($this->returnValue($shareType));
+ $this->shareBackend2->expects($this->any())
+ ->method('getShareType')
+ ->with($this->equalTo('user'))
+ ->will($this->returnValue($shareType));
+ $groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $groupManager->expects($this->atLeastOnce())
+ ->method('listen')
+ ->will($this->returnCallBack(array($this, 'listenPostRemoveUser')));
+ $groupWatcher = new \OC\Share\ShareType\GroupWatcher($this->shareManager, $groupManager);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function listenPostRemoveUser($scope, $method, $callback) {
+ if ($method === 'postRemoveUser') {
+ $this->assertEquals('\OC\Group', $scope);
+ // Fake PublicEmitter's emit
+ call_user_func_array($callback, array($this->group, $this->user2));
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharetype/link.php b/tests/lib/share/sharetype/link.php
new file mode 100644
index 000000000000..9293517a6f9e
--- /dev/null
+++ b/tests/lib/share/sharetype/link.php
@@ -0,0 +1,297 @@
+.
+ */
+
+namespace Test\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+
+class TestLink extends \OC\Share\ShareType\Link {
+
+ public function getId() {
+ return 'testlink';
+ }
+
+}
+
+class Link extends ShareType {
+
+ private $itemTargetMachine;
+ private $userManager;
+ private $tokenMachine;
+ private $counter;
+ private $hasher;
+ private $mtgap;
+ private $mtgapDisplay;
+ private $karlitschek;
+ private $karlitschekDisplay;
+ private $icewind;
+ private $icewindDisplay;
+
+ protected function setUp() {
+ $this->mtgap = 'MTGap';
+ $this->mtgapDisplay = 'Michael Gapczynski';
+ $this->karlitschek = 'karlitschek';
+ $this->karlitschekDisplay = 'Frank Karlitschek';
+ $this->icewind = 'Icewind';
+ $this->icewindDisplay = 'Robin Appelman';
+ $this->itemTargetMachine = $this->getMockBuilder('\OC\Share\ItemTargetMachine')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->itemTargetMachine->expects($this->any())
+ ->method('getItemTarget')
+ ->will($this->returnValue('Test Target'));
+ $this->userManager = $this->getMockBuilder('\OC\User\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->tokenMachine = $this->getMockBuilder('\OC\Share\ShareType\TokenMachine')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->counter = 0;
+ $this->hasher = $this->getMockBuilder('\PasswordHash')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->instance = new TestLink('test', new ShareFactory(), $this->itemTargetMachine,
+ $this->userManager, $this->tokenMachine, $this->hasher
+ );
+ }
+
+ protected function getTestShare($version) {
+ $share = new Share();
+ $share->setShareTypeId($this->instance->getId());
+ $share->setItemType('test');
+ $share->setItemSource('23');
+ $share->setPermissions(31);
+ $share->setShareTime(1370797580);
+ $mtgapUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mtgapUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->mtgapDisplay));
+ $karlitschekUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $karlitschekUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->karlitschekDisplay));
+ $icewindUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $icewindUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->icewindDisplay));
+ $map = array(
+ array($this->mtgap, $mtgapUser),
+ array($this->karlitschek, $karlitschekUser),
+ array($this->icewind, $icewindUser),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('get')
+ ->will($this->returnValueMap($map));
+ $counter = $this->counter;
+ switch ($version) {
+ case 1:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $this->tokenMachine->expects($this->at($counter))
+ ->method('getToken')
+ ->will($this->returnValue('2kla32ljadsfoj23kjab'));
+ break;
+ case 2:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $this->tokenMachine->expects($this->at($counter))
+ ->method('getToken')
+ ->will($this->returnValue('auoiu23k2jiapi2kjads'));
+ break;
+ case 3:
+ $share->setShareOwner($this->icewind);
+ $share->setItemOwner($this->icewind);
+ $this->tokenMachine->expects($this->at($counter))
+ ->method('getToken')
+ ->will($this->returnValue('82093jkadp2kjasdf212'));
+ break;
+ case 4:
+ $share->setShareOwner($this->karlitschek);
+ $share->setItemOwner($this->karlitschek);
+ $this->tokenMachine->expects($this->at($counter))
+ ->method('getToken')
+ ->will($this->returnValue('po2jad2ijajk32i0sads'));
+ break;
+ }
+ return $share;
+ }
+
+ protected function getSharedTestShare($version) {
+ $share = new Share();
+ $share->setShareTypeId($this->instance->getId());
+ $share->setItemType('test');
+ $share->setItemSource('23');
+ $share->setItemTarget('Test Target');
+ $share->setPermissions(31);
+ $share->setShareTime(1370797580);
+ switch ($version) {
+ case 1:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareOwnerDisplayName($this->mtgapDisplay);
+ $share->setToken('2kla32ljadsfoj23kjab');
+ break;
+ case 2:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareOwnerDisplayName($this->mtgapDisplay);
+ $share->setToken('auoiu23k2jiapi2kjads');
+ break;
+ case 3:
+ $share->setShareOwner($this->icewind);
+ $share->setItemOwner($this->icewind);
+ $share->setShareOwnerDisplayName($this->icewindDisplay);
+ $share->setToken('82093jkadp2kjasdf212');
+ break;
+ case 4:
+ $share->setShareOwner($this->karlitschek);
+ $share->setItemOwner($this->karlitschek);
+ $share->setShareOwnerDisplayName($this->karlitschekDisplay);
+ $share->setToken('po2jad2ijajk32i0sads');
+ break;
+ }
+ return $share;
+ }
+
+ public function testIsValidShare() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', 'yes');
+
+ $zimba12 = 'zimba12';
+ $share = new Share();
+ $share->setShareOwner($zimba12);
+ $map = array(
+ array($zimba12, true),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValue(true));
+ $this->assertTrue($this->instance->isValidShare($share));
+
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', $sharingPolicy);
+ }
+
+ public function testIsValidShareWithShareOwnerDoesNotExist() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', 'yes');
+
+ $tpn = 'tpn';
+ $bar = 'bar';
+ $share = new Share();
+ $share->setShareOwner($bar);
+ $share->setShareWith($tpn);
+ $map = array(
+ array($bar, false),
+ array($tpn, true),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share owner does not exist'
+ );
+ $this->instance->isValidShare($share);
+
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', $sharingPolicy);
+ }
+
+ public function testIsValidShareWithLinkSharingDisabled() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', 'no');
+
+ $zimba12 = 'zimba12';
+ $share = new Share();
+ $share->setShareOwner($zimba12);
+ $map = array(
+ array($zimba12, true),
+ );
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->will($this->returnValue(true));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The admin has disabled sharing via links'
+ );
+ $this->instance->isValidShare($share);
+
+ \OC_Appconfig::setValue('core', 'shareapi_allow_links', $sharingPolicy);
+ }
+
+ public function testShareWithPassword() {
+ $share = $this->getTestShare(1);
+ $share->setPassword('password');
+ $this->hasher->expects($this->once())
+ ->method('HashPassword')
+ ->will($this->returnValue('password'));
+ $result = $this->instance->share($share);
+ $this->assertNotNull($result->getId());
+ $this->assertEquals(array(), $result->getUpdatedProperties());
+ $share->setId($result->getId());
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ }
+
+ public function testSetPassword() {
+ $share = $this->getTestShare(2);
+ $share = $this->instance->share($share);
+ $this->hasher->expects($this->once())
+ ->method('HashPassword')
+ ->will($this->returnValue('1234'));
+ $share->setPassword('1234');
+ $this->instance->setPassword($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ }
+
+ public function testGetSharesWithFilter() {
+ $this->setupTestShares();
+ $filter = array(
+ 'token' => $this->share2->getToken(),
+ );
+ $shares = $this->instance->getShares($filter, null, null);
+ $this->assertCount(1, $shares);
+ $this->assertContains($this->share2, $shares, '', false, false);
+
+ $filter = array(
+ 'shareOwner' => $this->mtgap,
+ );
+ $shares = $this->instance->getShares($filter, null, null);
+ $this->assertCount(2, $shares);
+ $this->assertContains($this->share1, $shares, '', false, false);
+ $this->assertContains($this->share2, $shares, '', false, false);
+
+ $filter = array(
+ 'shareWith' => 'foo',
+ );
+ $this->assertEmpty($this->instance->getShares($filter, null, null));
+ }
+
+ public function testSearchForPotentialShareWiths() {
+ $this->assertEmpty($this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1));
+ }
+
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharetype/sharetype.php b/tests/lib/share/sharetype/sharetype.php
new file mode 100644
index 000000000000..a97f814933e3
--- /dev/null
+++ b/tests/lib/share/sharetype/sharetype.php
@@ -0,0 +1,175 @@
+.
+ */
+
+namespace Test\Share\ShareType;
+
+abstract class ShareType extends \PHPUnit_Framework_TestCase {
+
+ protected $instance;
+ protected $share1;
+ protected $share2;
+ protected $share3;
+ protected $share4;
+
+ /**
+ * Get a share with fake data, it will be passed into the share method
+ * @param int $version 1-4 Return a unique share for each version number
+ * @return \OC\Share\Share
+ */
+ abstract protected function getTestShare($version);
+
+ /**
+ * Get the same share as getTestShare, but as expected after being shared
+ * @param int $version 1-4 Return a unique share for each version number
+ * @return \OC\Share\Share
+ */
+ abstract protected function getSharedTestShare($version);
+
+ /**
+ * Setup four shares with fake data
+ */
+ protected function setupTestShares() {
+ $shares = array();
+ for ($i = 1; $i < 5; $i++) {
+ $share = $this->getTestShare($i);
+ $share = $this->instance->share($share);
+ $sharedShare = $this->getSharedTestShare($i);
+ $sharedShare->setId($share->getId());
+ $sharedShare->resetUpdatedProperties();
+ $this->assertEquals($sharedShare, $share);
+ $shares[] = $share;
+ }
+ list($this->share1, $this->share2, $this->share3, $this->share4) = $shares;
+ }
+
+ protected function tearDown() {
+ $this->instance->clear();
+ }
+
+ public function testShare() {
+ $share = $this->getTestShare(1);
+ $sharedShare = $this->getSharedTestShare(1);
+ $share = $this->instance->share($share);
+ $this->assertNotNull($share->getId());
+ $this->assertEquals(array(), $share->getUpdatedProperties());
+ $sharedShare->setId($share->getId());
+ $sharedShare->resetUpdatedProperties();
+ $this->assertEquals($sharedShare, $share);
+ $this->assertEquals($sharedShare, $this->getShareById($share->getId()));
+ }
+
+ public function testShareWithParents() {
+ $share = $this->getTestShare(2);
+ $share->setParentIds(array(1, 3));
+ $sharedShare = $this->getSharedTestShare(2);
+ $share = $this->instance->share($share);
+ $this->assertNotNull($share->getId());
+ $this->assertEquals(array(), $share->getUpdatedProperties());
+ $sharedShare->setId($share->getId());
+ $sharedShare->setParentIds(array(1, 3));
+ $sharedShare->resetUpdatedProperties();
+ $this->assertEquals($sharedShare, $share);
+ $this->assertEquals($sharedShare, $this->getShareById($share->getId()));
+ }
+
+ public function testUnshare() {
+ $share = $this->getTestShare(3);
+ $share = $this->instance->share($share);
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ $this->instance->unshare($share);
+ $this->assertFalse($this->getShareById($share->getId()));
+ }
+
+ public function testUpdate() {
+ $share = $this->getTestShare(4);
+ $share = $this->instance->share($share);
+ $share->setPermissions(1);
+ $this->instance->update($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ }
+
+ public function testUpdateTwoProperties() {
+ $share = $this->getTestShare(2);
+ $share = $this->instance->share($share);
+ $share->setPermissions(21);
+ $share->setExpirationTime(1370884027);
+ $this->instance->update($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ }
+
+ public function testSetParentIds() {
+ $share = $this->getTestShare(1);
+ $share->setParentIds(array(1, 2));
+ $share = $this->instance->share($share);
+ $share->setParentIds(array(2, 3, 4));
+ $this->instance->setParentIds($share);
+ $share->resetUpdatedProperties();
+ $this->assertEquals($share, $this->getShareById($share->getId()));
+ }
+
+ public function testGetShares() {
+ $this->setupTestShares();
+ $shares = $this->instance->getShares(array(), null, null);
+ $this->assertCount(4, $shares);
+ $this->assertContains($this->share1, $shares, '', false, false);
+ $this->assertContains($this->share2, $shares, '', false, false);
+ $this->assertContains($this->share3, $shares, '', false, false);
+ $this->assertContains($this->share4, $shares, '', false, false);
+ }
+
+ public function testGetSharesWithLimitOffset() {
+ $this->setupTestShares();
+ $shares = $this->instance->getShares(array(), 3, 1);
+ $this->assertCount(3, $shares);
+ $this->assertContains($this->share2, $shares, '', false, false);
+ $this->assertContains($this->share3, $shares, '', false, false);
+ $this->assertContains($this->share4, $shares, '', false, false);
+ }
+
+ public function testGetSharesWithParentId() {
+ $this->setupTestShares();
+ $this->share4->addParentId($this->share3->getId());
+ $this->instance->setParentIds($this->share4);
+ $this->share4->resetUpdatedProperties();
+ $filter = array(
+ 'parentId' => $this->share3->getId(),
+ );
+ $shares = $this->instance->getShares($filter, null, null);
+ $this->assertCount(1, $shares);
+ $this->assertContains($this->share4, $shares, '', false, false);
+ }
+
+ /**
+ * Get a share from the share type based on id
+ * @param int $id
+ * @return \OC\Share\Share | bool
+ */
+ protected function getShareById($id) {
+ $share = $this->instance->getShares(array('id' => $id), 1, null);
+ if (is_array($share) && count($share) === 1) {
+ return reset($share);
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php
new file mode 100644
index 000000000000..41e58f9b4be2
--- /dev/null
+++ b/tests/lib/share/sharetype/user.php
@@ -0,0 +1,580 @@
+.
+ */
+
+namespace Test\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\ShareFactory;
+
+class TestUser extends \OC\Share\ShareType\User {
+
+ public function getId() {
+ return 'testuser';
+ }
+
+}
+
+class User extends ShareType {
+
+ private $itemTargetMachine;
+ private $userManager;
+ private $groupManager;
+ private $mtgap;
+ private $mtgapDisplay;
+ private $karlitschek;
+ private $karlitschekDisplay;
+ private $icewind;
+ private $icewindDisplay;
+
+ protected function setUp() {
+ $this->mtgap = 'MTGap';
+ $this->mtgapDisplay = 'Michael Gapczynski';
+ $this->karlitschek = 'karlitschek';
+ $this->karlitschekDisplay = 'Frank Karlitschek';
+ $this->icewind = 'Icewind';
+ $this->icewindDisplay = 'Robin Appelman';
+ $this->itemTargetMachine = $this->getMockBuilder('\OC\Share\ItemTargetMachine')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->itemTargetMachine->expects($this->any())
+ ->method('getItemTarget')
+ ->will($this->returnValue('Test Target'));
+ $this->userManager = $this->getMockBuilder('\OC\User\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager = $this->getMockBuilder('\OC\Group\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->instance = new TestUser('test', new ShareFactory(), $this->itemTargetMachine,
+ $this->userManager, $this->groupManager
+ );
+ }
+
+ protected function getTestShare($version) {
+ $share = new Share();
+ $share->setShareTypeId($this->instance->getId());
+ $share->setItemType('test');
+ $share->setItemSource('23');
+ $share->setPermissions(31);
+ $share->setShareTime(1370797580);
+ $mtgapUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mtgapUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->mtgapDisplay));
+ $karlitschekUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $karlitschekUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->karlitschekDisplay));
+ $icewindUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $icewindUser->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue($this->icewindDisplay));
+ $map = array(
+ array($this->mtgap, $mtgapUser),
+ array($this->karlitschek, $karlitschekUser),
+ array($this->icewind, $icewindUser),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('get')
+ ->will($this->returnValueMap($map));
+ switch ($version) {
+ case 1:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareWith($this->karlitschek);
+ break;
+ case 2:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareWith($this->icewind);
+ break;
+ case 3:
+ $share->setShareOwner($this->icewind);
+ $share->setItemOwner($this->icewind);
+ $share->setShareWith($this->karlitschek);
+ break;
+ case 4:
+ $share->setShareOwner($this->karlitschek);
+ $share->setItemOwner($this->karlitschek);
+ $share->setShareWith($this->mtgap);
+ break;
+ }
+ return $share;
+ }
+
+ protected function getSharedTestShare($version) {
+ $share = new Share();
+ $share->setShareTypeId($this->instance->getId());
+ $share->setItemType('test');
+ $share->setItemSource('23');
+ $share->setItemTarget('Test Target');
+ $share->setPermissions(31);
+ $share->setShareTime(1370797580);
+ switch ($version) {
+ case 1:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareOwnerDisplayName($this->mtgapDisplay);
+ $share->setShareWith($this->karlitschek);
+ $share->setShareWithDisplayName($this->karlitschekDisplay);
+ break;
+ case 2:
+ $share->setShareOwner($this->mtgap);
+ $share->setItemOwner($this->mtgap);
+ $share->setShareOwnerDisplayName($this->mtgapDisplay);
+ $share->setShareWith($this->icewind);
+ $share->setShareWithDisplayName($this->icewindDisplay);
+ break;
+ case 3:
+ $share->setShareOwner($this->icewind);
+ $share->setItemOwner($this->icewind);
+ $share->setShareOwnerDisplayName($this->icewindDisplay);
+ $share->setShareWith($this->karlitschek);
+ $share->setShareWithDisplayName($this->karlitschekDisplay);
+ break;
+ case 4:
+ $share->setShareOwner($this->karlitschek);
+ $share->setItemOwner($this->karlitschek);
+ $share->setShareOwnerDisplayName($this->karlitschekDisplay);
+ $share->setShareWith($this->mtgap);
+ $share->setShareWithDisplayName($this->mtgapDisplay);
+ break;
+ }
+ return $share;
+ }
+
+ public function testIsValidShare() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $tanghus = 'tanghus';
+ $DeepDiver = 'DeepDiver';
+ $share = new Share();
+ $share->setShareOwner($tanghus);
+ $share->setShareWith($DeepDiver);
+ $map = array(
+ array($tanghus, true),
+ array($DeepDiver, true),
+ );
+ $this->userManager->expects($this->exactly(2))
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->assertTrue($this->instance->isValidShare($share));
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testIsValidShareWithSameUsers() {
+ $zimba12 = 'zimba12';
+ $share = new Share();
+ $share->setShareOwner($zimba12);
+ $share->setShareWith($zimba12);
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share owner is the user shared with'
+ );
+ $this->instance->isValidShare($share);
+ }
+
+ public function testIsValidShareWithShareOwnerDoesNotExist() {
+ $tpn = 'tpn';
+ $bar = 'bar';
+ $share = new Share();
+ $share->setShareOwner($bar);
+ $share->setShareWith($tpn);
+ $map = array(
+ array($bar, false),
+ array($tpn, true),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share owner does not exist'
+ );
+ $this->instance->isValidShare($share);
+ }
+
+ public function testIsValidShareWithShareWithDoesNotExist() {
+ $raydiation = 'Raydiation';
+ $foo = 'foo';
+ $share = new Share();
+ $share->setShareOwner($raydiation);
+ $share->setShareWith($foo);
+ $map = array(
+ array($raydiation, true),
+ array($foo, false),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The user shared with does not exist'
+ );
+ $this->instance->isValidShare($share);
+ }
+
+ public function testIsValidShareWithGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $jancborchardt = 'jancborchardt';
+ $raydiation = 'Raydiation';
+ $share = new Share();
+ $share->setShareOwner($jancborchardt);
+ $share->setShareWith($raydiation);
+ $map = array(
+ array($jancborchardt, true),
+ array($raydiation, true),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $shareWithUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $usersMap = array(
+ array($jancborchardt, $shareOwnerUser),
+ array($raydiation, $shareWithUser),
+ );
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->will($this->returnValueMap($usersMap));
+ $group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(array($group)));
+ $group->expects($this->atLeastOnce())
+ ->method('inGroup')
+ ->with($this->equalTo($shareWithUser))
+ ->will($this->returnValue(true));
+ $this->assertTrue($this->instance->isValidShare($share));
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testIsValidShareWithShareOwnerNotInShareWithGroupsAndGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $jancborchardt = 'jancborchardt';
+ $raydiation = 'Raydiation';
+ $share = new Share();
+ $share->setShareOwner($jancborchardt);
+ $share->setShareWith($raydiation);
+ $map = array(
+ array($jancborchardt, true),
+ array($raydiation, true),
+ );
+ $this->userManager->expects($this->atLeastOnce())
+ ->method('userExists')
+ ->will($this->returnValueMap($map));
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $shareWithUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $usersMap = array(
+ array($jancborchardt, $shareOwnerUser),
+ array($raydiation, $shareWithUser),
+ );
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->will($this->returnValueMap($usersMap));
+ $group = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(array($group)));
+ $group->expects($this->atLeastOnce())
+ ->method('inGroup')
+ ->with($this->equalTo($shareWithUser))
+ ->will($this->returnValue(false));
+ $this->setExpectedException('\OC\Share\Exception\InvalidShareException',
+ 'The share owner is not in any groups of the user shared with as required by the '.
+ 'groups only sharing policy set by the admin'
+ );
+ $this->instance->isValidShare($share);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testGetSharesWithFilter() {
+ $this->setupTestShares();
+ $filter = array(
+ 'shareWith' => $this->karlitschek,
+ );
+ $shares = $this->instance->getShares($filter, null, null);
+ $this->assertCount(2, $shares);
+ $this->assertContains($this->share1, $shares, '', false, false);
+ $this->assertContains($this->share3, $shares, '', false, false);
+ }
+
+ public function testSearchForPotentialShareWiths() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $user1 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user1->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+ $user1->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser1'));
+ $user2 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user2->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user2'));
+ $user2->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser2'));
+ $user3 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user3->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user3'));
+ $user3->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser3'));
+ $map = array(
+ array('foo', null, null, array($user1, $user2, $user3)),
+ );
+ $this->userManager->expects($this->once())
+ ->method('searchDisplayName')
+ ->will($this->returnValueMap($map));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', null, null);
+ $this->assertCount(2, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'user1',
+ 'shareWithDisplayName' => 'foouser1'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'user3',
+ 'shareWithDisplayName' => 'foouser3'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSearchForPotentialShareWithsWithLimitOffset() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global');
+
+ $user1 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user1->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+ $user1->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser1'));
+ $user2 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user2->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user2'));
+ $user2->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser2'));
+ $user3 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user3->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user3'));
+ $user3->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser3'));
+ $map = array(
+ array('foo', 5, null, array($user1, $user2, $user3)),
+ );
+ $this->userManager->expects($this->once())
+ ->method('searchDisplayName')
+ ->will($this->returnValueMap($map));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1);
+ $this->assertCount(1, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'user3',
+ 'shareWithDisplayName' => 'foouser3'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSearchForPotentialShareWithsWithGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->with($this->equalTo('user2'))
+ ->will($this->returnValue($shareOwnerUser));
+ $user1 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user1->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+ $user1->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser1'));
+ $user2 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user2->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user2'));
+ $user2->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser2'));
+ $user3 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user3->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user3'));
+ $user3->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser3'));
+ $group1 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1Map = array(
+ array('foo', null, null, array($user1, $user2, $user3)),
+ );
+ $group1->expects($this->once())
+ ->method('searchDisplayName')
+ ->will($this->returnValueMap($group1Map));
+ $group2 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2Map = array(
+ array('foo', null, null, array($user1, $user2)),
+ );
+ $group2->expects($this->once())
+ ->method('searchDisplayName')
+ ->will($this->returnValueMap($group2Map));
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(array($group1, $group2)));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', null, null);
+ $this->assertCount(2, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'user1',
+ 'shareWithDisplayName' => 'foouser1'), $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'user3',
+ 'shareWithDisplayName' => 'foouser3'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+
+ public function testSearchForPotentialShareWithsWithLimitOffsetAndGroupsOnlyPolicy() {
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only');
+
+ $shareOwnerUser = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->with($this->equalTo('user2'))
+ ->will($this->returnValue($shareOwnerUser));
+ $user1 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user1->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+ $user1->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser1'));
+ $user2 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user2->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user2'));
+ $user2->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser2'));
+ $user3 = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user3->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user3'));
+ $user3->expects($this->any())
+ ->method('getDisplayName')
+ ->will($this->returnValue('foouser3'));
+ $group1 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group1Map = array(
+ array('foo', 5, null, array($user1, $user2, $user3)),
+ );
+ $group1->expects($this->once())
+ ->method('searchDisplayName')
+ ->will($this->returnValueMap($group1Map));
+ $group2 = $this->getMockBuilder('\OC\Group\Group')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $group2Map = array(
+ array('foo', 5, null, array($user1, $user2)),
+ );
+ $group2->expects($this->once())
+ ->method('searchDisplayName')
+ ->will($this->returnValueMap($group2Map));
+ $this->groupManager->expects($this->once())
+ ->method('getUserGroups')
+ ->with($this->equalTo($shareOwnerUser))
+ ->will($this->returnValue(array($group1, $group2)));
+ $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1);
+ $this->assertCount(1, $shareWiths);
+ $this->assertContains(array(
+ 'shareWith' => 'user3',
+ 'shareWithDisplayName' => 'foouser3'), $shareWiths);
+
+ \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy);
+ }
+}
\ No newline at end of file
diff --git a/tests/lib/share/sharetype/userwatcher.php b/tests/lib/share/sharetype/userwatcher.php
new file mode 100644
index 000000000000..65975777f1eb
--- /dev/null
+++ b/tests/lib/share/sharetype/userwatcher.php
@@ -0,0 +1,131 @@
+.
+ */
+
+namespace Test\Share\ShareType;
+
+use OC\Share\Share;
+use OC\Share\Exception\ShareTypeDoesNotExistException;
+
+class UserWatcher extends \PHPUnit_Framework_TestCase {
+
+ private $shareManager;
+ private $user;
+
+ protected function setUp() {
+ $this->shareManager = $this->getMockBuilder('\OC\Share\ShareManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $shareBackend1 = $this->getMockBuilder('\OC\Share\ShareBackend')
+ ->disableOriginalConstructor()
+ ->setMethods(get_class_methods('\OC\Share\ShareBackend'))
+ ->getMockForAbstractClass();
+ $shareBackend1->expects($this->any())
+ ->method('getItemType')
+ ->will($this->returnValue('test1'));
+ $shareBackend2 = $this->getMockBuilder('\OC\Share\ShareBackend')
+ ->disableOriginalConstructor()
+ ->setMethods(get_class_methods('\OC\Share\ShareBackend'))
+ ->getMockForAbstractClass();
+ $shareBackend2->expects($this->any())
+ ->method('getItemType')
+ ->will($this->returnValue('test2'));
+ $this->shareManager->expects($this->any())
+ ->method('getShareBackends')
+ ->will($this->returnValue(array(
+ 'test1' => $shareBackend1,
+ 'test2' => $shareBackend2,
+ )));
+ }
+
+ public function testOnUserDeleted() {
+ $mtgap = 'MTGap';
+ $vicdeo = 'VicDeo';
+ $share1 = new Share();
+ $share1->setShareTypeId('link');
+ $share1->setShareOwner($mtgap);
+ $share1->setItemType('test1');
+ $share2 = new Share();
+ $share2->setShareTypeId('user');
+ $share2->setShareOwner($mtgap);
+ $share2->setShareWith($vicdeo);
+ $share2->setItemType('test2');
+ $share3 = new Share();
+ $share3->setShareTypeId('user');
+ $share3->setShareOwner($vicdeo);
+ $share3->setShareWith($mtgap);
+ $share3->setItemType('test1');
+ $share4 = new Share();
+ $share4->setShareTypeId('user');
+ $share4->setShareOwner($vicdeo);
+ $share4->setShareWith($mtgap);
+ $share4->setItemType('test2');
+ $this->user = $this->getMockBuilder('\OC\User\User')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue($mtgap));
+ $map = array(
+ array('test1', array('shareOwner' => $mtgap), null, null, array($share1)),
+ array('test2', array('shareOwner' => $mtgap), null, null, array($share2)),
+ array('test1', array('shareTypeId' => 'user', 'shareWith' => $mtgap), null, null,
+ array($share3)
+ ),
+ );
+ $this->shareManager->expects($this->at(0))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->at(1))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->at(2))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->at(3))
+ ->method('getShares')
+ ->will($this->returnValueMap($map));
+ $this->shareManager->expects($this->at(4))
+ ->method('getShares')
+ ->with($this->equalTo('test2'),
+ $this->equalTo(array('shareTypeId' => 'user', 'shareWith' => $mtgap)),
+ $this->equalTo(null), $this->equalTo(null)
+ )
+ ->will($this->throwException(new ShareTypeDoesNotExistException(
+ 'No share type found matching id'
+ )));
+ $this->shareManager->expects($this->exactly(3))
+ ->method('unshare');
+ $userManager = $this->getMockBuilder('\OC\User\Manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $userManager->expects($this->once())
+ ->method('listen')
+ ->with($this->equalTo('\OC\User'), $this->equalTo('postDelete'))
+ ->will($this->returnCallBack(array($this, 'listenPostDelete')));
+ $userWatcher = new \OC\Share\ShareType\UserWatcher($this->shareManager, $userManager);
+ }
+
+ public function listenPostDelete($scope, $method, $callback) {
+ // Fake PublicEmitter's emit
+ call_user_func_array($callback, array($this->user));
+ }
+
+}
\ No newline at end of file