From f318ea4e18e489f61f455ae0a276cfd2106e0eca Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 6 May 2013 14:46:45 -0400 Subject: [PATCH 01/85] Initial commit of Share API changes --- lib/share/collection.php | 31 +++ lib/share/common.php | 181 ++++++++++++++++++ lib/share/database.php | 180 +++++++++++++++++ .../exceptions/invalidshareexception.php | 30 +++ lib/share/filedependent.php | 59 ++++++ lib/share/hooks.php | 94 +++++++++ lib/share/itemtype.php | 31 +++ lib/share/permissions.php | 71 +++++++ lib/share/share.php | 167 ++++++++++++++++ lib/share/sharepublic.php | 118 ++++++++++++ lib/share/sharetype.php | 67 +++++++ lib/share/sharetypefac.php | 29 +++ lib/share/sharetypes/common.php | 173 +++++++++++++++++ lib/share/sharetypes/group.php | 87 +++++++++ lib/share/sharetypes/link.php | 73 +++++++ lib/share/sharetypes/user.php | 59 ++++++ lib/share/time.php | 90 +++++++++ lib/share/utility.php | 53 +++++ 18 files changed, 1593 insertions(+) create mode 100644 lib/share/collection.php create mode 100644 lib/share/common.php create mode 100644 lib/share/database.php create mode 100644 lib/share/exceptions/invalidshareexception.php create mode 100644 lib/share/filedependent.php create mode 100644 lib/share/hooks.php create mode 100644 lib/share/itemtype.php create mode 100644 lib/share/permissions.php create mode 100644 lib/share/share.php create mode 100644 lib/share/sharepublic.php create mode 100644 lib/share/sharetype.php create mode 100644 lib/share/sharetypefac.php create mode 100644 lib/share/sharetypes/common.php create mode 100644 lib/share/sharetypes/group.php create mode 100644 lib/share/sharetypes/link.php create mode 100644 lib/share/sharetypes/user.php create mode 100644 lib/share/time.php create mode 100644 lib/share/utility.php diff --git a/lib/share/collection.php b/lib/share/collection.php new file mode 100644 index 000000000000..012073b03d42 --- /dev/null +++ b/lib/share/collection.php @@ -0,0 +1,31 @@ +. +*/ + +namespace OC\Share; + +abstract class Collection extends Share { + + public function getChildren(); + + public function isChild(); + + public function search($pattern); +} \ No newline at end of file diff --git a/lib/share/common.php b/lib/share/common.php new file mode 100644 index 000000000000..b51a87fdf287 --- /dev/null +++ b/lib/share/common.php @@ -0,0 +1,181 @@ +. +*/ + +namespace OC\Share\ShareType; + +abstract class ShareType implements IShareType { + + protected itemType; + protected cache; + + public function __construct(ItemType $itemType, ShareMapper $cache) { + $this->itemType = $itemType; + $this->cache = $cache; + } + + public function isValidShare($share) { + if ($share instanceof OC\Share\FileDependent) { + if (!OCP\Share->isFileSharingEnabled()) { + throw new \InvalidShareException('files_sharing app not enabled'); + } + } + if (!$this->itemType->isValidItem($share)) { + return false; + } + // Check if this is a reshare + $parentId = $this->cache->getId(); + $parent = $this->cache->getShare($parentId); + if ($parent) { + $share->setParentId($parentId); + } + $permissionChecker = new PermissionChecker($this->cache); + if (!$permissionChecker->isValidPermission($share)) { + return false; + } + $timeChecker = new ExpirationChecker($this->cache); + if (!$timeChecker->isValidTime($share)) { + return false; + } + return true; + } + + /** + * Verify sharing conditions and insert share into cache + * @param OC/Share/Share $share + * @return + */ + public function share($share) { + if ($this->isValidShare($share)) { + if ($share instanceof OC\Share\FileDependent) { + // TODO get file id from file path + + $share->setFileTarget($this->generateFileTarget($share)); + } + $data['item_target'] = $this->generateItemTarget($share); + $id = $this->cache->insert($share->toArray()); + $share->setId($id); + return $share; + } + } + + public function generateItemTarget($share) { + if ($this->itemType->isUniqueTargetRequired()) { + $suggestedTarget = $this->itemType->suggestTarget($share); + $this->cache->getShare() + } else { + return $this->itemType->suggestTarget($share); + } + } + + public function generateFileTarget($share) { + if ($share instanceof OC\Share\FileDependent) { + + $suggestedTarget = OCP\Share::get('file')->suggestTarget($share); + + } else { + return false; + } + } + + public function unshare($share) { + $reshares = $this->cache->getReshares($share->getId()); + // Unshare all reshares + foreach ($reshares as $reshare) { + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->unshare($reshare); + } + $this->cache->delete($share->getId()); + } + + public function unshareFromSelf($share) { + $duplicates = $this->cache->getDuplicateShares($share); + // Unshare duplicates from self + foreach ($duplicates as $duplicate) { + $reshares = $this->cache->getReshares($duplicate->getId()); + // Unshare all reshares of duplicates + foreach ($reshares as $reshare) { + // We don't care about duplicates of reshares + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->unshare($reshare); + } + $shareAPI = new OCP\ShareAPI($duplicate->getItemType()); + $shareAPI->unshare($duplicate); + } + $this->unshare($share); + } + + public function setPermissions($share) { + // TODO Only check permission checker once + $permissionChecker = new PermissionChecker($this->cache); + if ($permissionChecker->isValidPermission($share)) { + $permissions = $share->getPermissions(); + $oldPermissions = $this->cache->getShare($share->getId())->getPermissions(); + // Check if permissions were removed + if (~$permissions & $oldPermissions) { + // Update permissions of all reshares + $reshares = $this->cache->getReshares($share->getId()); + foreach ($reshares as $reshare) { + $resharePermissions = $reshare->getPermissions(); + // Check if reshare's permissions were removed + if (~$permissions & resharePermissions) { + // If share permission is removed, delete all reshares + if (($oldPermissions & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE) { + // TODO Check if share permission came from this parent share + $reshare->unshare(); + } else { + $resharePermissions &= $permissions; + $reshare->setPermissions($resharePermissions); + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->update($reshare); + } + } + } + } + $this->cache->update($share->getId(), array('permissions' => $permissions)); + } + } + + public function setExpirationTime($share) { + // TODO Only check expiration checker once + $timeChecker = new ExpirationChecker($this->cache); + if ($timeChecker->isValidTime($share)) { + $time = $share->getExpirationTime(); + // Check if time was decreased + if (isset($time)) { + $oldTime = $this->cache->getShare($share->getId())->getExpirationTime(); + if (!isset($oldTime) || $time < $oldTime) { + // Truncate time of all reshares + $reshares = $cache->getReshares($share->getId()); + foreach ($reshares as $reshare) { + $reshareTime = $reshare->getExpirationTime(); + if (!isset($reshareTime) || $time < $reshareTime) { + $reshare->setExpirationTime($time); + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->update($reshare); + } + } + } + } + $this->cache->update($share->getId(), array('expiration' => $time)); + } + } + +} \ No newline at end of file diff --git a/lib/share/database.php b/lib/share/database.php new file mode 100644 index 000000000000..083ff7bdb7c8 --- /dev/null +++ b/lib/share/database.php @@ -0,0 +1,180 @@ +. +*/ + +namespace OC\Share; + +class ShareMapper { + + private $shareTypeId; + private $itemType; + + + // NOTE: If permissions is 0, don't return it - Group share that is unshared from self + + + /** + * @param \OC\Share\Share $itemType + */ + public function __construct(ItemType $itemType) { + $this->itemType = $itemType; + } + + public function getId($shareOwner, $shareWith, $itemSource) { + + } + + public function getShares($shareOwner, $shareWith, $shareType) { + + + } + + public function getShare($id) { + $query = \OC_DB::prepare('SELECT `parent` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $result = $query->execute(array($id)); + $data = $result->fetchRow(); + if ($data) { + $data = $this->typeCastFields($data); + // Look for duplicate shares + $query = \OC_DB::prepare('SELECT `parent` FROM `*PREFIX*share` WHERE `id` != ?'); + + foreach ($duplicateShares as $duplicateShare) { + $ + } + + + $share = new $itemType($data); + return $share; + } else { + return false; + } + } + + // Only gets the first level of reshares + public function getReshares($id) { + $reshares = array(); + $reshareIds = array(); + $parentId = $this->getShare($id)->getParentId(); + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `parent` = ?'); + $reshareIds = $query->execute(array($id))->fetchAll(); + // NOTE Don't include shares that are just duplicate shares i.e. user & group same owner + foreach ($reshareIds as $reshareId) { + $reshare = $this->getShare($reshareId); + if ($reshare) { + $reshares[$reshare->getId()] = $reshare; + } + } + return $reshares; + } + + /** + * Get identical shares from different owners or share types + * @return + */ + public function getDuplicateShares($id) { + $duplicates = array(); + $share = $this->getShare($id); + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `parent` = ?'); + return $duplicates; + } + + public function insert(array $data) { + list($queryParts, $params) = $this->buildParts($data); + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` + (' . implode(', ', $queryParts) . ')' + . ' VALUES( ' . implode(', ', $valuesPlaceholder) . ')'); + $result = $query->execute($params); + return (int)\OC_DB::insertid('*PREFIX*share'); + } + + public function update($id, array $data) { + if ($this->getShare($id)) { + list($queryParts, $params) = $this->buildParts($data); + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET '. + implode(' = ?, ', $queryParts).' = ? WHERE id = ?'); + $query->execute($params); + } else { + throw new \Exception(); + } + } + + public function delete($id) { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` = ?'); + $query->execute(array($id)); + } + + public function search($pattern) { + + } + + public function getItemTypeNumericId($itemType) { + + } + + public function getShareTypeNumericId($shareType) { + + } + + /** + * Remove all shares for this item type + */ + public function clear() { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `item_type` = ?'); + $query->execute(array($this->itemType)); + } + + public function mergeShares(Share $shares) { + + } + + private function typeCastFields(array $data) { + foreach ($data as $name => $value) { + if ($name === 'id' || $name === 'parent' || $name === 'permissions') { + $data[$name] = (int)$value; + } + } + return $data; + } + + /** + * Extract query parts and params array from Share + * + * @param array $data + * @return array + */ + private function buildParts(Share $share) { + $requiredFields = array('share_owner', 'share_type', 'share_with', 'permissions', + 'item_type', 'item_source', 'item_target'); + if ($share instanceof OC\Share\FileDependent) { + $requiredFields + } + $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'etag'); + $params = array(); + $queryParts = array(); + foreach ($data as $name => $value) { + if (array_search($name, $fields) !== false) { + $params[] = $value; + $queryParts[] = '`' . $name . '`'; + } + } + return array($queryParts, $params); + } + +} \ No newline at end of file diff --git a/lib/share/exceptions/invalidshareexception.php b/lib/share/exceptions/invalidshareexception.php new file mode 100644 index 000000000000..7e368765690c --- /dev/null +++ b/lib/share/exceptions/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/filedependent.php b/lib/share/filedependent.php new file mode 100644 index 000000000000..34d80668b95c --- /dev/null +++ b/lib/share/filedependent.php @@ -0,0 +1,59 @@ +. +*/ + +namespace OC\Share; + +abstract class FileDependent extends Share { + + private $fileId; + private $fileTarget; + + public function __construct($shareType, $data) { + parent::__construct($shareType, $data); + if (isset($data['fileId'])) { + $this->fileId = (int)$data['fileId']; + } + if (isset($data['fileSourcePath'])) { + + } + + } + + public function getFileId() { + if (!isset($this->fileId)) { + + } + return $this->fileSource; + } + + public function getFileTarget() { + return $this->fileTarget; + } + + public function getAbsolutePath() + + public function getSourcePath() + + public function getStorage() { + + } + +} \ No newline at end of file diff --git a/lib/share/hooks.php b/lib/share/hooks.php new file mode 100644 index 000000000000..6c5383a01445 --- /dev/null +++ b/lib/share/hooks.php @@ -0,0 +1,94 @@ +. +*/ + +namespace OC\Share; + +class Hooks { + + public static function post_deleteUser($arguments) { + $cache = new \OC\Share\Cache() + // Delete any items shared with the deleted user + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`' + .' WHERE `share_with` = ? AND `share_type` = ? OR `share_type` = ?'); + $result = $query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique)); + // Delete any items the deleted user shared + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?'); + $result = $query->execute(array($arguments['uid'])); + while ($item = $result->fetchRow()) { + self::delete($item['id']); + } + } + + public static function post_addToGroup($arguments) { + // Find the group shares and check if the user needs a unique target + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'); + $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'])); + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`,' + .' `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`,' + .' `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)'); + while ($item = $result->fetchRow()) { + if ($item['item_type'] == 'file' || $item['item_type'] == 'file') { + $itemTarget = null; + } else { + $itemTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, + $arguments['uid'], $item['uid_owner'], $item['item_target'], $item['id']); + } + if (isset($item['file_source'])) { + $fileTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, + $arguments['uid'], $item['uid_owner'], $item['file_target'], $item['id']); + } else { + $fileTarget = null; + } + // Insert an extra row for the group share if the item or file target is unique for this user + if ($itemTarget != $item['item_target'] || $fileTarget != $item['file_target']) { + $query->execute(array($item['item_type'], $item['item_source'], $itemTarget, $item['id'], + self::$shareTypeGroupUserUnique, $arguments['uid'], $item['uid_owner'], $item['permissions'], + $item['stime'], $item['file_source'], $fileTarget)); + \OC_DB::insertid('*PREFIX*share'); + } + } + } + + public static function post_removeFromGroup($arguments) { + // TODO Don't call if user deleted? + $query = \OC_DB::prepare('SELECT `id`, `share_type` FROM `*PREFIX*share`' + .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'); + $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'], self::$shareTypeGroupUserUnique, + $arguments['uid'])); + while ($item = $result->fetchRow()) { + if ($item['share_type'] == self::SHARE_TYPE_GROUP) { + // Delete all reshares by this user of the group share + self::delete($item['id'], true, $arguments['uid']); + } else { + self::delete($item['id']); + } + } + } + + public static function post_deleteGroup($arguments) { + $query = \OC_DB::prepare('SELECT id FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'); + $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'])); + while ($item = $result->fetchRow()) { + self::delete($item['id']); + } + } + +} \ No newline at end of file diff --git a/lib/share/itemtype.php b/lib/share/itemtype.php new file mode 100644 index 000000000000..f95277099325 --- /dev/null +++ b/lib/share/itemtype.php @@ -0,0 +1,31 @@ +. +*/ + +namespace OC\Share; + +interface ItemType { + + public function isValidItem($share); + public function getItem($shareType, $data); + public function suggestTarget($share); + public function isUniqueTargetRequired(); + +} \ No newline at end of file diff --git a/lib/share/permissions.php b/lib/share/permissions.php new file mode 100644 index 000000000000..2b98598100d3 --- /dev/null +++ b/lib/share/permissions.php @@ -0,0 +1,71 @@ +. +*/ + +namespace OC\Share; + +public class PermissionChecker { + + protected $mapper; + + public function __construct(ShareMapper $mapper) { + $this->mapper = $mapper; + } + + public function isValidPermission() { + if (!is_int($permissions) || $permisisons < 0 || $permissions > OCP\PERMISSION_All) { + throw new \Exception(); + } + $parentId = $share->getParentId(); + if (isset($parentId)) { + if (!$this->isResharingAllowed()) { + throw new \Exception(); + } + // Check if permissions exceed the parent share permissions + $parent = $this->mapper->getShare($parentId); + if ($permissions & ~$parent->getPermissions()) { + throw new \Exception($message); + } + // Check if share permission is granted + if (~$parentPermissions & PERMISSION_SHARE) { + return false; + } + } + // TODO Check if permission allowed for item + return true; + } + + /** + * Check if resharing is allowed + * @return bool + * + * Resharing is allowed by default if not configured + * + */ + public function isResharingAllowed() { + $configValue = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes'); + if ($configValue === 'yes') { + return true; + } else { + return false; + } + } + +} \ No newline at end of file diff --git a/lib/share/share.php b/lib/share/share.php new file mode 100644 index 000000000000..32dd6a2eb74e --- /dev/null +++ b/lib/share/share.php @@ -0,0 +1,167 @@ +. +*/ + +namespace OC\Share; + +abstract class Share { + + private $id; + private $parentId; + private $shareOwner; + private $shareType; + private $shareWith; + private $permissions; + private $itemSource; + private $itemTarget; + + public function __construct() { + $this->shareType = $shareType; + $this->permissions = (int)$data['permissions']; + } + + public function getId() { + return $this->id; + } + + public function setId($id) { + $this->id = $id; + } + + public function getParentId() { + return $this->parentId; + } + + public function setParentId($parentId) { + $this->parentId = $parentId; + } + + public function getShareType() { + return $this->shareType; + } + + public function getShareOwner() { + return $this->shareOwner; + } + + public function getShareWith() { + return $this->shareWith; + } + + public function getPermissions() { + return $this->permissions; + } + + public function setPermissions($permissions) { + $this->permissions = $permissions; + } + + public function isCreatable() { + return $this->getPermissions() & OCP\PERMISSION_CREATE; + } + + public function isReadable() { + return $this->getPermissions() & OCP\PERMISSION_READ; + } + + public function isUpdatable() { + return $this->getPermissions() & OCP\PERMISSION_UPDATE; + } + + public function isDeletable() { + return $this->getPermissions() & OCP\PERMISSION_DELETE; + } + + public function isSharable() { + return $this->getPermissions() & OCP\PERMISSION_SHARE; + } + + public function getItemType() { + return $this->itemType; + } + + public function getItemSource() { + return $this->itemSource; + } + + public function getItemTarget() { + return $this->itemTarget; + } + + public function getItemOwner() { + $parentId = $this->getParentId(); + if ($parentId > -1) { + $database = new \OC\Share\Cache(); + while ($parentId > -1) { + $parentShare = $database->getShare($parentId); + $parentId = $parentShare->getParentId(); + } + return $parentShare->getShareOwner(); + } else { + return $this->getShareOwner(); + } + } + + public function getExpirationTime() { + return $this->expirationTime; + } + + public function setExpirationTime($time) { + $this->expirationDate = $time; + } + + public function getUpdatedFields() { + + } + + /** + * Transform a database columnname to a property + * @param string $columnName the name of the column + * @return string the property name + */ + public function columnToProperty($columnName) { + $parts = explode('_', $columnName); + $property = null; + foreach ($parts as $part) { + if ($property === null) { + $property = $part; + } else { + $property .= ucfirst($part); + } + } + return $property; + } + + /** + * Maps the keys of the row array to the attributes + * @param array $row the row to map onto the entity + */ + public function fromRow(array $row) { + foreach ($row as $key => $value) { + $prop = $this->columnToProperty($key); + $this->$prop = $value; + } + } + + public function toArray() { + + } + +} \ No newline at end of file diff --git a/lib/share/sharepublic.php b/lib/share/sharepublic.php new file mode 100644 index 000000000000..b1f893ca993c --- /dev/null +++ b/lib/share/sharepublic.php @@ -0,0 +1,118 @@ +. +*/ +namespace OCP; + +/** +* 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. +* +* It provides the following hooks: +* - post_shared +*/ +class ShareAPI { + + private $itemType; + private $cache; + + + public function __construct(OC\Share\ItemType $itemType) { + $this->itemType = $itemType; + $this->cache = new \OC\Share\Cache($this->itemType); + } + + public function getShare() { + + } + + public function getShares() { + + } + + public function share(Share $share) { + $shareTypeId = $share->getShareType(); + $shareType = $this->getShareTypeObject($shareTypeId); + if ($shareType) { + return $shareType->share($share); + } else { + return false; + } + } + + public function unshare(Share $share) { + if ($share->getShareOwner() !== \OC_User::getUser()) { + return false; + } + $shareTypeId = $share->getShareType(); + $shareType = $this->getShareTypeObject($shareTypeId); + if ($shareType) { + return $shareType->unshare($share); + } else { + return false; + } + } + + public function unshareFromSelf(Share $share) { + // TODO better validation + if ($share->getShareOwner() === \OC_User::getUser()) { + return false; + } + $shareTypeId = $share->getShareType(); + $shareType = $this->getShareTypeObject($shareTypeId); + if ($shareType) { + return $shareType->unshareFromSelf($share); + } else { + return false; + } + } + + /** + * Update a Share in the cache + * @param Share $share + */ + public function update(Share $share) { + if ($share->getShareOwner() !== \OC_User::getUser()) { + return false; + } + $shareTypeId = $share->getShareType(); + $shareType = $this->getShareTypeObject($shareTypeId); + if ($shareType) { + $updatedFields = $share->getUpdatedFields(); + foreach ($updatedFields as $updatedField) { + $setter = 'set'.ucfirst($updatedField); + if (method_exists($shareType, $setter)) { + $shareType->$setter($share); + } else { + throw new \Exception(); + } + } + } else { + throw new \Exception(); + } + } + + public function getShareTypeObject($shareTypeId) { + if (!isset(self::$shareTypes[$shareTypeId])) { + // Check if item type supports this share type + } + return self::$shareTypes[$shareTypeId]; + } + +} \ No newline at end of file diff --git a/lib/share/sharetype.php b/lib/share/sharetype.php new file mode 100644 index 000000000000..97748587e157 --- /dev/null +++ b/lib/share/sharetype.php @@ -0,0 +1,67 @@ +. +*/ + +namespace OC\Share\ShareType; + +interface ShareType { + + /** + * + */ + public function getId(); + + /** + * Check if $shareOwner is allowed to share with $shareWith + * @param string $shareOwner + * @param string $shareWith + * @return bool + */ + public function isValidShare($shareOwner, $shareWith); + + + + /** + * + * @param \OC\Share\Share $share + * @return bool + */ + public function share($share); + + /** + * + */ + public function generateItemTarget($share); + + /** + * Generate a unique file target for the + * @param \OC\Share\Share $share + * @return string + */ + public function generateFileTarget($share); + + public function unshare($share); + public function unshareFromSelf($share); + public function setPermissions($id, $permissions); + public function setExpirationDate($id, $date); + + public function searchShareWith(); + +} \ No newline at end of file diff --git a/lib/share/sharetypefac.php b/lib/share/sharetypefac.php new file mode 100644 index 000000000000..0eefc61fe03a --- /dev/null +++ b/lib/share/sharetypefac.php @@ -0,0 +1,29 @@ +. +*/ + +namespace OC\Share; + +public class ShareTypeFactory { + + private $shareTypes; + + public function getShareType +} \ No newline at end of file diff --git a/lib/share/sharetypes/common.php b/lib/share/sharetypes/common.php new file mode 100644 index 000000000000..23d7493a6c78 --- /dev/null +++ b/lib/share/sharetypes/common.php @@ -0,0 +1,173 @@ +. +*/ + +namespace OC\Share\ShareType; + +abstract class ShareType implements IShareType { + + protected itemType; + protected cache; + + public function __construct(ItemType $itemType, ShareMapper $cache) { + $this->itemType = $itemType; + $this->cache = $cache; + } + + public function isValidShare($share) { + if ($share instanceof OC\Share\FileDependent) { + if (!OCP\Share->isFileSharingEnabled()) { + throw new \InvalidShareException('files_sharing app not enabled'); + } + } + if (!$this->itemType->isValidItem($share)) { + return false; + } + // Check if this is a reshare + $parentId = $this->cache->getId(); + $parent = $this->cache->getShare($parentId); + if ($parent) { + $share->setParentId($parentId); + } + $permissionChecker = new PermissionChecker($this->cache); + if (!$permissionChecker->isValidPermission($share)) { + return false; + } + $timeChecker = new ExpirationChecker($this->cache); + if (!$timeChecker->isValidTime($share)) { + return false; + } + return true; + } + + /** + * Verify sharing conditions and put share into cache + * @param OC/Share/Share $share + * @return + */ + public function share($share) { + if ($this->isValidShare($share)) { + if ($share instanceof OC\Share\FileDependent) { + // TODO get file id from file path + + $data['file_target'] = $this->generateFileTarget($share); + } + $data['item_target'] = $this->generateItemTarget($share); + $id = $this->cache->put($share); + $share->setId($id); + return $share; + } + } + + public function generateItemTarget($share) { + if ($this->itemType->isUniqueTargetRequired()) { + $suggestedTarget = $this->itemType->suggestTarget($share); + $this->cache->getShare() + } else { + return $this->itemType->suggestTarget($share); + } + } + + public function generateFileTarget($share) { + if ($share instanceof OC\Share\FileDependent) { + + $suggestedTarget = OCP\Share::get('file')->suggestTarget($share); + + } else { + return false; + } + } + + public function unshare($share) { + $reshares = $this->cache->getReshares($share->getId()); + // Unshare all reshares + foreach ($reshares as $reshare) { + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->unshare($reshare); + } + $this->cache->delete($share->getId()); + } + + public function unshareFromSelf($share) { + $duplicates = $this->cache->getDuplicateShares($share); + // Unshare duplicates from self + foreach ($duplicates as $duplicate) { + $reshares = $this->cache->getReshares($duplicate->getId()); + // Unshare all reshares of duplicates + foreach ($reshares as $reshare) { + // We don't care about duplicates of reshares + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->unshare($reshare); + } + $shareAPI = new OCP\ShareAPI($duplicate->getItemType()); + $shareAPI->unshare($duplicate); + } + $this->unshare($share); + } + + public function setPermissions($share) { + $permissions = $share->getPermissions(); + $oldPermissions = $this->cache->getShare($share->getId())->getPermissions(); + // Check if permissions were removed + if (~$permissions & $oldPermissions) { + // Update permissions of all reshares + $reshares = $this->cache->getReshares($share->getId()); + foreach ($reshares as $reshare) { + $resharePermissions = $reshare->getPermissions(); + // Check if reshare's permissions were removed + if (~$permissions & resharePermissions) { + // If share permission is removed, delete all reshares + if (($oldPermissions & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE) { + // TODO Check if share permission came from this parent share + $reshare->unshare(); + } else { + $resharePermissions &= $permissions; + $reshare->setPermissions($resharePermissions); + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->update($reshare); + } + } + } + } + $this->cache->update($share->getId(), array('permissions' => $permissions)); + } + + public function setExpirationTime($share) { + $time = $share->getExpirationTime(); + // Check if time was decreased + if (isset($time)) { + $oldTime = $this->cache->getShare($share->getId())->getExpirationTime(); + if (!isset($oldTime) || $time < $oldTime) { + // Truncate time of all reshares + $reshares = $cache->getReshares($share->getId()); + foreach ($reshares as $reshare) { + $reshareTime = $reshare->getExpirationTime(); + if (!isset($reshareTime) || $time < $reshareTime) { + $reshare->setExpirationTime($time); + $shareAPI = new OCP\ShareAPI($reshare->getItemType()); + $shareAPI->update($reshare); + } + } + } + } + $this->cache->update($share->getId(), array('expiration' => $time)); + } + +} \ No newline at end of file diff --git a/lib/share/sharetypes/group.php b/lib/share/sharetypes/group.php new file mode 100644 index 000000000000..dce3365dea6a --- /dev/null +++ b/lib/share/sharetypes/group.php @@ -0,0 +1,87 @@ +. +*/ + +namespace OC\Share\Type; + +class Group extends Common { + + public function getId() { + return 'group'; + } + + public function isValidShare($share) { + parent::isValidShare($share); + if (!\OC_Group::groupExists($shareWith)) { + $message = 'Sharing '.$itemSource.' failed, because the group '.$shareWith.' does not exist'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); + if ($sharingPolicy === 'groups_only' && !\OC_Group::inGroup($shareOwner, $shareWith)) { + $message = 'Sharing '.$itemSource.' failed, because ' + .$uidOwner.' is not a member of the group '.$shareWith; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } + + public function share($share) { + if ($this->isValidShare($share)) { + if ($this->itemType->isUniqueTargetRequired()) { + $users = \OC_Group::usersInGroup($share->getShareWith()); + $tempShare = $share; + foreach ($users as $user) { + $tempShare->setShareType('user'); + $tempShare->setShareWith($user); + $tempdata['item_target'] = $this->generateItemTarget($tempShare); + + if ($tempdata['']) + } + } + + $id = $this->cache->put($data; + $share->setId($id); + return $share; + } + } + + public function unshareFromSelf($share) { + + } + + public function search($pattern) { + return OC_Group::getGroups(); + } + + // Hook Listeners + public static function post_addToGroup($params) { + + } + + public static function post_removeFromGroup($params) { + + } + + public static function post_deleteGroup($params) { + + } + +} \ No newline at end of file diff --git a/lib/share/sharetypes/link.php b/lib/share/sharetypes/link.php new file mode 100644 index 000000000000..f8c396612e8e --- /dev/null +++ b/lib/share/sharetypes/link.php @@ -0,0 +1,73 @@ +. +*/ + +namespace OC\Share\Type; + +class Link extends Common { + + public function isValidShare($share) { + parent::isValidShare($share); + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes'); + if ($sharingPolicy !== 'yes') { + throw new \InvalidShareException('Sharing with links is not allowed'); + } else { + return true; + } + } + + public function share($share) { + $id = parent::share($share); + $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); + if ($id) { + return $share->getToken(); + } else { + return false; + } + } + + /** + * + * @return string + * + * Unique targets are not required for links + * + */ + public function generateItemTarget($share) { + $itemType = $share->getItemType(); + return $itemType->suggestTarget($share); + } + + /** + * + * @return string + * + * Unique targets are not required for links + * + */ + public function generateFileTarget($share) { + return OCP\Share::get('file')->suggestTarget($share); + } + + public function search($pattern) { + return null; + } + +} \ No newline at end of file diff --git a/lib/share/sharetypes/user.php b/lib/share/sharetypes/user.php new file mode 100644 index 000000000000..c12805794d83 --- /dev/null +++ b/lib/share/sharetypes/user.php @@ -0,0 +1,59 @@ +. +*/ + +namespace OC\Share\Type; + +class User extends Common { + + public function getId() { + return 'user'; + } + + public function isValidShare($shareOwner, $shareWith) { + if ($shareOwner === $shareWith) { + $message = 'the user '.$this->shareWith.' is the item owner'; + throw new \InvalidShareException($message); + } + if (!\OC_User::userExists($shareWith)) { + $message = 'the user '.$shareWith.' does not exist'; + throw new \Exception($message); + } + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); + if ($sharingPolicy === 'groups_only') { + $inGroup = array_intersect(\OC_Group::getUserGroups($shareOwner), \OC_Group::getUserGroups($shareWith)); + if (empty($inGroup)) { + $message = 'the user '.$shareWith.' is not a member of any groups that '.$shareOwner.' is a member of'; + throw new \Exception($message); + } + } + return true; + } + + public function search($pattern) { + return OC_User::getUsers(); + } + + // Hook Listener + public static function post_deleteUser($params) { + + } + +} \ No newline at end of file diff --git a/lib/share/time.php b/lib/share/time.php new file mode 100644 index 000000000000..5afe9184aded --- /dev/null +++ b/lib/share/time.php @@ -0,0 +1,90 @@ +. +*/ + +namespace OC\Share; + +public class ExpirationChecker { + + protected $mapper; + + public function __construct(ShareMapper $mapper) { + $this->mapper = $mapper; + } + + /** + * Check if the expiration time is valid + * @param + * @return bool + * + * A valid time is at least 1 hour in the future + * + */ + public function isValidTime(Share $share) { + $time = $share->getExpirationTime(); + if (isset($time) && !is_int($time)) { + throw new \Exception($message); + } + if (isset($time) && $time < time() + 3600) { + throw new \Exception($message); + } + $parentId = $share->getParentId(); + if (isset($parentId)) { + // Check if time is later than the parent expiration time + $parent = $this->mapper->getShare($parentId); + $parentTime = $parent->getExpirationTime(); + if (isset($parentTime)) { + if ((!isset($time) || $time > $parentTime) { + throw new \Exception($message); + } + } + } + return true; + } + + /** + * Check if Share is expired + * @param + * @return bool + */ + public function isExpired(Share $share) { + $time = $share->getExpirationTime(); + if (isset($time)) { + if ($time - time() > 0) { + return true; + } + } else if (($this->getDefaultTime() + $share->getShareTime()) - time() > 0) { + return true; + } + return false; + } + + /** + * Get the default expiration time + * @return time + * + * No expiration time is set by default + * + */ + public function getDefaultTime() { + return \OC_Appconfig::getValue('core', 'shareapi_expiration_time', null); + } + +} \ No newline at end of file diff --git a/lib/share/utility.php b/lib/share/utility.php new file mode 100644 index 000000000000..51a22d69597b --- /dev/null +++ b/lib/share/utility.php @@ -0,0 +1,53 @@ +. +*/ + +namespace OC\Share; + +public class Utility { + + /** + * Check if the Share API is enabled + * @return bool + * + * The Share API is enabled by default if not configured + * + */ + public function isEnabled() { + $configValue = \OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes'); + if ($configValue === 'yes') { + return true; + } else { + return false; + } + } + + /** + * Check if the files_sharing app is enabled + * @return bool + * + * Item types dependent on files will only work if the files_sharing app is enabled + * + */ + public function isFileSharingEnabled() { + return \OC_App::isEnabled('files_sharing'); + } + +} \ No newline at end of file From 43db1596665568821fbe816e89b5d110dd7cc7fa Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 24 May 2013 14:14:58 -0400 Subject: [PATCH 02/85] More crazy rewriting --- lib/share/common.php | 181 -------- lib/share/database.php | 180 -------- lib/share/filedependent.php | 59 --- lib/share/hooks.php | 94 ---- lib/share/iadvancedsharefactory.php | 67 +++ lib/share/itemtype.php | 31 -- lib/share/permissions.php | 71 --- lib/share/share.php | 226 ++++++---- .../{collection.php => sharefactory.php} | 19 +- lib/share/sharepublic.php | 403 ++++++++++++++++-- lib/share/sharetype.php | 67 --- lib/share/sharetype/group.php | 152 +++++++ lib/share/sharetype/isharetype.php | 89 ++++ lib/share/sharetype/link.php | 130 ++++++ lib/share/sharetype/sharetype.php | 152 +++++++ lib/share/{sharetypes => sharetype}/user.php | 6 +- lib/share/sharetypefac.php | 29 -- lib/share/sharetypes/common.php | 173 -------- lib/share/sharetypes/group.php | 87 ---- lib/share/sharetypes/link.php | 73 ---- lib/share/time.php | 90 ---- lib/share/utility.php | 42 ++ 22 files changed, 1140 insertions(+), 1281 deletions(-) delete mode 100644 lib/share/common.php delete mode 100644 lib/share/database.php delete mode 100644 lib/share/filedependent.php delete mode 100644 lib/share/hooks.php create mode 100644 lib/share/iadvancedsharefactory.php delete mode 100644 lib/share/itemtype.php delete mode 100644 lib/share/permissions.php rename lib/share/{collection.php => sharefactory.php} (81%) delete mode 100644 lib/share/sharetype.php create mode 100644 lib/share/sharetype/group.php create mode 100644 lib/share/sharetype/isharetype.php create mode 100644 lib/share/sharetype/link.php create mode 100644 lib/share/sharetype/sharetype.php rename lib/share/{sharetypes => sharetype}/user.php (90%) delete mode 100644 lib/share/sharetypefac.php delete mode 100644 lib/share/sharetypes/common.php delete mode 100644 lib/share/sharetypes/group.php delete mode 100644 lib/share/sharetypes/link.php delete mode 100644 lib/share/time.php diff --git a/lib/share/common.php b/lib/share/common.php deleted file mode 100644 index b51a87fdf287..000000000000 --- a/lib/share/common.php +++ /dev/null @@ -1,181 +0,0 @@ -. -*/ - -namespace OC\Share\ShareType; - -abstract class ShareType implements IShareType { - - protected itemType; - protected cache; - - public function __construct(ItemType $itemType, ShareMapper $cache) { - $this->itemType = $itemType; - $this->cache = $cache; - } - - public function isValidShare($share) { - if ($share instanceof OC\Share\FileDependent) { - if (!OCP\Share->isFileSharingEnabled()) { - throw new \InvalidShareException('files_sharing app not enabled'); - } - } - if (!$this->itemType->isValidItem($share)) { - return false; - } - // Check if this is a reshare - $parentId = $this->cache->getId(); - $parent = $this->cache->getShare($parentId); - if ($parent) { - $share->setParentId($parentId); - } - $permissionChecker = new PermissionChecker($this->cache); - if (!$permissionChecker->isValidPermission($share)) { - return false; - } - $timeChecker = new ExpirationChecker($this->cache); - if (!$timeChecker->isValidTime($share)) { - return false; - } - return true; - } - - /** - * Verify sharing conditions and insert share into cache - * @param OC/Share/Share $share - * @return - */ - public function share($share) { - if ($this->isValidShare($share)) { - if ($share instanceof OC\Share\FileDependent) { - // TODO get file id from file path - - $share->setFileTarget($this->generateFileTarget($share)); - } - $data['item_target'] = $this->generateItemTarget($share); - $id = $this->cache->insert($share->toArray()); - $share->setId($id); - return $share; - } - } - - public function generateItemTarget($share) { - if ($this->itemType->isUniqueTargetRequired()) { - $suggestedTarget = $this->itemType->suggestTarget($share); - $this->cache->getShare() - } else { - return $this->itemType->suggestTarget($share); - } - } - - public function generateFileTarget($share) { - if ($share instanceof OC\Share\FileDependent) { - - $suggestedTarget = OCP\Share::get('file')->suggestTarget($share); - - } else { - return false; - } - } - - public function unshare($share) { - $reshares = $this->cache->getReshares($share->getId()); - // Unshare all reshares - foreach ($reshares as $reshare) { - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->unshare($reshare); - } - $this->cache->delete($share->getId()); - } - - public function unshareFromSelf($share) { - $duplicates = $this->cache->getDuplicateShares($share); - // Unshare duplicates from self - foreach ($duplicates as $duplicate) { - $reshares = $this->cache->getReshares($duplicate->getId()); - // Unshare all reshares of duplicates - foreach ($reshares as $reshare) { - // We don't care about duplicates of reshares - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->unshare($reshare); - } - $shareAPI = new OCP\ShareAPI($duplicate->getItemType()); - $shareAPI->unshare($duplicate); - } - $this->unshare($share); - } - - public function setPermissions($share) { - // TODO Only check permission checker once - $permissionChecker = new PermissionChecker($this->cache); - if ($permissionChecker->isValidPermission($share)) { - $permissions = $share->getPermissions(); - $oldPermissions = $this->cache->getShare($share->getId())->getPermissions(); - // Check if permissions were removed - if (~$permissions & $oldPermissions) { - // Update permissions of all reshares - $reshares = $this->cache->getReshares($share->getId()); - foreach ($reshares as $reshare) { - $resharePermissions = $reshare->getPermissions(); - // Check if reshare's permissions were removed - if (~$permissions & resharePermissions) { - // If share permission is removed, delete all reshares - if (($oldPermissions & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE) { - // TODO Check if share permission came from this parent share - $reshare->unshare(); - } else { - $resharePermissions &= $permissions; - $reshare->setPermissions($resharePermissions); - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->update($reshare); - } - } - } - } - $this->cache->update($share->getId(), array('permissions' => $permissions)); - } - } - - public function setExpirationTime($share) { - // TODO Only check expiration checker once - $timeChecker = new ExpirationChecker($this->cache); - if ($timeChecker->isValidTime($share)) { - $time = $share->getExpirationTime(); - // Check if time was decreased - if (isset($time)) { - $oldTime = $this->cache->getShare($share->getId())->getExpirationTime(); - if (!isset($oldTime) || $time < $oldTime) { - // Truncate time of all reshares - $reshares = $cache->getReshares($share->getId()); - foreach ($reshares as $reshare) { - $reshareTime = $reshare->getExpirationTime(); - if (!isset($reshareTime) || $time < $reshareTime) { - $reshare->setExpirationTime($time); - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->update($reshare); - } - } - } - } - $this->cache->update($share->getId(), array('expiration' => $time)); - } - } - -} \ No newline at end of file diff --git a/lib/share/database.php b/lib/share/database.php deleted file mode 100644 index 083ff7bdb7c8..000000000000 --- a/lib/share/database.php +++ /dev/null @@ -1,180 +0,0 @@ -. -*/ - -namespace OC\Share; - -class ShareMapper { - - private $shareTypeId; - private $itemType; - - - // NOTE: If permissions is 0, don't return it - Group share that is unshared from self - - - /** - * @param \OC\Share\Share $itemType - */ - public function __construct(ItemType $itemType) { - $this->itemType = $itemType; - } - - public function getId($shareOwner, $shareWith, $itemSource) { - - } - - public function getShares($shareOwner, $shareWith, $shareType) { - - - } - - public function getShare($id) { - $query = \OC_DB::prepare('SELECT `parent` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $result = $query->execute(array($id)); - $data = $result->fetchRow(); - if ($data) { - $data = $this->typeCastFields($data); - // Look for duplicate shares - $query = \OC_DB::prepare('SELECT `parent` FROM `*PREFIX*share` WHERE `id` != ?'); - - foreach ($duplicateShares as $duplicateShare) { - $ - } - - - $share = new $itemType($data); - return $share; - } else { - return false; - } - } - - // Only gets the first level of reshares - public function getReshares($id) { - $reshares = array(); - $reshareIds = array(); - $parentId = $this->getShare($id)->getParentId(); - $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `parent` = ?'); - $reshareIds = $query->execute(array($id))->fetchAll(); - // NOTE Don't include shares that are just duplicate shares i.e. user & group same owner - foreach ($reshareIds as $reshareId) { - $reshare = $this->getShare($reshareId); - if ($reshare) { - $reshares[$reshare->getId()] = $reshare; - } - } - return $reshares; - } - - /** - * Get identical shares from different owners or share types - * @return - */ - public function getDuplicateShares($id) { - $duplicates = array(); - $share = $this->getShare($id); - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `parent` = ?'); - return $duplicates; - } - - public function insert(array $data) { - list($queryParts, $params) = $this->buildParts($data); - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` - (' . implode(', ', $queryParts) . ')' - . ' VALUES( ' . implode(', ', $valuesPlaceholder) . ')'); - $result = $query->execute($params); - return (int)\OC_DB::insertid('*PREFIX*share'); - } - - public function update($id, array $data) { - if ($this->getShare($id)) { - list($queryParts, $params) = $this->buildParts($data); - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET '. - implode(' = ?, ', $queryParts).' = ? WHERE id = ?'); - $query->execute($params); - } else { - throw new \Exception(); - } - } - - public function delete($id) { - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` = ?'); - $query->execute(array($id)); - } - - public function search($pattern) { - - } - - public function getItemTypeNumericId($itemType) { - - } - - public function getShareTypeNumericId($shareType) { - - } - - /** - * Remove all shares for this item type - */ - public function clear() { - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `item_type` = ?'); - $query->execute(array($this->itemType)); - } - - public function mergeShares(Share $shares) { - - } - - private function typeCastFields(array $data) { - foreach ($data as $name => $value) { - if ($name === 'id' || $name === 'parent' || $name === 'permissions') { - $data[$name] = (int)$value; - } - } - return $data; - } - - /** - * Extract query parts and params array from Share - * - * @param array $data - * @return array - */ - private function buildParts(Share $share) { - $requiredFields = array('share_owner', 'share_type', 'share_with', 'permissions', - 'item_type', 'item_source', 'item_target'); - if ($share instanceof OC\Share\FileDependent) { - $requiredFields - } - $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'etag'); - $params = array(); - $queryParts = array(); - foreach ($data as $name => $value) { - if (array_search($name, $fields) !== false) { - $params[] = $value; - $queryParts[] = '`' . $name . '`'; - } - } - return array($queryParts, $params); - } - -} \ No newline at end of file diff --git a/lib/share/filedependent.php b/lib/share/filedependent.php deleted file mode 100644 index 34d80668b95c..000000000000 --- a/lib/share/filedependent.php +++ /dev/null @@ -1,59 +0,0 @@ -. -*/ - -namespace OC\Share; - -abstract class FileDependent extends Share { - - private $fileId; - private $fileTarget; - - public function __construct($shareType, $data) { - parent::__construct($shareType, $data); - if (isset($data['fileId'])) { - $this->fileId = (int)$data['fileId']; - } - if (isset($data['fileSourcePath'])) { - - } - - } - - public function getFileId() { - if (!isset($this->fileId)) { - - } - return $this->fileSource; - } - - public function getFileTarget() { - return $this->fileTarget; - } - - public function getAbsolutePath() - - public function getSourcePath() - - public function getStorage() { - - } - -} \ No newline at end of file diff --git a/lib/share/hooks.php b/lib/share/hooks.php deleted file mode 100644 index 6c5383a01445..000000000000 --- a/lib/share/hooks.php +++ /dev/null @@ -1,94 +0,0 @@ -. -*/ - -namespace OC\Share; - -class Hooks { - - public static function post_deleteUser($arguments) { - $cache = new \OC\Share\Cache() - // Delete any items shared with the deleted user - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`' - .' WHERE `share_with` = ? AND `share_type` = ? OR `share_type` = ?'); - $result = $query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique)); - // Delete any items the deleted user shared - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?'); - $result = $query->execute(array($arguments['uid'])); - while ($item = $result->fetchRow()) { - self::delete($item['id']); - } - } - - public static function post_addToGroup($arguments) { - // Find the group shares and check if the user needs a unique target - $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'); - $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'])); - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`,' - .' `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`,' - .' `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)'); - while ($item = $result->fetchRow()) { - if ($item['item_type'] == 'file' || $item['item_type'] == 'file') { - $itemTarget = null; - } else { - $itemTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, - $arguments['uid'], $item['uid_owner'], $item['item_target'], $item['id']); - } - if (isset($item['file_source'])) { - $fileTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, - $arguments['uid'], $item['uid_owner'], $item['file_target'], $item['id']); - } else { - $fileTarget = null; - } - // Insert an extra row for the group share if the item or file target is unique for this user - if ($itemTarget != $item['item_target'] || $fileTarget != $item['file_target']) { - $query->execute(array($item['item_type'], $item['item_source'], $itemTarget, $item['id'], - self::$shareTypeGroupUserUnique, $arguments['uid'], $item['uid_owner'], $item['permissions'], - $item['stime'], $item['file_source'], $fileTarget)); - \OC_DB::insertid('*PREFIX*share'); - } - } - } - - public static function post_removeFromGroup($arguments) { - // TODO Don't call if user deleted? - $query = \OC_DB::prepare('SELECT `id`, `share_type` FROM `*PREFIX*share`' - .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'); - $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'], self::$shareTypeGroupUserUnique, - $arguments['uid'])); - while ($item = $result->fetchRow()) { - if ($item['share_type'] == self::SHARE_TYPE_GROUP) { - // Delete all reshares by this user of the group share - self::delete($item['id'], true, $arguments['uid']); - } else { - self::delete($item['id']); - } - } - } - - public static function post_deleteGroup($arguments) { - $query = \OC_DB::prepare('SELECT id FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'); - $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'])); - while ($item = $result->fetchRow()) { - self::delete($item['id']); - } - } - -} \ No newline at end of file diff --git a/lib/share/iadvancedsharefactory.php b/lib/share/iadvancedsharefactory.php new file mode 100644 index 000000000000..17433bc60d4e --- /dev/null +++ b/lib/share/iadvancedsharefactory.php @@ -0,0 +1,67 @@ +. +*/ + +namespace OC\Share; + +/** + * An Advanced Share Factory to reduce the number of queries needed to generate a Share object + * Setup JOINs in the share queries to retrieve additional properties for the Share object + * The columns specified in getColumns() will be returned in the $row passed to mapToShare($row) + */ +interface IAdvancedShareFactory extends IShareFactory { + + /** + * Get JOIN(s) to app table(s) + * @return array + * + * Example: + * + * return array( + * 'table1' => array( + * 'share' => 'item_source', + * 'table1' => 'id' + * ) + * ); + * + * Equivalent: JOIN table1 ON share.item_source = table1.id + * + */ + public function getJoins(); + + /** + * Get app table column(s) + * @return array + * + * Example: + * + * return array( + * 'table1' => array( + * 'id', + * 'name' + * ) + * ); + * + * Equivalent: SELECT table1.id, table1.name + * + */ + public function getColumns(); + +} \ No newline at end of file diff --git a/lib/share/itemtype.php b/lib/share/itemtype.php deleted file mode 100644 index f95277099325..000000000000 --- a/lib/share/itemtype.php +++ /dev/null @@ -1,31 +0,0 @@ -. -*/ - -namespace OC\Share; - -interface ItemType { - - public function isValidItem($share); - public function getItem($shareType, $data); - public function suggestTarget($share); - public function isUniqueTargetRequired(); - -} \ No newline at end of file diff --git a/lib/share/permissions.php b/lib/share/permissions.php deleted file mode 100644 index 2b98598100d3..000000000000 --- a/lib/share/permissions.php +++ /dev/null @@ -1,71 +0,0 @@ -. -*/ - -namespace OC\Share; - -public class PermissionChecker { - - protected $mapper; - - public function __construct(ShareMapper $mapper) { - $this->mapper = $mapper; - } - - public function isValidPermission() { - if (!is_int($permissions) || $permisisons < 0 || $permissions > OCP\PERMISSION_All) { - throw new \Exception(); - } - $parentId = $share->getParentId(); - if (isset($parentId)) { - if (!$this->isResharingAllowed()) { - throw new \Exception(); - } - // Check if permissions exceed the parent share permissions - $parent = $this->mapper->getShare($parentId); - if ($permissions & ~$parent->getPermissions()) { - throw new \Exception($message); - } - // Check if share permission is granted - if (~$parentPermissions & PERMISSION_SHARE) { - return false; - } - } - // TODO Check if permission allowed for item - return true; - } - - /** - * Check if resharing is allowed - * @return bool - * - * Resharing is allowed by default if not configured - * - */ - public function isResharingAllowed() { - $configValue = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes'); - if ($configValue === 'yes') { - return true; - } else { - return false; - } - } - -} \ No newline at end of file diff --git a/lib/share/share.php b/lib/share/share.php index 32dd6a2eb74e..0ac17289885c 100644 --- a/lib/share/share.php +++ b/lib/share/share.php @@ -2,7 +2,9 @@ /** * ownCloud * +* @author Bernhard Posselt * @author Michael Gapczynski +* @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 @@ -21,114 +23,138 @@ namespace OC\Share; -abstract class Share { - - private $id; - private $parentId; - private $shareOwner; - private $shareType; - private $shareWith; - private $permissions; - private $itemSource; - private $itemTarget; - - public function __construct() { - $this->shareType = $shareType; - $this->permissions = (int)$data['permissions']; - } - - public function getId() { - return $this->id; - } - - public function setId($id) { - $this->id = $id; - } - - public function getParentId() { - return $this->parentId; - } - - public function setParentId($parentId) { - $this->parentId = $parentId; - } - - public function getShareType() { - return $this->shareType; - } - - public function getShareOwner() { - return $this->shareOwner; - } - - public function getShareWith() { - return $this->shareWith; - } - - public function getPermissions() { - return $this->permissions; - } - - public function setPermissions($permissions) { - $this->permissions = $permissions; - } +/** + * Data holder for shared items. Extend this class for your items. + * + * A setter does not imply that property can change. + * + * Extension of OCA\AppFramework\Db\Entity + * + */ +class Share { + + public $id; + public $parentId; + public $shareTypeId; + public $uidOwner; + public $shareWith; + public $permissions; + public $itemSource; + public $itemTarget; + public $itemOwner; + public $expirationTime; + public $shareTime; + + private $updatedFields = array(); + private $fieldTypes = array( + 'id' => 'int', + 'parentId' => 'int', + 'permissions' => 'int', + 'expirationTime' => 'int', + 'shareTime' => 'int' + ); public function isCreatable() { - return $this->getPermissions() & OCP\PERMISSION_CREATE; + return $this->permissions & OCP\PERMISSION_CREATE; } public function isReadable() { - return $this->getPermissions() & OCP\PERMISSION_READ; + return $this->permissions & OCP\PERMISSION_READ; } public function isUpdatable() { - return $this->getPermissions() & OCP\PERMISSION_UPDATE; + return $this->permissions & OCP\PERMISSION_UPDATE; } public function isDeletable() { - return $this->getPermissions() & OCP\PERMISSION_DELETE; + return $this->permissions & OCP\PERMISSION_DELETE; } public function isSharable() { - return $this->getPermissions() & OCP\PERMISSION_SHARE; + return $this->permissions & OCP\PERMISSION_SHARE; } - public function getItemType() { - return $this->itemType; + /** + * 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 $key => $value) { + $method = 'set'.ucfirst($key); + $instance->$method($value); + } + return $instance; } - public function getItemSource() { - return $this->itemSource; - } - public function getItemTarget() { - return $this->itemTarget; + /** + * 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 $key => $value) { + $prop = $this->columnToProperty($key); + if ($value !== null && isset($this->fieldTypes[$prop])) { + settype($value, $this->fieldTypes[$prop]); + } + $method = 'set'.ucfirst($key); + $instance->$method($value); + $this->$prop = $value; + } + return $instance; + } + + /** + * Marks the entity as clean needed for setting the id after the insertion + */ + public function resetUpdatedFields() { + $this->updatedFields = array(); } - public function getItemOwner() { - $parentId = $this->getParentId(); - if ($parentId > -1) { - $database = new \OC\Share\Cache(); - while ($parentId > -1) { - $parentShare = $database->getShare($parentId); - $parentId = $parentShare->getParentId(); + /** + * Each time a setter is called, push the part after set + * into an array: for instance setId will save Id in the + * updated fields array so it can be easily used to create the + * getter method + */ + public function __call($methodName, $args) { + // setters + if (strpos($methodName, 'set') === 0) { + $attr = lcfirst( substr($methodName, 3) ); + // setters should only work for existing attributes + if (property_exists($this, $attr)) { + $this->markFieldUpdated($attr); + $this->$attr = $args[0]; + } else { + throw new \BadFunctionCallException($attr . + ' is not a valid attribute'); + } + // getters + } elseif (strpos($methodName, 'get') === 0) { + $attr = lcfirst(substr($methodName, 3)); + // getters should only work for existing attributes + if (property_exists($this, $attr)) { + return $this->$attr; + } else { + throw new \BadFunctionCallException($attr . + ' is not a valid attribute'); } - return $parentShare->getShareOwner(); } else { - return $this->getShareOwner(); + throw new \BadFunctionCallException($methodName . + ' does not exist'); } } - public function getExpirationTime() { - return $this->expirationTime; - } - - public function setExpirationTime($time) { - $this->expirationDate = $time; - } - - public function getUpdatedFields() { - + /** + * Mark an attribute as updated + * @param string $attribute the name of the attribute + */ + protected function markFieldUpdated($attribute) { + $this->updatedFields[$attribute] = true; } /** @@ -150,18 +176,38 @@ public function columnToProperty($columnName) { } /** - * Maps the keys of the row array to the attributes - * @param array $row the row to map onto the entity + * Transform a property to a database column name + * @param string $property the name of the property + * @return string the column name */ - public function fromRow(array $row) { - foreach ($row as $key => $value) { - $prop = $this->columnToProperty($key); - $this->$prop = $value; + public 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; } - public function toArray() { - + /** + * @return array array of updated fields for update query + */ + public function getUpdatedFields() { + return $this->updatedFields; + } + + /** + * Adds type information for a field so that its automatically casted to + * that value once its being returned from the database + * @param string $fieldName the name of the attribute + * @param string $type the type which will be used to call settype() + */ + protected function addType($fieldName, $type) { + $this->fieldTypes[$fieldName] = $type; } } \ No newline at end of file diff --git a/lib/share/collection.php b/lib/share/sharefactory.php similarity index 81% rename from lib/share/collection.php rename to lib/share/sharefactory.php index 012073b03d42..a89522c45683 100644 --- a/lib/share/collection.php +++ b/lib/share/sharefactory.php @@ -21,11 +21,16 @@ namespace OC\Share; -abstract class Collection extends Share { - - public function getChildren(); - - public function isChild(); - - public function search($pattern); +/** + * + */ +interface IShareFactory { + + /** + * [mapToShare description] + * @param [type] $row [description] + * @return Share + */ + public function mapToShare($row); + } \ No newline at end of file diff --git a/lib/share/sharepublic.php b/lib/share/sharepublic.php index b1f893ca993c..073a7c5097b8 100644 --- a/lib/share/sharepublic.php +++ b/lib/share/sharepublic.php @@ -18,79 +18,217 @@ * You should have received a copy of the GNU Affero General Public * License along with this library. If not, see . */ + namespace OCP; -/** -* 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. -* -* It provides the following hooks: -* - post_shared -*/ -class ShareAPI { +abstract class ShareAPI { - private $itemType; - private $cache; + /** + * Check if an item is valid for the user specified by uidOwner + * @param Share $share + * @return bool + * + * Needs to check if the user owns this item or has access to it through a share + * + */ + abstract public function isValidItem(Share $share); + /** + * Get the ShareFactory object for this item type + * @return ShareFactory + */ + abstract public function getShareFactory(); - public function __construct(OC\Share\ItemType $itemType) { - $this->itemType = $itemType; - $this->cache = new \OC\Share\Cache($this->itemType); + /** + * Check if a unique target per user is required for this item type + * @return bool + */ + abstract public function isUniqueTargetRequired(); + + /** + * Get a unique + * @return string + */ + abstract public function generateUniqueTarget(Share $share); + + // TODO I guess we should merge duplicate shares somewhere out here + public function getShares($shareWith = null, $uidOwner = null, $isShareWithUser = true, + $extraFilter = null + ) { + $shareTypes = Utility::getSupportedShareTypes($this); + $shares = array(); + foreach ($shareTypes as $shareType) { + $result = $shareType->getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter); + foreach ($result as $share) { + if (!$this->isExpired($share)) { + $shares[] = $share; + } else { + $this->unshare($share); + } + } + } + return $shares; } - public function getShare() { + /** + * Get the shares with the specified item target and additional parameters + * @param string $itemTarget + * @param string $shareWith (optional) + * @param string $uidOwner (optional) + * @param bool $isShareWithUser (optional, default = true) + * @return array + */ + public function getSharesByTarget($itemTarget, $shareWith = null, $uidOwner = null, + $isShareWithUser = true + ) { + $extraFilter = array('`item_target` = ?', array($itemTarget)); + return $shareType->getShares($itemSource, $shareWith, $uidOwner, $extraFilter); + } + /** + * Get the shares with the specified item source and additional parameters + * @param string $itemSource + * @param string $shareWith (optional) + * @param string $uidOwner (optional) + * @param bool $isShareWithUser (optional, default = true) + * @return array + */ + public function getSharesBySource($itemSource, $shareWith = null, $uidOwner = null, + $isShareWithUser = true + ) { + $extraFilter = array('`item_source` = ?', array($itemSource)); + return $shareType->getShares($itemSource, $shareWith, $uidOwner, $extraFilter); } - public function getShares() { + /** + * Get the reshares of a share + * @param Share $share + * @return array + */ + public function getReshares(Share $share) { + $extraFilter = array('`parent_id` = ?', array($share->getId())); + return $this->getShares(null, null, true, $extraFilter); + } + /** + * Get the duplicates of a share + * @param Share $share + * @return array + * + * These are shares to the same person of the same item from different owners + * + */ + public function getDuplicates(Share $share) { + $where = '`item_source` = ? AND `id != ?'; + $params = array($share->getItemSource(), $share->getId()); + $extraFilter = array($where, $params); + return $this->getShares($share->getUidOwner(), null, true, $extraFilter); } - public function share(Share $share) { - $shareTypeId = $share->getShareType(); - $shareType = $this->getShareTypeObject($shareTypeId); - if ($shareType) { - return $shareType->share($share); + /** + * Get the parent share of a share + * @param Share $share + * @param bool $find (optional, default = false) + * @return Share + */ + public function getParent(Share $share, $find = false) { + // TODO need to know about collections here - find parent item types + if ($find === false) { + $parents = $this->getShares(null, null, true, array('`id` = ?', $id)); + if (!empty($parents)) { + if (count($parents) > 1) { + throw new \Exception(); + } else { + return current($parents); + } + } else { + return false; + } } else { - return false; + $extraFilter = array('`item_source` = ?', $share->getItemSource()); + $parents = $this->getShares($share->getUidOwner(), null, true, $extraFilter); + if (!empty($parents)) { + foreach ($parents as $parent) { + if ($parent->getPermissions() & OCP\PERMISSION_SHARE) { + return $parent; + } + } + // Resharing not allowed + throw new \Exception() + } else { + return false; + } } } - public function unshare(Share $share) { - if ($share->getShareOwner() !== \OC_User::getUser()) { - return false; - } - $shareTypeId = $share->getShareType(); - $shareType = $this->getShareTypeObject($shareTypeId); - if ($shareType) { - return $shareType->unshare($share); + public function searchForShares($pattern) { + // TODO + } + + /** + * Share a share + * @param Share $share + * @return bool + */ + public function share(Share $share) { + if ($this->isValidItem($share)) { + $shareType = Utility::getSupportedShareType($this, $share->getShareTypeId()); + if ($shareType) { + $parent = $this->getParent($share, true); + if ($parent) { + $share->setParentId($parent->getId()); + } + if ($shareType->isValidShare($share) + && $this->areValidPermissions($share) + && $this->isValidExpirationTime($share) + ) { + return $shareType->share($share); + } + } else { + return false; + } } else { return false; } } - public function unshareFromSelf(Share $share) { - // TODO better validation - if ($share->getShareOwner() === \OC_User::getUser()) { - return false; - } - $shareTypeId = $share->getShareType(); - $shareType = $this->getShareTypeObject($shareTypeId); + /** + * Unshare a share + * @param Share $share + */ + public function unshare(Share $share) { + $shareType = Utility::getSupportedShareType($this, $share->getShareTypeId()); if ($shareType) { - return $shareType->unshareFromSelf($share); - } else { - return false; + $reshares = $this->getReshares($share); + if (!empty($reshares)) { + // Try to find a duplicate share, to switch parent ids of reshares + $parentId = null; + $duplicates = $this->getDuplicates($share); + foreach ($duplicates as $duplicate) { + if ($duplicate->getPermissions() & OCP\PERMISSION_SHARE) { + $parentId = $duplicate->getId(); + break; + } + } + foreach ($reshares as $reshare) { + if (isset($parentId)) { + $reshare->setParentId($parentId); + $this->update($reshare); + } else { + $this->unshare($reshare); + } + } + } + $shareType->unshare($share); } } /** - * Update a Share in the cache + * Update a share in the database * @param Share $share */ public function update(Share $share) { - if ($share->getShareOwner() !== \OC_User::getUser()) { - return false; - } + // TODO Fix $shareTypeId = $share->getShareType(); $shareType = $this->getShareTypeObject($shareTypeId); if ($shareType) { @@ -102,17 +240,188 @@ public function update(Share $share) { } else { throw new \Exception(); } + if ($setter === 'setPermissions') { + + } else if ($setter === 'setExpirationTime') { + + } } } else { throw new \Exception(); } } - public function getShareTypeObject($shareTypeId) { - if (!isset(self::$shareTypes[$shareTypeId])) { - // Check if item type supports this share type + /** + * Unshare all shares of an item + * @param any $itemSource + * + * Call this if an item is deleted by the item owner + * + */ + public function deleteItem($itemSource) { + $shares = $this->getSharesBySource($itemSource); + foreach ($shares as $share) { + $this->unshare($share); + } + } + + /** + * Get potential people to share with based on the given pattern + * @param string $pattern + * @return array + */ + public function searchForShareWiths($pattern) { + $shareTypes = Utility::getSupportedShareTypes($this); + $shareWiths = array(); + foreach ($shareTypes as $shareType) { + $shareWiths += $shareType->searchForShareWiths($pattern); + } + return $shareWiths; + } + + /** + * Check if a share is expired + * @param Share $share + * @return bool + */ + protected function isExpired(Share $share) { + $time = $share->getExpirationTime(); + if (isset($time)) { + if ($time - time() > 0) { + return true; + } else { + return false; + } + } else { + $defaultTime = $this->getDefaultTime(); + if ($defaultTime > 0 && ($defaultTime + $share->getShareTime()) - time() > 0)) { + return true; + } else { + return false; + } + } + } + + /** + * Check if a share's permissions are valid + * @param Share $share + * @return bool + */ + protected function areValidPermissions($share) { + $permissions = $share->getPermissions(); + if (!is_int($permissions) || $permisisons < 0 || $permissions > OCP\PERMISSION_All) { + throw new \Exception(); + } + $parent = $this->getParent($share) + if ($parent) { + if (!Utility::isResharingAllowed()) { + throw new \Exception(); + } + // Check if permissions exceed the parent share permissions + if ($permissions & ~$parent->getPermissions()) { + throw new \Exception($message); + } + // Check if share permission is granted + if (~$parentPermissions & OCP\PERMISSION_SHARE) { + throw new \Exception(); + } + } + // TODO Check if permission allowed for item + return true; + } + + /** + * Update permissions of all reshares of a share + * @param Share $share + */ + protected function updateResharesPermissions(Share $share, $oldPermissions) { + $permissions = $share->getPermissions(); + // Check if permissions were removed + if (~$permissions & $oldPermissions) { + // Update permissions of all reshares + $reshares = $this->getReshares($share); + if (!empty($reshares)) { + // Try to find a duplicate share, to switch parent ids of reshares + if (~$permissions & OCP\PERMISSION_SHARE) { + $parentId = null; + $duplicates = $this->getDuplicates($share); + foreach ($duplicates as $duplicate) { + if ($duplicate->getPermissions() & OCP\PERMISSION_SHARE) { + $parentId = $duplicate->getId(); + break; + } + } + } + foreach ($reshares as $reshare) { + $resharePermissions = $reshare->getPermissions(); + // Check if reshare's permissions were removed + if (~$permissions & resharePermissions) { + $resharePermissions &= $permissions; + $reshare->setPermissions($resharePermissions); + // If share permission is removed, unshare all reshares + if (~$permissions & OCP\PERMISSION_SHARE) { + if (isset($parentId)) { + $reshare->setParentId($parentId); + $this->update($reshare); + } else { + $this->unshare($reshare); + } + } else { + $this->update($reshare); + } + } + } + } + } + } + + /** + * Check if a share's expiration time is valid + * @param Share $share + * @return bool + */ + protected function isValidExpirationTime(Share $share) { + $time = $share->getExpirationTime(); + if (isset($time) && !is_int($time)) { + throw new \Exception($message); + } + // Time must be at least 1 hour in the future + if (isset($time) && $time < time() + 3600) { + throw new \Exception($message); + } + $parent = $this->getParent($share) + if ($parent) { + // Check if time is later than the parent expiration time + $parentTime = $parent->getExpirationTime(); + if (isset($parentTime)) { + if ((!isset($time) || $time > $parentTime) { + throw new \Exception($message); + } + } + } + return true; + } + + /** + * Update expiration time of all reshares of a share + * @param Share $share + */ + protected function updateResharesExpirationTime(Share $share, $oldTime) { + $time = $share->getExpirationTime(); + // Check if time was decreased + if (isset($time)) { + if (!isset($oldTime) || $time < $oldTime) { + // Truncate time of all reshares + $reshares = $this->getReshares($share); + foreach ($reshares as $reshare) { + $reshareTime = $reshare->getExpirationTime(); + if (!isset($reshareTime) || $time < $reshareTime) { + $reshare->setExpirationTime($time); + $this->update($reshare); + } + } + } } - return self::$shareTypes[$shareTypeId]; } } \ No newline at end of file diff --git a/lib/share/sharetype.php b/lib/share/sharetype.php deleted file mode 100644 index 97748587e157..000000000000 --- a/lib/share/sharetype.php +++ /dev/null @@ -1,67 +0,0 @@ -. -*/ - -namespace OC\Share\ShareType; - -interface ShareType { - - /** - * - */ - public function getId(); - - /** - * Check if $shareOwner is allowed to share with $shareWith - * @param string $shareOwner - * @param string $shareWith - * @return bool - */ - public function isValidShare($shareOwner, $shareWith); - - - - /** - * - * @param \OC\Share\Share $share - * @return bool - */ - public function share($share); - - /** - * - */ - public function generateItemTarget($share); - - /** - * Generate a unique file target for the - * @param \OC\Share\Share $share - * @return string - */ - public function generateFileTarget($share); - - public function unshare($share); - public function unshareFromSelf($share); - public function setPermissions($id, $permissions); - public function setExpirationDate($id, $date); - - public function searchShareWith(); - -} \ 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..0e6b68bde481 --- /dev/null +++ b/lib/share/sharetype/group.php @@ -0,0 +1,152 @@ +. +*/ + +namespace OC\Share\Type; + +class Group extends Common { + + protected $groupTable; + + public function __construct($itemType, IShareFactory $shareFactory) { + parent::__construct($itemType, $shareFactory); + $this->groupTable = '*PREFIX*groupshares'; + } + + public function getId() { + return 'group'; + } + + public function getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter) { + if ($isShareWithUser === true) { + list($where, $params) = $this->getDefaultFilter($shareWith, $uidOwner); + if (isset($extraFilter)) { + list($extraWhere, $extraParams) = $extraFilter; + $where .= ' '.ltrim($extraWhere); + $params += $extraParams; + } + // Select all columns in the share table + $columns = '`'.$this->table.'`.*'; + // LEFT JOIN with the unique group shares table + $joins = 'LEFT JOIN `'.$this->groupTable.'` ON `'; + $joins .= '`'.$this->table.'`.`id` = '; + $joins .= '`'.$this->groupTable.'`.`id`'; + // Select all columns in the unique group shares table + $columns .= ', `'.$this->groupTable.'`.*'; + list($appColumns, $appJoins) = $this->getAppJoins(); + $columns .= $appColumns; + $joins .= ltrim($appJoins); + $sql = 'SELECT '.$columns.' FROM `'.$this->table.'` '.$joins.' WHERE '.$where; + $query = \OC_DB::prepare($sql); + $result = $query->execute(array($params)); + $shares = array(); + while ($row = $result->fetchRow()) { + $share = $this->shareFactory->mapToShare($row); + // TODO + if (isset($row[$this->groupTable.'.target'])) { + $share->setItemTarget() + } + $shares[] = $share; + } + return $shares; + } else { + return parent::getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter); + } + } + + public function isValidShare(Share $share) { + $uidOwner = $share->getUidOwner(); + $shareWith = $share->getShareWith(); + if (!\OC_Group::groupExists($shareWith)) { + $message = 'Sharing '.$itemSource.' failed, because the group '.$shareWith.' does not exist'; + throw new \Exception($message); + } + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); + if ($sharingPolicy === 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) { + $message = 'Sharing '.$itemSource.' failed, because ' + .$uidOwner.' is not a member of the group '.$shareWith; + throw new \Exception($message); + } + return true; + } + + public function share($share) { + if ($this->itemType->isUniqueTargetRequired()) { + $users = \OC_Group::usersInGroup($share->getShareWith()); + $tempShare = $share; + foreach ($users as $user) { + $tempShare->setShareType('user'); + $tempShare->setShareWith($user); + $tempdata['item_target'] = $this->generateItemTarget($tempShare); + + if ($tempdata['']) + } + } + + $id = $this->cache->put($data; + $share->setId($id); + return $share; + } + + public function unshareFromSelf($share) { + + } + + public function searchForShareWiths($pattern) { + return OC_Group::getGroups(); + } + + protected function getDefaultFilter($shareWith, $uidOwner, $isShareWithUser) { + $where = ''; + $params = array($this->getId(), $this->itemType); + if (isset($shareWith)) { + if ($isShareWithUser === true) { + $groups = \OC_Group::getUserGroups($shareWith); + $placeholders = join(',', array_fill(0, count($groups), '?')); + $where .= ' AND share_with IN ('.$placeholders.')'; + $params += $groups; + $params[] + } else { + $where .= '`share_type` = ? AND `share_with` = ?'; + $params[] = $this->getId(); + $params[] = $shareWith; + } + } + if (isset($uidOwner)) { + $where .= ' AND `uid_owner` = ?'; + $params[] = $uidOwner; + } + return array($where, $params); + } + + // Hook Listeners + public static function post_addToGroup($params) { + + } + + public static function post_removeFromGroup($params) { + + } + + public static function post_deleteGroup($params) { + + } + +} \ 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..480222185b0e --- /dev/null +++ b/lib/share/sharetype/isharetype.php @@ -0,0 +1,89 @@ +. +*/ + +namespace OC\Share\ShareType; + +interface IShareType { + + /** + * Get the id for this share type + * @return string id + */ + public function getId(); + + /** + * Get the shares for this share type based on the given parameters + * @param string $shareWith + * @param string $uidOwner + * @param bool $isShareWithUser + * @return array + */ + public function getShares($shareWith, $uidOwner, $isShareWithUser); + + /** + * Check if this share is valid for this share type + * @param Share $share + * @return bool + */ + public function isValidShare(Share $share); + + /** + * Insert the share into the database + * @param Share $share + * @return Share + */ + public function share(Share $share); + + /** + * Remove the share from the database + * @param Share $share + */ + public function unshare(Share $share); + + /** + * Update the share's parent id in the database + * @param Share $share + * + * Call this to switch parent ids of a reshare if the current parent share is being removed + * + */ + public function setParentId(Share $share); + + /** + * Update the share's permissions in the database + * @param Share $share + */ + public function setPermissions(Share $share); + + /** + * Update the share's expiration time in the database + * @param Share $share + */ + public function setExpirationTime(Share $share); + + /** + * Get potential people to share with based on the given pattern + * @param string $pattern + * @return array + */ + public function searchForShareWiths($pattern); + +} \ 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..83ed33885d07 --- /dev/null +++ b/lib/share/sharetype/link.php @@ -0,0 +1,130 @@ +. +*/ + +namespace OC\Share\Type; + +class Link extends Common { + + protected $linkTable; + private const TOKEN_LENGTH = 32; + + public function __construct($itemType, IShareFactory $shareFactory) { + parent::__construct($itemType, $shareFactory); + $this->linkTable = '*PREFIX*links'; + } + + public function getId() { + return 'link'; + } + + public function getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter) { + if (isset($shareWith)) { + // Links are not associated with a person + return array(); + } else { + list($where, $params) = $this->getDefaultFilter($shareWith, $uidOwner); + if (isset($extraFilter)) { + list($extraWhere, $extraParams) = $extraFilter; + $where .= ' '.ltrim($extraWhere); + $params += $extraParams; + } + // Select all columns in the share table + $columns = '`'.$this->table.'`.*'; + // JOIN with the links table + $joins = 'JOIN `'.$this->linkTable.'` ON `'; + $joins .= '`'.$this->table.'`.`id` = '; + $joins .= '`'.$this->linkTable.'`.`id`'; + // Select all columns in the link table + $columns .= ', `'.$this->linkTable.'`.*'; + list($appColumns, $appJoins) = $this->getAppJoins(); + $columns .= $appColumns; + $joins .= ' '.$appJoins; + $sql = 'SELECT '.$columns.' FROM `'.$this->table.'` '.$joins.' WHERE '.$where; + $query = \OC_DB::prepare($sql); + $result = $query->execute(array($params)); + $shares = array(); + while ($row = $result->fetchRow()) { + $shares[] = $this->shareFactory->mapToShare($row); + } + return $shares; + } + } + + public function isValidShare(Share $share) { + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes'); + if ($sharingPolicy !== 'yes') { + throw new \InvalidShareException('Sharing with links is not allowed'); + // Share permission for links doesn't make sense + } else if ($share->getPermissions() & OCP\PERMISSION_SHARE) { + throw new \Exception(); + } else { + return true; + } + } + + public function share(Share $share) { + $share = parent::share($share); + if ($share) { + // Create a token for a link + $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); + // Store the id, token, password in the database + $query = \OC_DB::prepare('INSERT INTO `'.$this->linkTable.'` + (`id`, `token`, `password`) VALUES (?, ?, ?)' + ); + $query->execute(array($share->getId(), $token, $share->getPassword())); + $share->setToken($token); + return $share; + } else { + return false; + } + } + + public function unshare(Share $share) { + parent::unshare($share); + $query = \OC_DB::prepare('DELETE FROM `'.$this->linkTable.'` WHERE `id` = ?'); + $query->execute(array($share->getId())); + } + + public function setPermissions(Share $share) { + // Share permission for links doesn't make sense + if ($share->getPermissions() & OCP\PERMISSION_SHARE) { + throw new \Exception(); + } else { + parent::setPermissions($share); + } + } + + /** + * Update the share's password for the link in the database + * @param Share $share + */ + public function setPassword(Share $share) { + $query = \OC_DB::prepare('UPDATE `'.$this->linkTable.'` SET `password` = ? + WHERE `id` = ?' + ); + $query->execute(array($share->getPassword(), $share->getId())); + } + + public function searchForShareWiths($pattern) { + return array(); + } + +} \ No newline at end of file diff --git a/lib/share/sharetype/sharetype.php b/lib/share/sharetype/sharetype.php new file mode 100644 index 000000000000..1be4fe34f951 --- /dev/null +++ b/lib/share/sharetype/sharetype.php @@ -0,0 +1,152 @@ +. +*/ + +namespace OC\Share\ShareType; + +abstract class ShareType implements IShareType { + + protected $table; + protected $shareFactory; + + public function __construct($itemType, IShareFactory $shareFactory) { + $this->table = '*PREFIX*share'; + $this->shareFactory = $shareFactory; + } + + abstract public function getId(); + + public function getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter) { + list($where, $params) = $this->getDefaultFilter($shareWith, $uidOwner); + if (isset($extraFilter)) { + list($extraWhere, $extraParams) = $extraFilter; + $where .= ' '.ltrim($extraWhere); + $params += $extraParams; + } + // Select all columns in the share table + $columns = '`'.$this->table.'`.*'; + list($appColumns, $appJoins) = $this->getAppJoins(); + $columns .= $appColumns; + $sql = 'SELECT '.$columns.' FROM `'.$this->table.'` '.$appJoins.' WHERE '.$where; + $query = \OC_DB::prepare($sql); + $result = $query->execute(array($params)); + $shares = array(); + while ($row = $result->fetchRow()) { + $shares[] = $this->shareFactory->mapToShare($row); + } + return $shares; + } + + abstract public function isValidShare(Share $share); + + public function share(Share $share) { + // TODO + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` + (' . implode(', ', $queryParts) . ')' + . ' VALUES( ' . implode(', ', $valuesPlaceholder) . ')'); + $result = $query->execute($params); + $id = (int)\OC_DB::insertid($this->table); + $share->setId($id); + return $share; + } + + public function unshare(Share $share) { + $query = \OC_DB::prepare('DELETE FROM `'.$this->table.'` WHERE `id` = ?'); + $query->execute(array($share->getId())); + } + + public function setParentId(Share $share) { + $parentId = $share->getParentId(); + $this->update($share->getId(), array('parent' => $parentId)); + } + + public function setPermissions(Share $share) { + $permissions = $share->getPermissions(); + $this->update($share->getId(), array('permissions' => $permissions)); + } + + public function setExpirationTime(Share $share) { + $time = $share->getExpirationTime(); + $this->update($share->getId(), array('expiration' => $time)); + } + + abstract public function searchForShareWiths($pattern); + + /** + * Get the default database filter for this share type + * @param string $shareWith + * @param string $uidOwner + * @param bool $isShareWithUser + * @return array($where, $params) + */ + protected function getDefaultFilter($shareWith, $uidOwner, $isShareWithUser) { + $where = '`share_type` = ? AND `item_type` = ?'; + $params = array($this->getId(), $this->itemType); + if (isset($shareWith)) { + $where .= ' AND share_with = ?'; + $params[] = $shareWith; + } + if (isset($uidOwner)) { + $where .= ' AND uid_owner = ?'; + $params[] = $uidOwner; + } + return array($where, $params); + } + + protected function getAppJoins() { + $columns = ''; + $joins = ''; + // Check if IAdvancedShareFactory is used and additional properties are needed + if ($this->shareFactory instanceof IAdvancedShareFactory) { + // Setup JOINs to fetch properties from app's tables + $appJoins = $this->shareFactory->getJoins(); + foreach ($appJoins as $appTable => $appJoin) { + $tables = array_keys($appJoin); + $joinColumns = array_values($appJoin); + if (count($tables) === 2) { + $joins .= ' JOIN `*PREFIX*'.$appTable.'` ON `'; + $joins .= '`*PREFIX*'.$tables[0].'`.`'.$joinColumns[0].'` = '; + $joins .= '`*PREFIX*'.$tables[1].'`.`'.$joinColumns[1].'`'; + } else { + throw new \Exception() + } + } + $joins = ltrim($joins); + // Add app specific columns to SELECT + $appTables = $this->shareFactory->getColumns(); + foreach ($appTables as $appTable => $appColumns) { + foreach ($appColumns as $appColumn) { + $columns .= ', `*PREFIX*'.$appTable.'`.`'.$appColumn.'`'; + } + } + } + return array($columns, $joins); + } + + /** + * Update the share's properties in the database + * @param int $id + * @param array $data + */ + protected function update($id, array $data) { + // TODO + } + +} \ No newline at end of file diff --git a/lib/share/sharetypes/user.php b/lib/share/sharetype/user.php similarity index 90% rename from lib/share/sharetypes/user.php rename to lib/share/sharetype/user.php index c12805794d83..ab88624e3ebb 100644 --- a/lib/share/sharetypes/user.php +++ b/lib/share/sharetype/user.php @@ -27,7 +27,9 @@ public function getId() { return 'user'; } - public function isValidShare($shareOwner, $shareWith) { + public function isValidShare(Share $share) { + $shareOwner = $share->getShareOwner(); + $shareWith = $share->getShareWith(); if ($shareOwner === $shareWith) { $message = 'the user '.$this->shareWith.' is the item owner'; throw new \InvalidShareException($message); @@ -47,7 +49,7 @@ public function isValidShare($shareOwner, $shareWith) { return true; } - public function search($pattern) { + public function searchForShareWiths($pattern) { return OC_User::getUsers(); } diff --git a/lib/share/sharetypefac.php b/lib/share/sharetypefac.php deleted file mode 100644 index 0eefc61fe03a..000000000000 --- a/lib/share/sharetypefac.php +++ /dev/null @@ -1,29 +0,0 @@ -. -*/ - -namespace OC\Share; - -public class ShareTypeFactory { - - private $shareTypes; - - public function getShareType -} \ No newline at end of file diff --git a/lib/share/sharetypes/common.php b/lib/share/sharetypes/common.php deleted file mode 100644 index 23d7493a6c78..000000000000 --- a/lib/share/sharetypes/common.php +++ /dev/null @@ -1,173 +0,0 @@ -. -*/ - -namespace OC\Share\ShareType; - -abstract class ShareType implements IShareType { - - protected itemType; - protected cache; - - public function __construct(ItemType $itemType, ShareMapper $cache) { - $this->itemType = $itemType; - $this->cache = $cache; - } - - public function isValidShare($share) { - if ($share instanceof OC\Share\FileDependent) { - if (!OCP\Share->isFileSharingEnabled()) { - throw new \InvalidShareException('files_sharing app not enabled'); - } - } - if (!$this->itemType->isValidItem($share)) { - return false; - } - // Check if this is a reshare - $parentId = $this->cache->getId(); - $parent = $this->cache->getShare($parentId); - if ($parent) { - $share->setParentId($parentId); - } - $permissionChecker = new PermissionChecker($this->cache); - if (!$permissionChecker->isValidPermission($share)) { - return false; - } - $timeChecker = new ExpirationChecker($this->cache); - if (!$timeChecker->isValidTime($share)) { - return false; - } - return true; - } - - /** - * Verify sharing conditions and put share into cache - * @param OC/Share/Share $share - * @return - */ - public function share($share) { - if ($this->isValidShare($share)) { - if ($share instanceof OC\Share\FileDependent) { - // TODO get file id from file path - - $data['file_target'] = $this->generateFileTarget($share); - } - $data['item_target'] = $this->generateItemTarget($share); - $id = $this->cache->put($share); - $share->setId($id); - return $share; - } - } - - public function generateItemTarget($share) { - if ($this->itemType->isUniqueTargetRequired()) { - $suggestedTarget = $this->itemType->suggestTarget($share); - $this->cache->getShare() - } else { - return $this->itemType->suggestTarget($share); - } - } - - public function generateFileTarget($share) { - if ($share instanceof OC\Share\FileDependent) { - - $suggestedTarget = OCP\Share::get('file')->suggestTarget($share); - - } else { - return false; - } - } - - public function unshare($share) { - $reshares = $this->cache->getReshares($share->getId()); - // Unshare all reshares - foreach ($reshares as $reshare) { - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->unshare($reshare); - } - $this->cache->delete($share->getId()); - } - - public function unshareFromSelf($share) { - $duplicates = $this->cache->getDuplicateShares($share); - // Unshare duplicates from self - foreach ($duplicates as $duplicate) { - $reshares = $this->cache->getReshares($duplicate->getId()); - // Unshare all reshares of duplicates - foreach ($reshares as $reshare) { - // We don't care about duplicates of reshares - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->unshare($reshare); - } - $shareAPI = new OCP\ShareAPI($duplicate->getItemType()); - $shareAPI->unshare($duplicate); - } - $this->unshare($share); - } - - public function setPermissions($share) { - $permissions = $share->getPermissions(); - $oldPermissions = $this->cache->getShare($share->getId())->getPermissions(); - // Check if permissions were removed - if (~$permissions & $oldPermissions) { - // Update permissions of all reshares - $reshares = $this->cache->getReshares($share->getId()); - foreach ($reshares as $reshare) { - $resharePermissions = $reshare->getPermissions(); - // Check if reshare's permissions were removed - if (~$permissions & resharePermissions) { - // If share permission is removed, delete all reshares - if (($oldPermissions & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE) { - // TODO Check if share permission came from this parent share - $reshare->unshare(); - } else { - $resharePermissions &= $permissions; - $reshare->setPermissions($resharePermissions); - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->update($reshare); - } - } - } - } - $this->cache->update($share->getId(), array('permissions' => $permissions)); - } - - public function setExpirationTime($share) { - $time = $share->getExpirationTime(); - // Check if time was decreased - if (isset($time)) { - $oldTime = $this->cache->getShare($share->getId())->getExpirationTime(); - if (!isset($oldTime) || $time < $oldTime) { - // Truncate time of all reshares - $reshares = $cache->getReshares($share->getId()); - foreach ($reshares as $reshare) { - $reshareTime = $reshare->getExpirationTime(); - if (!isset($reshareTime) || $time < $reshareTime) { - $reshare->setExpirationTime($time); - $shareAPI = new OCP\ShareAPI($reshare->getItemType()); - $shareAPI->update($reshare); - } - } - } - } - $this->cache->update($share->getId(), array('expiration' => $time)); - } - -} \ No newline at end of file diff --git a/lib/share/sharetypes/group.php b/lib/share/sharetypes/group.php deleted file mode 100644 index dce3365dea6a..000000000000 --- a/lib/share/sharetypes/group.php +++ /dev/null @@ -1,87 +0,0 @@ -. -*/ - -namespace OC\Share\Type; - -class Group extends Common { - - public function getId() { - return 'group'; - } - - public function isValidShare($share) { - parent::isValidShare($share); - if (!\OC_Group::groupExists($shareWith)) { - $message = 'Sharing '.$itemSource.' failed, because the group '.$shareWith.' does not exist'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); - if ($sharingPolicy === 'groups_only' && !\OC_Group::inGroup($shareOwner, $shareWith)) { - $message = 'Sharing '.$itemSource.' failed, because ' - .$uidOwner.' is not a member of the group '.$shareWith; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } - - public function share($share) { - if ($this->isValidShare($share)) { - if ($this->itemType->isUniqueTargetRequired()) { - $users = \OC_Group::usersInGroup($share->getShareWith()); - $tempShare = $share; - foreach ($users as $user) { - $tempShare->setShareType('user'); - $tempShare->setShareWith($user); - $tempdata['item_target'] = $this->generateItemTarget($tempShare); - - if ($tempdata['']) - } - } - - $id = $this->cache->put($data; - $share->setId($id); - return $share; - } - } - - public function unshareFromSelf($share) { - - } - - public function search($pattern) { - return OC_Group::getGroups(); - } - - // Hook Listeners - public static function post_addToGroup($params) { - - } - - public static function post_removeFromGroup($params) { - - } - - public static function post_deleteGroup($params) { - - } - -} \ No newline at end of file diff --git a/lib/share/sharetypes/link.php b/lib/share/sharetypes/link.php deleted file mode 100644 index f8c396612e8e..000000000000 --- a/lib/share/sharetypes/link.php +++ /dev/null @@ -1,73 +0,0 @@ -. -*/ - -namespace OC\Share\Type; - -class Link extends Common { - - public function isValidShare($share) { - parent::isValidShare($share); - $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes'); - if ($sharingPolicy !== 'yes') { - throw new \InvalidShareException('Sharing with links is not allowed'); - } else { - return true; - } - } - - public function share($share) { - $id = parent::share($share); - $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); - if ($id) { - return $share->getToken(); - } else { - return false; - } - } - - /** - * - * @return string - * - * Unique targets are not required for links - * - */ - public function generateItemTarget($share) { - $itemType = $share->getItemType(); - return $itemType->suggestTarget($share); - } - - /** - * - * @return string - * - * Unique targets are not required for links - * - */ - public function generateFileTarget($share) { - return OCP\Share::get('file')->suggestTarget($share); - } - - public function search($pattern) { - return null; - } - -} \ No newline at end of file diff --git a/lib/share/time.php b/lib/share/time.php deleted file mode 100644 index 5afe9184aded..000000000000 --- a/lib/share/time.php +++ /dev/null @@ -1,90 +0,0 @@ -. -*/ - -namespace OC\Share; - -public class ExpirationChecker { - - protected $mapper; - - public function __construct(ShareMapper $mapper) { - $this->mapper = $mapper; - } - - /** - * Check if the expiration time is valid - * @param - * @return bool - * - * A valid time is at least 1 hour in the future - * - */ - public function isValidTime(Share $share) { - $time = $share->getExpirationTime(); - if (isset($time) && !is_int($time)) { - throw new \Exception($message); - } - if (isset($time) && $time < time() + 3600) { - throw new \Exception($message); - } - $parentId = $share->getParentId(); - if (isset($parentId)) { - // Check if time is later than the parent expiration time - $parent = $this->mapper->getShare($parentId); - $parentTime = $parent->getExpirationTime(); - if (isset($parentTime)) { - if ((!isset($time) || $time > $parentTime) { - throw new \Exception($message); - } - } - } - return true; - } - - /** - * Check if Share is expired - * @param - * @return bool - */ - public function isExpired(Share $share) { - $time = $share->getExpirationTime(); - if (isset($time)) { - if ($time - time() > 0) { - return true; - } - } else if (($this->getDefaultTime() + $share->getShareTime()) - time() > 0) { - return true; - } - return false; - } - - /** - * Get the default expiration time - * @return time - * - * No expiration time is set by default - * - */ - public function getDefaultTime() { - return \OC_Appconfig::getValue('core', 'shareapi_expiration_time', null); - } - -} \ No newline at end of file diff --git a/lib/share/utility.php b/lib/share/utility.php index 51a22d69597b..9e75a7d5d720 100644 --- a/lib/share/utility.php +++ b/lib/share/utility.php @@ -50,4 +50,46 @@ public function isFileSharingEnabled() { return \OC_App::isEnabled('files_sharing'); } + /** + * Check if resharing is allowed + * @return bool + * + * Resharing is allowed by default if not configured + * + */ + public function isResharingAllowed() { + $configValue = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes'); + if ($configValue === 'yes') { + return true; + } else { + return false; + } + } + + /** + * Get the default expiration time + * @return int + * + * No expiration time is set by default + * + */ + public function getDefaultTime() { + return \OC_Appconfig::getValue('core', 'shareapi_expiration_time', 0); + } + + public static function getSupportedShareTypes($class) { + // TODO Fetch share type objects based on marker interfaces + $shareTypeIds = class_implements($class); + foreach ($shareTypeIds as $shareTypeId) { + $shareTypes[$shareTypdId] = new \$shareTypeId.'ShareType'; + } + } + + public static function getSupportedShareType($class, $shareTypeId) { + if (!isset(self::$shareTypes[$shareTypeId])) { + + } + return self::$shareTypes[$shareTypeId]; + } + } \ No newline at end of file From 76af3ad3466524ad7ca32a0e8eb9d7c8c1db284b Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sun, 7 Jul 2013 19:43:11 -0400 Subject: [PATCH 03/85] Another snapshot of the share changes --- db_structure.xml | 191 ++ lib/share/advancedsharefactory.php | 49 + lib/share/collectionshares.php | 70 + .../invalidexpirationtimeexception.php | 30 + lib/share/exception/invaliditemexception.php | 30 + .../exception/invalidpermissionsexception.php | 30 + lib/share/exception/invalidshareexception.php | 30 + .../exception/sharedoesnotexistexception.php | 30 + .../sharesbackenddoesnotexistexception.php | 30 + .../sharetypedoesnotexistexception.php | 30 + .../exceptions/invalidshareexception.php | 30 - lib/share/iadvancedsharefactory.php | 67 - lib/share/share.php | 225 +- lib/share/sharefactory.php | 50 +- lib/share/sharepublic.php | 427 ---- lib/share/shares.php | 303 +++ lib/share/sharesmanager.php | 516 +++++ lib/share/sharetype/common.php | 198 ++ lib/share/sharetype/group.php | 305 ++- lib/share/sharetype/isharetype.php | 48 +- lib/share/sharetype/link.php | 230 +- lib/share/sharetype/sharetype.php | 152 -- lib/share/sharetype/user.php | 91 +- lib/share/timemachine.php | 37 + lib/share/utility.php | 95 - tests/lib/share/backend.php | 71 - tests/lib/share/share.php | 536 ++--- tests/lib/share/shares.php | 542 +++++ tests/lib/share/sharesmanager.php | 1918 +++++++++++++++++ tests/lib/share/sharetype/group.php | 269 +++ tests/lib/share/sharetype/link.php | 203 ++ tests/lib/share/sharetype/sharetype.php | 148 ++ tests/lib/share/sharetype/user.php | 253 +++ 33 files changed, 5631 insertions(+), 1603 deletions(-) create mode 100644 lib/share/advancedsharefactory.php create mode 100644 lib/share/collectionshares.php create mode 100644 lib/share/exception/invalidexpirationtimeexception.php create mode 100644 lib/share/exception/invaliditemexception.php create mode 100644 lib/share/exception/invalidpermissionsexception.php create mode 100644 lib/share/exception/invalidshareexception.php create mode 100644 lib/share/exception/sharedoesnotexistexception.php create mode 100644 lib/share/exception/sharesbackenddoesnotexistexception.php create mode 100644 lib/share/exception/sharetypedoesnotexistexception.php delete mode 100644 lib/share/exceptions/invalidshareexception.php delete mode 100644 lib/share/iadvancedsharefactory.php delete mode 100644 lib/share/sharepublic.php create mode 100644 lib/share/shares.php create mode 100644 lib/share/sharesmanager.php create mode 100644 lib/share/sharetype/common.php delete mode 100644 lib/share/sharetype/sharetype.php create mode 100644 lib/share/timemachine.php delete mode 100644 lib/share/utility.php delete mode 100644 tests/lib/share/backend.php create mode 100644 tests/lib/share/shares.php create mode 100644 tests/lib/share/sharesmanager.php create mode 100644 tests/lib/share/sharetype/group.php create mode 100644 tests/lib/share/sharetype/link.php create mode 100644 tests/lib/share/sharetype/sharetype.php create mode 100644 tests/lib/share/sharetype/user.php diff --git a/db_structure.xml b/db_structure.xml index cefb7fc52c91..15894c204e76 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -857,6 +857,197 @@ + *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 + + true + 250 + + + + +
+ + + + *dbprefix*shares_parents + + + + + id + integer + 0 + true + 4 + + + + parent_id + integer + 0 + true + 4 + + + + +
+ *dbprefix*jobs 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/collectionshares.php b/lib/share/collectionshares.php new file mode 100644 index 000000000000..e9f3c3777e7c --- /dev/null +++ b/lib/share/collectionshares.php @@ -0,0 +1,70 @@ +. + */ + +namespace OC\Share; + +use OC\Share\Share; +use OC\Share\Shares; +use OC\Share\TimeMachine; + +/** + * Backend class that apps extend and register with the SharesManager to share content + * This class should be used if the app has content that can have children that are also shared + * using a different backend class e.g. folders + * + * Hooks available in class name scope + * - preShare(Share $share) + * - postShare(Share $share) + * - preUnshare(Share $share) + * - postUnshare(Share $share) + * - preUpdate(Share $share) + * - postUpdate(Share $share) + * + * @version 2.0.0 BETA + */ +abstract class CollectionShares extends Shares { + + /** + * The constructor + * @param TimeMachine $timeMachine The time() mock + * @param array $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); + } + + /** + * Get the identifiers for the children item types of this backend + * @return array + */ + abstract public function getChildrenItemTypes(); + + /** + * Search for shares of this collection item type that contain the child item source and + * shared with $shareWith + * @param string $shareWith + * @param any $itemSource + * @return array + */ + abstract public function searchForChildren($shareWith, $itemSource); + +} \ 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/sharedoesnotexistexception.php b/lib/share/exception/sharedoesnotexistexception.php new file mode 100644 index 000000000000..50b887eb4e79 --- /dev/null +++ b/lib/share/exception/sharedoesnotexistexception.php @@ -0,0 +1,30 @@ +. + */ + +namespace OC\Share\Exception; + +class ShareDoesNotExistException extends \Exception { + + public function __construct($message) { + parent::__construct($message); + } + +} \ No newline at end of file diff --git a/lib/share/exception/sharesbackenddoesnotexistexception.php b/lib/share/exception/sharesbackenddoesnotexistexception.php new file mode 100644 index 000000000000..e4e783c17a90 --- /dev/null +++ b/lib/share/exception/sharesbackenddoesnotexistexception.php @@ -0,0 +1,30 @@ +. + */ + +namespace OC\Share\Exception; + +class SharesBackendDoesNotExistException extends \Exception { + + public function __construct($message) { + 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..4efd6c235462 --- /dev/null +++ b/lib/share/exception/sharetypedoesnotexistexception.php @@ -0,0 +1,30 @@ +. + */ + +namespace OC\Share\Exception; + +class ShareTypeDoesNotExistException extends \Exception { + + public function __construct($message) { + parent::__construct($message); + } + +} \ No newline at end of file diff --git a/lib/share/exceptions/invalidshareexception.php b/lib/share/exceptions/invalidshareexception.php deleted file mode 100644 index 7e368765690c..000000000000 --- a/lib/share/exceptions/invalidshareexception.php +++ /dev/null @@ -1,30 +0,0 @@ -. -*/ - -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/iadvancedsharefactory.php b/lib/share/iadvancedsharefactory.php deleted file mode 100644 index 17433bc60d4e..000000000000 --- a/lib/share/iadvancedsharefactory.php +++ /dev/null @@ -1,67 +0,0 @@ -. -*/ - -namespace OC\Share; - -/** - * An Advanced Share Factory to reduce the number of queries needed to generate a Share object - * Setup JOINs in the share queries to retrieve additional properties for the Share object - * The columns specified in getColumns() will be returned in the $row passed to mapToShare($row) - */ -interface IAdvancedShareFactory extends IShareFactory { - - /** - * Get JOIN(s) to app table(s) - * @return array - * - * Example: - * - * return array( - * 'table1' => array( - * 'share' => 'item_source', - * 'table1' => 'id' - * ) - * ); - * - * Equivalent: JOIN table1 ON share.item_source = table1.id - * - */ - public function getJoins(); - - /** - * Get app table column(s) - * @return array - * - * Example: - * - * return array( - * 'table1' => array( - * 'id', - * 'name' - * ) - * ); - * - * Equivalent: SELECT table1.id, table1.name - * - */ - public function getColumns(); - -} \ No newline at end of file diff --git a/lib/share/share.php b/lib/share/share.php index 0ac17289885c..c753ebb24913 100644 --- a/lib/share/share.php +++ b/lib/share/share.php @@ -1,77 +1,116 @@ . -*/ + * ownCloud + * + * @author Bernhard Posselt + * @author Michael Gapczynski + * @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 . + */ namespace OC\Share; /** - * Data holder for shared items. Extend this class for your items. - * - * A setter does not imply that property can change. + * Data holder for shared items + * Extend this class to store additional properties * - * Extension of OCA\AppFramework\Db\Entity + * Adapated from OCA\AppFramework\Db\Entity * */ class Share { - public $id; - public $parentId; - public $shareTypeId; - public $uidOwner; - public $shareWith; - public $permissions; - public $itemSource; - public $itemTarget; - public $itemOwner; - public $expirationTime; - public $shareTime; - - private $updatedFields = array(); - private $fieldTypes = array( + protected $id; + protected $parentIds = array(); + protected $shareTypeId; + protected $shareOwner; + protected $shareWith; + 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', - 'parentId' => 'int', 'permissions' => 'int', 'expirationTime' => 'int', 'shareTime' => 'int' ); + /** + * Check if the share has create permission + * @return bool + */ public function isCreatable() { - return $this->permissions & OCP\PERMISSION_CREATE; + return ($this->permissions & \OCP\PERMISSION_CREATE) !== 0; } + /** + * Check if the share has read permission + * @return bool + */ public function isReadable() { - return $this->permissions & OCP\PERMISSION_READ; + return ($this->permissions & \OCP\PERMISSION_READ) !== 0; } + /** + * Check if the share has update permission + * @return bool + */ public function isUpdatable() { - return $this->permissions & OCP\PERMISSION_UPDATE; + return ($this->permissions & \OCP\PERMISSION_UPDATE) !== 0; } + /** + * Check if the share has delete permission + * @return bool + */ public function isDeletable() { - return $this->permissions & OCP\PERMISSION_DELETE; + return ($this->permissions & \OCP\PERMISSION_DELETE) !== 0; } + /** + * Check if the share has share permission + * @return bool + */ public function isSharable() { - return $this->permissions & OCP\PERMISSION_SHARE; + return ($this->permissions & \OCP\PERMISSION_SHARE) !== 0; + } + + /** + * Add a reference to a parent share + * @param Share $share + */ + public function addParentId($id) { + $this->parentIds[] = $id; + $this->markPropertyUpdated('parentIds'); + } + + /** + * Remove a reference to a parent share + * @param Share $share + */ + public function removeParentId($id) { + $this->parentIds = array_diff($this->parentIds, array($id)); + $this->markPropertyUpdated('parentIds'); } /** @@ -82,39 +121,30 @@ public function isSharable() { */ public static function fromParams(array $params) { $instance = new static(); - foreach ($params as $key => $value) { - $method = 'set'.ucfirst($key); + foreach ($params as $property => $value) { + $method = 'set'.ucfirst($property); $instance->$method($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 $key => $value) { - $prop = $this->columnToProperty($key); - if ($value !== null && isset($this->fieldTypes[$prop])) { - settype($value, $this->fieldTypes[$prop]); + foreach ($row as $column => $value) { + $property = $instance::columnToProperty($column); + if (isset($value) && isset($instance->propertyTypes[$property])) { + settype($value, $instance->propertyTypes[$property]); } - $method = 'set'.ucfirst($key); + $method = 'set'.ucfirst($property); $instance->$method($value); - $this->$prop = $value; } return $instance; } - /** - * Marks the entity as clean needed for setting the id after the insertion - */ - public function resetUpdatedFields() { - $this->updatedFields = array(); - } - /** * Each time a setter is called, push the part after set * into an array: for instance setId will save Id in the @@ -124,45 +154,57 @@ public function resetUpdatedFields() { public function __call($methodName, $args) { // setters if (strpos($methodName, 'set') === 0) { - $attr = lcfirst( substr($methodName, 3) ); + $property = lcfirst(substr($methodName, 3)); // setters should only work for existing attributes - if (property_exists($this, $attr)) { - $this->markFieldUpdated($attr); - $this->$attr = $args[0]; + if (property_exists($this, $property)) { + $this->markPropertyUpdated($property); + $this->$property = $args[0]; } else { - throw new \BadFunctionCallException($attr . - ' is not a valid attribute'); + throw new \BadFunctionCallException($property.' is not a valid property'); } // getters - } elseif (strpos($methodName, 'get') === 0) { - $attr = lcfirst(substr($methodName, 3)); + } else if (strpos($methodName, 'get') === 0) { + $property = lcfirst(substr($methodName, 3)); // getters should only work for existing attributes - if (property_exists($this, $attr)) { - return $this->$attr; + if (property_exists($this, $property)) { + return $this->$property; } else { - throw new \BadFunctionCallException($attr . - ' is not a valid attribute'); + throw new \BadFunctionCallException($property.' is not a valid property'); } } else { - throw new \BadFunctionCallException($methodName . - ' does not exist'); + throw new \BadFunctionCallException($methodName.' does not exist'); } } /** - * Mark an attribute as updated - * @param string $attribute the name of the attribute + * 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 */ - protected function markFieldUpdated($attribute) { - $this->updatedFields[$attribute] = true; + public function resetUpdatedProperties() { + $this->updatedProperties = array(); } /** - * Transform a database columnname to a property + * Transform a database column name to a property * @param string $columnName the name of the column * @return string the property name */ - public function columnToProperty($columnName) { + public static function columnToProperty($columnName) { + $columnName = trim($columnName, '`'); $parts = explode('_', $columnName); $property = null; foreach ($parts as $part) { @@ -180,34 +222,17 @@ public function columnToProperty($columnName) { * @param string $property the name of the property * @return string the column name */ - public function propertyToColumn($property) { + public static function propertyToColumn($property) { $parts = preg_split('/(?=[A-Z])/', $property); $column = null; - foreach($parts as $part) { + foreach ($parts as $part) { if ($column === null) { $column = $part; } else { $column .= '_'.lcfirst($part); } } - return $column; - } - - /** - * @return array array of updated fields for update query - */ - public function getUpdatedFields() { - return $this->updatedFields; - } - - /** - * Adds type information for a field so that its automatically casted to - * that value once its being returned from the database - * @param string $fieldName the name of the attribute - * @param string $type the type which will be used to call settype() - */ - protected function addType($fieldName, $type) { - $this->fieldTypes[$fieldName] = $type; + return '`'.$column.'`'; } } \ No newline at end of file diff --git a/lib/share/sharefactory.php b/lib/share/sharefactory.php index a89522c45683..7388dc99e41e 100644 --- a/lib/share/sharefactory.php +++ b/lib/share/sharefactory.php @@ -1,36 +1,38 @@ . -*/ + * ownCloud + * + * @author Michael Gapczynski + * @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 . + */ namespace OC\Share; /** - * + * Creates Share entities from the database */ -interface IShareFactory { +class ShareFactory { /** - * [mapToShare description] - * @param [type] $row [description] + * Map a database row to a Share entity + * @param array $row A key => value array of share properties * @return Share */ - public function mapToShare($row); - + public function mapToShare($row) { + return Share::fromRow($row); + } + } \ No newline at end of file diff --git a/lib/share/sharepublic.php b/lib/share/sharepublic.php deleted file mode 100644 index 073a7c5097b8..000000000000 --- a/lib/share/sharepublic.php +++ /dev/null @@ -1,427 +0,0 @@ -. -*/ - -namespace OCP; - -abstract class ShareAPI { - - /** - * Check if an item is valid for the user specified by uidOwner - * @param Share $share - * @return bool - * - * Needs to check if the user owns this item or has access to it through a share - * - */ - abstract public function isValidItem(Share $share); - - /** - * Get the ShareFactory object for this item type - * @return ShareFactory - */ - abstract public function getShareFactory(); - - /** - * Check if a unique target per user is required for this item type - * @return bool - */ - abstract public function isUniqueTargetRequired(); - - /** - * Get a unique - * @return string - */ - abstract public function generateUniqueTarget(Share $share); - - // TODO I guess we should merge duplicate shares somewhere out here - public function getShares($shareWith = null, $uidOwner = null, $isShareWithUser = true, - $extraFilter = null - ) { - $shareTypes = Utility::getSupportedShareTypes($this); - $shares = array(); - foreach ($shareTypes as $shareType) { - $result = $shareType->getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter); - foreach ($result as $share) { - if (!$this->isExpired($share)) { - $shares[] = $share; - } else { - $this->unshare($share); - } - } - } - return $shares; - } - - /** - * Get the shares with the specified item target and additional parameters - * @param string $itemTarget - * @param string $shareWith (optional) - * @param string $uidOwner (optional) - * @param bool $isShareWithUser (optional, default = true) - * @return array - */ - public function getSharesByTarget($itemTarget, $shareWith = null, $uidOwner = null, - $isShareWithUser = true - ) { - $extraFilter = array('`item_target` = ?', array($itemTarget)); - return $shareType->getShares($itemSource, $shareWith, $uidOwner, $extraFilter); - } - - /** - * Get the shares with the specified item source and additional parameters - * @param string $itemSource - * @param string $shareWith (optional) - * @param string $uidOwner (optional) - * @param bool $isShareWithUser (optional, default = true) - * @return array - */ - public function getSharesBySource($itemSource, $shareWith = null, $uidOwner = null, - $isShareWithUser = true - ) { - $extraFilter = array('`item_source` = ?', array($itemSource)); - return $shareType->getShares($itemSource, $shareWith, $uidOwner, $extraFilter); - } - - /** - * Get the reshares of a share - * @param Share $share - * @return array - */ - public function getReshares(Share $share) { - $extraFilter = array('`parent_id` = ?', array($share->getId())); - return $this->getShares(null, null, true, $extraFilter); - } - - /** - * Get the duplicates of a share - * @param Share $share - * @return array - * - * These are shares to the same person of the same item from different owners - * - */ - public function getDuplicates(Share $share) { - $where = '`item_source` = ? AND `id != ?'; - $params = array($share->getItemSource(), $share->getId()); - $extraFilter = array($where, $params); - return $this->getShares($share->getUidOwner(), null, true, $extraFilter); - } - - /** - * Get the parent share of a share - * @param Share $share - * @param bool $find (optional, default = false) - * @return Share - */ - public function getParent(Share $share, $find = false) { - // TODO need to know about collections here - find parent item types - if ($find === false) { - $parents = $this->getShares(null, null, true, array('`id` = ?', $id)); - if (!empty($parents)) { - if (count($parents) > 1) { - throw new \Exception(); - } else { - return current($parents); - } - } else { - return false; - } - } else { - $extraFilter = array('`item_source` = ?', $share->getItemSource()); - $parents = $this->getShares($share->getUidOwner(), null, true, $extraFilter); - if (!empty($parents)) { - foreach ($parents as $parent) { - if ($parent->getPermissions() & OCP\PERMISSION_SHARE) { - return $parent; - } - } - // Resharing not allowed - throw new \Exception() - } else { - return false; - } - } - } - - public function searchForShares($pattern) { - // TODO - } - - /** - * Share a share - * @param Share $share - * @return bool - */ - public function share(Share $share) { - if ($this->isValidItem($share)) { - $shareType = Utility::getSupportedShareType($this, $share->getShareTypeId()); - if ($shareType) { - $parent = $this->getParent($share, true); - if ($parent) { - $share->setParentId($parent->getId()); - } - if ($shareType->isValidShare($share) - && $this->areValidPermissions($share) - && $this->isValidExpirationTime($share) - ) { - return $shareType->share($share); - } - } else { - return false; - } - } else { - return false; - } - } - - /** - * Unshare a share - * @param Share $share - */ - public function unshare(Share $share) { - $shareType = Utility::getSupportedShareType($this, $share->getShareTypeId()); - if ($shareType) { - $reshares = $this->getReshares($share); - if (!empty($reshares)) { - // Try to find a duplicate share, to switch parent ids of reshares - $parentId = null; - $duplicates = $this->getDuplicates($share); - foreach ($duplicates as $duplicate) { - if ($duplicate->getPermissions() & OCP\PERMISSION_SHARE) { - $parentId = $duplicate->getId(); - break; - } - } - foreach ($reshares as $reshare) { - if (isset($parentId)) { - $reshare->setParentId($parentId); - $this->update($reshare); - } else { - $this->unshare($reshare); - } - } - } - $shareType->unshare($share); - } - } - - /** - * Update a share in the database - * @param Share $share - */ - public function update(Share $share) { - // TODO Fix - $shareTypeId = $share->getShareType(); - $shareType = $this->getShareTypeObject($shareTypeId); - if ($shareType) { - $updatedFields = $share->getUpdatedFields(); - foreach ($updatedFields as $updatedField) { - $setter = 'set'.ucfirst($updatedField); - if (method_exists($shareType, $setter)) { - $shareType->$setter($share); - } else { - throw new \Exception(); - } - if ($setter === 'setPermissions') { - - } else if ($setter === 'setExpirationTime') { - - } - } - } else { - throw new \Exception(); - } - } - - /** - * Unshare all shares of an item - * @param any $itemSource - * - * Call this if an item is deleted by the item owner - * - */ - public function deleteItem($itemSource) { - $shares = $this->getSharesBySource($itemSource); - foreach ($shares as $share) { - $this->unshare($share); - } - } - - /** - * Get potential people to share with based on the given pattern - * @param string $pattern - * @return array - */ - public function searchForShareWiths($pattern) { - $shareTypes = Utility::getSupportedShareTypes($this); - $shareWiths = array(); - foreach ($shareTypes as $shareType) { - $shareWiths += $shareType->searchForShareWiths($pattern); - } - return $shareWiths; - } - - /** - * Check if a share is expired - * @param Share $share - * @return bool - */ - protected function isExpired(Share $share) { - $time = $share->getExpirationTime(); - if (isset($time)) { - if ($time - time() > 0) { - return true; - } else { - return false; - } - } else { - $defaultTime = $this->getDefaultTime(); - if ($defaultTime > 0 && ($defaultTime + $share->getShareTime()) - time() > 0)) { - return true; - } else { - return false; - } - } - } - - /** - * Check if a share's permissions are valid - * @param Share $share - * @return bool - */ - protected function areValidPermissions($share) { - $permissions = $share->getPermissions(); - if (!is_int($permissions) || $permisisons < 0 || $permissions > OCP\PERMISSION_All) { - throw new \Exception(); - } - $parent = $this->getParent($share) - if ($parent) { - if (!Utility::isResharingAllowed()) { - throw new \Exception(); - } - // Check if permissions exceed the parent share permissions - if ($permissions & ~$parent->getPermissions()) { - throw new \Exception($message); - } - // Check if share permission is granted - if (~$parentPermissions & OCP\PERMISSION_SHARE) { - throw new \Exception(); - } - } - // TODO Check if permission allowed for item - return true; - } - - /** - * Update permissions of all reshares of a share - * @param Share $share - */ - protected function updateResharesPermissions(Share $share, $oldPermissions) { - $permissions = $share->getPermissions(); - // Check if permissions were removed - if (~$permissions & $oldPermissions) { - // Update permissions of all reshares - $reshares = $this->getReshares($share); - if (!empty($reshares)) { - // Try to find a duplicate share, to switch parent ids of reshares - if (~$permissions & OCP\PERMISSION_SHARE) { - $parentId = null; - $duplicates = $this->getDuplicates($share); - foreach ($duplicates as $duplicate) { - if ($duplicate->getPermissions() & OCP\PERMISSION_SHARE) { - $parentId = $duplicate->getId(); - break; - } - } - } - foreach ($reshares as $reshare) { - $resharePermissions = $reshare->getPermissions(); - // Check if reshare's permissions were removed - if (~$permissions & resharePermissions) { - $resharePermissions &= $permissions; - $reshare->setPermissions($resharePermissions); - // If share permission is removed, unshare all reshares - if (~$permissions & OCP\PERMISSION_SHARE) { - if (isset($parentId)) { - $reshare->setParentId($parentId); - $this->update($reshare); - } else { - $this->unshare($reshare); - } - } else { - $this->update($reshare); - } - } - } - } - } - } - - /** - * Check if a share's expiration time is valid - * @param Share $share - * @return bool - */ - protected function isValidExpirationTime(Share $share) { - $time = $share->getExpirationTime(); - if (isset($time) && !is_int($time)) { - throw new \Exception($message); - } - // Time must be at least 1 hour in the future - if (isset($time) && $time < time() + 3600) { - throw new \Exception($message); - } - $parent = $this->getParent($share) - if ($parent) { - // Check if time is later than the parent expiration time - $parentTime = $parent->getExpirationTime(); - if (isset($parentTime)) { - if ((!isset($time) || $time > $parentTime) { - throw new \Exception($message); - } - } - } - return true; - } - - /** - * Update expiration time of all reshares of a share - * @param Share $share - */ - protected function updateResharesExpirationTime(Share $share, $oldTime) { - $time = $share->getExpirationTime(); - // Check if time was decreased - if (isset($time)) { - if (!isset($oldTime) || $time < $oldTime) { - // Truncate time of all reshares - $reshares = $this->getReshares($share); - foreach ($reshares as $reshare) { - $reshareTime = $reshare->getExpirationTime(); - if (!isset($reshareTime) || $time < $reshareTime) { - $reshare->setExpirationTime($time); - $this->update($reshare); - } - } - } - } - } - -} \ No newline at end of file diff --git a/lib/share/shares.php b/lib/share/shares.php new file mode 100644 index 000000000000..53f1b6642338 --- /dev/null +++ b/lib/share/shares.php @@ -0,0 +1,303 @@ +. + */ + +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 SharesManager to share content + * + * Hooks available in class name scope + * - preShare(Share $share) + * - postShare(Share $share) + * - preUnshare(Share $share) + * - postUnshare(Share $share) + * - preUpdate(Share $share) + * - postUpdate(Share $share) + * + * @version 2.0.0 BETA + */ +abstract class Shares extends BasicEmitter { + + protected $timeMachine; + protected $shareTypes; + + /** + * The constructor + * @param TimeMachine $timeMachine The time() mock + * @param array $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; + $this->shareTypes = $shareTypes; + } + + /** + * Get the identifier for the item type this backend handles + * @return string + */ + abstract public function getItemType(); + + /** + * Check if an item is valid for the share owner + * @param Share $share + * @throws 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); + + + /** + * Generate an item target for the share with + * @param Share $share + * @return string|array + */ + abstract protected function generateItemTarget(Share $share); + + /** + * Share a share + * @param Share $share + * @throws InvalidItemException + * @throws InvalidShareException + * @throws InvalidPermissionsException + * @throws InvalidExpirationTimeException + * @return 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) + ) { + $share->setItemTarget($this->generateItemTarget($share)); + $this->emit(get_class($this), 'preShare', array($share)); + $share->setShareTime($this->timeMachine->getTime()); + $share = $shareType->share($share); + $this->emit(get_class($this), 'postShare', array($share)); + return $share; + } + } + return false; + } + + /** + * Unshare a share + * @param Share $share + */ + public function unshare(Share $share) { + $shareType = $this->getShareType($share->getShareTypeId()); + $this->emit(get_class($this), 'preUnshare', array($share)); + $shareType->unshare($share); + $this->emit(get_class($this), 'postUnshare', array($share)); + } + + /** + * Update a share's properties in the database + * @param Share $share + */ + public function update(Share $share) { + $shareType = $this->getShareType($share->getShareTypeId()); + $this->emit(get_class($this), 'preUpdate', array($share)); + $properties = $share->getUpdatedProperties(); + 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(get_class($this), '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 array + */ + 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) { + break 2; + } + } + if (isset($offset) && $offset > 0) { + $offset--; + } + } + } + return $shares; + } + + /** + * Search for potential people to share with based on the given pattern + * @param string $pattern + * @param int $limit (optional) + * @param int $offset (optional) + * @return array + */ + public function searchForPotentialShareWiths($pattern, $limit = null, $offset = null) { + $shareWiths = array(); + foreach ($this->shareTypes as $shareType) { + $result = $shareType->searchForPotentialShareWiths($pattern, $limit, $offset); + foreach ($result as $shareWith) { + $shareWiths[] = $shareWith; + if (isset($limit)) { + $limit--; + if ($limit === 0) { + break 2; + } + } + if (isset($offset) && $offset > 0) { + $offset--; + } + } + } + return $shareWiths; + } + + /** + * Check if a share is expired + * @param 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; + } + } + } + + /** + * Get share type by id + * @param string $shareTypeId + * @throws ShareTypeDoesNotExistException + * @return ShareType + */ + protected function getShareType($shareTypeId) { + foreach ($this->shareTypes as $shareType) { + if ($shareType->getId() === $shareTypeId) { + return $shareType; + } + } + throw new ShareTypeDoesNotExistException('No share type found matching id'); + } + + /** + * Check if a share's permissions are valid + * @param Share $share + * @throws InvalidPermissionsException + * @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) { + $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 Share $share + * @throws InvalidExpirationTimeException + * @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/sharesmanager.php b/lib/share/sharesmanager.php new file mode 100644 index 000000000000..0e4c4f4729e8 --- /dev/null +++ b/lib/share/sharesmanager.php @@ -0,0 +1,516 @@ +. + */ + +namespace OC\Share; + +use OC\Share\Share; +use OC\Share\Shares; +use OC\Share\CollectionShares; +use OC\Share\Exception\InvalidShareException; +use OC\Share\Exception\ShareDoesNotExistException; +use OC\Share\Exception\SharesBackendDoesNotExistException; +use OC\Share\Exception\InvalidPermissionsException; +use OC\Share\Exception\InvalidExpirationTimeException; + +/** + * This is the gateway for sharing content between users in ownCloud, aka Share API + * Apps must create a shares backend class that extends OC\Share\Shares and register it here + * + * The SharesManager's primary purpose is to ensure consistency between shares and their reshares + * + * @version 2.0.0 BETA + */ +class SharesManager { + + protected $sharesBackends; + + /** + * Register a shares backend + * @param Shares $shares + */ + public function registerSharesBackend(Shares $shares) { + $this->sharesBackends[$shares->getItemType()] = $shares; + } + + /** + * Share a share in the shares backend + * @param Share $share + * @throws InvalidItemException + * @throws InvalidShareException + * @throws InvalidPermissionsException + * @throws InvalidExpirationTimeException + * @return bool + */ + public function share(Share $share) { + $backend = $this->getSharesBackend($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 = $backend->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 shares backend + * @param Share $share + */ + public function unshare(Share $share) { + $backend = $this->getSharesBackend($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); + } + $backend->unshare($share); + } + + /** + * Update a share's properties in the shares backend + * @param Share $share + * @throws ShareDoesNotExistException + * @throws InvalidPermissionsException + * @throws 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 + $filter = array( + 'id' => $share->getId(), + 'shareTypeId' => $share->getShareTypeId(), + ); + $result = $this->getShares($itemType, $filter, 1); + if (empty($result)) { + throw new ShareDoesNotExistException('The share does not exist for update'); + } else { + $oldShare = reset($result); + $backend = $this->getSharesBackend($itemType); + $backend->update($share); + if (isset($properties['permissions']) || isset($properties['expirationTime'])) { + $this->updateReshares($share, $oldShare); + } + } + } + + /** + * Get the shares with the specified parameters in the shares backend + * @param string $itemType + * @param array $filter (optional) A key => value array of share properties + * @param int $limit (optional) + * @param int $offset (optional) + * @return array + */ + public function getShares($itemType, $filter = array(), $limit = null, $offset = null) { + $shares = array(); + $backend = $this->getSharesBackend($itemType); + $results = $backend->getShares($filter, $limit, $offset); + $expired = 0; + foreach ($results as $share) { + if ($backend->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; + } + + /** + * Search for potential people to share with based on the given pattern in the shares backend + * @param string $itemType + * @param string $pattern + * @param int $limit (optional) + * @param int $offset (optional) + * @return array + */ + public function searchForPotentialShareWiths($itemType, $pattern, $limit = null, + $offset = null + ) { + $backend = $this->getSharesBackend($itemType); + return $backend->searchForPotentialShareWiths($pattern, $limit, $offset); + } + + /** + * Unshare all shares of an item + * @param string $itemType + * @param any $itemSource + * + * Call this if an item is deleted by the item owner + * + */ + 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 Share $share + * @return array + * + * 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); + $backend = $this->getSharesBackend($itemType); + if ($backend instanceof CollectionShares) { + // Find reshares in children item types + foreach ($backend->getChildrenItemTypes() as $childItemType) { + $childReshares = $this->getShares($childItemType, $filter); + $reshares = array_merge($reshares, $childReshares); + } + } + return $reshares; + } + + /** + * Get all parents of a share + * @param Share $share + * @throws ShareDoesNotExistException + * @return array + * + * 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->sharesBackends as $backend) { + if ($backend instanceof CollectionShares + && in_array($itemType, $backend->getChildrenItemTypes()) + && !in_array($backend->getItemType(), $parentItemTypes) + ) { + $parentItemTypes[] = $backend->getItemType(); + } + } + foreach ($parentIds as $parentId) { + $filter = array( + 'id' => $parentId, + ); + foreach ($parentItemTypes as $parentItemType) { + $result = $this->getShares($parentItemType, $filter, 1); + if (!empty($result)) { + $parents[] = reset($result); + break; + } else if ($parentItemType === end($parentItemTypes)) { + throw new ShareDoesNotExistException('The parent share does not exist'); + } + } + } + } + return $parents; + } + + /** + * Get shares backend by item type + * @param string $itemType + * @throws SharesBackendDoesNotExistException + * @return Shares + */ + protected function getSharesBackend($itemType) { + if (isset($this->sharesBackends[$itemType])) { + return $this->sharesBackends[$itemType]; + } else { + throw new SharesBackendDoesNotExistException( + 'A share backend does not exist for the item type' + ); + } + } + + /** + * Search for reshares of a share + * @param Share $share + * @return array 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 Share $share + * @return array 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(); + $shareOwner = $share->getShareOwner(); + $itemSource = $share->getItemSource(); + $filter = array( + 'shareWith' => $shareOwner, + 'itemSource' => $itemSource, + ); + $parents = $this->getShares($itemType, $filter); + // Search in collections for parents in case children were reshared + foreach ($this->sharesBackends as $backend) { + if ($backend instanceof CollectionShares + && in_array($itemType, $backend->getChildrenItemTypes()) + ) { + $collectionParents = $backend->searchForChildren($shareOwner, $itemSource); + $parents = array_merge($parents, $collectionParents); + } + } + return $parents; + } + + /** + * Get the total permissions of an array of shares + * @param array $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 array $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 Share $share + * @throws 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'.$share->getId() + ); + } + } + return true; + } + + /** + * Check if a share's expiration time is valid with respect to the parent shares + * @param Share $share + * @throws 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 Share $share + * @param Share $oldShare + * + * The share has to be updated in the shares 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..c90b8da2b14d --- /dev/null +++ b/lib/share/sharetype/common.php @@ -0,0 +1,198 @@ +. + */ + +namespace OC\Share\ShareType; + +use OC\Share\Share; +use OC\Share\ShareFactory; + +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($this->table); + $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, + ); + $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 '.$this->parentsTable.' FROM '.$this->parentsTable.' '. + 'LEFT JOIN '.$this->table.' ON '.$this->parentsTable.'.`id` = '.$this->table.'.`id` '. + 'WHERE '.$this->table.'.`id` IS NULL'; + \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 index 0e6b68bde481..a129f7e90372 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -1,152 +1,235 @@ . -*/ - -namespace OC\Share\Type; + * ownCloud + * + * @author Michael Gapczynski + * @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 . + */ + +namespace OC\Share\ShareType; + +use OC\Share\Share; +use OC\Share\ShareFactory; +use OC\Share\Exception\InvalidShareException; +use OC\User\Manager as UserManager; +/** + * Controller for shares between a user and a group + */ class Group extends Common { + protected $userManager; protected $groupTable; - public function __construct($itemType, IShareFactory $shareFactory) { + /** + * The constructor + * @param string $itemType + * @param ShareFactory $shareFactory + * @param Manager $userManager + */ + public function __construct($itemType, ShareFactory $shareFactory, UserManager $userManager) { parent::__construct($itemType, $shareFactory); - $this->groupTable = '*PREFIX*groupshares'; + $this->userManager = $userManager; + $this->groupsTable = '`*PREFIX*shares_groups`'; } public function getId() { return 'group'; } - public function getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter) { - if ($isShareWithUser === true) { - list($where, $params) = $this->getDefaultFilter($shareWith, $uidOwner); - if (isset($extraFilter)) { - list($extraWhere, $extraParams) = $extraFilter; - $where .= ' '.ltrim($extraWhere); - $params += $extraParams; - } - // Select all columns in the share table - $columns = '`'.$this->table.'`.*'; - // LEFT JOIN with the unique group shares table - $joins = 'LEFT JOIN `'.$this->groupTable.'` ON `'; - $joins .= '`'.$this->table.'`.`id` = '; - $joins .= '`'.$this->groupTable.'`.`id`'; - // Select all columns in the unique group shares table - $columns .= ', `'.$this->groupTable.'`.*'; - list($appColumns, $appJoins) = $this->getAppJoins(); - $columns .= $appColumns; - $joins .= ltrim($appJoins); - $sql = 'SELECT '.$columns.' FROM `'.$this->table.'` '.$joins.' WHERE '.$where; - $query = \OC_DB::prepare($sql); - $result = $query->execute(array($params)); - $shares = array(); - while ($row = $result->fetchRow()) { - $share = $this->shareFactory->mapToShare($row); - // TODO - if (isset($row[$this->groupTable.'.target'])) { - $share->setItemTarget() - } - $shares[] = $share; - } - return $shares; - } else { - return parent::getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter); - } - } - public function isValidShare(Share $share) { - $uidOwner = $share->getUidOwner(); + $shareOwner = $share->getShareOwner(); $shareWith = $share->getShareWith(); + if (!$this->userManager->userExists($shareOwner)) { + throw new InvalidShareException('The share owner does not exist'); + } if (!\OC_Group::groupExists($shareWith)) { - $message = 'Sharing '.$itemSource.' failed, because the group '.$shareWith.' does not exist'; - throw new \Exception($message); + throw new InvalidShareException('The group shared with does not exist'); } $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); - if ($sharingPolicy === 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) { - $message = 'Sharing '.$itemSource.' failed, because ' - .$uidOwner.' is not a member of the group '.$shareWith; - throw new \Exception($message); + if ($sharingPolicy === 'groups_only' && !\OC_Group::inGroup($shareOwner, $shareWith)) { + 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) { - if ($this->itemType->isUniqueTargetRequired()) { - $users = \OC_Group::usersInGroup($share->getShareWith()); - $tempShare = $share; - foreach ($users as $user) { - $tempShare->setShareType('user'); - $tempShare->setShareWith($user); - $tempdata['item_target'] = $this->generateItemTarget($tempShare); - - if ($tempdata['']) - } + public function share(Share $share) { + $itemTargets = $share->getItemTarget(); + if (is_array($itemTargets)) { + // The first element is the default group item target + $share->setItemTarget(reset($itemTargets)); + } + $share = parent::share($share); + if ($share) { + $share->setItemTarget($itemTargets); + $this->setItemTarget($share); + $share->resetUpdatedProperties(); } - - $id = $this->cache->put($data; - $share->setId($id); return $share; } - public function unshareFromSelf($share) { - - } - - public function searchForShareWiths($pattern) { - return OC_Group::getGroups(); + /** + * Update the share's item targets in the database + * @param 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)); + } + } } - protected function getDefaultFilter($shareWith, $uidOwner, $isShareWithUser) { - $where = ''; - $params = array($this->getId(), $this->itemType); - if (isset($shareWith)) { - if ($isShareWithUser === true) { - $groups = \OC_Group::getUserGroups($shareWith); - $placeholders = join(',', array_fill(0, count($groups), '?')); - $where .= ' AND share_with IN ('.$placeholders.')'; - $params += $groups; - $params[] - } else { - $where .= '`share_type` = ? AND `share_with` = ?'; - $params[] = $this->getId(); - $params[] = $shareWith; + public function getShares(array $filter, $limit, $offset) { + $shares = array(); + if (!isset($filter['shareWith']) + || (isset($filter['isShareWithGroup']) && $filter['isShareWithGroup'] === true) + ) { + unset($filter['isShareWithGroup']); + $shares = parent::getShares($filter, $limit, $offset); + } else { + unset($filter['isShareWithGroup']); + $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 = \OC_Group::getUserGroups($value); + 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 + $placeholders = join(',', array_fill(0, count($groups), '?')); + $where .= $column.' IN ('.$placeholders.') AND `share_owner` != ? AND '; + $params = array_merge($params, $groups); + $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; } } - if (isset($uidOwner)) { - $where .= ' AND `uid_owner` = ?'; - $params[] = $uidOwner; + foreach ($shares as $share) { + $userItemTargets = $this->getUserItemTargets($share->getId()); + if (!empty($userItemTargets)) { + if (isset($filter['shareWith'])) { + if (isset($userItemTargets[$filter['shareWith']])) { + $share->setItemTarget($userItemTargets[$filter['shareWith']]); + } + } else { + $itemTargets = array($share->getItemTarget()); + $itemTargets['users'] = $userItemTargets; + $share->setItemTarget($itemTargets); + $share->resetUpdatedProperties(); + } + } } - return array($where, $params); + return $shares; } - // Hook Listeners - public static function post_addToGroup($params) { - + public function clear() { + parent::clear(); + $sql = 'DELETE '.$this->groupsTable.' FROM '.$this->groupsTable.' '. + 'LEFT JOIN '.$this->table.' ON '.$this->groupsTable.'.`id` = '.$this->table.'.`id` '. + 'WHERE '.$this->table.'.`id` IS NULL'; + \OC_DB::executeAudited($sql); } - public static function post_removeFromGroup($params) { - + public function searchForPotentialShareWiths($pattern, $limit, $offset) { + return \OC_Group::getGroups($pattern, $limit, $offset); } - public static function post_deleteGroup($params) { - + 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; } } \ No newline at end of file diff --git a/lib/share/sharetype/isharetype.php b/lib/share/sharetype/isharetype.php index 480222185b0e..12f197c8bd8e 100644 --- a/lib/share/sharetype/isharetype.php +++ b/lib/share/sharetype/isharetype.php @@ -21,27 +21,24 @@ namespace OC\Share\ShareType; +use OC\Share\Share; + +/** + * Interface for a controller of shares + */ interface IShareType { /** - * Get the id for this share type + * Get the identifier for this share type * @return string id */ public function getId(); - /** - * Get the shares for this share type based on the given parameters - * @param string $shareWith - * @param string $uidOwner - * @param bool $isShareWithUser - * @return array - */ - public function getShares($shareWith, $uidOwner, $isShareWithUser); - /** * Check if this share is valid for this share type * @param Share $share * @return bool + * @throws InvalidShareException */ public function isValidShare(Share $share); @@ -59,31 +56,32 @@ public function share(Share $share); public function unshare(Share $share); /** - * Update the share's parent id in the database + * Update the share's properties in the database * @param Share $share - * - * Call this to switch parent ids of a reshare if the current parent share is being removed - * - */ - public function setParentId(Share $share); + */ + public function update(Share $share); /** - * Update the share's permissions in the database - * @param 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 array Share */ - public function setPermissions(Share $share); - + public function getShares(array $filter, $limit, $offset); + /** - * Update the share's expiration time in the database - * @param Share $share + * Remove all shares of this share type in the database */ - public function setExpirationTime(Share $share); + public function clear(); /** - * Get potential people to share with based on the given pattern + * Search for potential people of this share type to share with based on the given pattern * @param string $pattern + * @param int $limit + * @param int $offset * @return array */ - public function searchForShareWiths($pattern); + public function searchForPotentialShareWiths($pattern, $limit, $offset); } \ No newline at end of file diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index 83ed33885d07..975b03506738 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -1,115 +1,94 @@ . -*/ - -namespace OC\Share\Type; + * ownCloud + * + * @author Michael Gapczynski + * @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 . + */ +namespace OC\Share\ShareType; + +use OC\Share\Share; +use OC\Share\ShareFactory; +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 $userManager; + protected $hasher; protected $linkTable; - private const TOKEN_LENGTH = 32; - public function __construct($itemType, IShareFactory $shareFactory) { + const TOKEN_LENGTH = 32; + + /** + * The constructor + * @param string $itemType + * @param ShareFactory $shareFactory + * @param Manager $userManager + * @param PasswordHash $hasher + */ + public function __construct($itemType, ShareFactory $shareFactory, Manager $userManager, + PasswordHash $hasher + ) { parent::__construct($itemType, $shareFactory); - $this->linkTable = '*PREFIX*links'; + $this->userManager = $userManager; + $this->hasher = $hasher; + $this->linksTable = '`*PREFIX*shares_links`'; } public function getId() { return 'link'; } - public function getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter) { - if (isset($shareWith)) { - // Links are not associated with a person - return array(); - } else { - list($where, $params) = $this->getDefaultFilter($shareWith, $uidOwner); - if (isset($extraFilter)) { - list($extraWhere, $extraParams) = $extraFilter; - $where .= ' '.ltrim($extraWhere); - $params += $extraParams; - } - // Select all columns in the share table - $columns = '`'.$this->table.'`.*'; - // JOIN with the links table - $joins = 'JOIN `'.$this->linkTable.'` ON `'; - $joins .= '`'.$this->table.'`.`id` = '; - $joins .= '`'.$this->linkTable.'`.`id`'; - // Select all columns in the link table - $columns .= ', `'.$this->linkTable.'`.*'; - list($appColumns, $appJoins) = $this->getAppJoins(); - $columns .= $appColumns; - $joins .= ' '.$appJoins; - $sql = 'SELECT '.$columns.' FROM `'.$this->table.'` '.$joins.' WHERE '.$where; - $query = \OC_DB::prepare($sql); - $result = $query->execute(array($params)); - $shares = array(); - while ($row = $result->fetchRow()) { - $shares[] = $this->shareFactory->mapToShare($row); - } - return $shares; - } - } - 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('Sharing with links is not allowed'); - // Share permission for links doesn't make sense - } else if ($share->getPermissions() & OCP\PERMISSION_SHARE) { - throw new \Exception(); - } else { - return true; + throw new InvalidShareException('The admin has disabled sharing via links'); } + return true; } public function share(Share $share) { $share = parent::share($share); if ($share) { - // Create a token for a link $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); - // Store the id, token, password in the database - $query = \OC_DB::prepare('INSERT INTO `'.$this->linkTable.'` - (`id`, `token`, `password`) VALUES (?, ?, ?)' - ); - $query->execute(array($share->getId(), $token, $share->getPassword())); + $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); - return $share; - } else { - return false; + $share->setPassword($password); + $share->resetUpdatedProperties(); } + return $share; } public function unshare(Share $share) { parent::unshare($share); - $query = \OC_DB::prepare('DELETE FROM `'.$this->linkTable.'` WHERE `id` = ?'); - $query->execute(array($share->getId())); - } - - public function setPermissions(Share $share) { - // Share permission for links doesn't make sense - if ($share->getPermissions() & OCP\PERMISSION_SHARE) { - throw new \Exception(); - } else { - parent::setPermissions($share); - } + $sql = 'DELETE FROM '.$this->linksTable.' WHERE `id` = ?'; + \OC_DB::executeAudited($sql, array($share->getId())); } /** @@ -117,14 +96,91 @@ public function setPermissions(Share $share) { * @param Share $share */ public function setPassword(Share $share) { - $query = \OC_DB::prepare('UPDATE `'.$this->linkTable.'` SET `password` = ? - WHERE `id` = ?' - ); - $query->execute(array($share->getPassword(), $share->getId())); + $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->resetUpdatedProperties(); + $shares[] = $share; + } + return $shares; + } + } + + public function clear() { + parent::clear(); + $sql = 'DELETE '.$this->linksTable.' FROM '.$this->linksTable.' '. + 'LEFT JOIN '.$this->table.' ON '.$this->linksTable.'.`id` = '.$this->table.'.`id` '. + 'WHERE '.$this->table.'.`id` IS NULL'; + \OC_DB::executeAudited($sql); } - public function searchForShareWiths($pattern) { + public function searchForPotentialShareWiths($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; + } + } \ No newline at end of file diff --git a/lib/share/sharetype/sharetype.php b/lib/share/sharetype/sharetype.php deleted file mode 100644 index 1be4fe34f951..000000000000 --- a/lib/share/sharetype/sharetype.php +++ /dev/null @@ -1,152 +0,0 @@ -. -*/ - -namespace OC\Share\ShareType; - -abstract class ShareType implements IShareType { - - protected $table; - protected $shareFactory; - - public function __construct($itemType, IShareFactory $shareFactory) { - $this->table = '*PREFIX*share'; - $this->shareFactory = $shareFactory; - } - - abstract public function getId(); - - public function getShares($shareWith, $uidOwner, $isShareWithUser, $extraFilter) { - list($where, $params) = $this->getDefaultFilter($shareWith, $uidOwner); - if (isset($extraFilter)) { - list($extraWhere, $extraParams) = $extraFilter; - $where .= ' '.ltrim($extraWhere); - $params += $extraParams; - } - // Select all columns in the share table - $columns = '`'.$this->table.'`.*'; - list($appColumns, $appJoins) = $this->getAppJoins(); - $columns .= $appColumns; - $sql = 'SELECT '.$columns.' FROM `'.$this->table.'` '.$appJoins.' WHERE '.$where; - $query = \OC_DB::prepare($sql); - $result = $query->execute(array($params)); - $shares = array(); - while ($row = $result->fetchRow()) { - $shares[] = $this->shareFactory->mapToShare($row); - } - return $shares; - } - - abstract public function isValidShare(Share $share); - - public function share(Share $share) { - // TODO - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` - (' . implode(', ', $queryParts) . ')' - . ' VALUES( ' . implode(', ', $valuesPlaceholder) . ')'); - $result = $query->execute($params); - $id = (int)\OC_DB::insertid($this->table); - $share->setId($id); - return $share; - } - - public function unshare(Share $share) { - $query = \OC_DB::prepare('DELETE FROM `'.$this->table.'` WHERE `id` = ?'); - $query->execute(array($share->getId())); - } - - public function setParentId(Share $share) { - $parentId = $share->getParentId(); - $this->update($share->getId(), array('parent' => $parentId)); - } - - public function setPermissions(Share $share) { - $permissions = $share->getPermissions(); - $this->update($share->getId(), array('permissions' => $permissions)); - } - - public function setExpirationTime(Share $share) { - $time = $share->getExpirationTime(); - $this->update($share->getId(), array('expiration' => $time)); - } - - abstract public function searchForShareWiths($pattern); - - /** - * Get the default database filter for this share type - * @param string $shareWith - * @param string $uidOwner - * @param bool $isShareWithUser - * @return array($where, $params) - */ - protected function getDefaultFilter($shareWith, $uidOwner, $isShareWithUser) { - $where = '`share_type` = ? AND `item_type` = ?'; - $params = array($this->getId(), $this->itemType); - if (isset($shareWith)) { - $where .= ' AND share_with = ?'; - $params[] = $shareWith; - } - if (isset($uidOwner)) { - $where .= ' AND uid_owner = ?'; - $params[] = $uidOwner; - } - return array($where, $params); - } - - protected function getAppJoins() { - $columns = ''; - $joins = ''; - // Check if IAdvancedShareFactory is used and additional properties are needed - if ($this->shareFactory instanceof IAdvancedShareFactory) { - // Setup JOINs to fetch properties from app's tables - $appJoins = $this->shareFactory->getJoins(); - foreach ($appJoins as $appTable => $appJoin) { - $tables = array_keys($appJoin); - $joinColumns = array_values($appJoin); - if (count($tables) === 2) { - $joins .= ' JOIN `*PREFIX*'.$appTable.'` ON `'; - $joins .= '`*PREFIX*'.$tables[0].'`.`'.$joinColumns[0].'` = '; - $joins .= '`*PREFIX*'.$tables[1].'`.`'.$joinColumns[1].'`'; - } else { - throw new \Exception() - } - } - $joins = ltrim($joins); - // Add app specific columns to SELECT - $appTables = $this->shareFactory->getColumns(); - foreach ($appTables as $appTable => $appColumns) { - foreach ($appColumns as $appColumn) { - $columns .= ', `*PREFIX*'.$appTable.'`.`'.$appColumn.'`'; - } - } - } - return array($columns, $joins); - } - - /** - * Update the share's properties in the database - * @param int $id - * @param array $data - */ - protected function update($id, array $data) { - // TODO - } - -} \ No newline at end of file diff --git a/lib/share/sharetype/user.php b/lib/share/sharetype/user.php index ab88624e3ebb..16df3eef7433 100644 --- a/lib/share/sharetype/user.php +++ b/lib/share/sharetype/user.php @@ -1,28 +1,49 @@ . -*/ - -namespace OC\Share\Type; + * ownCloud + * + * @author Michael Gapczynski + * @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 . + */ +namespace OC\Share\ShareType; + +use OC\Share\Share; +use OC\Share\ShareFactory; +use OC\Share\Exception\InvalidShareException; +use OC\User\Manager; + +/** + * Controller for shares between two users + */ class User extends Common { + protected $userManager; + + /** + * The constructor + * @param string $itemType + * @param ShareFactory $shareFactory + * @param Manager $userManager + */ + public function __construct($itemType, ShareFactory $shareFactory, Manager $userManager) { + parent::__construct($itemType, $shareFactory); + $this->userManager = $userManager; + } + public function getId() { return 'user'; } @@ -31,31 +52,31 @@ public function isValidShare(Share $share) { $shareOwner = $share->getShareOwner(); $shareWith = $share->getShareWith(); if ($shareOwner === $shareWith) { - $message = 'the user '.$this->shareWith.' is the item owner'; - throw new \InvalidShareException($message); + 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 (!\OC_User::userExists($shareWith)) { - $message = 'the user '.$shareWith.' does not exist'; - throw new \Exception($message); + 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') { - $inGroup = array_intersect(\OC_Group::getUserGroups($shareOwner), \OC_Group::getUserGroups($shareWith)); + $inGroup = array_intersect(\OC_Group::getUserGroups($shareOwner), + \OC_Group::getUserGroups($shareWith) + ); if (empty($inGroup)) { - $message = 'the user '.$shareWith.' is not a member of any groups that '.$shareOwner.' is a member of'; - throw new \Exception($message); + 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 searchForShareWiths($pattern) { - return OC_User::getUsers(); - } - - // Hook Listener - public static function post_deleteUser($params) { - + public function searchForPotentialShareWiths($pattern, $limit, $offset) { + return $this->userManager->searchDisplayName($pattern, $limit, $offset); } } \ 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/utility.php b/lib/share/utility.php deleted file mode 100644 index 9e75a7d5d720..000000000000 --- a/lib/share/utility.php +++ /dev/null @@ -1,95 +0,0 @@ -. -*/ - -namespace OC\Share; - -public class Utility { - - /** - * Check if the Share API is enabled - * @return bool - * - * The Share API is enabled by default if not configured - * - */ - public function isEnabled() { - $configValue = \OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes'); - if ($configValue === 'yes') { - return true; - } else { - return false; - } - } - - /** - * Check if the files_sharing app is enabled - * @return bool - * - * Item types dependent on files will only work if the files_sharing app is enabled - * - */ - public function isFileSharingEnabled() { - return \OC_App::isEnabled('files_sharing'); - } - - /** - * Check if resharing is allowed - * @return bool - * - * Resharing is allowed by default if not configured - * - */ - public function isResharingAllowed() { - $configValue = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes'); - if ($configValue === 'yes') { - return true; - } else { - return false; - } - } - - /** - * Get the default expiration time - * @return int - * - * No expiration time is set by default - * - */ - public function getDefaultTime() { - return \OC_Appconfig::getValue('core', 'shareapi_expiration_time', 0); - } - - public static function getSupportedShareTypes($class) { - // TODO Fetch share type objects based on marker interfaces - $shareTypeIds = class_implements($class); - foreach ($shareTypeIds as $shareTypeId) { - $shareTypes[$shareTypdId] = new \$shareTypeId.'ShareType'; - } - } - - public static function getSupportedShareType($class, $shareTypeId) { - if (!isset(self::$shareTypes[$shareTypeId])) { - - } - return self::$shareTypes[$shareTypeId]; - } - -} \ No newline at end of file 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..f181ffb33864 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -1,413 +1,191 @@ . + * ownCloud - News + * + * @author Alessandro Copyright + * @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 { +namespace Test\Share; - protected $itemType; - protected $userBackend; - protected $user1; - protected $user2; - protected $groupBackend; - protected $group1; - protected $group2; - protected $resharing; +use OC\Share\Share; - 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'); - } +class ShareTest extends \PHPUnit_Framework_TestCase { - 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)); + $share->setPermissions(0); + $this->assertFalse($share->isReadable()); + } - 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 testIsUpdatable() { + $share = new Share(); + $share->setPermissions(\OCP\PERMISSION_UPDATE); + $this->assertTrue($share->isUpdatable()); - // 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(\OCP\PERMISSION_READ); + $this->assertFalse($share->isUpdatable()); } - 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 testIsDeletable() { + $share = new Share(); + $share->setPermissions(\OCP\PERMISSION_DELETE); + $this->assertTrue($share->isDeletable()); - // 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)); + $share->setPermissions(\OCP\PERMISSION_READ); + $this->assertFalse($share->isDeletable()); + } - // 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()); - } + public function testIsSharable() { + $share = new Share(); + $share->setPermissions(\OCP\PERMISSION_SHARE); + $this->assertTrue($share->isSharable()); - // 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()); - } + $share->setPermissions(\OCP\PERMISSION_READ); + $this->assertFalse($share->isSharable()); + } - // 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()); - } + 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()); + } - // 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 testRemoveParentId() { + $share = new Share(); + $share->setParentIds(array(1, 3)); + $share->removeParentId(3); + $this->assertEquals(array(1), $share->getParentIds()); + $this->assertContains('parentIds', $share->getUpdatedProperties()); + } - // Unshare - OC_User::setUserId($this->user1); - $this->assertTrue(OCP\Share::unshare('test', 'test.txt', OCP\Share::SHARE_TYPE_GROUP, $this->group1)); + 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 - 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 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); + } - // 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 testGetSetId() { + $id = 3; + $share = new Share(); + $share->setId($id); + $this->assertEquals($id, $share->getId()); + } - // 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 testCallShouldOnlyWorkForGetterSetter() { + $this->setExpectedException('\BadFunctionCallException'); + $share = new Share(); + $share->something(); + } - // 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 testGetterShouldFailIfPropertyNotDefined() { + $this->setExpectedException('\BadFunctionCallException'); + $share = new Share(); + $share->getTest(); + } - // 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 testSetterShouldFailIfPropertyNotDefined() { + $this->setExpectedException('\BadFunctionCallException'); + $share = new Share(); + $share->setTest(); + } - // 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->setId(3); + $this->assertContains('id', $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->setId(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/shares.php b/tests/lib/share/shares.php new file mode 100644 index 000000000000..0d53d2dffdd9 --- /dev/null +++ b/tests/lib/share/shares.php @@ -0,0 +1,542 @@ +. + */ + +namespace Test\Share; + +use OC\Share\Share; +use OC\Share\TimeMachine; + +class TestShares extends \OC\Share\Shares { + + private $isValidItem; + + public function getItemType() { + return 'test'; + } + + protected function isValidItem(Share $share) { + if ($this->isValidItem === false) { + throw new \OC\Share\Exception\InvalidItemException( + 'The item does not exist' + ); + } else { + return true; + } + } + + protected function generateItemTarget(Share $share) { + return 'Item Target'; + } + + public function setIsValidItem($isValidItem) { + $this->isValidItem = $isValidItem; + } + + public function pGetShareType($shareTypeId) { + return parent::getShareType($shareTypeId); + } + + public function pAreValidPermissions(Share $share) { + return parent::areValidPermissions($share); + } + + public function pIsValidExpirationTime(Share $share) { + return parent::isValidExpirationTime($share); + } + +} + +class Shares extends \PHPUnit_Framework_TestCase { + + protected $timeMachine; + protected $user; + protected $group; + protected $link; + protected $shares; + + 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->shares = new TestShares($this->timeMachine, + array($this->user, $this->group, $this->link) + ); + $this->shares->setIsValidItem(true); + } + + public function testShare() { + $this->shares->setIsValidItem(true); + + $mtgap = 'MTGap'; + $icewind = 'Icewind'; + $item = 1; + $share = new Share(); + $share->setShareTypeId('user'); + $share->setShareOwner($mtgap); + $share->setShareWith($icewind); + $share->setItemSource($item); + $share->setPermissions(31); + $share->resetUpdatedProperties(); + $sharedShare = clone $share; + $sharedShare->setShareTime(1370797580); + $sharedShare->setItemTarget('Item Target'); + $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->shares->share($share); + $this->assertEquals($sharedShare, $share); + } + + public function testShareWithInvalidItem() { + $this->shares->setIsValidItem(false); + + $share = new Share(); + $this->setExpectedException('\OC\Share\Exception\InvalidItemException', + 'The item does not exist' + ); + $this->shares->share($share); + } + + public function testShareAgain() { + $this->shares->setIsValidItem(true); + + $butonic = 'butonic'; + $bartv = 'bartv'; + $item = 2; + $share = new Share(); + $share->setShareTypeId('user'); + $share->setShareOwner($butonic); + $share->setShareWith($bartv); + $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->shares->share($share); + } + + public function testShareWithInvalidShare() { + $this->shares->setIsValidItem(true); + + $mtgap = 'MTGap'; + $icewind = 'Icewind'; + $item = 1; + $share = new Share(); + $share->setShareTypeId('user'); + $share->setShareOwner($mtgap); + $share->setShareWith($icewind); + $share->setItemSource($item); + $share->setPermissions(31); + $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->shares->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->shares->unshare($share); + } + + 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->shares->update($share); + } + + 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->shares->update($share); + } + + public function testUpdateWithNoChanges() { + $share = new Share(); + $share->setId(1); + $share->setShareTypeId('link'); + $share->resetUpdatedProperties(); + $this->link->expects($this->never()) + ->method('update'); + $this->shares->update($share); + } + + 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->shares->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->shares->getShares(array('itemSource' => $item)); + $this->assertCount(2, $shares); + $this->assertContains($share1, $shares); + $this->assertContains($share2, $shares); + + $share = $this->shares->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->shares->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->shares->getShares(array(), 3, 1); + $this->assertCount(3, $shares); + $this->assertContains($share2, $shares); + $this->assertContains($share3, $shares); + $this->assertContains($share4, $shares); + } + + public function testSearchForPotentialShareWiths() { + $userMap = array( + array('foo', null, null, array('foouser1', 'foouser2', 'foouser3')), + ); + $this->user->expects($this->once()) + ->method('searchForPotentialShareWiths') + ->will($this->returnValueMap($userMap)); + $groupMap = array( + array('foo', null, null, array('foogroup1', 'foogroup2')), + ); + $this->group->expects($this->once()) + ->method('searchForPotentialShareWiths') + ->will($this->returnValueMap($groupMap)); + $linkMap = array( + array('foo', null, null, array()), + ); + $this->link->expects($this->once()) + ->method('searchForPotentialShareWiths') + ->will($this->returnValueMap($linkMap)); + $shareWiths = $this->shares->searchForPotentialShareWiths('foo'); + $this->assertCount(5, $shareWiths); + $this->assertContains('foouser1', $shareWiths); + $this->assertContains('foouser2', $shareWiths); + $this->assertContains('foouser3', $shareWiths); + $this->assertContains('foogroup1', $shareWiths); + $this->assertContains('foogroup2', $shareWiths); + } + + public function testSearchForPotentialShareWithsWithLimitOffset() { + $userMap = array( + array('foo', 3, 1, array('foouser2', 'foouser3')), + ); + $this->user->expects($this->once()) + ->method('searchForPotentialShareWiths') + ->will($this->returnValueMap($userMap)); + $groupMap = array( + array('foo', 1, 0, array('foogroup1')), + ); + $this->group->expects($this->once()) + ->method('searchForPotentialShareWiths') + ->will($this->returnValueMap($groupMap)); + $this->link->expects($this->never()) + ->method('searchForPotentialShareWiths'); + $shareWiths = $this->shares->searchForPotentialShareWiths('foo', 3, 1); + $this->assertCount(3, $shareWiths); + $this->assertContains('foouser2', $shareWiths); + $this->assertContains('foouser3', $shareWiths); + $this->assertContains('foogroup1', $shareWiths); + } + + public function testGetShareType() { + $this->assertEquals($this->group, $this->shares->pGetShareType('group')); + } + + public function testGetShareTypeDoesNotExist() { + $this->setExpectedException('\OC\Share\Exception\ShareTypeDoesNotExistException', + 'No share type found matching id' + ); + $this->shares->pGetShareType('foo'); + } + + public function testIsExpired() { + // No expiration time + $share = new Share(); + $this->assertFalse($this->shares->isExpired($share)); + + // 1 second in the past + $share->setExpirationTime(1370797579); + $this->assertTrue($this->shares->isExpired($share)); + + // 1 second in the future + $share->setExpirationTime(1370797581); + $this->assertFalse($this->shares->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->shares->isExpired($share)); + + // 2 hours 1 second in the past + $share->setShareTime(1370790379); + $this->assertTrue($this->shares->isExpired($share)); + \OC_Appconfig::setValue('core', 'shareapi_expiration_time', $defaultTime); + } + + public function testAreValidPermissions() { + $share = new Share(); + $share->setPermissions(31); + $this->assertTrue($this->shares->pAreValidPermissions($share)); + } + + public function testAreValidPermissionsWithString() { + $share = new Share(); + $share->setPermissions('31'); + $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', + 'The permissions are not an integer' + ); + $this->shares->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->shares->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->shares->pAreValidPermissions($share); + } + + public function testIsValidExpirationTime() { + // No expiration time + $share = new Share(); + $this->assertTrue($this->shares->pIsValidExpirationTime($share)); + + // 1 hour in the future + $share->setExpirationTime(1370801180); + $this->assertTrue($this->shares->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->shares->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->shares->pIsValidExpirationTime($share); + } + +} \ No newline at end of file diff --git a/tests/lib/share/sharesmanager.php b/tests/lib/share/sharesmanager.php new file mode 100644 index 000000000000..a2f81cfdb5d7 --- /dev/null +++ b/tests/lib/share/sharesmanager.php @@ -0,0 +1,1918 @@ +. + */ + +namespace Test\Share; + +use OC\Share\Share; + +class TestSharesManager extends \OC\Share\SharesManager { + + public function pGetSharesBackend($itemType) { + return parent::getSharesBackend($itemType); + } + + public function pAreValidPermissionsForParents(Share $share) { + return parent::areValidPermissionsForParents($share); + } + + public function pIsValidExpirationTimeForParents(Share $share) { + return parent::isValidExpirationTimeForParents($share); + } + +} + +class SharesManager extends \PHPUnit_Framework_TestCase { + + private $shares; + private $collectionShares; + private $sharesManager; + 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->shares = $this->getMockBuilder('\OC\Share\Shares') + ->disableOriginalConstructor() + ->setMethods(get_class_methods('\OC\Share\Shares')) + ->getMockForAbstractClass(); + $this->shares->expects($this->any()) + ->method('getItemType') + ->will($this->returnValue('test')); + $this->shares->expects($this->any()) + ->method('isValidItem') + ->will($this->returnValue(true)); + $this->areCollectionsEnabled = false; + $this->collectionShares = $this->getMockBuilder('\OC\Share\CollectionShares') + ->disableOriginalConstructor() + ->setMethods(get_class_methods('\OC\Share\CollectionShares')) + ->getMockForAbstractClass(); + $this->collectionShares->expects($this->any()) + ->method('getItemType') + ->will($this->returnValue('testCollection')); + $this->collectionShares->expects($this->any()) + ->method('isValidItem') + ->will($this->returnValue(true)); + $this->collectionShares->expects($this->any()) + ->method('getChildrenItemTypes') + ->will($this->returnCallback(array($this, 'getChildrenItemTypesMock'))); + $this->sharesManager = new TestSharesManager(); + $this->sharesManager->registerSharesBackend($this->shares); + $this->sharesManager->registerSharesBackend($this->collectionShares); + } + + public function getChildrenItemTypesMock() { + if ($this->areCollectionsEnabled) { + return array('test'); + } else { + return array(); + } + } + + 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, '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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->once()) + ->method('share') + ->with($this->equalTo($share)) + ->will($this->returnValue($share)); + $share = $this->sharesManager->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, 'itemSource' => $item), null, null, + array($parent) + ), + ); + $this->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->never()) + ->method('share'); + $this->setExpectedException('\OC\Share\Exception\InvalidShareException', + 'The admin has disabled resharing' + ); + $this->sharesManager->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, 'itemSource' => $item), null, null, + array($parent) + ), + ); + $this->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->never()) + ->method('share'); + $this->setExpectedException('\OC\Share\Exception\InvalidShareException', + 'The parent shares don\'t allow resharing' + ); + $this->sharesManager->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, 'itemSource' => $item), null, null, + array($parent) + ), + ); + $this->shares->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->sharesManager->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, 'itemSource' => $item), null, null, + array($parent) + ), + ); + $this->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->setExpectedException('\OC\Share\Exception\InvalidShareException', + 'The parent share has the same share with' + ); + $this->sharesManager->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, '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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->once()) + ->method('share') + ->with($this->equalTo($share)) + ->will($this->returnValue($share)); + $this->shares->expects($this->never()) + ->method('update'); + $share->resetUpdatedProperties(); + $share = $this->sharesManager->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, '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, 'itemSource' => $item), null, null, + array($duplicate, $share) + ), + array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare)), + ); + $this->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->once()) + ->method('share') + ->with($this->equalTo($share)) + ->will($this->returnValue($share)); + $this->shares->expects($this->once()) + ->method('update') + ->with($this->equalTo($reshare)); + $share->resetUpdatedProperties(); + $share = $this->sharesManager->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'; + $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); + $parent = new Share(); + $parent->setId(1); + $parent->setShareTypeId('user'); + $parent->setShareOwner($jancborchardt); + $parent->setShareWith($danimo); + $parent->setItemOwner($jancborchardt); + $parent->setItemType('testCollection'); + $parent->setItemSource($collectionItem); + $parent->setPermissions(31); + $sharesMap = array( + array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, array()), + array(array('id' => 1), 1, null, array()), + array(array('shareOwner' => $danimo, 'itemSource' => $item), null, null, + array($share) + ), + ); + $childMap = array( + array($danimo, $item, array($parent)), + ); + $collectionMap = array( + array(array('id' => 1), 1, null, array($parent)), + ); + $this->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($sharesMap)); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('searchForChildren') + ->will($this->returnValueMap($childMap)); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($collectionMap)); + $this->shares->expects($this->once()) + ->method('share') + ->with($this->equalTo($share)) + ->will($this->returnValue($share)); + $share = $this->sharesManager->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, '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, 'itemSource' => $collectionItem), null, null, + array($duplicate, $share) + ), + array(array('shareWith' => $dragotin, '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, 'itemSource' => $item), null, null, + array() + ), + array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare1)), + ); + $childMap = array( + array($anybodyelse, $item, array($duplicate, $share)), + ); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($collectionMap)); + $this->collectionShares->expects($this->once()) + ->method('share') + ->with($this->equalTo($share)) + ->will($this->returnValue($share)); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('searchForChildren') + ->will($this->returnValueMap($childMap)); + $this->collectionShares->expects($this->once()) + ->method('update') + ->with($this->equalTo($reshare2)); + $this->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($sharesMap)); + $this->shares->expects($this->once()) + ->method('update') + ->with($this->equalTo($reshare1)); + $share = $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(3)) + ->method('unshare'); + $this->shares->expects($this->never()) + ->method('update'); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(2)) + ->method('update'); + $this->shares->expects($this->once()) + ->method('unshare') + ->with($this->equalTo($parent1)); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(2)) + ->method('update'); + $this->shares->expects($this->once()) + ->method('unshare') + ->with($this->equalTo($parent1)); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($sharesMap)); + $this->shares->expects($this->once()) + ->method('update'); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($collectionMap)); + $this->collectionShares->expects($this->once()) + ->method('update'); + $this->collectionShares->expects($this->exactly(2)) + ->method('unshare'); + $this->sharesManager->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->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', + 'The share does not exist for update' + ); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(3)) + ->method('update'); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->once()) + ->method('update'); + $this->shares->expects($this->exactly(3)) + ->method('unshare'); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(3)) + ->method('update'); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(4)) + ->method('update'); + $this->sharesManager->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, '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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->exactly(3)) + ->method('update'); + $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->once()) + ->method('update'); + $this->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->at(2)) + ->method('isExpired') + ->will($this->returnValue(true)); + $this->shares->expects($this->once()) + ->method('unshare') + ->with($this->equalTo($share2)); + $shares = $this->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->at(2)) + ->method('isExpired') + ->will($this->returnValue(true)); + $this->shares->expects($this->once()) + ->method('unshare') + ->with($this->equalTo($share2)); + $shares = $this->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->at(1)) + ->method('isExpired') + ->will($this->returnValue(true)); + $this->shares->expects($this->once()) + ->method('unshare') + ->with($this->equalTo($share2)); + $shares = $this->sharesManager->getShares('test', array(), 3, 1); + $this->assertCount(3, $shares); + $this->assertContains($share3, $shares); + $this->assertContains($share4, $shares); + $this->assertContains($share5, $shares); + } + + public function testSearchForPotentialShareWiths() { + $map = array( + array('foo', 3, 1, array('foouser2', 'foouser3', 'foogroup1')), + ); + $this->shares->expects($this->once()) + ->method('searchForPotentialShareWiths') + ->will($this->returnValueMap($map)); + $shareWiths = $this->sharesManager->searchForPotentialShareWiths('test', 'foo', 3, 1); + $this->assertCount(3, $shareWiths); + $this->assertContains('foouser2', $shareWiths); + $this->assertContains('foouser3', $shareWiths); + $this->assertContains('foogroup1', $shareWiths); + } + + 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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shares->expects($this->any()) + ->method('unshare'); + $this->sharesManager->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->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $reshares = $this->sharesManager->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->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->assertEmpty($this->sharesManager->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->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($shareMap)); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($collectionMap)); + $reshares = $this->sharesManager->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->shares->expects($this->exactly(3)) + ->method('getShares') + ->will($this->returnValueMap($map)); + $parents = $this->sharesManager->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->shares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($sharesMap)); + $this->collectionShares->expects($this->atLeastOnce()) + ->method('getShares') + ->will($this->returnValueMap($collectionMap)); + $parents = $this->sharesManager->getParents($share); + $this->assertCount(2, $parents); + $this->assertContains($parent1, $parents); + $this->assertContains($parent2, $parents); + } + + public function testGetParentsWithNoParents() { + $share = new Share(); + $this->shares->expects($this->never()) + ->method('getShares'); + $this->collectionShares->expects($this->never()) + ->method('getShares'); + $this->assertEmpty($this->sharesManager->getParents($share)); + } + + public function testGetParentsWithNotExistingParent() { + $share = new Share(); + $share->setItemType('test'); + $share->addParentId(1); + $map = array( + array(array('id' => 1), 1, null, array()), + ); + $this->shares->expects($this->once()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', + 'The parent share does not exist' + ); + $this->sharesManager->getParents($share); + } + + public function testGetSharesBackend() { + $this->setExpectedException('\OC\Share\Exception\SharesBackendDoesNotExistException', + 'A share backend does not exist for the item type' + ); + $this->sharesManager->pGetSharesBackend('foo'); + } + + 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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->assertTrue($this->sharesManager->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->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', + 'The permissions exceeds the parent shares\' permissions' + ); + $this->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->assertTrue($this->sharesManager->pAreValidPermissionsForParents($share)); + + // Share and parent remove Create permission + $share->setPermissions(27); + $parent2->setPermissions(25); + $this->assertTrue($this->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', + 'The permissions exceeds the parent shares\' permissions' + ); + $this->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + + // Share expires 1 second before parent + $share->setExpirationTime(1370884024); + $parent->setExpirationTime(1370884025); + $this->assertTrue($this->sharesManager->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->shares->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->sharesManager->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->shares->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->sharesManager->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->shares->expects($this->any()) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + + // 1 parent expires, the other parent and share have no expiration time + $parent1->setExpirationTime(1370884025); + $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + + // Share expires 1 second after 1 parent, the other parent has no expiration time + $share->setExpirationTime(1370884026); + $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + + // 1 parent expires 1 second before share, the other parent expires 1 second after share + $parent2->setExpirationTime(1370884027); + $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + + // Share expires 1 second before both parents + $share->setExpirationTime(1370884024); + $parent2->setExpirationTime(1370884025); + $this->assertTrue($this->sharesManager->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->shares->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->sharesManager->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->shares->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->sharesManager->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..1422af3fe3b4 --- /dev/null +++ b/tests/lib/share/sharetype/group.php @@ -0,0 +1,269 @@ +. + */ + +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 $userManager; + private $user1; + private $user2; + private $user3; + private $group1; + private $group2; + + protected function setUp() { + $this->userManager = $this->getMockBuilder('\OC\User\Manager') + ->disableOriginalConstructor() + ->getMock(); + $this->instance = new TestGroup('test', new ShareFactory(), $this->userManager); + } + + protected function getTestShare() { + $share = new Share(); + $share->setShareTypeId($this->instance->getId()); + $share->setShareOwner('MTGap'); + $share->setShareWith('friends'); + $share->setItemType('test'); + $share->setItemOwner('MTGap'); + $share->setItemSource('23'); + $share->setItemTarget('secrets'); + $share->setPermissions(31); + return $share; + } + + protected function setupTestShares() { + $this->user1 = 'MTGap'; + $this->user2 = 'karlitschek'; + $this->user3 = 'Icewind'; + $this->group1 = 'designers'; + $this->group2 = 'friends'; + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup($this->group1); + \OC_Group::createGroup($this->group2); + \OC_Group::addToGroup($this->user1, $this->group1); + \OC_Group::addToGroup($this->user1, $this->group2); + \OC_Group::addToGroup($this->user2, $this->group1); + \OC_Group::addToGroup($this->user2, $this->group2); + \OC_Group::addToGroup($this->user3, $this->group1); + + $this->share1 = $this->getTestShare(); + $this->share1->setShareOwner($this->user1); + $this->share1->setShareWith($this->group1); + $this->share1 = $this->instance->share($this->share1); + + $this->share2 = $this->getTestShare(); + $this->share2->setShareOwner($this->user1); + $this->share2->setShareWith($this->group2); + $this->share2 = $this->instance->share($this->share2); + + $this->share3 = $this->getTestShare(); + $this->share3->setShareOwner($this->user3); + $this->share3->setShareWith($this->group1); + $this->share3 = $this->instance->share($this->share3); + + $this->share4 = $this->getTestShare(); + $this->share4->setShareOwner($this->user2); + $this->share4->setShareWith($this->group2); + $this->share4->addParentId($this->share3->getId()); + $this->share4 = $this->instance->share($this->share4); + } + + public function testIsValidShare() { + $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)); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup($designers); + \OC_Group::addToGroup($jancborchardt, $designers); + $this->assertTrue($this->instance->isValidShare($share)); + } + + 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)); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup($designers); + $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)); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + $this->setExpectedException('\OC\Share\Exception\InvalidShareException', + 'The group shared with does not exist' + ); + $this->instance->isValidShare($share); + } + + public function testIsValidShareWithShareOwnerNotInGroup() { + $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)); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup($designers); + $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 testShareWithItemTargets() { + $itemTargets = array( + 'Group Item Target', + 'users' => array( + 'tpn' => 'tpn\'s Target', + 'bartv' => 'bartv\'s Target', + ), + ); + $share = $this->getTestShare(); + $share->setItemTarget($itemTargets); + $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 testSetItemTarget() { + $share = $this->getTestShare(); + $share->setItemTarget('Group Item Target'); + $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())); + } + + public function testGetSharesWithFilter() { + $this->setupTestShares(); + $filter = array( + 'shareWith' => $this->user3, + ); + $shares = $this->instance->getShares($filter, null, null); + $this->assertCount(1, $shares); + $this->assertContains($this->share1, $shares, '', false, false); + } + + public function testSearchForPotentialShareWiths() { + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup('foogroup1'); + \OC_Group::createGroup('foogroup2'); + \OC_Group::createGroup('foogroup3'); + $shareWiths = $this->instance->searchForPotentialShareWiths('foo', null, null); + $this->assertCount(3, $shareWiths); + $this->assertContains('foogroup1', $shareWiths); + $this->assertContains('foogroup2', $shareWiths); + $this->assertContains('foogroup3', $shareWiths); + } + + public function testSearchForPotentialShareWithsWithLimitOffset() { + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup('foogroup1'); + \OC_Group::createGroup('foogroup2'); + \OC_Group::createGroup('foogroup3'); + $shareWiths = $this->instance->searchForPotentialShareWiths('foo', 3, 1); + $this->assertCount(2, $shareWiths); + $this->assertContains('foogroup2', $shareWiths); + $this->assertContains('foogroup3', $shareWiths); + } + +} \ 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..f3b0c5278fdf --- /dev/null +++ b/tests/lib/share/sharetype/link.php @@ -0,0 +1,203 @@ +. + */ + +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 $userManager; + private $hasher; + + protected function setUp() { + $this->userManager = $this->getMockBuilder('\OC\User\Manager') + ->disableOriginalConstructor() + ->getMock(); + $this->hasher = $this->getMockBuilder('\PasswordHash') + ->disableOriginalConstructor() + ->getMock(); + $this->instance = new TestLink('test', new ShareFactory(), $this->userManager, + $this->hasher + ); + } + + protected function getTestShare() { + $share = new Share(); + $share->setShareTypeId($this->instance->getId()); + $share->setShareOwner('MTGap'); + $share->setShareWith(null); + $share->setItemType('test'); + $share->setItemOwner('MTGap'); + $share->setItemSource('23'); + $share->setItemTarget('secrets'); + $share->setPermissions(31); + return $share; + } + + protected function setupTestShares() { + $this->user1 = 'MTGap'; + $this->user2 = 'karlitschek'; + $this->user3 = 'Icewind'; + $this->share1 = $this->getTestShare(); + $this->share1->setShareOwner($this->user1); + $this->share1 = $this->instance->share($this->share1); + + $this->share2 = $this->getTestShare(); + $this->share2->setShareOwner($this->user1); + $this->share2 = $this->instance->share($this->share2); + + $this->share3 = $this->getTestShare(); + $this->share3->setShareOwner($this->user3); + $this->share3 = $this->instance->share($this->share3); + + $this->share4 = $this->getTestShare(); + $this->share4->setShareOwner($this->user2); + $this->share4->addParentId($this->share3->getId()); + $this->share4 = $this->instance->share($this->share4); + } + + 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(); + $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(); + $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->user1, + ); + $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('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..dfa1c8cd2c01 --- /dev/null +++ b/tests/lib/share/sharetype/sharetype.php @@ -0,0 +1,148 @@ +. + */ + +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 + * @return Share + */ + abstract protected function getTestShare(); + + /** + * Setup four shares with fake data assigned to their respective class property + * The fourth share has the third share as a parent (even if it doesn't make sense) + */ + abstract protected function setupTestShares(); + + protected function tearDown() { + $this->instance->clear(); + } + + public function testShare() { + $share = $this->getTestShare(); + $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 testShareWithParents() { + $share = $this->getTestShare(); + $share->setParentIds(array(1, 3)); + $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 testUnshare() { + $share = $this->getTestShare(); + $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(); + $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(); + $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(); + $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(); + $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 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..3c4218aad120 --- /dev/null +++ b/tests/lib/share/sharetype/user.php @@ -0,0 +1,253 @@ +. + */ + +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 $userManager; + private $user1; + private $user2; + private $user3; + + protected function setUp() { + $this->userManager = $this->getMockBuilder('\OC\User\Manager') + ->disableOriginalConstructor() + ->getMock(); + $this->instance = new TestUser('test', new ShareFactory(), $this->userManager); + } + + protected function getTestShare() { + $share = new Share(); + $share->setShareTypeId($this->instance->getId()); + $share->setShareOwner('MTGap'); + $share->setShareWith('karlitschek'); + $share->setItemType('test'); + $share->setItemOwner('MTGap'); + $share->setItemSource('23'); + $share->setItemTarget('secrets'); + $share->setPermissions(31); + return $share; + } + + protected function setupTestShares() { + $this->user1 = 'MTGap'; + $this->user2 = 'karlitschek'; + $this->user3 = 'Icewind'; + $this->share1 = $this->getTestShare(); + $this->share1->setShareOwner($this->user1); + $this->share1->setShareWith($this->user2); + $this->share1 = $this->instance->share($this->share1); + + $this->share2 = $this->getTestShare(); + $this->share2->setShareOwner($this->user1); + $this->share2->setShareWith($this->user3); + $this->share2 = $this->instance->share($this->share2); + + $this->share3 = $this->getTestShare(); + $this->share3->setShareOwner($this->user3); + $this->share3->setShareWith($this->user2); + $this->share3 = $this->instance->share($this->share3); + + $this->share4 = $this->getTestShare(); + $this->share4->setShareOwner($this->user2); + $this->share4->setShareWith($this->user1); + $this->share4->addParentId($this->share3->getId()); + $this->share4 = $this->instance->share($this->share4); + } + + 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 testIsValidShareWithGroupOnlyPolicy() { + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); + \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only'); + + $jancborchardt = 'jancborchardt'; + $raydiation = 'Raydiation'; + $devs = 'devs'; + $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)); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup($devs); + \OC_Group::addToGroup($jancborchardt, $devs); + \OC_Group::addToGroup($raydiation, $devs); + $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'; + $devs = 'devs'; + $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)); + \OC_Group::clearBackends(); + \OC_Group::useBackend(new \OC_Group_Dummy); + \OC_Group::createGroup($devs); + \OC_Group::addToGroup($raydiation, $devs); + $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->user2, + ); + $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() { + $map = array( + array('foo', null, null, array('foouser1', 'foouser2', 'foouser3')), + ); + $this->userManager->expects($this->once()) + ->method('searchDisplayName') + ->will($this->returnValueMap($map)); + $shareWiths = $this->instance->searchForPotentialShareWiths('foo', null, null); + $this->assertCount(3, $shareWiths); + $this->assertContains('foouser1', $shareWiths); + $this->assertContains('foouser2', $shareWiths); + $this->assertContains('foouser3', $shareWiths); + } + + public function testSearchForPotentialShareWithsWithLimitOffset() { + $map = array( + array('foo', 3, 1, array('foouser2', 'foouser3')), + ); + $this->userManager->expects($this->once()) + ->method('searchDisplayName') + ->will($this->returnValueMap($map)); + $shareWiths = $this->instance->searchForPotentialShareWiths('foo', 3, 1); + $this->assertCount(2, $shareWiths); + $this->assertContains('foouser2', $shareWiths); + $this->assertContains('foouser3', $shareWiths); + } + +} \ No newline at end of file From 11f81b9e668db94e3dce1231ea370d03b2643317 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 8 Jul 2013 12:16:10 -0400 Subject: [PATCH 04/85] Add check for valid permissions and expiration time for update --- lib/share/shares.php | 8 +++++++- tests/lib/share/shares.php | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/share/shares.php b/lib/share/shares.php index 53f1b6642338..140420f6e8ba 100644 --- a/lib/share/shares.php +++ b/lib/share/shares.php @@ -134,9 +134,15 @@ public function unshare(Share $share) { * @param Share $share */ public function update(Share $share) { + $properties = $share->getUpdatedProperties(); + if (isset($properties['permissions'])) { + $this->areValidPermissions($share); + } + if (isset($properties['expirationTime'])) { + $this->isValidExpirationTime($share); + } $shareType = $this->getShareType($share->getShareTypeId()); $this->emit(get_class($this), 'preUpdate', array($share)); - $properties = $share->getUpdatedProperties(); foreach ($properties as $property => $updated) { $setter = 'set'.ucfirst($property); if (method_exists($shareType, $setter)) { diff --git a/tests/lib/share/shares.php b/tests/lib/share/shares.php index 0d53d2dffdd9..a7f1bd0bc9bd 100644 --- a/tests/lib/share/shares.php +++ b/tests/lib/share/shares.php @@ -267,6 +267,29 @@ public function testUpdateWithNoChanges() { $this->shares->update($share); } + 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->shares->update($share); + } + + 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->shares->update($share); + } + public function testGetShares() { $share1 = new Share(); $share1->setId(1); From 5cbf16f3e8e6b37e3fdfe27528915666bf1e31b7 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 8 Jul 2013 12:19:03 -0400 Subject: [PATCH 05/85] Correct Alessandro's name in the header --- tests/lib/share/share.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index f181ffb33864..ca92674963ec 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -3,7 +3,7 @@ /** * ownCloud - News * - * @author Alessandro Copyright + * @author Alessandro Cosentino * @author Bernhard Posselt * @author Michael Gapczynski * @copyright 2012 Alessandro Cosentino cosenal@gmail.com From 6c03722c23d04c06c1c855d60a67f7798050c7f6 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 8 Jul 2013 12:22:02 -0400 Subject: [PATCH 06/85] Return instead of break 2 --- lib/share/shares.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/share/shares.php b/lib/share/shares.php index 140420f6e8ba..632f5c40f920 100644 --- a/lib/share/shares.php +++ b/lib/share/shares.php @@ -178,7 +178,7 @@ public function getShares($filter = array(), $limit = null, $offset = null) { if (isset($limit)) { $limit--; if ($limit === 0) { - break 2; + return $shares; } } if (isset($offset) && $offset > 0) { @@ -205,7 +205,7 @@ public function searchForPotentialShareWiths($pattern, $limit = null, $offset = if (isset($limit)) { $limit--; if ($limit === 0) { - break 2; + return $shareWiths; } } if (isset($offset) && $offset > 0) { From b747f40ff4e69b2a3d3b852c058c0d0148d306d6 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 8 Jul 2013 17:50:03 -0400 Subject: [PATCH 07/85] Fix database xml --- db_structure.xml | 4 +++- lib/util.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/db_structure.xml b/db_structure.xml index 15894c204e76..3c4d29b33dd2 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -857,7 +857,9 @@
- *dbprefix*shares + + + *dbprefix*shares diff --git a/lib/util.php b/lib/util.php index 4bc02daf36e9..d1dfdb51afeb 100755 --- a/lib/util.php +++ b/lib/util.php @@ -80,7 +80,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, 06); } /** From 2863824662592670d391bd5ebfad0a054c4ef0b5 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 8 Jul 2013 18:06:38 -0400 Subject: [PATCH 08/85] Fix database tests --- db_structure.xml | 2 +- tests/lib/share/sharetype/group.php | 1 + tests/lib/share/sharetype/link.php | 1 + tests/lib/share/sharetype/user.php | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/db_structure.xml b/db_structure.xml index 3c4d29b33dd2..e64af8e143fb 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -1016,7 +1016,7 @@ password text - true + false 250 diff --git a/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php index 1422af3fe3b4..52200cfb5ddb 100644 --- a/tests/lib/share/sharetype/group.php +++ b/tests/lib/share/sharetype/group.php @@ -58,6 +58,7 @@ protected function getTestShare() { $share->setItemSource('23'); $share->setItemTarget('secrets'); $share->setPermissions(31); + $share->setShareTime(1370797580); return $share; } diff --git a/tests/lib/share/sharetype/link.php b/tests/lib/share/sharetype/link.php index f3b0c5278fdf..74286b9ae1af 100644 --- a/tests/lib/share/sharetype/link.php +++ b/tests/lib/share/sharetype/link.php @@ -59,6 +59,7 @@ protected function getTestShare() { $share->setItemSource('23'); $share->setItemTarget('secrets'); $share->setPermissions(31); + $share->setShareTime(1370797580); return $share; } diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php index 3c4218aad120..b7912085fd19 100644 --- a/tests/lib/share/sharetype/user.php +++ b/tests/lib/share/sharetype/user.php @@ -56,6 +56,7 @@ protected function getTestShare() { $share->setItemSource('23'); $share->setItemTarget('secrets'); $share->setPermissions(31); + $share->setShareTime(1370797580); return $share; } From 28713c65378375402fc517b4be5d61b17e472aa4 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 8 Jul 2013 20:02:07 -0400 Subject: [PATCH 09/85] Change delete query to try to work with other databases --- lib/share/sharetype/common.php | 2 +- lib/share/sharetype/group.php | 2 +- lib/share/sharetype/link.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/share/sharetype/common.php b/lib/share/sharetype/common.php index c90b8da2b14d..c81370b8afe9 100644 --- a/lib/share/sharetype/common.php +++ b/lib/share/sharetype/common.php @@ -174,7 +174,7 @@ public function getShares(array $filter, $limit, $offset) { public function clear() { $sql = 'DELETE FROM '.$this->table.' WHERE `share_type_id` = ?'; \OC_DB::executeAudited($sql, array($this->getId())); - $sql = 'DELETE '.$this->parentsTable.' FROM '.$this->parentsTable.' '. + $sql = 'DELETE FROM '.$this->parentsTable.' USING '.$this->parentsTable.' '. 'LEFT JOIN '.$this->table.' ON '.$this->parentsTable.'.`id` = '.$this->table.'.`id` '. 'WHERE '.$this->table.'.`id` IS NULL'; \OC_DB::executeAudited($sql); diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index a129f7e90372..7981886ae8d5 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -212,7 +212,7 @@ public function getShares(array $filter, $limit, $offset) { public function clear() { parent::clear(); - $sql = 'DELETE '.$this->groupsTable.' FROM '.$this->groupsTable.' '. + $sql = 'DELETE FROM '.$this->groupsTable.' USING '.$this->groupsTable.' '. 'LEFT JOIN '.$this->table.' ON '.$this->groupsTable.'.`id` = '.$this->table.'.`id` '. 'WHERE '.$this->table.'.`id` IS NULL'; \OC_DB::executeAudited($sql); diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index 975b03506738..3276e3190cca 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -159,7 +159,7 @@ public function getShares(array $filter, $limit, $offset) { public function clear() { parent::clear(); - $sql = 'DELETE '.$this->linksTable.' FROM '.$this->linksTable.' '. + $sql = 'DELETE FROM '.$this->linksTable.' USING '.$this->linksTable.' '. 'LEFT JOIN '.$this->table.' ON '.$this->linksTable.'.`id` = '.$this->table.'.`id` '. 'WHERE '.$this->table.'.`id` IS NULL'; \OC_DB::executeAudited($sql); From b7bcf3f1b817a1f22691a7cfa30f6b50cf414fa0 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 9 Jul 2013 11:35:13 -0400 Subject: [PATCH 10/85] Rename classes to avoid confusion --- lib/share/collectionshares.php | 6 +- .../sharesbackenddoesnotexistexception.php | 2 +- lib/share/shares.php | 4 +- lib/share/sharesmanager.php | 94 +++--- tests/lib/share/shares.php | 82 ++--- tests/lib/share/sharesmanager.php | 310 +++++++++--------- 6 files changed, 249 insertions(+), 249 deletions(-) diff --git a/lib/share/collectionshares.php b/lib/share/collectionshares.php index e9f3c3777e7c..c0e1109796ec 100644 --- a/lib/share/collectionshares.php +++ b/lib/share/collectionshares.php @@ -22,11 +22,11 @@ namespace OC\Share; use OC\Share\Share; -use OC\Share\Shares; +use OC\Share\ShareBackend; use OC\Share\TimeMachine; /** - * Backend class that apps extend and register with the SharesManager to share content + * Backend class that apps extend and register with the ShareManager to share content * This class should be used if the app has content that can have children that are also shared * using a different backend class e.g. folders * @@ -40,7 +40,7 @@ * * @version 2.0.0 BETA */ -abstract class CollectionShares extends Shares { +abstract class CollectionShareBackend extends ShareBackend { /** * The constructor diff --git a/lib/share/exception/sharesbackenddoesnotexistexception.php b/lib/share/exception/sharesbackenddoesnotexistexception.php index e4e783c17a90..098b7af9e211 100644 --- a/lib/share/exception/sharesbackenddoesnotexistexception.php +++ b/lib/share/exception/sharesbackenddoesnotexistexception.php @@ -21,7 +21,7 @@ namespace OC\Share\Exception; -class SharesBackendDoesNotExistException extends \Exception { +class ShareBackendDoesNotExistException extends \Exception { public function __construct($message) { parent::__construct($message); diff --git a/lib/share/shares.php b/lib/share/shares.php index 632f5c40f920..cbe4889ca6d4 100644 --- a/lib/share/shares.php +++ b/lib/share/shares.php @@ -30,7 +30,7 @@ use OC\Share\Exception\InvalidExpirationTimeException; /** - * Backend class that apps extend and register with the SharesManager to share content + * Backend class that apps extend and register with the ShareManager to share content * * Hooks available in class name scope * - preShare(Share $share) @@ -42,7 +42,7 @@ * * @version 2.0.0 BETA */ -abstract class Shares extends BasicEmitter { +abstract class ShareBackend extends BasicEmitter { protected $timeMachine; protected $shareTypes; diff --git a/lib/share/sharesmanager.php b/lib/share/sharesmanager.php index 0e4c4f4729e8..76539c586165 100644 --- a/lib/share/sharesmanager.php +++ b/lib/share/sharesmanager.php @@ -22,36 +22,36 @@ namespace OC\Share; use OC\Share\Share; -use OC\Share\Shares; -use OC\Share\CollectionShares; +use OC\Share\ShareBackend; +use OC\Share\CollectionShareBackend; use OC\Share\Exception\InvalidShareException; use OC\Share\Exception\ShareDoesNotExistException; -use OC\Share\Exception\SharesBackendDoesNotExistException; +use OC\Share\Exception\ShareBackendDoesNotExistException; use OC\Share\Exception\InvalidPermissionsException; use OC\Share\Exception\InvalidExpirationTimeException; /** * This is the gateway for sharing content between users in ownCloud, aka Share API - * Apps must create a shares backend class that extends OC\Share\Shares and register it here + * Apps must create a share backend class that extends OC\Share\ShareBackend and register it here * - * The SharesManager's primary purpose is to ensure consistency between shares and their reshares + * The ShareManager's primary purpose is to ensure consistency between shares and their reshares * * @version 2.0.0 BETA */ -class SharesManager { +class ShareManager { - protected $sharesBackends; + protected $shareBackends; /** - * Register a shares backend - * @param Shares $shares + * Register a share backend + * @param ShareBackend $shareBackend */ - public function registerSharesBackend(Shares $shares) { - $this->sharesBackends[$shares->getItemType()] = $shares; + public function registerShareBackend(ShareBackend $shareBackend) { + $this->shareBackends[$shareBackend->getItemType()] = $shareBackend; } /** - * Share a share in the shares backend + * Share a share in the share backend * @param Share $share * @throws InvalidItemException * @throws InvalidShareException @@ -60,7 +60,7 @@ public function registerSharesBackend(Shares $shares) { * @return bool */ public function share(Share $share) { - $backend = $this->getSharesBackend($share->getItemType()); + $shareBackend = $this->getShareBackend($share->getItemType()); $parents = $this->searchForParents($share); // See if the share is a reshare if (!empty($parents)) { @@ -97,7 +97,7 @@ public function share(Share $share) { } else { $share->setItemOwner($share->getShareOwner()); } - $share = $backend->share($share); + $share = $shareBackend->share($share); if ($share !== false && $share->isSharable()) { $id = $share->getId(); // Add this share to existing reshares' parent ids @@ -111,22 +111,22 @@ public function share(Share $share) { } /** - * Unshare a share in the shares backend + * Unshare a share in the share backend * @param Share $share */ public function unshare(Share $share) { - $backend = $this->getSharesBackend($share->getItemType()); + $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); } - $backend->unshare($share); + $shareBackend->unshare($share); } /** - * Update a share's properties in the shares backend + * Update a share's properties in the share backend * @param Share $share * @throws ShareDoesNotExistException * @throws InvalidPermissionsException @@ -155,8 +155,8 @@ public function update(Share $share) { throw new ShareDoesNotExistException('The share does not exist for update'); } else { $oldShare = reset($result); - $backend = $this->getSharesBackend($itemType); - $backend->update($share); + $shareBackend = $this->getShareBackend($itemType); + $shareBackend->update($share); if (isset($properties['permissions']) || isset($properties['expirationTime'])) { $this->updateReshares($share, $oldShare); } @@ -164,7 +164,7 @@ public function update(Share $share) { } /** - * Get the shares with the specified parameters in the shares backend + * 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) @@ -173,11 +173,11 @@ public function update(Share $share) { */ public function getShares($itemType, $filter = array(), $limit = null, $offset = null) { $shares = array(); - $backend = $this->getSharesBackend($itemType); - $results = $backend->getShares($filter, $limit, $offset); + $shareBackend = $this->getShareBackend($itemType); + $results = $shareBackend->getShares($filter, $limit, $offset); $expired = 0; foreach ($results as $share) { - if ($backend->isExpired($share)) { + if ($shareBackend->isExpired($share)) { $this->unshare($share); $expired++; } else { @@ -199,7 +199,7 @@ public function getShares($itemType, $filter = array(), $limit = null, $offset = } /** - * Search for potential people to share with based on the given pattern in the shares backend + * Search for potential people to share with based on the given pattern in the share backend * @param string $itemType * @param string $pattern * @param int $limit (optional) @@ -209,8 +209,8 @@ public function getShares($itemType, $filter = array(), $limit = null, $offset = public function searchForPotentialShareWiths($itemType, $pattern, $limit = null, $offset = null ) { - $backend = $this->getSharesBackend($itemType); - return $backend->searchForPotentialShareWiths($pattern, $limit, $offset); + $shareBackend = $this->getShareBackend($itemType); + return $shareBackend->searchForPotentialShareWiths($pattern, $limit, $offset); } /** @@ -246,10 +246,10 @@ public function getReshares(Share $share) { 'parentId' => $share->getId(), ); $reshares = $this->getShares($itemType, $filter); - $backend = $this->getSharesBackend($itemType); - if ($backend instanceof CollectionShares) { + $shareBackend = $this->getShareBackend($itemType); + if ($shareBackend instanceof CollectionShareBackend) { // Find reshares in children item types - foreach ($backend->getChildrenItemTypes() as $childItemType) { + foreach ($shareBackend->getChildrenItemTypes() as $childItemType) { $childReshares = $this->getShares($childItemType, $filter); $reshares = array_merge($reshares, $childReshares); } @@ -273,12 +273,12 @@ public function getParents(Share $share) { if (!empty($parentIds)) { $itemType = $share->getItemType(); $parentItemTypes = array($itemType); - foreach ($this->sharesBackends as $backend) { - if ($backend instanceof CollectionShares - && in_array($itemType, $backend->getChildrenItemTypes()) - && !in_array($backend->getItemType(), $parentItemTypes) + foreach ($this->shareBackends as $shareBackend) { + if ($shareBackend instanceof CollectionShareBackend + && in_array($itemType, $shareBackend->getChildrenItemTypes()) + && !in_array($shareBackend->getItemType(), $parentItemTypes) ) { - $parentItemTypes[] = $backend->getItemType(); + $parentItemTypes[] = $shareBackend->getItemType(); } } foreach ($parentIds as $parentId) { @@ -300,16 +300,16 @@ public function getParents(Share $share) { } /** - * Get shares backend by item type + * Get share backend by item type * @param string $itemType - * @throws SharesBackendDoesNotExistException - * @return Shares + * @throws ShareBackendDoesNotExistException + * @return ShareBackend */ - protected function getSharesBackend($itemType) { - if (isset($this->sharesBackends[$itemType])) { - return $this->sharesBackends[$itemType]; + protected function getShareBackend($itemType) { + if (isset($this->shareBackends[$itemType])) { + return $this->shareBackends[$itemType]; } else { - throw new SharesBackendDoesNotExistException( + throw new ShareBackendDoesNotExistException( 'A share backend does not exist for the item type' ); } @@ -370,11 +370,11 @@ protected function searchForParents(Share $share) { ); $parents = $this->getShares($itemType, $filter); // Search in collections for parents in case children were reshared - foreach ($this->sharesBackends as $backend) { - if ($backend instanceof CollectionShares - && in_array($itemType, $backend->getChildrenItemTypes()) + foreach ($this->shareBackends as $shareBackend) { + if ($shareBackend instanceof CollectionShareBackend + && in_array($itemType, $shareBackend->getChildrenItemTypes()) ) { - $collectionParents = $backend->searchForChildren($shareOwner, $itemSource); + $collectionParents = $shareBackend->searchForChildren($shareOwner, $itemSource); $parents = array_merge($parents, $collectionParents); } } @@ -459,7 +459,7 @@ protected function isValidExpirationTimeForParents(Share $share) { * @param Share $share * @param Share $oldShare * - * The share has to be updated in the shares backend before this is called + * The share has to be updated in the share backend before this is called * */ protected function updateReshares(Share $share, Share $oldShare) { diff --git a/tests/lib/share/shares.php b/tests/lib/share/shares.php index a7f1bd0bc9bd..e946d3aff2fb 100644 --- a/tests/lib/share/shares.php +++ b/tests/lib/share/shares.php @@ -24,7 +24,7 @@ use OC\Share\Share; use OC\Share\TimeMachine; -class TestShares extends \OC\Share\Shares { +class TestShareBackend extends \OC\Share\ShareBackend { private $isValidItem; @@ -64,13 +64,13 @@ public function pIsValidExpirationTime(Share $share) { } -class Shares extends \PHPUnit_Framework_TestCase { +class ShareBackend extends \PHPUnit_Framework_TestCase { protected $timeMachine; protected $user; protected $group; protected $link; - protected $shares; + protected $shareBackend; protected function setUp() { $this->timeMachine = $this->getMockBuilder('\OC\Share\TimeMachine') @@ -97,14 +97,14 @@ protected function setUp() { $this->link->expects($this->any()) ->method('getId') ->will($this->returnValue('link')); - $this->shares = new TestShares($this->timeMachine, + $this->shareBackend = new TestShareBackend($this->timeMachine, array($this->user, $this->group, $this->link) ); - $this->shares->setIsValidItem(true); + $this->shareBackend->setIsValidItem(true); } public function testShare() { - $this->shares->setIsValidItem(true); + $this->shareBackend->setIsValidItem(true); $mtgap = 'MTGap'; $icewind = 'Icewind'; @@ -151,22 +151,22 @@ public function testShare() { ->method('update'); $this->link->expects($this->never()) ->method('setParentIds'); - $share = $this->shares->share($share); + $share = $this->shareBackend->share($share); $this->assertEquals($sharedShare, $share); } public function testShareWithInvalidItem() { - $this->shares->setIsValidItem(false); + $this->shareBackend->setIsValidItem(false); $share = new Share(); $this->setExpectedException('\OC\Share\Exception\InvalidItemException', 'The item does not exist' ); - $this->shares->share($share); + $this->shareBackend->share($share); } public function testShareAgain() { - $this->shares->setIsValidItem(true); + $this->shareBackend->setIsValidItem(true); $butonic = 'butonic'; $bartv = 'bartv'; @@ -187,11 +187,11 @@ public function testShareAgain() { $this->setExpectedException('\OC\Share\Exception\InvalidShareException', 'The share already exists' ); - $this->shares->share($share); + $this->shareBackend->share($share); } public function testShareWithInvalidShare() { - $this->shares->setIsValidItem(true); + $this->shareBackend->setIsValidItem(true); $mtgap = 'MTGap'; $icewind = 'Icewind'; @@ -218,7 +218,7 @@ public function testShareWithInvalidShare() { ->method('isValidShare') ->with($this->equalTo($share)) ->will($this->returnValue(false)); - $this->assertFalse($this->shares->share($share)); + $this->assertFalse($this->shareBackend->share($share)); } public function testUnshare() { @@ -228,7 +228,7 @@ public function testUnshare() { $this->user->expects($this->once()) ->method('unshare') ->with($this->equalTo($share)); - $this->shares->unshare($share); + $this->shareBackend->unshare($share); } public function testUpdate() { @@ -240,7 +240,7 @@ public function testUpdate() { $this->user->expects($this->once()) ->method('update') ->with($this->equalTo($share)); - $this->shares->update($share); + $this->shareBackend->update($share); } public function testUpdateWithCustomUpdateMethod() { @@ -254,7 +254,7 @@ public function testUpdateWithCustomUpdateMethod() { $this->user->expects($this->once()) ->method('setParentIds') ->with($this->equalTo($share)); - $this->shares->update($share); + $this->shareBackend->update($share); } public function testUpdateWithNoChanges() { @@ -264,7 +264,7 @@ public function testUpdateWithNoChanges() { $share->resetUpdatedProperties(); $this->link->expects($this->never()) ->method('update'); - $this->shares->update($share); + $this->shareBackend->update($share); } public function testUpdateWithInvalidPermissions() { @@ -275,7 +275,7 @@ public function testUpdateWithInvalidPermissions() { $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL ); - $this->shares->update($share); + $this->shareBackend->update($share); } public function testUpdateWithInvalidExpirationTime() { @@ -287,7 +287,7 @@ public function testUpdateWithInvalidExpirationTime() { $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException', 'The expiration time is not at least 1 hour in the future' ); - $this->shares->update($share); + $this->shareBackend->update($share); } public function testGetShares() { @@ -315,7 +315,7 @@ public function testGetShares() { $this->link->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($linkMap)); - $shares = $this->shares->getShares(); + $shares = $this->shareBackend->getShares(); $this->assertCount(2, $shares); $this->assertContains($share1, $shares); $this->assertContains($share2, $shares); @@ -352,12 +352,12 @@ public function testGetSharesWithFilter() { $this->link->expects($this->exactly(2)) ->method('getShares') ->will($this->returnValueMap($linkMap)); - $shares = $this->shares->getShares(array('itemSource' => $item)); + $shares = $this->shareBackend->getShares(array('itemSource' => $item)); $this->assertCount(2, $shares); $this->assertContains($share1, $shares); $this->assertContains($share2, $shares); - $share = $this->shares->getShares(array('id' => 2)); + $share = $this->shareBackend->getShares(array('id' => 2)); $this->assertCount(1, $share); $this->assertContains($share2, $share); } @@ -376,7 +376,7 @@ public function testGetSharesWithShareTypeId() { $this->link->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($linkMap)); - $shares = $this->shares->getShares(array('shareTypeId' => 'link')); + $shares = $this->shareBackend->getShares(array('shareTypeId' => 'link')); $this->assertCount(1, $shares); $this->assertContains($share, $shares); } @@ -405,7 +405,7 @@ public function testGetSharesWithLimitOffset() { ->will($this->returnValueMap($groupMap)); $this->link->expects($this->never()) ->method('getShares'); - $shares = $this->shares->getShares(array(), 3, 1); + $shares = $this->shareBackend->getShares(array(), 3, 1); $this->assertCount(3, $shares); $this->assertContains($share2, $shares); $this->assertContains($share3, $shares); @@ -431,7 +431,7 @@ public function testSearchForPotentialShareWiths() { $this->link->expects($this->once()) ->method('searchForPotentialShareWiths') ->will($this->returnValueMap($linkMap)); - $shareWiths = $this->shares->searchForPotentialShareWiths('foo'); + $shareWiths = $this->shareBackend->searchForPotentialShareWiths('foo'); $this->assertCount(5, $shareWiths); $this->assertContains('foouser1', $shareWiths); $this->assertContains('foouser2', $shareWiths); @@ -455,7 +455,7 @@ public function testSearchForPotentialShareWithsWithLimitOffset() { ->will($this->returnValueMap($groupMap)); $this->link->expects($this->never()) ->method('searchForPotentialShareWiths'); - $shareWiths = $this->shares->searchForPotentialShareWiths('foo', 3, 1); + $shareWiths = $this->shareBackend->searchForPotentialShareWiths('foo', 3, 1); $this->assertCount(3, $shareWiths); $this->assertContains('foouser2', $shareWiths); $this->assertContains('foouser3', $shareWiths); @@ -463,28 +463,28 @@ public function testSearchForPotentialShareWithsWithLimitOffset() { } public function testGetShareType() { - $this->assertEquals($this->group, $this->shares->pGetShareType('group')); + $this->assertEquals($this->group, $this->shareBackend->pGetShareType('group')); } public function testGetShareTypeDoesNotExist() { $this->setExpectedException('\OC\Share\Exception\ShareTypeDoesNotExistException', 'No share type found matching id' ); - $this->shares->pGetShareType('foo'); + $this->shareBackend->pGetShareType('foo'); } public function testIsExpired() { // No expiration time $share = new Share(); - $this->assertFalse($this->shares->isExpired($share)); + $this->assertFalse($this->shareBackend->isExpired($share)); // 1 second in the past $share->setExpirationTime(1370797579); - $this->assertTrue($this->shares->isExpired($share)); + $this->assertTrue($this->shareBackend->isExpired($share)); // 1 second in the future $share->setExpirationTime(1370797581); - $this->assertFalse($this->shares->isExpired($share)); + $this->assertFalse($this->shareBackend->isExpired($share)); // Default expiration time set for 2 hours from share time $share->setExpirationTime(null); @@ -492,18 +492,18 @@ public function testIsExpired() { \OC_Appconfig::setValue('core', 'shareapi_expiration_time', 7200); // 1 hour 59 minutes 59 seconds in the past $share->setShareTime(1370790381); - $this->assertFalse($this->shares->isExpired($share)); + $this->assertFalse($this->shareBackend->isExpired($share)); // 2 hours 1 second in the past $share->setShareTime(1370790379); - $this->assertTrue($this->shares->isExpired($share)); + $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->shares->pAreValidPermissions($share)); + $this->assertTrue($this->shareBackend->pAreValidPermissions($share)); } public function testAreValidPermissionsWithString() { @@ -512,7 +512,7 @@ public function testAreValidPermissionsWithString() { $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', 'The permissions are not an integer' ); - $this->shares->pAreValidPermissions($share); + $this->shareBackend->pAreValidPermissions($share); } public function testAreValidPermissionsWithZero() { @@ -521,7 +521,7 @@ public function testAreValidPermissionsWithZero() { $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL ); - $this->shares->pAreValidPermissions($share); + $this->shareBackend->pAreValidPermissions($share); } public function testAreValidPermissionsWithOneMoreThanAll() { @@ -530,17 +530,17 @@ public function testAreValidPermissionsWithOneMoreThanAll() { $this->setExpectedException('\OC\Share\Exception\InvalidPermissionsException', 'The permissions are not in the range of 1 to '.\OCP\PERMISSION_ALL ); - $this->shares->pAreValidPermissions($share); + $this->shareBackend->pAreValidPermissions($share); } public function testIsValidExpirationTime() { // No expiration time $share = new Share(); - $this->assertTrue($this->shares->pIsValidExpirationTime($share)); + $this->assertTrue($this->shareBackend->pIsValidExpirationTime($share)); // 1 hour in the future $share->setExpirationTime(1370801180); - $this->assertTrue($this->shares->pIsValidExpirationTime($share)); + $this->assertTrue($this->shareBackend->pIsValidExpirationTime($share)); } public function testIsValidExpirationTimeWithString() { @@ -549,7 +549,7 @@ public function testIsValidExpirationTimeWithString() { $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException', 'The expiration time is not an integer' ); - $this->shares->pIsValidExpirationTime($share); + $this->shareBackend->pIsValidExpirationTime($share); } public function testIsValidExpirationTimeNot1HourInTheFuture() { @@ -559,7 +559,7 @@ public function testIsValidExpirationTimeNot1HourInTheFuture() { $this->setExpectedException('\OC\Share\Exception\InvalidExpirationTimeException', 'The expiration time is not at least 1 hour in the future' ); - $this->shares->pIsValidExpirationTime($share); + $this->shareBackend->pIsValidExpirationTime($share); } } \ No newline at end of file diff --git a/tests/lib/share/sharesmanager.php b/tests/lib/share/sharesmanager.php index a2f81cfdb5d7..77526cde215c 100644 --- a/tests/lib/share/sharesmanager.php +++ b/tests/lib/share/sharesmanager.php @@ -23,10 +23,10 @@ use OC\Share\Share; -class TestSharesManager extends \OC\Share\SharesManager { +class TestShareManager extends \OC\Share\ShareManager { - public function pGetSharesBackend($itemType) { - return parent::getSharesBackend($itemType); + public function pGetShareBackend($itemType) { + return parent::getShareBackend($itemType); } public function pAreValidPermissionsForParents(Share $share) { @@ -39,11 +39,11 @@ public function pIsValidExpirationTimeForParents(Share $share) { } -class SharesManager extends \PHPUnit_Framework_TestCase { +class ShareManager extends \PHPUnit_Framework_TestCase { - private $shares; - private $collectionShares; - private $sharesManager; + private $shareBackend; + private $collectionShareBackend; + private $shareManager; private $areCollectionsEnabled; /** @@ -54,33 +54,33 @@ class SharesManager extends \PHPUnit_Framework_TestCase { protected function setUp() { // Found workaround for mocks of abstract classes with concrete functions here: // https://github.com/sebastianbergmann/phpunit-mock-objects/issues/95 - $this->shares = $this->getMockBuilder('\OC\Share\Shares') + $this->shareBackend = $this->getMockBuilder('\OC\Share\ShareBackend') ->disableOriginalConstructor() - ->setMethods(get_class_methods('\OC\Share\Shares')) + ->setMethods(get_class_methods('\OC\Share\ShareBackend')) ->getMockForAbstractClass(); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getItemType') ->will($this->returnValue('test')); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('isValidItem') ->will($this->returnValue(true)); $this->areCollectionsEnabled = false; - $this->collectionShares = $this->getMockBuilder('\OC\Share\CollectionShares') + $this->collectionShare = $this->getMockBuilder('\OC\Share\CollectionShareBackend') ->disableOriginalConstructor() - ->setMethods(get_class_methods('\OC\Share\CollectionShares')) + ->setMethods(get_class_methods('\OC\Share\CollectionShareBackend')) ->getMockForAbstractClass(); - $this->collectionShares->expects($this->any()) + $this->collectionShare->expects($this->any()) ->method('getItemType') ->will($this->returnValue('testCollection')); - $this->collectionShares->expects($this->any()) + $this->collectionShare->expects($this->any()) ->method('isValidItem') ->will($this->returnValue(true)); - $this->collectionShares->expects($this->any()) + $this->collectionShare->expects($this->any()) ->method('getChildrenItemTypes') ->will($this->returnCallback(array($this, 'getChildrenItemTypesMock'))); - $this->sharesManager = new TestSharesManager(); - $this->sharesManager->registerSharesBackend($this->shares); - $this->sharesManager->registerSharesBackend($this->collectionShares); + $this->shareManager = new TestShareManager(); + $this->shareManager->registerShareBackend($this->shareBackend); + $this->shareManager->registerShareBackend($this->collectionShare); } public function getChildrenItemTypesMock() { @@ -128,14 +128,14 @@ public function testShareWithOneParent() { array($share) ), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('share') ->with($this->equalTo($share)) ->will($this->returnValue($share)); - $share = $this->sharesManager->share($share); + $share = $this->shareManager->share($share); $this->assertEquals($sharedShare, $share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -169,15 +169,15 @@ public function testShareWithOneParentAndResharingDisabled() { array($parent) ), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->never()) + $this->shareBackend->expects($this->never()) ->method('share'); $this->setExpectedException('\OC\Share\Exception\InvalidShareException', 'The admin has disabled resharing' ); - $this->sharesManager->share($share); + $this->shareManager->share($share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -210,15 +210,15 @@ public function testShareWithOneParentWithoutSharePermission() { array($parent) ), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->never()) + $this->shareBackend->expects($this->never()) ->method('share'); $this->setExpectedException('\OC\Share\Exception\InvalidShareException', 'The parent shares don\'t allow resharing' ); - $this->sharesManager->share($share); + $this->shareManager->share($share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -250,13 +250,13 @@ public function testShareWithOneParentAndReshareBackToOwner() { array($parent) ), ); - $this->shares->expects($this->once()) + $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->sharesManager->share($share); + $this->shareManager->share($share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -289,13 +289,13 @@ public function testShareWithOneParentAndReshareWithSamePeople() { array($parent) ), ); - $this->shares->expects($this->once()) + $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->sharesManager->share($share); + $this->shareManager->share($share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -347,17 +347,17 @@ public function testShareWithTwoParents() { array($share) ), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('share') ->with($this->equalTo($share)) ->will($this->returnValue($share)); - $this->shares->expects($this->never()) + $this->shareBackend->expects($this->never()) ->method('update'); $share->resetUpdatedProperties(); - $share = $this->sharesManager->share($share); + $share = $this->shareManager->share($share); $this->assertEquals($sharedShare, $share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -417,18 +417,18 @@ public function testShareWithExistingReshares() { ), array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare)), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('share') ->with($this->equalTo($share)) ->will($this->returnValue($share)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('update') ->with($this->equalTo($reshare)); $share->resetUpdatedProperties(); - $share = $this->sharesManager->share($share); + $share = $this->shareManager->share($share); $this->assertEquals($sharedShare, $share); $this->assertEquals($updatedReshare, $reshare); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); @@ -477,20 +477,20 @@ public function testShareWithOneParentInCollection() { $collectionMap = array( array(array('id' => 1), 1, null, array($parent)), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($sharesMap)); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('searchForChildren') ->will($this->returnValueMap($childMap)); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('share') ->with($this->equalTo($share)) ->will($this->returnValue($share)); - $share = $this->sharesManager->share($share); + $share = $this->shareManager->share($share); $this->assertEquals($sharedShare, $share); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', $resharing); } @@ -591,26 +591,26 @@ public function testShareCollectionWithExistingReshares() { $childMap = array( array($anybodyelse, $item, array($duplicate, $share)), ); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $this->collectionShares->expects($this->once()) + $this->collectionShare->expects($this->once()) ->method('share') ->with($this->equalTo($share)) ->will($this->returnValue($share)); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('searchForChildren') ->will($this->returnValueMap($childMap)); - $this->collectionShares->expects($this->once()) + $this->collectionShare->expects($this->once()) ->method('update') ->with($this->equalTo($reshare2)); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($sharesMap)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('update') ->with($this->equalTo($reshare1)); - $share = $this->sharesManager->share($share); + $share = $this->shareManager->share($share); $this->assertEquals($sharedShare, $share); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -639,14 +639,14 @@ public function testUnshareWithReshares() { array(array('parentId' => 2), null, null, array()), array(array('parentId' => 3), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(3)) + $this->shareBackend->expects($this->exactly(3)) ->method('unshare'); - $this->shares->expects($this->never()) + $this->shareBackend->expects($this->never()) ->method('update'); - $this->sharesManager->unshare($parent); + $this->shareManager->unshare($parent); } public function testUnshareWithResharesAndTwoParents() { @@ -698,15 +698,15 @@ public function testUnshareWithResharesAndTwoParents() { array(array('parentId' => 2), null, null, array()), array(array('parentId' => 3), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(2)) + $this->shareBackend->expects($this->exactly(2)) ->method('update'); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('unshare') ->with($this->equalTo($parent1)); - $this->sharesManager->unshare($parent1); + $this->shareManager->unshare($parent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -761,15 +761,15 @@ public function testUnshareWithResharesAndTwoParentsAndOneParentDoesNotExpire() array(array('parentId' => 2), null, null, array()), array(array('parentId' => 3), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(2)) + $this->shareBackend->expects($this->exactly(2)) ->method('update'); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('unshare') ->with($this->equalTo($parent1)); - $this->sharesManager->unshare($parent1); + $this->shareManager->unshare($parent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -849,19 +849,19 @@ public function testUnshareCollectionWithResharesAndDifferentParents() { array(array('parentId' => 3), null, null, array()), array(array('parentId' => 4), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($sharesMap)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('update'); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $this->collectionShares->expects($this->once()) + $this->collectionShare->expects($this->once()) ->method('update'); - $this->collectionShares->expects($this->exactly(2)) + $this->collectionShare->expects($this->exactly(2)) ->method('unshare'); - $this->sharesManager->unshare($parent1); + $this->shareManager->unshare($parent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -877,13 +877,13 @@ public function testUpdateWithShareDoesNotExist() { $map = array( array(array('id' => 1, 'shareTypeId' => 'group'), 1, null, array()), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', 'The share does not exist for update' ); - $this->sharesManager->update($share); + $this->shareManager->update($share); } public function testUpdateResharesWithOneParent() { @@ -943,12 +943,12 @@ public function testUpdateResharesWithOneParent() { array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($oldReshare3)), array(array('parentId' => 4), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(3)) + $this->shareBackend->expects($this->exactly(3)) ->method('update'); - $this->sharesManager->update($updatedParent); + $this->shareManager->update($updatedParent); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); $this->assertEquals($updatedReshare3, $reshare3); @@ -996,14 +996,14 @@ public function testUpdateResharesWithOneParentAndSharePermissionRemoved() { array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($reshare3)), array(array('parentId' => 4), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('update'); - $this->shares->expects($this->exactly(3)) + $this->shareBackend->expects($this->exactly(3)) ->method('unshare'); - $this->sharesManager->update($updatedParent); + $this->shareManager->update($updatedParent); } public function testUpdateResharesWithTwoParents() { @@ -1071,12 +1071,12 @@ public function testUpdateResharesWithTwoParents() { array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($oldReshare3)), array(array('parentId' => 4), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(3)) + $this->shareBackend->expects($this->exactly(3)) ->method('update'); - $this->sharesManager->update($updatedParent1); + $this->shareManager->update($updatedParent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -1151,12 +1151,12 @@ public function testUpdateResharesWithTwoParentsAndSharePermissionRemoved() { array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($oldReshare3)), array(array('parentId' => 4), null, null, array()), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(4)) + $this->shareBackend->expects($this->exactly(4)) ->method('update'); - $this->sharesManager->update($updatedParent1); + $this->shareManager->update($updatedParent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -1243,12 +1243,12 @@ public function testUpdateResharesWithSharePermissionAdded() { array(array('id' => 2, 'shareTypeId' => 'link'), 1, null, array($reshare1)), array(array('id' => 3, 'shareTypeId' => 'group'), 1, null, array($reshare2)), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->exactly(3)) + $this->shareBackend->expects($this->exactly(3)) ->method('update'); - $this->sharesManager->update($updatedParent1); + $this->shareManager->update($updatedParent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -1305,12 +1305,12 @@ public function testUpdateResharesTwoParentsAndOneParentDoesNotExpire() { array(array('id' => 1), 1, null, array($parent1)), array(array('id' => 5), 1, null, array($parent2)), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('update'); - $this->sharesManager->update($updatedParent1); + $this->shareManager->update($updatedParent1); $this->assertEquals($updatedParent2, $parent2); $this->assertEquals($updatedReshare1, $reshare1); $this->assertEquals($updatedReshare2, $reshare2); @@ -1331,16 +1331,16 @@ public function testGetSharesWithExpiredShare() { array(array(), null, null, array($share1, $share2, $share3)), array(array('parentId' => 2), null, null, array()), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->at(2)) + $this->shareBackend->expects($this->at(2)) ->method('isExpired') ->will($this->returnValue(true)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('unshare') ->with($this->equalTo($share2)); - $shares = $this->sharesManager->getShares('test'); + $shares = $this->shareManager->getShares('test'); $this->assertEquals(2, count($shares)); $this->assertContains($share1, $shares); $this->assertContains($share3, $shares); @@ -1364,16 +1364,16 @@ public function testGetSharesWithExpiredSharesAndLimit() { array(array('parentId' => 2), null, null, array()), array(array(), 1, 2, array($share4)), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->at(2)) + $this->shareBackend->expects($this->at(2)) ->method('isExpired') ->will($this->returnValue(true)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('unshare') ->with($this->equalTo($share2)); - $shares = $this->sharesManager->getShares('test', array(), 3); + $shares = $this->shareManager->getShares('test', array(), 3); $this->assertCount(3, $shares); $this->assertContains($share1, $shares); $this->assertContains($share3, $shares); @@ -1398,16 +1398,16 @@ public function testGetSharesWithExpiredSharesAndLimitOffset() { array(array('parentId' => 2), null, null, array()), array(array(), 1, 3, array($share5)), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->at(1)) + $this->shareBackend->expects($this->at(1)) ->method('isExpired') ->will($this->returnValue(true)); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('unshare') ->with($this->equalTo($share2)); - $shares = $this->sharesManager->getShares('test', array(), 3, 1); + $shares = $this->shareManager->getShares('test', array(), 3, 1); $this->assertCount(3, $shares); $this->assertContains($share3, $shares); $this->assertContains($share4, $shares); @@ -1418,10 +1418,10 @@ public function testSearchForPotentialShareWiths() { $map = array( array('foo', 3, 1, array('foouser2', 'foouser3', 'foogroup1')), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('searchForPotentialShareWiths') ->will($this->returnValueMap($map)); - $shareWiths = $this->sharesManager->searchForPotentialShareWiths('test', 'foo', 3, 1); + $shareWiths = $this->shareManager->searchForPotentialShareWiths('test', 'foo', 3, 1); $this->assertCount(3, $shareWiths); $this->assertContains('foouser2', $shareWiths); $this->assertContains('foouser3', $shareWiths); @@ -1482,12 +1482,12 @@ public function testUnshareItem() { array(array('id' => 5), 1, null, array($reshare2)), array(array('id' => 4, 'shareTypeId' => 'user'), 1, null, array($reshare3)), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('unshare'); - $this->sharesManager->unshareItem('test', $item); + $this->shareManager->unshareItem('test', $item); } public function testGetReshares() { @@ -1506,10 +1506,10 @@ public function testGetReshares() { $map = array( array(array('parentId' => 1), null, null, array($share1, $share2, $share3)), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($map)); - $reshares = $this->sharesManager->getReshares($parent); + $reshares = $this->shareManager->getReshares($parent); $this->assertCount(3, $reshares); $this->assertContains($share1, $reshares); $this->assertContains($share2, $reshares); @@ -1523,10 +1523,10 @@ public function testGetResharesWithNoReshares() { $map = array( array(array('parentId' => 1), null, null, array()), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->assertEmpty($this->sharesManager->getReshares($parent)); + $this->assertEmpty($this->shareManager->getReshares($parent)); } public function testGetResharesInCollection() { @@ -1550,13 +1550,13 @@ public function testGetResharesInCollection() { $collectionMap = array( array(array('parentId' => 1), null, null, array($share2)), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($shareMap)); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $reshares = $this->sharesManager->getReshares($parent); + $reshares = $this->shareManager->getReshares($parent); $this->assertCount(3, $reshares); $this->assertContains($share1, $reshares); $this->assertContains($share2, $reshares); @@ -1581,10 +1581,10 @@ public function testGetParents() { array(array('id' => 2), 1, null, array($parent2)), array(array('id' => 3), 1, null, array($parent3)), ); - $this->shares->expects($this->exactly(3)) + $this->shareBackend->expects($this->exactly(3)) ->method('getShares') ->will($this->returnValueMap($map)); - $parents = $this->sharesManager->getParents($share); + $parents = $this->shareManager->getParents($share); $this->assertCount(3, $parents); $this->assertContains($parent1, $parents); $this->assertContains($parent2, $parents); @@ -1611,13 +1611,13 @@ public function testGetParentsInCollection() { array(array('id' => 1), 1, null, array()), array(array('id' => 2), 1, null, array($parent2)), ); - $this->shares->expects($this->atLeastOnce()) + $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($sharesMap)); - $this->collectionShares->expects($this->atLeastOnce()) + $this->collectionShare->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $parents = $this->sharesManager->getParents($share); + $parents = $this->shareManager->getParents($share); $this->assertCount(2, $parents); $this->assertContains($parent1, $parents); $this->assertContains($parent2, $parents); @@ -1625,11 +1625,11 @@ public function testGetParentsInCollection() { public function testGetParentsWithNoParents() { $share = new Share(); - $this->shares->expects($this->never()) + $this->shareBackend->expects($this->never()) ->method('getShares'); - $this->collectionShares->expects($this->never()) + $this->collectionShare->expects($this->never()) ->method('getShares'); - $this->assertEmpty($this->sharesManager->getParents($share)); + $this->assertEmpty($this->shareManager->getParents($share)); } public function testGetParentsWithNotExistingParent() { @@ -1639,20 +1639,20 @@ public function testGetParentsWithNotExistingParent() { $map = array( array(array('id' => 1), 1, null, array()), ); - $this->shares->expects($this->once()) + $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', 'The parent share does not exist' ); - $this->sharesManager->getParents($share); + $this->shareManager->getParents($share); } - public function testGetSharesBackend() { - $this->setExpectedException('\OC\Share\Exception\SharesBackendDoesNotExistException', + public function testGetShareBackend() { + $this->setExpectedException('\OC\Share\Exception\ShareBackendDoesNotExistException', 'A share backend does not exist for the item type' ); - $this->sharesManager->pGetSharesBackend('foo'); + $this->shareManager->pGetShareBackend('foo'); } public function testAreValidPermissionsWithOneParent() { @@ -1668,15 +1668,15 @@ public function testAreValidPermissionsWithOneParent() { $map = array( array(array('id' => 1), 1, null, array($parent)), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->assertTrue($this->sharesManager->pAreValidPermissionsForParents($share)); + $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->sharesManager->pAreValidPermissionsForParents($share)); + $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share)); } public function testAreValidPermissionsWithOneParentAndShareExceedsPermissions() { @@ -1692,13 +1692,13 @@ public function testAreValidPermissionsWithOneParentAndShareExceedsPermissions() $map = array( array(array('id' => 1), 1, null, array($parent)), ); - $this->shares->expects($this->any()) + $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->sharesManager->pAreValidPermissionsForParents($share); + $this->shareManager->pAreValidPermissionsForParents($share); } public function testAreValidPermissionsWithTwoParents() { @@ -1720,15 +1720,15 @@ public function testAreValidPermissionsWithTwoParents() { array(array('id' => 1), 1, null, array($parent1)), array(array('id' => 2), 1, null, array($parent2)), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->assertTrue($this->sharesManager->pAreValidPermissionsForParents($share)); + $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share)); // Share and parent remove Create permission $share->setPermissions(27); $parent2->setPermissions(25); - $this->assertTrue($this->sharesManager->pAreValidPermissionsForParents($share)); + $this->assertTrue($this->shareManager->pAreValidPermissionsForParents($share)); } public function testAreValidPermissionsWithTwoParentsAndShareExceedsPermissions() { @@ -1750,13 +1750,13 @@ public function testAreValidPermissionsWithTwoParentsAndShareExceedsPermissions( array(array('id' => 1), 1, null, array($parent1)), array(array('id' => 2), 1, null, array($parent2)), ); - $this->shares->expects($this->any()) + $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->sharesManager->pAreValidPermissionsForParents($share); + $this->shareManager->pAreValidPermissionsForParents($share); } public function testIsValidExpirationTimeWithOneParent() { @@ -1770,15 +1770,15 @@ public function testIsValidExpirationTimeWithOneParent() { $map = array( array(array('id' => 1), 1, null, array($parent)), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share)); // Share expires 1 second before parent $share->setExpirationTime(1370884024); $parent->setExpirationTime(1370884025); - $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share)); } public function testIsValidExpirationTimeWithOneParentExpiresAndShareDoesNotExpire() { @@ -1793,13 +1793,13 @@ public function testIsValidExpirationTimeWithOneParentExpiresAndShareDoesNotExpi $map = array( array(array('id' => 1), 1, null, array($parent)), ); - $this->shares->expects($this->any()) + $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->sharesManager->pIsValidExpirationTimeForParents($share); + $this->shareManager->pIsValidExpirationTimeForParents($share); } public function testIsValidExpirationTimeWithOneParentExpiresAndShareExpiresAfter() { @@ -1815,13 +1815,13 @@ public function testIsValidExpirationTimeWithOneParentExpiresAndShareExpiresAfte $map = array( array(array('id' => 1), 1, null, array($parent)), ); - $this->shares->expects($this->any()) + $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->sharesManager->pIsValidExpirationTimeForParents($share); + $this->shareManager->pIsValidExpirationTimeForParents($share); } public function testIsValidExpirationTimeWithTwoParents() { @@ -1839,27 +1839,27 @@ public function testIsValidExpirationTimeWithTwoParents() { array(array('id' => 1), 1, null, array($parent1)), array(array('id' => 2), 1, null, array($parent2)), ); - $this->shares->expects($this->any()) + $this->shareBackend->expects($this->any()) ->method('getShares') ->will($this->returnValueMap($map)); - $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share)); // 1 parent expires, the other parent and share have no expiration time $parent1->setExpirationTime(1370884025); - $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + $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->sharesManager->pIsValidExpirationTimeForParents($share)); + $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->sharesManager->pIsValidExpirationTimeForParents($share)); + $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share)); // Share expires 1 second before both parents $share->setExpirationTime(1370884024); $parent2->setExpirationTime(1370884025); - $this->assertTrue($this->sharesManager->pIsValidExpirationTimeForParents($share)); + $this->assertTrue($this->shareManager->pIsValidExpirationTimeForParents($share)); } public function testIsValidExpirationTimeWithTwoParentsExpireAndShareDoesNotExpire() { @@ -1879,13 +1879,13 @@ public function testIsValidExpirationTimeWithTwoParentsExpireAndShareDoesNotExpi array(array('id' => 1), 1, null, array($parent1)), array(array('id' => 2), 1, null, array($parent2)), ); - $this->shares->expects($this->any()) + $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->sharesManager->pIsValidExpirationTimeForParents($share); + $this->shareManager->pIsValidExpirationTimeForParents($share); } public function testIsValidExpirationTimeWithTwoParentsExpireAndShareExpiresAfter() { @@ -1906,13 +1906,13 @@ public function testIsValidExpirationTimeWithTwoParentsExpireAndShareExpiresAfte array(array('id' => 1), 1, null, array($parent1)), array(array('id' => 2), 1, null, array($parent2)), ); - $this->shares->expects($this->any()) + $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->sharesManager->pIsValidExpirationTimeForParents($share); + $this->shareManager->pIsValidExpirationTimeForParents($share); } } \ No newline at end of file From e376ec0f1581e80513aeb6f181838e7dcaac4e3a Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 9 Jul 2013 11:38:21 -0400 Subject: [PATCH 11/85] Rename files from last commit --- lib/share/{collectionshares.php => collectionsharebackend.php} | 0 ...otexistexception.php => sharebackenddoesnotexistexception.php} | 0 lib/share/{shares.php => sharebackend.php} | 0 lib/share/{sharesmanager.php => sharemanager.php} | 0 tests/lib/share/{shares.php => sharebackend.php} | 0 tests/lib/share/{sharesmanager.php => sharemanager.php} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename lib/share/{collectionshares.php => collectionsharebackend.php} (100%) rename lib/share/exception/{sharesbackenddoesnotexistexception.php => sharebackenddoesnotexistexception.php} (100%) rename lib/share/{shares.php => sharebackend.php} (100%) rename lib/share/{sharesmanager.php => sharemanager.php} (100%) rename tests/lib/share/{shares.php => sharebackend.php} (100%) rename tests/lib/share/{sharesmanager.php => sharemanager.php} (100%) diff --git a/lib/share/collectionshares.php b/lib/share/collectionsharebackend.php similarity index 100% rename from lib/share/collectionshares.php rename to lib/share/collectionsharebackend.php diff --git a/lib/share/exception/sharesbackenddoesnotexistexception.php b/lib/share/exception/sharebackenddoesnotexistexception.php similarity index 100% rename from lib/share/exception/sharesbackenddoesnotexistexception.php rename to lib/share/exception/sharebackenddoesnotexistexception.php diff --git a/lib/share/shares.php b/lib/share/sharebackend.php similarity index 100% rename from lib/share/shares.php rename to lib/share/sharebackend.php diff --git a/lib/share/sharesmanager.php b/lib/share/sharemanager.php similarity index 100% rename from lib/share/sharesmanager.php rename to lib/share/sharemanager.php diff --git a/tests/lib/share/shares.php b/tests/lib/share/sharebackend.php similarity index 100% rename from tests/lib/share/shares.php rename to tests/lib/share/sharebackend.php diff --git a/tests/lib/share/sharesmanager.php b/tests/lib/share/sharemanager.php similarity index 100% rename from tests/lib/share/sharesmanager.php rename to tests/lib/share/sharemanager.php From a92b78a12914252429275d6bb43b6b8615fc9808 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 9 Jul 2013 13:48:43 -0400 Subject: [PATCH 12/85] Emit hooks in share backend in scope \OC\Share --- lib/share/sharebackend.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index cbe4889ca6d4..b6f1297067b6 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -32,7 +32,7 @@ /** * Backend class that apps extend and register with the ShareManager to share content * - * Hooks available in class name scope + * Hooks available in scope \OC\Share: * - preShare(Share $share) * - postShare(Share $share) * - preUnshare(Share $share) @@ -108,10 +108,10 @@ public function share(Share $share) { && $this->isValidExpirationTime($share) ) { $share->setItemTarget($this->generateItemTarget($share)); - $this->emit(get_class($this), 'preShare', array($share)); + $this->emit('\OC\Share', 'preShare', array($share)); $share->setShareTime($this->timeMachine->getTime()); $share = $shareType->share($share); - $this->emit(get_class($this), 'postShare', array($share)); + $this->emit('\OC\Share', 'postShare', array($share)); return $share; } } @@ -124,9 +124,9 @@ public function share(Share $share) { */ public function unshare(Share $share) { $shareType = $this->getShareType($share->getShareTypeId()); - $this->emit(get_class($this), 'preUnshare', array($share)); + $this->emit('\OC\Share', 'preUnshare', array($share)); $shareType->unshare($share); - $this->emit(get_class($this), 'postUnshare', array($share)); + $this->emit('\OC\Share', 'postUnshare', array($share)); } /** @@ -142,7 +142,7 @@ public function update(Share $share) { $this->isValidExpirationTime($share); } $shareType = $this->getShareType($share->getShareTypeId()); - $this->emit(get_class($this), 'preUpdate', array($share)); + $this->emit('\OC\Share', 'preUpdate', array($share)); foreach ($properties as $property => $updated) { $setter = 'set'.ucfirst($property); if (method_exists($shareType, $setter)) { @@ -153,7 +153,7 @@ public function update(Share $share) { if (!empty($properties)) { $shareType->update($share); } - $this->emit(get_class($this), 'postUpdate', array($share)); + $this->emit('\OC\Share', 'postUpdate', array($share)); } /** From c8c30fb56d1d76dd4d393e54333f2acdb190891c Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 10 Jul 2013 14:23:21 -0400 Subject: [PATCH 13/85] Add UserWatcher for listening to user delete hook --- lib/share/sharemanager.php | 43 +++++++----- lib/share/userwatcher.php | 61 ++++++++++++++++ tests/lib/share/sharemanager.php | 27 ++++--- tests/lib/share/userwatcher.php | 117 +++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+), 28 deletions(-) create mode 100644 lib/share/userwatcher.php create mode 100644 tests/lib/share/userwatcher.php diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index 76539c586165..4ed6d99cf08d 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -50,6 +50,30 @@ public function registerShareBackend(ShareBackend $shareBackend) { $this->shareBackends[$shareBackend->getItemType()] = $shareBackend; } + /** + * Get all registered share backends + * @return array + */ + public function getShareBackends() { + return $this->shareBackends; + } + + /** + * Get a share backend by item type + * @param string $itemType + * @throws ShareBackendDoesNotExistException + * @return ShareBackend + */ + public function getShareBackend($itemType) { + if (isset($this->shareBackends[$itemType])) { + return $this->shareBackends[$itemType]; + } else { + throw new ShareBackendDoesNotExistException( + 'A share backend does not exist for the item type' + ); + } + } + /** * Share a share in the share backend * @param Share $share @@ -218,7 +242,8 @@ public function searchForPotentialShareWiths($itemType, $pattern, $limit = null, * @param string $itemType * @param any $itemSource * - * Call this if an item is deleted by the item owner + * 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) { @@ -299,22 +324,6 @@ public function getParents(Share $share) { return $parents; } - /** - * Get share backend by item type - * @param string $itemType - * @throws ShareBackendDoesNotExistException - * @return ShareBackend - */ - protected function getShareBackend($itemType) { - if (isset($this->shareBackends[$itemType])) { - return $this->shareBackends[$itemType]; - } else { - throw new ShareBackendDoesNotExistException( - 'A share backend does not exist for the item type' - ); - } - } - /** * Search for reshares of a share * @param Share $share diff --git a/lib/share/userwatcher.php b/lib/share/userwatcher.php new file mode 100644 index 000000000000..f6bfb02aad1c --- /dev/null +++ b/lib/share/userwatcher.php @@ -0,0 +1,61 @@ +. + */ + +namespace OC\Share; + +use OC\Share\ShareManager; +use OC\User\Manager; +use Oc\User\User; + +/** + * 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')); + } + + public function onUserDeleted(User $user) { + $uid = $user->getUID(); + $shares = array(); + $filterShareOwner = array( + 'shareOwner' => $uid, + ); + $filterShareWith = array( + 'shareTypeId' => 'user', + 'shareWith' => $uid, + ); + $itemTypes = array_keys($this->shareManager->getShareBackends()); + foreach ($itemTypes as $itemType) { + $shareOwnerShares = $this->shareManager->getShares($itemType, $filterShareOwner); + $shareWithShares = $this->shareManager->getShares($itemType, $filterShareWith); + $shares = array_merge($shares, $shareOwnerShares, $shareWithShares); + } + foreach ($shares as $share) { + $this->shareManager->unshare($share); + } + } + +} \ No newline at end of file diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index 77526cde215c..12d2b6d9c4f9 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -25,10 +25,6 @@ class TestShareManager extends \OC\Share\ShareManager { - public function pGetShareBackend($itemType) { - return parent::getShareBackend($itemType); - } - public function pAreValidPermissionsForParents(Share $share) { return parent::areValidPermissionsForParents($share); } @@ -91,6 +87,22 @@ public function getChildrenItemTypesMock() { } } + 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->collectionShare, $backends['testCollection']); + } + + public function testGetShareBackend() { + $this->setExpectedException('\OC\Share\Exception\ShareBackendDoesNotExistException', + 'A share backend does not exist for the item type' + ); + $this->shareManager->getShareBackend('foo'); + } + public function testShareWithOneParent() { $resharing = \OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes'); \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes'); @@ -1648,13 +1660,6 @@ public function testGetParentsWithNotExistingParent() { $this->shareManager->getParents($share); } - public function testGetShareBackend() { - $this->setExpectedException('\OC\Share\Exception\ShareBackendDoesNotExistException', - 'A share backend does not exist for the item type' - ); - $this->shareManager->pGetShareBackend('foo'); - } - public function testAreValidPermissionsWithOneParent() { // Share and parent have all permissions $share = new Share(); diff --git a/tests/lib/share/userwatcher.php b/tests/lib/share/userwatcher.php new file mode 100644 index 000000000000..d9dcb1ad4626 --- /dev/null +++ b/tests/lib/share/userwatcher.php @@ -0,0 +1,117 @@ +. + */ + +namespace Test\Share; + +use OC\Share\Share; +use OC\User\User; + +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) + ), + array('test2', array('shareTypeId' => 'user', 'shareWith' => $mtgap), null, null, + array($share4) + ), + ); + $this->shareManager->expects($this->exactly(4)) + ->method('getShares') + ->will($this->returnValueMap($map)); + $this->shareManager->expects($this->exactly(4)) + ->method('unshare'); + $userManager = $this->getMockBuilder('\OC\User\Manager') + ->disableOriginalConstructor() + ->getMock(); + $userManager->expects($this->once()) + ->method('listen') + ->will($this->returnCallBack(array($this, 'listenPostDelete'))); + $userWatcher = new \OC\Share\UserWatcher($this->shareManager, $userManager); + } + + public function listenPostDelete($scope, $method, $callback) { + // Fake PublicEmitter's emit + $this->assertEquals('\OC\User', $scope); + $this->assertEquals('postDelete', $method); + call_user_func_array($callback, array($this->user)); + } + +} \ No newline at end of file From b7a56519d017a59f7647bcb00a5a877f985adf75 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 10 Jul 2013 14:25:41 -0400 Subject: [PATCH 14/85] Rename test variable for consistency --- tests/lib/share/sharemanager.php | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index 12d2b6d9c4f9..9158cdb54d07 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -61,22 +61,22 @@ protected function setUp() { ->method('isValidItem') ->will($this->returnValue(true)); $this->areCollectionsEnabled = false; - $this->collectionShare = $this->getMockBuilder('\OC\Share\CollectionShareBackend') + $this->collectionShareBackend = $this->getMockBuilder('\OC\Share\CollectionShareBackend') ->disableOriginalConstructor() ->setMethods(get_class_methods('\OC\Share\CollectionShareBackend')) ->getMockForAbstractClass(); - $this->collectionShare->expects($this->any()) + $this->collectionShareBackend->expects($this->any()) ->method('getItemType') ->will($this->returnValue('testCollection')); - $this->collectionShare->expects($this->any()) + $this->collectionShareBackend->expects($this->any()) ->method('isValidItem') ->will($this->returnValue(true)); - $this->collectionShare->expects($this->any()) + $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->collectionShare); + $this->shareManager->registerShareBackend($this->collectionShareBackend); } public function getChildrenItemTypesMock() { @@ -93,7 +93,7 @@ public function testGetShareBackends() { $this->assertArrayHasKey('test', $backends); $this->assertEquals($this->shareBackend, $backends['test']); $this->assertArrayHasKey('testCollection', $backends); - $this->assertEquals($this->collectionShare, $backends['testCollection']); + $this->assertEquals($this->collectionShareBackend, $backends['testCollection']); } public function testGetShareBackend() { @@ -492,10 +492,10 @@ public function testShareWithOneParentInCollection() { $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($sharesMap)); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('searchForChildren') ->will($this->returnValueMap($childMap)); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); $this->shareBackend->expects($this->once()) @@ -603,17 +603,17 @@ public function testShareCollectionWithExistingReshares() { $childMap = array( array($anybodyelse, $item, array($duplicate, $share)), ); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $this->collectionShare->expects($this->once()) + $this->collectionShareBackend->expects($this->once()) ->method('share') ->with($this->equalTo($share)) ->will($this->returnValue($share)); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('searchForChildren') ->will($this->returnValueMap($childMap)); - $this->collectionShare->expects($this->once()) + $this->collectionShareBackend->expects($this->once()) ->method('update') ->with($this->equalTo($reshare2)); $this->shareBackend->expects($this->atLeastOnce()) @@ -866,12 +866,12 @@ public function testUnshareCollectionWithResharesAndDifferentParents() { ->will($this->returnValueMap($sharesMap)); $this->shareBackend->expects($this->once()) ->method('update'); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); - $this->collectionShare->expects($this->once()) + $this->collectionShareBackend->expects($this->once()) ->method('update'); - $this->collectionShare->expects($this->exactly(2)) + $this->collectionShareBackend->expects($this->exactly(2)) ->method('unshare'); $this->shareManager->unshare($parent1); $this->assertEquals($updatedParent2, $parent2); @@ -1565,7 +1565,7 @@ public function testGetResharesInCollection() { $this->shareBackend->expects($this->once()) ->method('getShares') ->will($this->returnValueMap($shareMap)); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); $reshares = $this->shareManager->getReshares($parent); @@ -1626,7 +1626,7 @@ public function testGetParentsInCollection() { $this->shareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($sharesMap)); - $this->collectionShare->expects($this->atLeastOnce()) + $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('getShares') ->will($this->returnValueMap($collectionMap)); $parents = $this->shareManager->getParents($share); @@ -1639,7 +1639,7 @@ public function testGetParentsWithNoParents() { $share = new Share(); $this->shareBackend->expects($this->never()) ->method('getShares'); - $this->collectionShare->expects($this->never()) + $this->collectionShareBackend->expects($this->never()) ->method('getShares'); $this->assertEmpty($this->shareManager->getParents($share)); } From ddcdfd9f4d79436e3cf2bb210bd5ccdebfa75844 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 10 Jul 2013 14:41:39 -0400 Subject: [PATCH 15/85] Make ShareManager extend ForwardingEmitter --- lib/share/sharemanager.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index 4ed6d99cf08d..f6f2ad0bc2e4 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -29,6 +29,7 @@ use OC\Share\Exception\ShareBackendDoesNotExistException; use OC\Share\Exception\InvalidPermissionsException; use OC\Share\Exception\InvalidExpirationTimeException; +use OC\Hooks\ForwardingEmitter; /** * This is the gateway for sharing content between users in ownCloud, aka Share API @@ -36,9 +37,17 @@ * * The ShareManager's primary purpose is to ensure consistency between shares and their reshares * + * Hooks available in scope \OC\Share: + * - preShare(Share $share) + * - postShare(Share $share) + * - preUnshare(Share $share) + * - postUnshare(Share $share) + * - preUpdate(Share $share) + * - postUpdate(Share $share) + * * @version 2.0.0 BETA */ -class ShareManager { +class ShareManager extends ForwardingEmitter { protected $shareBackends; @@ -48,6 +57,7 @@ class ShareManager { */ public function registerShareBackend(ShareBackend $shareBackend) { $this->shareBackends[$shareBackend->getItemType()] = $shareBackend; + $this->forward($shareBackend); } /** From b9990377fca4f4fc0d49ae346b3c35a8e8cf19fd Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 10 Jul 2013 15:12:25 -0400 Subject: [PATCH 16/85] Add tests for emitting hooks in ShareBackend and fix when update emits events --- lib/share/sharebackend.php | 36 ++++++++++++++------------- tests/lib/share/sharebackend.php | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index b6f1297067b6..8804ae1a83c5 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -135,25 +135,27 @@ public function unshare(Share $share) { */ public function update(Share $share) { $properties = $share->getUpdatedProperties(); - 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); + 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)); } - $this->emit('\OC\Share', 'postUpdate', array($share)); } /** diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php index e946d3aff2fb..ec95d8d00d27 100644 --- a/tests/lib/share/sharebackend.php +++ b/tests/lib/share/sharebackend.php @@ -27,6 +27,7 @@ class TestShareBackend extends \OC\Share\ShareBackend { private $isValidItem; + private $events; public function getItemType() { return 'test'; @@ -62,6 +63,15 @@ 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 { @@ -153,6 +163,9 @@ public function testShare() { ->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() { @@ -229,6 +242,9 @@ public function testUnshare() { ->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() { @@ -241,6 +257,9 @@ public function testUpdate() { ->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() { @@ -255,6 +274,9 @@ public function testUpdateWithCustomUpdateMethod() { ->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() { @@ -265,6 +287,22 @@ public function testUpdateWithNoChanges() { $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() { @@ -276,6 +314,8 @@ public function testUpdateWithInvalidPermissions() { '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() { @@ -288,6 +328,8 @@ public function testUpdateWithInvalidExpirationTime() { '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() { From 24b253d7365134ad44e89e9ad726b514e7d2741a Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 15 Jul 2013 10:36:03 -0400 Subject: [PATCH 17/85] Fix case in class name --- lib/share/userwatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/share/userwatcher.php b/lib/share/userwatcher.php index f6bfb02aad1c..fcf7217f9a8f 100644 --- a/lib/share/userwatcher.php +++ b/lib/share/userwatcher.php @@ -23,7 +23,7 @@ use OC\Share\ShareManager; use OC\User\Manager; -use Oc\User\User; +use OC\User\User; /** * Listen to user events that require updating shares From 9967b7b01b6a1e99519d67333f7ad43002a94029 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 18 Jul 2013 16:37:52 -0400 Subject: [PATCH 18/85] Add getShareById method to ShareManager --- lib/share/sharemanager.php | 74 ++++++++++++++++++++++---------- tests/lib/share/sharemanager.php | 43 ++++++++++++++++++- 2 files changed, 93 insertions(+), 24 deletions(-) diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index f6f2ad0bc2e4..bd684757aa04 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -27,8 +27,10 @@ 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; /** @@ -180,20 +182,11 @@ public function update(Share $share) { $this->isValidExpirationTimeForParents($share); } // Find the share in the backend to compare old/new properties for reshares' updates - $filter = array( - 'id' => $share->getId(), - 'shareTypeId' => $share->getShareTypeId(), - ); - $result = $this->getShares($itemType, $filter, 1); - if (empty($result)) { - throw new ShareDoesNotExistException('The share does not exist for update'); - } else { - $oldShare = reset($result); - $shareBackend = $this->getShareBackend($itemType); - $shareBackend->update($share); - if (isset($properties['permissions']) || isset($properties['expirationTime'])) { - $this->updateReshares($share, $oldShare); - } + $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); } } @@ -232,6 +225,45 @@ public function getShares($itemType, $filter = array(), $limit = null, $offset = return $shares; } + /** + * Get a share by id + * @param int $id + * @param string $itemType (optional) + * @param string $shareTypeId (optional) + * @throws ShareDoesNotExistException + * @return 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->shareBackends 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('A share could not be found with that id'); + } else if (count($share) > 1) { + throw new MultipleSharesReturnedException( + 'Multiple shares were returned with that id' + ); + } else { + return reset($share); + } + } + /** * Search for potential people to share with based on the given pattern in the share backend * @param string $itemType @@ -317,16 +349,14 @@ public function getParents(Share $share) { } } foreach ($parentIds as $parentId) { - $filter = array( - 'id' => $parentId, - ); foreach ($parentItemTypes as $parentItemType) { - $result = $this->getShares($parentItemType, $filter, 1); - if (!empty($result)) { - $parents[] = reset($result); + try { + $parents[] = $this->getShareById($parentId, $parentItemType); break; - } else if ($parentItemType === end($parentItemTypes)) { - throw new ShareDoesNotExistException('The parent share does not exist'); + } catch (ShareDoesNotExistException $exception) { + if ($parentItemType === end($parentItemTypes)) { + throw $exception; + } } } } diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index 9158cdb54d07..e7421ba85530 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -22,6 +22,7 @@ namespace Test\Share; use OC\Share\Share; +use OC\Share\Exception\ShareTypeDoesNotExistException; class TestShareManager extends \OC\Share\ShareManager { @@ -893,7 +894,7 @@ public function testUpdateWithShareDoesNotExist() { ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', - 'The share does not exist for update' + 'A share could not be found with that id' ); $this->shareManager->update($share); } @@ -1426,6 +1427,44 @@ public function testGetSharesWithExpiredSharesAndLimitOffset() { $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 with that id' + ); + $this->shareManager->getShareById(1, 'test'); + } + public function testSearchForPotentialShareWiths() { $map = array( array('foo', 3, 1, array('foouser2', 'foouser3', 'foogroup1')), @@ -1655,7 +1694,7 @@ public function testGetParentsWithNotExistingParent() { ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', - 'The parent share does not exist' + 'A share could not be found with that id' ); $this->shareManager->getParents($share); } From c835212a84cd0b277d77b8cc7cd6b20cb4a56e50 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 18 Jul 2013 16:44:46 -0400 Subject: [PATCH 19/85] Update docs to show that arrays are arrays of Share objects --- lib/share/sharebackend.php | 6 +++--- lib/share/sharemanager.php | 16 ++++++++-------- lib/share/sharetype/isharetype.php | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index 8804ae1a83c5..5cbe33d2c30b 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -50,8 +50,8 @@ abstract class ShareBackend extends BasicEmitter { /** * The constructor * @param TimeMachine $timeMachine The time() mock - * @param array $shareTypes An array of share type objects that items can be shared through - * e.g. User, Group, Link + * @param ShareType[] $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; @@ -163,7 +163,7 @@ public function update(Share $share) { * @param array $filter (optional) A key => value array of share properties * @param int $limit (optional) * @param int $offset (optional) - * @return array + * @return Share[] */ public function getShares($filter = array(), $limit = null, $offset = null) { if (isset($filter['shareTypeId'])) { diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index bd684757aa04..9a1564d4152e 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -64,7 +64,7 @@ public function registerShareBackend(ShareBackend $shareBackend) { /** * Get all registered share backends - * @return array + * @return ShareBackend[] */ public function getShareBackends() { return $this->shareBackends; @@ -196,7 +196,7 @@ public function update(Share $share) { * @param array $filter (optional) A key => value array of share properties * @param int $limit (optional) * @param int $offset (optional) - * @return array + * @return Share[] */ public function getShares($itemType, $filter = array(), $limit = null, $offset = null) { $shares = array(); @@ -301,7 +301,7 @@ public function unshareItem($itemType, $itemSource) { /** * Get all reshares of a share * @param Share $share - * @return array + * @return Share[] * * It is possible for the reshares to be of a different item type if the share's item type * is a collection @@ -328,7 +328,7 @@ public function getReshares(Share $share) { * Get all parents of a share * @param Share $share * @throws ShareDoesNotExistException - * @return array + * @return 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 @@ -367,7 +367,7 @@ public function getParents(Share $share) { /** * Search for reshares of a share * @param Share $share - * @return array Share + * @return Share[] * * Call this to determine if the share has existing reshares because there is a duplicate share * @@ -402,7 +402,7 @@ protected function searchForReshares(Share $share) { /** * Search for parent shares of a share * @param Share $share - * @return array Share + * @return Share[] * * Call this to determine if the share is a reshare and needs to set the parent ids property * @@ -432,7 +432,7 @@ protected function searchForParents(Share $share) { /** * Get the total permissions of an array of shares - * @param array $shares + * @param Share[] $shares * @return int */ protected function getTotalPermissions(array $shares) { @@ -445,7 +445,7 @@ protected function getTotalPermissions(array $shares) { /** * Get the latest expiration time of an array of shares - * @param array $shares + * @param Share[] $shares * @return int|null */ protected function getLatestExpirationTime(array $shares) { diff --git a/lib/share/sharetype/isharetype.php b/lib/share/sharetype/isharetype.php index 12f197c8bd8e..0c0453b7c1a7 100644 --- a/lib/share/sharetype/isharetype.php +++ b/lib/share/sharetype/isharetype.php @@ -66,7 +66,7 @@ public function update(Share $share); * @param array $filter A key => value array of share properties * @param int $limit * @param int $offset - * @return array Share + * @return Share[] */ public function getShares(array $filter, $limit, $offset); From ea04c3d85b7a1a8638f0a9b24c2226d0589bf3a3 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 18 Jul 2013 16:52:57 -0400 Subject: [PATCH 20/85] Modify ShareBackend tests to facilitate reuse --- tests/lib/share/sharebackend.php | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php index ec95d8d00d27..2dcd055c24b3 100644 --- a/tests/lib/share/sharebackend.php +++ b/tests/lib/share/sharebackend.php @@ -22,7 +22,6 @@ namespace Test\Share; use OC\Share\Share; -use OC\Share\TimeMachine; class TestShareBackend extends \OC\Share\ShareBackend { @@ -110,21 +109,31 @@ protected function setUp() { $this->shareBackend = new TestShareBackend($this->timeMachine, array($this->user, $this->group, $this->link) ); - $this->shareBackend->setIsValidItem(true); } - public function testShare() { + /** + * 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 testShare() { $mtgap = 'MTGap'; $icewind = 'Icewind'; - $item = 1; $share = new Share(); $share->setShareTypeId('user'); $share->setShareOwner($mtgap); $share->setShareWith($icewind); - $share->setItemSource($item); + $share->setItemOwner($mtgap); $share->setPermissions(31); + $item = $this->getValidItemSource($share); + $share->setItemSource($item); $share->resetUpdatedProperties(); $sharedShare = clone $share; $sharedShare->setShareTime(1370797580); @@ -179,15 +188,14 @@ public function testShareWithInvalidItem() { } public function testShareAgain() { - $this->shareBackend->setIsValidItem(true); - $butonic = 'butonic'; $bartv = 'bartv'; - $item = 2; $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), @@ -204,8 +212,6 @@ public function testShareAgain() { } public function testShareWithInvalidShare() { - $this->shareBackend->setIsValidItem(true); - $mtgap = 'MTGap'; $icewind = 'Icewind'; $item = 1; @@ -213,8 +219,10 @@ public function testShareWithInvalidShare() { $share->setShareTypeId('user'); $share->setShareOwner($mtgap); $share->setShareWith($icewind); - $share->setItemSource($item); + $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() From 65ac5b71e7bacd647ed0b752bb5ad22719ab1b63 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 18 Jul 2013 17:16:22 -0400 Subject: [PATCH 21/85] Make some of the exceptions more verbose --- .../multiplesharesreturnedexception.php | 31 +++++++++++++++++++ .../sharebackenddoesnotexistexception.php | 3 +- .../exception/sharedoesnotexistexception.php | 3 +- .../sharetypedoesnotexistexception.php | 3 +- lib/share/sharebackend.php | 2 +- lib/share/sharemanager.php | 12 +++---- tests/lib/share/sharebackend.php | 2 +- tests/lib/share/sharemanager.php | 8 ++--- 8 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 lib/share/exception/multiplesharesreturnedexception.php 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 index 098b7af9e211..afe54634cf60 100644 --- a/lib/share/exception/sharebackenddoesnotexistexception.php +++ b/lib/share/exception/sharebackenddoesnotexistexception.php @@ -23,7 +23,8 @@ class ShareBackendDoesNotExistException extends \Exception { - public function __construct($message) { + public function __construct($itemType) { + $message = 'A share backend does not exist for the item type '.$itemType; parent::__construct($message); } diff --git a/lib/share/exception/sharedoesnotexistexception.php b/lib/share/exception/sharedoesnotexistexception.php index 50b887eb4e79..a7da075dc27a 100644 --- a/lib/share/exception/sharedoesnotexistexception.php +++ b/lib/share/exception/sharedoesnotexistexception.php @@ -23,7 +23,8 @@ class ShareDoesNotExistException extends \Exception { - public function __construct($message) { + public function __construct($id) { + $message = 'A share does not exist with the id '.$id; parent::__construct($message); } diff --git a/lib/share/exception/sharetypedoesnotexistexception.php b/lib/share/exception/sharetypedoesnotexistexception.php index 4efd6c235462..71e629609a27 100644 --- a/lib/share/exception/sharetypedoesnotexistexception.php +++ b/lib/share/exception/sharetypedoesnotexistexception.php @@ -23,7 +23,8 @@ class ShareTypeDoesNotExistException extends \Exception { - public function __construct($message) { + public function __construct($shareTypeId) { + $message = 'A share type does not exist with the id '.$shareTypeId; parent::__construct($message); } diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index 5cbe33d2c30b..cd11a45be320 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -255,7 +255,7 @@ protected function getShareType($shareTypeId) { return $shareType; } } - throw new ShareTypeDoesNotExistException('No share type found matching id'); + throw new ShareTypeDoesNotExistException($shareTypeId); } /** diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index 9a1564d4152e..dd7e96a84b8b 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -80,9 +80,7 @@ public function getShareBackend($itemType) { if (isset($this->shareBackends[$itemType])) { return $this->shareBackends[$itemType]; } else { - throw new ShareBackendDoesNotExistException( - 'A share backend does not exist for the item type' - ); + throw new ShareBackendDoesNotExistException($itemType); } } @@ -254,11 +252,9 @@ public function getShareById($id, $itemType = null, $shareTypeId = null) { } } if (empty($share)) { - throw new ShareDoesNotExistException('A share could not be found with that id'); + throw new ShareDoesNotExistException($id); } else if (count($share) > 1) { - throw new MultipleSharesReturnedException( - 'Multiple shares were returned with that id' - ); + throw new MultipleSharesReturnedException($id); } else { return reset($share); } @@ -475,7 +471,7 @@ protected function areValidPermissionsForParents(Share $share) { $parentPermissions = $this->getTotalPermissions($parents); if ($permissions & ~$parentPermissions) { throw new InvalidPermissionsException( - 'The permissions exceeds the parent shares\' permissions'.$share->getId() + 'The permissions exceeds the parent shares\' permissions' ); } } diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php index 2dcd055c24b3..277b6415b840 100644 --- a/tests/lib/share/sharebackend.php +++ b/tests/lib/share/sharebackend.php @@ -518,7 +518,7 @@ public function testGetShareType() { public function testGetShareTypeDoesNotExist() { $this->setExpectedException('\OC\Share\Exception\ShareTypeDoesNotExistException', - 'No share type found matching id' + 'A share type does not exist with the id foo' ); $this->shareBackend->pGetShareType('foo'); } diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index e7421ba85530..c65c246e2041 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -99,7 +99,7 @@ public function testGetShareBackends() { public function testGetShareBackend() { $this->setExpectedException('\OC\Share\Exception\ShareBackendDoesNotExistException', - 'A share backend does not exist for the item type' + 'A share backend does not exist for the item type foo' ); $this->shareManager->getShareBackend('foo'); } @@ -894,7 +894,7 @@ public function testUpdateWithShareDoesNotExist() { ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', - 'A share could not be found with that id' + 'A share does not exist with the id 1' ); $this->shareManager->update($share); } @@ -1460,7 +1460,7 @@ public function testGetShareByIdWithMultipleSharesReturned() { ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\MultipleSharesReturnedException', - 'Multiple shares were returned with that id' + 'Multiple shares were returned for the id 1' ); $this->shareManager->getShareById(1, 'test'); } @@ -1694,7 +1694,7 @@ public function testGetParentsWithNotExistingParent() { ->method('getShares') ->will($this->returnValueMap($map)); $this->setExpectedException('\OC\Share\Exception\ShareDoesNotExistException', - 'A share could not be found with that id' + 'A share does not exist with the id 1' ); $this->shareManager->getParents($share); } From 9e089f4bbf6a64ebb87af3aee7ee9042785f79f1 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 22 Jul 2013 18:02:40 -0400 Subject: [PATCH 22/85] Remove searchForPotentialShareWiths from ShareManager and ShareBackend, this will be replaced by the controller using the share types directly --- lib/share/sharebackend.php | 69 ++++++++++--------------- lib/share/sharemanager.php | 15 ------ tests/lib/share/sharebackend.php | 87 ++++++++------------------------ tests/lib/share/sharemanager.php | 14 ----- 4 files changed, 48 insertions(+), 137 deletions(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index cd11a45be320..e48e1ae41963 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -55,7 +55,9 @@ abstract class ShareBackend extends BasicEmitter { */ public function __construct(TimeMachine $timeMachine, array $shareTypes) { $this->timeMachine = $timeMachine; - $this->shareTypes = $shareTypes; + foreach ($shareTypes as $shareType) { + $this->shareTypes[$shareType->getId()] = $shareType; + } } /** @@ -81,6 +83,29 @@ abstract protected function isValidItem(Share $share); */ abstract protected function generateItemTarget(Share $share); + + /** + * Get all share types + * @return ShareType[] + */ + public function getShareTypes() { + return $this->shareTypes; + } + + /** + * Get share type by id + * @param string $shareTypeId + * @throws ShareTypeDoesNotExistException + * @return ShareType + */ + public function getShareType($shareTypeId) { + if (isset($this->shareTypes[$shareTypeId])) { + return $this->shareTypes[$shareTypeId]; + } else { + throw new ShareTypeDoesNotExistException($shareTypeId); + } + } + /** * Share a share * @param Share $share @@ -191,33 +216,6 @@ public function getShares($filter = array(), $limit = null, $offset = null) { return $shares; } - /** - * Search for potential people to share with based on the given pattern - * @param string $pattern - * @param int $limit (optional) - * @param int $offset (optional) - * @return array - */ - public function searchForPotentialShareWiths($pattern, $limit = null, $offset = null) { - $shareWiths = array(); - foreach ($this->shareTypes as $shareType) { - $result = $shareType->searchForPotentialShareWiths($pattern, $limit, $offset); - foreach ($result as $shareWith) { - $shareWiths[] = $shareWith; - if (isset($limit)) { - $limit--; - if ($limit === 0) { - return $shareWiths; - } - } - if (isset($offset) && $offset > 0) { - $offset--; - } - } - } - return $shareWiths; - } - /** * Check if a share is expired * @param Share $share @@ -243,21 +241,6 @@ public function isExpired(Share $share) { } } - /** - * Get share type by id - * @param string $shareTypeId - * @throws ShareTypeDoesNotExistException - * @return ShareType - */ - protected function getShareType($shareTypeId) { - foreach ($this->shareTypes as $shareType) { - if ($shareType->getId() === $shareTypeId) { - return $shareType; - } - } - throw new ShareTypeDoesNotExistException($shareTypeId); - } - /** * Check if a share's permissions are valid * @param Share $share diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index dd7e96a84b8b..52a7b5813fe4 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -260,21 +260,6 @@ public function getShareById($id, $itemType = null, $shareTypeId = null) { } } - /** - * Search for potential people to share with based on the given pattern in the share backend - * @param string $itemType - * @param string $pattern - * @param int $limit (optional) - * @param int $offset (optional) - * @return array - */ - public function searchForPotentialShareWiths($itemType, $pattern, $limit = null, - $offset = null - ) { - $shareBackend = $this->getShareBackend($itemType); - return $shareBackend->searchForPotentialShareWiths($pattern, $limit, $offset); - } - /** * Unshare all shares of an item * @param string $itemType diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php index 277b6415b840..e6476dc940d4 100644 --- a/tests/lib/share/sharebackend.php +++ b/tests/lib/share/sharebackend.php @@ -50,10 +50,6 @@ public function setIsValidItem($isValidItem) { $this->isValidItem = $isValidItem; } - public function pGetShareType($shareTypeId) { - return parent::getShareType($shareTypeId); - } - public function pAreValidPermissions(Share $share) { return parent::areValidPermissions($share); } @@ -123,6 +119,28 @@ protected function getValidItemSource(Share $share) { 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'; @@ -462,67 +480,6 @@ public function testGetSharesWithLimitOffset() { $this->assertContains($share4, $shares); } - public function testSearchForPotentialShareWiths() { - $userMap = array( - array('foo', null, null, array('foouser1', 'foouser2', 'foouser3')), - ); - $this->user->expects($this->once()) - ->method('searchForPotentialShareWiths') - ->will($this->returnValueMap($userMap)); - $groupMap = array( - array('foo', null, null, array('foogroup1', 'foogroup2')), - ); - $this->group->expects($this->once()) - ->method('searchForPotentialShareWiths') - ->will($this->returnValueMap($groupMap)); - $linkMap = array( - array('foo', null, null, array()), - ); - $this->link->expects($this->once()) - ->method('searchForPotentialShareWiths') - ->will($this->returnValueMap($linkMap)); - $shareWiths = $this->shareBackend->searchForPotentialShareWiths('foo'); - $this->assertCount(5, $shareWiths); - $this->assertContains('foouser1', $shareWiths); - $this->assertContains('foouser2', $shareWiths); - $this->assertContains('foouser3', $shareWiths); - $this->assertContains('foogroup1', $shareWiths); - $this->assertContains('foogroup2', $shareWiths); - } - - public function testSearchForPotentialShareWithsWithLimitOffset() { - $userMap = array( - array('foo', 3, 1, array('foouser2', 'foouser3')), - ); - $this->user->expects($this->once()) - ->method('searchForPotentialShareWiths') - ->will($this->returnValueMap($userMap)); - $groupMap = array( - array('foo', 1, 0, array('foogroup1')), - ); - $this->group->expects($this->once()) - ->method('searchForPotentialShareWiths') - ->will($this->returnValueMap($groupMap)); - $this->link->expects($this->never()) - ->method('searchForPotentialShareWiths'); - $shareWiths = $this->shareBackend->searchForPotentialShareWiths('foo', 3, 1); - $this->assertCount(3, $shareWiths); - $this->assertContains('foouser2', $shareWiths); - $this->assertContains('foouser3', $shareWiths); - $this->assertContains('foogroup1', $shareWiths); - } - - public function testGetShareType() { - $this->assertEquals($this->group, $this->shareBackend->pGetShareType('group')); - } - - public function testGetShareTypeDoesNotExist() { - $this->setExpectedException('\OC\Share\Exception\ShareTypeDoesNotExistException', - 'A share type does not exist with the id foo' - ); - $this->shareBackend->pGetShareType('foo'); - } - public function testIsExpired() { // No expiration time $share = new Share(); diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index c65c246e2041..c3c3c28f1fda 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -1465,20 +1465,6 @@ public function testGetShareByIdWithMultipleSharesReturned() { $this->shareManager->getShareById(1, 'test'); } - public function testSearchForPotentialShareWiths() { - $map = array( - array('foo', 3, 1, array('foouser2', 'foouser3', 'foogroup1')), - ); - $this->shareBackend->expects($this->once()) - ->method('searchForPotentialShareWiths') - ->will($this->returnValueMap($map)); - $shareWiths = $this->shareManager->searchForPotentialShareWiths('test', 'foo', 3, 1); - $this->assertCount(3, $shareWiths); - $this->assertContains('foouser2', $shareWiths); - $this->assertContains('foouser3', $shareWiths); - $this->assertContains('foogroup1', $shareWiths); - } - public function testUnshareItem() { $item = 1; $parent1 = new Share(); From f922c66c4df54565440f0673055e3a475511a16b Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 25 Jul 2013 11:18:11 -0400 Subject: [PATCH 23/85] Fix searchForPotentialShareWiths for user sharetype --- lib/share/sharetype/user.php | 7 +++++- tests/lib/share/sharetype/user.php | 34 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/share/sharetype/user.php b/lib/share/sharetype/user.php index 16df3eef7433..25f94ca0640d 100644 --- a/lib/share/sharetype/user.php +++ b/lib/share/sharetype/user.php @@ -76,7 +76,12 @@ public function isValidShare(Share $share) { } public function searchForPotentialShareWiths($pattern, $limit, $offset) { - return $this->userManager->searchDisplayName($pattern, $limit, $offset); + $shareWiths = array(); + $result = $this->userManager->searchDisplayName($pattern, $limit, $offset); + foreach ($result as $user) { + $shareWiths[] = $user->getDisplayName(); + } + return $shareWiths; } } \ No newline at end of file diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php index b7912085fd19..7b852a0a2bb4 100644 --- a/tests/lib/share/sharetype/user.php +++ b/tests/lib/share/sharetype/user.php @@ -225,8 +225,26 @@ public function testGetSharesWithFilter() { } public function testSearchForPotentialShareWiths() { + $user1 = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $user1->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('foouser1')); + $user2 = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $user2->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('foouser2')); + $user3 = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $user3->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('foouser3')); $map = array( - array('foo', null, null, array('foouser1', 'foouser2', 'foouser3')), + array('foo', null, null, array($user1, $user2, $user3)), ); $this->userManager->expects($this->once()) ->method('searchDisplayName') @@ -239,8 +257,20 @@ public function testSearchForPotentialShareWiths() { } public function testSearchForPotentialShareWithsWithLimitOffset() { + $user2 = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $user2->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('foouser2')); + $user3 = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $user3->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('foouser3')); $map = array( - array('foo', 3, 1, array('foouser2', 'foouser3')), + array('foo', 3, 1, array($user2, $user3)), ); $this->userManager->expects($this->once()) ->method('searchDisplayName') From 5b346cae08d905374754528a69d50dcabc6fffa5 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 25 Jul 2013 13:16:30 -0400 Subject: [PATCH 24/85] Use group manager class in user share type --- lib/share/sharetype/user.php | 31 ++++++++----- tests/lib/share/sharetype/user.php | 73 ++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/lib/share/sharetype/user.php b/lib/share/sharetype/user.php index 25f94ca0640d..5deded2f2c76 100644 --- a/lib/share/sharetype/user.php +++ b/lib/share/sharetype/user.php @@ -24,7 +24,8 @@ use OC\Share\Share; use OC\Share\ShareFactory; use OC\Share\Exception\InvalidShareException; -use OC\User\Manager; +use OC\User\Manager as UserManager; +use OC\Group\Manager as GroupManager; /** * Controller for shares between two users @@ -32,16 +33,21 @@ class User extends Common { protected $userManager; + protected $groupManager; /** * The constructor * @param string $itemType * @param ShareFactory $shareFactory - * @param Manager $userManager + * @param UserManager $userManager + * @param GroupManager $groupManager */ - public function __construct($itemType, ShareFactory $shareFactory, Manager $userManager) { + public function __construct($itemType, ShareFactory $shareFactory, UserManager $userManager, + GroupManager $groupManager + ) { parent::__construct($itemType, $shareFactory); $this->userManager = $userManager; + $this->groupManager = $groupManager; } public function getId() { @@ -62,15 +68,18 @@ public function isValidShare(Share $share) { } $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); if ($sharingPolicy === 'groups_only') { - $inGroup = array_intersect(\OC_Group::getUserGroups($shareOwner), - \OC_Group::getUserGroups($shareWith) - ); - if (empty($inGroup)) { - 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' - ); + $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; } diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php index 7b852a0a2bb4..beb47dc8a15e 100644 --- a/tests/lib/share/sharetype/user.php +++ b/tests/lib/share/sharetype/user.php @@ -35,6 +35,7 @@ public function getId() { class User extends ShareType { private $userManager; + private $groupManager; private $user1; private $user2; private $user3; @@ -43,7 +44,12 @@ protected function setUp() { $this->userManager = $this->getMockBuilder('\OC\User\Manager') ->disableOriginalConstructor() ->getMock(); - $this->instance = new TestUser('test', new ShareFactory(), $this->userManager); + $this->groupManager = $this->getMockBuilder('\OC\Group\Manager') + ->disableOriginalConstructor() + ->getMock(); + $this->instance = new TestUser('test', new ShareFactory(), $this->userManager, + $this->groupManager + ); } protected function getTestShare() { @@ -156,13 +162,12 @@ public function testIsValidShareWithShareWithDoesNotExist() { $this->instance->isValidShare($share); } - public function testIsValidShareWithGroupOnlyPolicy() { + 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'; - $devs = 'devs'; $share = new Share(); $share->setShareOwner($jancborchardt); $share->setShareWith($raydiation); @@ -173,11 +178,30 @@ public function testIsValidShareWithGroupOnlyPolicy() { $this->userManager->expects($this->atLeastOnce()) ->method('userExists') ->will($this->returnValueMap($map)); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup($devs); - \OC_Group::addToGroup($jancborchardt, $devs); - \OC_Group::addToGroup($raydiation, $devs); + $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); @@ -189,7 +213,6 @@ public function testIsValidShareWithShareOwnerNotInShareWithGroupsAndGroupsOnlyP $jancborchardt = 'jancborchardt'; $raydiation = 'Raydiation'; - $devs = 'devs'; $share = new Share(); $share->setShareOwner($jancborchardt); $share->setShareWith($raydiation); @@ -200,13 +223,33 @@ public function testIsValidShareWithShareOwnerNotInShareWithGroupsAndGroupsOnlyP $this->userManager->expects($this->atLeastOnce()) ->method('userExists') ->will($this->returnValueMap($map)); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup($devs); - \OC_Group::addToGroup($raydiation, $devs); + $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' + '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); From 9402d9b4bd2fc3aea346ebfe14f4168ff969bf22 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 26 Jul 2013 19:46:55 -0400 Subject: [PATCH 25/85] Use group manager class in group share type --- lib/share/sharetype/group.php | 41 ++++-- tests/lib/share/sharetype/group.php | 187 ++++++++++++++++++++++------ 2 files changed, 181 insertions(+), 47 deletions(-) diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index 7981886ae8d5..66ff60ab9965 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -24,6 +24,7 @@ use OC\Share\Share; use OC\Share\ShareFactory; use OC\Share\Exception\InvalidShareException; +use OC\Group\Manager as GroupManager; use OC\User\Manager as UserManager; /** @@ -31,6 +32,7 @@ */ class Group extends Common { + protected $groupManager; protected $userManager; protected $groupTable; @@ -38,10 +40,14 @@ class Group extends Common { * The constructor * @param string $itemType * @param ShareFactory $shareFactory - * @param Manager $userManager + * @param GroupManager $groupManager + * @param UserManager $userManager */ - public function __construct($itemType, ShareFactory $shareFactory, UserManager $userManager) { + public function __construct($itemType, ShareFactory $shareFactory, GroupManager $groupManager, + UserManager $userManager + ) { parent::__construct($itemType, $shareFactory); + $this->groupManager = $groupManager; $this->userManager = $userManager; $this->groupsTable = '`*PREFIX*shares_groups`'; } @@ -56,14 +62,19 @@ public function isValidShare(Share $share) { if (!$this->userManager->userExists($shareOwner)) { throw new InvalidShareException('The share owner does not exist'); } - if (!\OC_Group::groupExists($shareWith)) { + 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' && !\OC_Group::inGroup($shareOwner, $shareWith)) { - 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' - ); + 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; } @@ -147,15 +158,18 @@ public function getShares(array $filter, $limit, $offset) { foreach ($filter as $property => $value) { $column = Share::propertyToColumn($property); if ($property === 'shareWith') { - $groups = \OC_Group::getUserGroups($value); + $shareWithUser = $this->userManager->get($value); + $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 = array_merge($params, $groups); $params[] = $value; } } else { @@ -203,8 +217,8 @@ public function getShares(array $filter, $limit, $offset) { $itemTargets = array($share->getItemTarget()); $itemTargets['users'] = $userItemTargets; $share->setItemTarget($itemTargets); - $share->resetUpdatedProperties(); } + $share->resetUpdatedProperties(); } } return $shares; @@ -219,7 +233,12 @@ public function clear() { } public function searchForPotentialShareWiths($pattern, $limit, $offset) { - return \OC_Group::getGroups($pattern, $limit, $offset); + $shareWiths = array(); + $result = $this->groupManager->search($pattern, $limit, $offset); + foreach ($result as $group) { + $shareWiths[] = $group->getGID(); + } + return $shareWiths; } protected function getUserItemTargets($id) { diff --git a/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php index 52200cfb5ddb..6d06f54ef122 100644 --- a/tests/lib/share/sharetype/group.php +++ b/tests/lib/share/sharetype/group.php @@ -34,6 +34,7 @@ public function getId() { class Group extends ShareType { + private $groupManager; private $userManager; private $user1; private $user2; @@ -42,10 +43,15 @@ class Group extends ShareType { private $group2; protected function setUp() { + $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->userManager); + $this->instance = new TestGroup('test', new ShareFactory(), $this->groupManager, + $this->userManager + ); } protected function getTestShare() { @@ -66,17 +72,8 @@ protected function setupTestShares() { $this->user1 = 'MTGap'; $this->user2 = 'karlitschek'; $this->user3 = 'Icewind'; - $this->group1 = 'designers'; + $this->group1 = 'devs'; $this->group2 = 'friends'; - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup($this->group1); - \OC_Group::createGroup($this->group2); - \OC_Group::addToGroup($this->user1, $this->group1); - \OC_Group::addToGroup($this->user1, $this->group2); - \OC_Group::addToGroup($this->user2, $this->group1); - \OC_Group::addToGroup($this->user2, $this->group2); - \OC_Group::addToGroup($this->user3, $this->group1); $this->share1 = $this->getTestShare(); $this->share1->setShareOwner($this->user1); @@ -101,6 +98,9 @@ protected function setupTestShares() { } 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(); @@ -112,11 +112,13 @@ public function testIsValidShare() { $this->userManager->expects($this->once()) ->method('userExists') ->will($this->returnValueMap($map)); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup($designers); - \OC_Group::addToGroup($jancborchardt, $designers); + $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() { @@ -131,9 +133,10 @@ public function testIsValidShareWithShareOwnerDoesNotExist() { $this->userManager->expects($this->once()) ->method('userExists') ->will($this->returnValueMap($map)); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup($designers); + $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' ); @@ -151,15 +154,17 @@ public function testIsValidShareWithShareWithDoesNotExist() { $this->userManager->expects($this->once()) ->method('userExists') ->will($this->returnValueMap($map)); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); + $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 testIsValidShareWithShareOwnerNotInGroup() { + public function testIsValidShareWithGroupsOnlyPolicy() { $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'groups_only'); @@ -174,12 +179,73 @@ public function testIsValidShareWithShareOwnerNotInGroup() { $this->userManager->expects($this->once()) ->method('userExists') ->will($this->returnValueMap($map)); - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup($designers); + $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' + '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); @@ -234,6 +300,23 @@ public function testSetItemTarget() { public function testGetSharesWithFilter() { $this->setupTestShares(); + $shareWithUser = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $this->userManager->expects($this->once()) + ->method('get') + ->with($this->equalTo($this->user3)) + ->will($this->returnValue($shareWithUser)); + $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') + ->with($this->equalTo($shareWithUser)) + ->will($this->returnValue(array($group1))); $filter = array( 'shareWith' => $this->user3, ); @@ -243,11 +326,30 @@ public function testGetSharesWithFilter() { } public function testSearchForPotentialShareWiths() { - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup('foogroup1'); - \OC_Group::createGroup('foogroup2'); - \OC_Group::createGroup('foogroup3'); + $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('foo', null, null); $this->assertCount(3, $shareWiths); $this->assertContains('foogroup1', $shareWiths); @@ -256,11 +358,24 @@ public function testSearchForPotentialShareWiths() { } public function testSearchForPotentialShareWithsWithLimitOffset() { - \OC_Group::clearBackends(); - \OC_Group::useBackend(new \OC_Group_Dummy); - \OC_Group::createGroup('foogroup1'); - \OC_Group::createGroup('foogroup2'); - \OC_Group::createGroup('foogroup3'); + $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('foo', 3, 1); $this->assertCount(2, $shareWiths); $this->assertContains('foogroup2', $shareWiths); From a9d5f3f506316f879523ebe47fd3c4459d16aec0 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 27 Jul 2013 17:05:24 -0400 Subject: [PATCH 26/85] Add shareOwner parameter to searchForPotentialShareWiths method to ensure the groups only sharing policy can be handled in the UI --- lib/share/sharetype/group.php | 26 +++- lib/share/sharetype/isharetype.php | 3 +- lib/share/sharetype/link.php | 2 +- lib/share/sharetype/user.php | 41 +++++- tests/lib/share/sharetype/group.php | 139 +++++++++++++++++++- tests/lib/share/sharetype/link.php | 2 +- tests/lib/share/sharetype/user.php | 196 ++++++++++++++++++++++++++-- 7 files changed, 381 insertions(+), 28 deletions(-) diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index 66ff60ab9965..3f058d875e0d 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -232,11 +232,29 @@ public function clear() { \OC_DB::executeAudited($sql); } - public function searchForPotentialShareWiths($pattern, $limit, $offset) { + public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset) { $shareWiths = array(); - $result = $this->groupManager->search($pattern, $limit, $offset); - foreach ($result as $group) { - $shareWiths[] = $group->getGID(); + $groups = array(); + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); + if ($sharingPolicy === 'groups_only') { + $shareOwnerUser = $this->userManager->get($shareOwner); + if ($shareOwnerUser) { + $result = $this->groupManager->getUserGroups($shareOwnerUser); + foreach ($result as $group) { + if (stripos($group->getGID(), $pattern) !== false) { + $groups[] = $group; + } + } + $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; } diff --git a/lib/share/sharetype/isharetype.php b/lib/share/sharetype/isharetype.php index 0c0453b7c1a7..d572cbd0a47c 100644 --- a/lib/share/sharetype/isharetype.php +++ b/lib/share/sharetype/isharetype.php @@ -77,11 +77,12 @@ 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($pattern, $limit, $offset); + 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 index 3276e3190cca..04b6addfc1c3 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -165,7 +165,7 @@ public function clear() { \OC_DB::executeAudited($sql); } - public function searchForPotentialShareWiths($pattern, $limit, $offset) { + public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset) { // Links are not associated with a person return array(); } diff --git a/lib/share/sharetype/user.php b/lib/share/sharetype/user.php index 5deded2f2c76..ca4bc230f0ae 100644 --- a/lib/share/sharetype/user.php +++ b/lib/share/sharetype/user.php @@ -84,13 +84,44 @@ public function isValidShare(Share $share) { return true; } - public function searchForPotentialShareWiths($pattern, $limit, $offset) { + public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $offset) { $shareWiths = array(); - $result = $this->userManager->searchDisplayName($pattern, $limit, $offset); - foreach ($result as $user) { - $shareWiths[] = $user->getDisplayName(); + $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(), + ); + } } - return $shareWiths; + $shareWiths = array_slice($shareWiths, $offset, $limit); + return array_values($shareWiths); } } \ No newline at end of file diff --git a/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php index 6d06f54ef122..ecbd5199d382 100644 --- a/tests/lib/share/sharetype/group.php +++ b/tests/lib/share/sharetype/group.php @@ -326,6 +326,9 @@ public function testGetSharesWithFilter() { } 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(); @@ -350,14 +353,25 @@ public function testSearchForPotentialShareWiths() { $this->groupManager->expects($this->once()) ->method('search') ->will($this->returnValueMap($map)); - $shareWiths = $this->instance->searchForPotentialShareWiths('foo', null, null); + $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', null, null); $this->assertCount(3, $shareWiths); - $this->assertContains('foogroup1', $shareWiths); - $this->assertContains('foogroup2', $shareWiths); - $this->assertContains('foogroup3', $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(); @@ -376,10 +390,121 @@ public function testSearchForPotentialShareWithsWithLimitOffset() { $this->groupManager->expects($this->once()) ->method('search') ->will($this->returnValueMap($map)); - $shareWiths = $this->instance->searchForPotentialShareWiths('foo', 3, 1); + $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('bargroup3')); + $group4 = $this->getMockBuilder('\OC\Group\Group') + ->disableOriginalConstructor() + ->getMock(); + $group4->expects($this->any()) + ->method('getGID') + ->will($this->returnValue('foogroup3')); + $this->groupManager->expects($this->once()) + ->method('getUserGroups') + ->with($this->equalTo($shareOwnerUser)) + ->will($this->returnValue(array($group1, $group2, $group3, $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' => 'foogroup3', + 'shareWithDisplayName' => 'foogroup3 (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('bargroup3')); + $group4 = $this->getMockBuilder('\OC\Group\Group') + ->disableOriginalConstructor() + ->getMock(); + $group4->expects($this->any()) + ->method('getGID') + ->will($this->returnValue('foogroup3')); + $this->groupManager->expects($this->once()) + ->method('getUserGroups') + ->with($this->equalTo($shareOwnerUser)) + ->will($this->returnValue(array($group1, $group2, $group3, $group4))); + $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1); $this->assertCount(2, $shareWiths); - $this->assertContains('foogroup2', $shareWiths); - $this->assertContains('foogroup3', $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); } } \ No newline at end of file diff --git a/tests/lib/share/sharetype/link.php b/tests/lib/share/sharetype/link.php index 74286b9ae1af..b68cabc05dbc 100644 --- a/tests/lib/share/sharetype/link.php +++ b/tests/lib/share/sharetype/link.php @@ -198,7 +198,7 @@ public function testGetSharesWithFilter() { } public function testSearchForPotentialShareWiths() { - $this->assertEmpty($this->instance->searchForPotentialShareWiths('foo', 3, 1)); + $this->assertEmpty($this->instance->searchForPotentialShareWiths('user2', 'foo', 3, 1)); } } \ No newline at end of file diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php index beb47dc8a15e..530320c39ceb 100644 --- a/tests/lib/share/sharetype/user.php +++ b/tests/lib/share/sharetype/user.php @@ -268,21 +268,33 @@ public function testGetSharesWithFilter() { } 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')); @@ -292,36 +304,202 @@ public function testSearchForPotentialShareWiths() { $this->userManager->expects($this->once()) ->method('searchDisplayName') ->will($this->returnValueMap($map)); - $shareWiths = $this->instance->searchForPotentialShareWiths('foo', null, null); - $this->assertCount(3, $shareWiths); - $this->assertContains('foouser1', $shareWiths); - $this->assertContains('foouser2', $shareWiths); - $this->assertContains('foouser3', $shareWiths); + $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', 3, 1, array($user2, $user3)), + array('foo', 5, null, array($user1, $user2, $user3)), ); $this->userManager->expects($this->once()) ->method('searchDisplayName') ->will($this->returnValueMap($map)); - $shareWiths = $this->instance->searchForPotentialShareWiths('foo', 3, 1); + $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('foouser2', $shareWiths); - $this->assertContains('foouser3', $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 From f30775bc0a5dd5b83f188a8c0741134420846b75 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 30 Jul 2013 09:49:27 -0400 Subject: [PATCH 27/85] Fix UserWatcher for share backend without user share type --- lib/share/{ => sharetype}/userwatcher.php | 23 ++++++++----- .../lib/share/{ => sharetype}/userwatcher.php | 34 +++++++++++++------ 2 files changed, 38 insertions(+), 19 deletions(-) rename lib/share/{ => sharetype}/userwatcher.php (72%) rename tests/lib/share/{ => sharetype}/userwatcher.php (77%) diff --git a/lib/share/userwatcher.php b/lib/share/sharetype/userwatcher.php similarity index 72% rename from lib/share/userwatcher.php rename to lib/share/sharetype/userwatcher.php index fcf7217f9a8f..b5ae4c248b01 100644 --- a/lib/share/userwatcher.php +++ b/lib/share/sharetype/userwatcher.php @@ -19,11 +19,11 @@ * License along with this library. If not, see . */ -namespace OC\Share; +namespace OC\Share\ShareType; use OC\Share\ShareManager; +use OC\Share\Exception\ShareTypeDoesNotExistException; use OC\User\Manager; -use OC\User\User; /** * Listen to user events that require updating shares @@ -37,7 +37,7 @@ public function __construct(ShareManager $shareManager, Manager $userManager) { $userManager->listen('\OC\User', 'postDelete', array($this, 'onUserDeleted')); } - public function onUserDeleted(User $user) { + public function onUserDeleted(\OC\User\User $user) { $uid = $user->getUID(); $shares = array(); $filterShareOwner = array( @@ -47,15 +47,20 @@ public function onUserDeleted(User $user) { 'shareTypeId' => 'user', 'shareWith' => $uid, ); - $itemTypes = array_keys($this->shareManager->getShareBackends()); - foreach ($itemTypes as $itemType) { + $shareBackends = $this->shareManager->getShareBackends(); + foreach ($shareBackends as $shareBackend) { + $itemType = $shareBackend->getItemType(); $shareOwnerShares = $this->shareManager->getShares($itemType, $filterShareOwner); - $shareWithShares = $this->shareManager->getShares($itemType, $filterShareWith); - $shares = array_merge($shares, $shareOwnerShares, $shareWithShares); + $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/tests/lib/share/userwatcher.php b/tests/lib/share/sharetype/userwatcher.php similarity index 77% rename from tests/lib/share/userwatcher.php rename to tests/lib/share/sharetype/userwatcher.php index d9dcb1ad4626..65975777f1eb 100644 --- a/tests/lib/share/userwatcher.php +++ b/tests/lib/share/sharetype/userwatcher.php @@ -19,10 +19,10 @@ * License along with this library. If not, see . */ -namespace Test\Share; +namespace Test\Share\ShareType; use OC\Share\Share; -use OC\User\User; +use OC\Share\Exception\ShareTypeDoesNotExistException; class UserWatcher extends \PHPUnit_Framework_TestCase { @@ -89,28 +89,42 @@ public function testOnUserDeleted() { array('test1', array('shareTypeId' => 'user', 'shareWith' => $mtgap), null, null, array($share3) ), - array('test2', array('shareTypeId' => 'user', 'shareWith' => $mtgap), null, null, - array($share4) - ), ); - $this->shareManager->expects($this->exactly(4)) + $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->exactly(4)) + $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\UserWatcher($this->shareManager, $userManager); + $userWatcher = new \OC\Share\ShareType\UserWatcher($this->shareManager, $userManager); } public function listenPostDelete($scope, $method, $callback) { // Fake PublicEmitter's emit - $this->assertEquals('\OC\User', $scope); - $this->assertEquals('postDelete', $method); call_user_func_array($callback, array($this->user)); } From ffb17f0f4fb964003cfdb6ca0540092c63de87b7 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 30 Jul 2013 10:16:14 -0400 Subject: [PATCH 28/85] Add display name properties and toAPI method to Share object --- lib/share/share.php | 27 +++++++++++++++++++++++++++ tests/lib/share/share.php | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/lib/share/share.php b/lib/share/share.php index c753ebb24913..f0a0f3e5f4c5 100644 --- a/lib/share/share.php +++ b/lib/share/share.php @@ -36,7 +36,9 @@ class Share { protected $parentIds = array(); protected $shareTypeId; protected $shareOwner; + protected $shareOwnerDisplayName; protected $shareWith; + protected $shareWithDisplayName; protected $itemType; protected $itemSource; protected $itemTarget; @@ -55,6 +57,31 @@ class Share { 'shareTime' => 'int' ); + /** + * Get all properties in an array + * @return array + */ + public function toAPI() { + return array( + 'id' => $this->id, + 'parentIds' => $this->parentIds, + 'shareTypeId' => $this->shareTypeId, + 'shareOwner' => $this->shareOwner, + 'shareOwnerDisplayName' => $this->shareOwnerDisplayName, + 'shareWith' => $this->shareWith, + 'shareWithDisplayName' => $this->shareWithDisplayName, + 'itemType' => $this->itemType, + 'itemSource' => $this->itemSource, + 'itemTarget' => $this->itemTarget, + 'itemOwner' => $this->itemOwner, + 'permissions' => $this->permissions, + 'expirationTime' => $this->expirationTime, + 'shareTime' => $this->shareTime, + 'token' => $this->token, + 'password' => $this->password, + ); + } + /** * Check if the share has create permission * @return bool diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index ca92674963ec..9303f4de9c2a 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -31,6 +31,42 @@ 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 testIsCreatable() { $share = new Share(); $share->setPermissions(\OCP\PERMISSION_CREATE); From 5d38ccfe7a3b9888cf7623c44aeeac0f13c5e345 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 30 Jul 2013 10:19:00 -0400 Subject: [PATCH 29/85] Set display names for Share objects in share types --- lib/share/sharetype/group.php | 21 +++++++-- lib/share/sharetype/link.php | 18 ++++++- lib/share/sharetype/user.php | 34 +++++++++++++ tests/lib/share/sharetype/group.php | 63 +++++++++++++++++++++---- tests/lib/share/sharetype/link.php | 42 +++++++++++++++++ tests/lib/share/sharetype/sharetype.php | 35 +++++++++----- tests/lib/share/sharetype/user.php | 42 +++++++++++++++++ 7 files changed, 229 insertions(+), 26 deletions(-) diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index 3f058d875e0d..f00fd4c95ee7 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -89,7 +89,7 @@ public function share(Share $share) { if ($share) { $share->setItemTarget($itemTargets); $this->setItemTarget($share); - $share->resetUpdatedProperties(); + $share = $this->setShareDisplayNames($share); } return $share; } @@ -206,7 +206,7 @@ public function getShares(array $filter, $limit, $offset) { $shares[] = $share; } } - foreach ($shares as $share) { + foreach ($shares as &$share) { $userItemTargets = $this->getUserItemTargets($share->getId()); if (!empty($userItemTargets)) { if (isset($filter['shareWith'])) { @@ -218,8 +218,8 @@ public function getShares(array $filter, $limit, $offset) { $itemTargets['users'] = $userItemTargets; $share->setItemTarget($itemTargets); } - $share->resetUpdatedProperties(); } + $share = $this->setShareDisplayNames($share); } return $shares; } @@ -269,4 +269,19 @@ protected function getUserItemTargets($id) { return $itemTargets; } + /** + * Set the display names for the share owner and share with + * @param Share $share + * @return 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/link.php b/lib/share/sharetype/link.php index 04b6addfc1c3..7282380723ec 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -80,7 +80,7 @@ public function share(Share $share) { \OC_DB::executeAudited($sql, array($share->getId(), $token, $password)); $share->setToken($token); $share->setPassword($password); - $share->resetUpdatedProperties(); + $share = $this->setShareDisplayName($share); } return $share; } @@ -150,7 +150,7 @@ public function getShares(array $filter, $limit, $offset) { $share = $this->shareFactory->mapToShare($row); $parentIds = $this->getParentIds($share->getId()); $share->setParentIds($parentIds); - $share->resetUpdatedProperties(); + $share = $this->setShareDisplayName($share); $shares[] = $share; } return $shares; @@ -183,4 +183,18 @@ protected function hashPassword($password) { return $password; } + /** + * Set the display name for the share owner + * @param Share $share + * @return 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/user.php b/lib/share/sharetype/user.php index ca4bc230f0ae..e7188845f264 100644 --- a/lib/share/sharetype/user.php +++ b/lib/share/sharetype/user.php @@ -84,6 +84,22 @@ public function isValidShare(Share $share) { return true; } + public function share(Share $share) { + $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(); @@ -124,4 +140,22 @@ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $off return array_values($shareWiths); } + /** + * Set the display names for the share owner and share with + * @param Share $share + * @return 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/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php index ecbd5199d382..940781fc42e4 100644 --- a/tests/lib/share/sharetype/group.php +++ b/tests/lib/share/sharetype/group.php @@ -55,6 +55,32 @@ protected function setUp() { } protected function getTestShare() { + $mtgap = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $mtgap->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Michael Gapczynski')); + $karlitschek = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $karlitschek->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Frank Karlitschek')); + $icewind = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $icewind->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Robin Appelman')); + $map = array( + array('MTGap', $mtgap), + array('karlitschek', $karlitschek), + array('Icewind', $icewind), + ); + $this->userManager->expects($this->atLeastOnce()) + ->method('get') + ->will($this->returnValueMap($map)); $share = new Share(); $share->setShareTypeId($this->instance->getId()); $share->setShareOwner('MTGap'); @@ -68,6 +94,22 @@ protected function getTestShare() { return $share; } + protected function getSharedTestShare() { + $share = new Share(); + $share->setShareTypeId($this->instance->getId()); + $share->setShareOwner('MTGap'); + $share->setShareOwnerDisplayName('Michael Gapczynski'); + $share->setShareWith('friends'); + $share->setShareWithDisplayName('friends (group)'); + $share->setItemType('test'); + $share->setItemOwner('MTGap'); + $share->setItemSource('23'); + $share->setItemTarget('secrets'); + $share->setPermissions(31); + $share->setShareTime(1370797580); + return $share; + } + protected function setupTestShares() { $this->user1 = 'MTGap'; $this->user2 = 'karlitschek'; @@ -298,15 +340,8 @@ public function testSetItemTarget() { $this->assertEquals($share, $this->getShareById($share->getId())); } - public function testGetSharesWithFilter() { + public function testGetSharesWithShareWithFilter() { $this->setupTestShares(); - $shareWithUser = $this->getMockBuilder('\OC\User\User') - ->disableOriginalConstructor() - ->getMock(); - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->equalTo($this->user3)) - ->will($this->returnValue($shareWithUser)); $group1 = $this->getMockBuilder('\OC\Group\Group') ->disableOriginalConstructor() ->getMock(); @@ -315,7 +350,6 @@ public function testGetSharesWithFilter() { ->will($this->returnValue($this->group1)); $this->groupManager->expects($this->once()) ->method('getUserGroups') - ->with($this->equalTo($shareWithUser)) ->will($this->returnValue(array($group1))); $filter = array( 'shareWith' => $this->user3, @@ -325,6 +359,17 @@ public function testGetSharesWithFilter() { $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->user1, + ); + $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'); diff --git a/tests/lib/share/sharetype/link.php b/tests/lib/share/sharetype/link.php index b68cabc05dbc..baa2b273cf31 100644 --- a/tests/lib/share/sharetype/link.php +++ b/tests/lib/share/sharetype/link.php @@ -50,9 +50,51 @@ protected function setUp() { } protected function getTestShare() { + $mtgap = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $mtgap->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Michael Gapczynski')); + $karlitschek = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $karlitschek->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Frank Karlitschek')); + $icewind = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $icewind->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Robin Appelman')); + $map = array( + array('MTGap', $mtgap), + array('karlitschek', $karlitschek), + array('Icewind', $icewind), + ); + $this->userManager->expects($this->atLeastOnce()) + ->method('get') + ->will($this->returnValueMap($map)); + $share = new Share(); + $share->setShareTypeId($this->instance->getId()); + $share->setShareOwner('MTGap'); + $share->setShareWith(null); + $share->setItemType('test'); + $share->setItemOwner('MTGap'); + $share->setItemSource('23'); + $share->setItemTarget('secrets'); + $share->setPermissions(31); + $share->setShareTime(1370797580); + return $share; + } + + protected function getSharedTestShare() { + // TODO Fix token $share = new Share(); $share->setShareTypeId($this->instance->getId()); $share->setShareOwner('MTGap'); + $share->setShareOwnerDisplayName('Michael Gapczynski'); $share->setShareWith(null); $share->setItemType('test'); $share->setItemOwner('MTGap'); diff --git a/tests/lib/share/sharetype/sharetype.php b/tests/lib/share/sharetype/sharetype.php index dfa1c8cd2c01..a3363d6bc5b2 100644 --- a/tests/lib/share/sharetype/sharetype.php +++ b/tests/lib/share/sharetype/sharetype.php @@ -35,6 +35,12 @@ abstract class ShareType extends \PHPUnit_Framework_TestCase { */ abstract protected function getTestShare(); + /** + * Get the same share as getTestShare, but as expected after being shared + * @return Share + */ + abstract protected function getSharedTestShare(); + /** * Setup four shares with fake data assigned to their respective class property * The fourth share has the third share as a parent (even if it doesn't make sense) @@ -47,23 +53,28 @@ protected function tearDown() { public function testShare() { $share = $this->getTestShare(); - $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())); + $sharedShare = $this->getSharedTestShare(); + $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(); $share->setParentIds(array(1, 3)); - $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())); + $sharedShare = $this->getSharedTestShare(); + $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() { diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php index 530320c39ceb..b66c8a71beef 100644 --- a/tests/lib/share/sharetype/user.php +++ b/tests/lib/share/sharetype/user.php @@ -53,10 +53,52 @@ protected function setUp() { } protected function getTestShare() { + $mtgap = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $mtgap->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Michael Gapczynski')); + $karlitschek = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $karlitschek->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Frank Karlitschek')); + $icewind = $this->getMockBuilder('\OC\User\User') + ->disableOriginalConstructor() + ->getMock(); + $icewind->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Robin Appelman')); + $map = array( + array('MTGap', $mtgap), + array('karlitschek', $karlitschek), + array('Icewind', $icewind), + ); + $this->userManager->expects($this->atLeastOnce()) + ->method('get') + ->will($this->returnValueMap($map)); + $share = new Share(); + $share->setShareTypeId($this->instance->getId()); + $share->setShareOwner('MTGap'); + $share->setShareWith('karlitschek'); + $share->setItemType('test'); + $share->setItemOwner('MTGap'); + $share->setItemSource('23'); + $share->setItemTarget('secrets'); + $share->setPermissions(31); + $share->setShareTime(1370797580); + return $share; + } + + protected function getSharedTestShare() { $share = new Share(); $share->setShareTypeId($this->instance->getId()); $share->setShareOwner('MTGap'); + $share->setShareOwnerDisplayName('Michael Gapczynski'); $share->setShareWith('karlitschek'); + $share->setShareWithDisplayName('Frank Karlitschek'); $share->setItemType('test'); $share->setItemOwner('MTGap'); $share->setItemSource('23'); From 0bb874f684e2c9f54cddaf1b37a09c19c31899d3 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 30 Jul 2013 10:41:01 -0400 Subject: [PATCH 30/85] Add docs to UserWatcher --- lib/share/sharetype/userwatcher.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/share/sharetype/userwatcher.php b/lib/share/sharetype/userwatcher.php index b5ae4c248b01..0ef9bc255082 100644 --- a/lib/share/sharetype/userwatcher.php +++ b/lib/share/sharetype/userwatcher.php @@ -37,6 +37,10 @@ public function __construct(ShareManager $shareManager, Manager $userManager) { $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(); @@ -63,4 +67,5 @@ public function onUserDeleted(\OC\User\User $user) { $this->shareManager->unshare($share); } } -} + +} \ No newline at end of file From 375ccbf269cd6e3c382d27d787f31a455da32711 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 30 Jul 2013 16:35:02 -0400 Subject: [PATCH 31/85] Fix doc in Share test --- tests/lib/share/share.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index 9303f4de9c2a..894be8fdd25f 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -1,7 +1,6 @@ Date: Wed, 31 Jul 2013 14:40:17 -0400 Subject: [PATCH 32/85] Fix docs for ShareBackend --- lib/share/sharebackend.php | 66 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index e48e1ae41963..68f60d60b524 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -32,13 +32,13 @@ /** * Backend class that apps extend and register with the ShareManager to share content * - * Hooks available in scope \OC\Share: - * - preShare(Share $share) - * - postShare(Share $share) - * - preUnshare(Share $share) - * - postUnshare(Share $share) - * - preUpdate(Share $share) - * - postUpdate(Share $share) + * 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 */ @@ -49,9 +49,9 @@ abstract class ShareBackend extends BasicEmitter { /** * The constructor - * @param TimeMachine $timeMachine The time() mock - * @param ShareType[] $shareTypes An array of share type objects that items can be shared - * through e.g. User, Group, Link + * @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; @@ -68,9 +68,9 @@ abstract public function getItemType(); /** * Check if an item is valid for the share owner - * @param Share $share - * @throws InvalidItemException If the item does not exist or the share owner does not have - * access to the item + * @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); @@ -78,15 +78,15 @@ abstract protected function isValidItem(Share $share); /** * Generate an item target for the share with - * @param Share $share - * @return string|array + * @param \OC\Share\Share $share + * @return string | array */ abstract protected function generateItemTarget(Share $share); /** * Get all share types - * @return ShareType[] + * @return \OC\Share\ShareType\IShareType[] */ public function getShareTypes() { return $this->shareTypes; @@ -95,8 +95,8 @@ public function getShareTypes() { /** * Get share type by id * @param string $shareTypeId - * @throws ShareTypeDoesNotExistException - * @return ShareType + * @throws \OC\Share\Exception\ShareTypeDoesNotExistException + * @return \OC\Share\IShareType */ public function getShareType($shareTypeId) { if (isset($this->shareTypes[$shareTypeId])) { @@ -108,12 +108,12 @@ public function getShareType($shareTypeId) { /** * Share a share - * @param Share $share - * @throws InvalidItemException - * @throws InvalidShareException - * @throws InvalidPermissionsException - * @throws InvalidExpirationTimeException - * @return Share|bool + * @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)) { @@ -145,7 +145,7 @@ public function share(Share $share) { /** * Unshare a share - * @param Share $share + * @param \OC\Share\Share $share */ public function unshare(Share $share) { $shareType = $this->getShareType($share->getShareTypeId()); @@ -156,7 +156,7 @@ public function unshare(Share $share) { /** * Update a share's properties in the database - * @param Share $share + * @param \OC\Share\Share $share */ public function update(Share $share) { $properties = $share->getUpdatedProperties(); @@ -188,7 +188,7 @@ public function update(Share $share) { * @param array $filter (optional) A key => value array of share properties * @param int $limit (optional) * @param int $offset (optional) - * @return Share[] + * @return \OC\Share\Share[] */ public function getShares($filter = array(), $limit = null, $offset = null) { if (isset($filter['shareTypeId'])) { @@ -218,7 +218,7 @@ public function getShares($filter = array(), $limit = null, $offset = null) { /** * Check if a share is expired - * @param Share $share + * @param \OC\Share\Share $share * @return bool */ public function isExpired(Share $share) { @@ -243,8 +243,9 @@ public function isExpired(Share $share) { /** * Check if a share's permissions are valid - * @param Share $share - * @throws InvalidPermissionsException + * @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 @@ -270,8 +271,9 @@ protected function areValidPermissions($share) { /** * Check if a share's expiration time is valid - * @param Share $share - * @throws InvalidExpirationTimeException + * @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 From 55f444be177ac77eaeae847a6beefe24df0c2cdd Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 31 Jul 2013 14:46:37 -0400 Subject: [PATCH 33/85] Fix docs for ShareManager --- lib/share/sharemanager.php | 84 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index 52a7b5813fe4..39f0278c61b1 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -39,13 +39,13 @@ * * The ShareManager's primary purpose is to ensure consistency between shares and their reshares * - * Hooks available in scope \OC\Share: - * - preShare(Share $share) - * - postShare(Share $share) - * - preUnshare(Share $share) - * - postUnshare(Share $share) - * - preUpdate(Share $share) - * - postUpdate(Share $share) + * 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 */ @@ -55,7 +55,7 @@ class ShareManager extends ForwardingEmitter { /** * Register a share backend - * @param ShareBackend $shareBackend + * @param \OC\Share\ShareBackend $shareBackend */ public function registerShareBackend(ShareBackend $shareBackend) { $this->shareBackends[$shareBackend->getItemType()] = $shareBackend; @@ -64,7 +64,7 @@ public function registerShareBackend(ShareBackend $shareBackend) { /** * Get all registered share backends - * @return ShareBackend[] + * @return \OC\Share\ShareBackend[] */ public function getShareBackends() { return $this->shareBackends; @@ -73,8 +73,8 @@ public function getShareBackends() { /** * Get a share backend by item type * @param string $itemType - * @throws ShareBackendDoesNotExistException - * @return ShareBackend + * @throws \OC\Share\Exception\ShareBackendDoesNotExistException + * @return \OC\Share\ShareBackend */ public function getShareBackend($itemType) { if (isset($this->shareBackends[$itemType])) { @@ -87,11 +87,11 @@ public function getShareBackend($itemType) { /** * Share a share in the share backend * @param Share $share - * @throws InvalidItemException - * @throws InvalidShareException - * @throws InvalidPermissionsException - * @throws InvalidExpirationTimeException - * @return bool + * @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()); @@ -146,7 +146,7 @@ public function share(Share $share) { /** * Unshare a share in the share backend - * @param Share $share + * @param \OC\Share\Share $share */ public function unshare(Share $share) { $shareBackend = $this->getShareBackend($share->getItemType()); @@ -161,10 +161,10 @@ public function unshare(Share $share) { /** * Update a share's properties in the share backend - * @param Share $share - * @throws ShareDoesNotExistException - * @throws InvalidPermissionsException - * @throws InvalidExpirationTimeException + * @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 @@ -194,7 +194,7 @@ public function update(Share $share) { * @param array $filter (optional) A key => value array of share properties * @param int $limit (optional) * @param int $offset (optional) - * @return Share[] + * @return \OC\Share\Share[] */ public function getShares($itemType, $filter = array(), $limit = null, $offset = null) { $shares = array(); @@ -228,8 +228,8 @@ public function getShares($itemType, $filter = array(), $limit = null, $offset = * @param int $id * @param string $itemType (optional) * @param string $shareTypeId (optional) - * @throws ShareDoesNotExistException - * @return Share + * @throws \OC\Share\Exception\ShareDoesNotExistException + * @return \OC\Share\Share */ public function getShareById($id, $itemType = null, $shareTypeId = null) { $share = array(); @@ -281,8 +281,8 @@ public function unshareItem($itemType, $itemSource) { /** * Get all reshares of a share - * @param Share $share - * @return 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 @@ -307,9 +307,9 @@ public function getReshares(Share $share) { /** * Get all parents of a share - * @param Share $share - * @throws ShareDoesNotExistException - * @return 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 @@ -347,8 +347,8 @@ public function getParents(Share $share) { /** * Search for reshares of a share - * @param Share $share - * @return 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 * @@ -382,8 +382,8 @@ protected function searchForReshares(Share $share) { /** * Search for parent shares of a share - * @param Share $share - * @return 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 * @@ -413,7 +413,7 @@ protected function searchForParents(Share $share) { /** * Get the total permissions of an array of shares - * @param Share[] $shares + * @param \OC\Share\Share[] $shares * @return int */ protected function getTotalPermissions(array $shares) { @@ -426,8 +426,8 @@ protected function getTotalPermissions(array $shares) { /** * Get the latest expiration time of an array of shares - * @param Share[] $shares - * @return int|null + * @param \OC\Share\Share[] $shares + * @return int | null */ protected function getLatestExpirationTime(array $shares) { $latestTime = null; @@ -444,8 +444,8 @@ protected function getLatestExpirationTime(array $shares) { /** * Check if a share's permissions are valid with respect to the parent shares - * @param Share $share - * @throws InvalidPermissionsException + * @param \OC\Share\Share $share + * @throws \OC\Share\Exception\InvalidPermissionsException * @return bool */ protected function areValidPermissionsForParents(Share $share) { @@ -465,8 +465,8 @@ protected function areValidPermissionsForParents(Share $share) { /** * Check if a share's expiration time is valid with respect to the parent shares - * @param Share $share - * @throws InvalidExpirationTimeException + * @param \OC\Share\Share $share + * @throws \OC\Share\Exception\InvalidExpirationTimeException * @return bool */ protected function isValidExpirationTimeForParents(Share $share) { @@ -486,8 +486,8 @@ protected function isValidExpirationTimeForParents(Share $share) { /** * Update the reshares of a share to ensure consistency of permissions and expiration time - * @param Share $share - * @param Share $oldShare + * @param \OC\Share\Share $share + * @param \OC\Share\Share $oldShare * * The share has to be updated in the share backend before this is called * From f06ac6d4f297cd925c0afe42ca8b950a604194db Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 31 Jul 2013 18:32:25 -0400 Subject: [PATCH 34/85] Add ItemTargetMachine class and use it in the share types --- lib/share/itemtargetmachine.php | 39 ++++ lib/share/sharebackend.php | 10 - lib/share/sharetype/group.php | 81 +++++-- lib/share/sharetype/link.php | 21 +- lib/share/sharetype/user.php | 20 +- tests/lib/share/sharebackend.php | 5 - tests/lib/share/sharetype/group.php | 287 ++++++++++++++++-------- tests/lib/share/sharetype/link.php | 141 +++++++----- tests/lib/share/sharetype/sharetype.php | 50 +++-- tests/lib/share/sharetype/user.php | 157 ++++++++----- 10 files changed, 533 insertions(+), 278 deletions(-) create mode 100644 lib/share/itemtargetmachine.php 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/sharebackend.php b/lib/share/sharebackend.php index 68f60d60b524..84bf79e3d950 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -75,15 +75,6 @@ abstract public function getItemType(); */ abstract protected function isValidItem(Share $share); - - /** - * Generate an item target for the share with - * @param \OC\Share\Share $share - * @return string | array - */ - abstract protected function generateItemTarget(Share $share); - - /** * Get all share types * @return \OC\Share\ShareType\IShareType[] @@ -132,7 +123,6 @@ public function share(Share $share) { if ($shareType->isValidShare($share) && $this->areValidPermissions($share) && $this->isValidExpirationTime($share) ) { - $share->setItemTarget($this->generateItemTarget($share)); $this->emit('\OC\Share', 'preShare', array($share)); $share->setShareTime($this->timeMachine->getTime()); $share = $shareType->share($share); diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index f00fd4c95ee7..897ab1a9c015 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -23,6 +23,7 @@ use OC\Share\Share; use OC\Share\ShareFactory; +use OC\Share\ItemTargetMachine; use OC\Share\Exception\InvalidShareException; use OC\Group\Manager as GroupManager; use OC\User\Manager as UserManager; @@ -32,6 +33,7 @@ */ class Group extends Common { + protected $itemTargetMachine; protected $groupManager; protected $userManager; protected $groupTable; @@ -39,14 +41,16 @@ class Group extends Common { /** * The constructor * @param string $itemType - * @param ShareFactory $shareFactory - * @param GroupManager $groupManager - * @param UserManager $userManager + * @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, GroupManager $groupManager, - UserManager $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`'; @@ -80,15 +84,28 @@ public function isValidShare(Share $share) { } public function share(Share $share) { - $itemTargets = $share->getItemTarget(); - if (is_array($itemTargets)) { - // The first element is the default group item target - $share->setItemTarget(reset($itemTargets)); - } + $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); - $this->setItemTarget($share); + if (!empty($userItemTargets)) { + $this->setItemTarget($share); + } $share = $this->setShareDisplayNames($share); } return $share; @@ -96,7 +113,7 @@ public function share(Share $share) { /** * Update the share's item targets in the database - * @param Share $share + * @param \OC\Share\Share $share * * Group shares can have different item targets for users in the group * and are stored in a separate table @@ -140,13 +157,15 @@ public function setItemTarget(Share $share) { public function getShares(array $filter, $limit, $offset) { $shares = array(); - if (!isset($filter['shareWith']) - || (isset($filter['isShareWithGroup']) && $filter['isShareWithGroup'] === true) - ) { - unset($filter['isShareWithGroup']); + $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['isShareWithGroup']); + unset($filter['isShareWithUser']); + $isShareWithUser = true; $defaults = array( 'shareTypeId' => $this->getId(), 'itemType' => $this->itemType, @@ -158,8 +177,11 @@ public function getShares(array $filter, $limit, $offset) { foreach ($filter as $property => $value) { $column = Share::propertyToColumn($property); if ($property === 'shareWith') { + $groups = array(); $shareWithUser = $this->userManager->get($value); - $groups = $this->groupManager->getUserGroups($shareWithUser); + if ($shareWithUser) { + $groups = $this->groupManager->getUserGroups($shareWithUser); + } if (empty($groups)) { // The user has no groups, no group shares are possible return array(); @@ -209,10 +231,8 @@ public function getShares(array $filter, $limit, $offset) { foreach ($shares as &$share) { $userItemTargets = $this->getUserItemTargets($share->getId()); if (!empty($userItemTargets)) { - if (isset($filter['shareWith'])) { - if (isset($userItemTargets[$filter['shareWith']])) { - $share->setItemTarget($userItemTargets[$filter['shareWith']]); - } + if ($isShareWithUser && isset($userItemTargets[$filter['shareWith']])) { + $share->setItemTarget($userItemTargets[$filter['shareWith']]); } else { $itemTargets = array($share->getItemTarget()); $itemTargets['users'] = $userItemTargets; @@ -259,6 +279,19 @@ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $off 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)); @@ -271,8 +304,8 @@ protected function getUserItemTargets($id) { /** * Set the display names for the share owner and share with - * @param Share $share - * @return Share + * @param \OC\Share\Share $share + * @return \OC\Share\Share */ protected function setShareDisplayNames(Share $share) { $shareOwnerUser = $this->userManager->get($share->getShareOwner()); diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index 7282380723ec..a809676fa433 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -23,6 +23,7 @@ use OC\Share\Share; use OC\Share\ShareFactory; +use OC\Share\ItemTargetMachine; use OC\Share\Exception\InvalidShareException; use OC\User\Manager; use PasswordHash; @@ -32,6 +33,7 @@ */ class Link extends Common { + protected $itemTargetMachine; protected $userManager; protected $hasher; protected $linkTable; @@ -41,14 +43,16 @@ class Link extends Common { /** * The constructor * @param string $itemType - * @param ShareFactory $shareFactory - * @param Manager $userManager - * @param PasswordHash $hasher + * @param \OC\Share\ShareFactory $shareFactory + * @param \OC\Share\ItemTargetMachine $itemTargetMachine + * @param \OC\User\Manager $userManager + * @param \PasswordHash $hasher */ - public function __construct($itemType, ShareFactory $shareFactory, Manager $userManager, - PasswordHash $hasher + public function __construct($itemType, ShareFactory $shareFactory, + ItemTargetMachine $itemTargetMachine, Manager $userManager, PasswordHash $hasher ) { parent::__construct($itemType, $shareFactory); + $this->itemTargetMachine = $itemTargetMachine; $this->userManager = $userManager; $this->hasher = $hasher; $this->linksTable = '`*PREFIX*shares_links`'; @@ -71,6 +75,7 @@ public function isValidShare(Share $share) { } public function share(Share $share) { + $share->setItemTarget($this->itemTargetMachine->getItemTarget($share)); $share = parent::share($share); if ($share) { $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); @@ -93,7 +98,7 @@ public function unshare(Share $share) { /** * Update the share's password for the link in the database - * @param Share $share + * @param \OC\Share\Share $share */ public function setPassword(Share $share) { $password = $this->hashPassword($share->getPassword()); @@ -185,8 +190,8 @@ protected function hashPassword($password) { /** * Set the display name for the share owner - * @param Share $share - * @return Share + * @param \OC\Share\Share $share + * @return \OC\Share\Share */ protected function setShareDisplayName(Share $share) { $shareOwnerUser = $this->userManager->get($share->getShareOwner()); diff --git a/lib/share/sharetype/user.php b/lib/share/sharetype/user.php index e7188845f264..304d1d27b830 100644 --- a/lib/share/sharetype/user.php +++ b/lib/share/sharetype/user.php @@ -23,6 +23,7 @@ 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; @@ -32,20 +33,23 @@ */ class User extends Common { + protected $itemTargetMachine; protected $userManager; protected $groupManager; /** * The constructor * @param string $itemType - * @param ShareFactory $shareFactory - * @param UserManager $userManager - * @param GroupManager $groupManager + * @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, UserManager $userManager, - GroupManager $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; } @@ -85,6 +89,8 @@ public function isValidShare(Share $share) { } 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); @@ -142,8 +148,8 @@ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $off /** * Set the display names for the share owner and share with - * @param Share $share - * @return Share + * @param \OC\Share\Share $share + * @return \OC\Share\Share */ protected function setShareDisplayNames(Share $share) { $shareOwnerUser = $this->userManager->get($share->getShareOwner()); diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php index e6476dc940d4..4e53b559bb8f 100644 --- a/tests/lib/share/sharebackend.php +++ b/tests/lib/share/sharebackend.php @@ -42,10 +42,6 @@ protected function isValidItem(Share $share) { } } - protected function generateItemTarget(Share $share) { - return 'Item Target'; - } - public function setIsValidItem($isValidItem) { $this->isValidItem = $isValidItem; } @@ -155,7 +151,6 @@ public function testShare() { $share->resetUpdatedProperties(); $sharedShare = clone $share; $sharedShare->setShareTime(1370797580); - $sharedShare->setItemTarget('Item Target'); $userMap = array( array(array('shareOwner' => $mtgap, 'shareWith' => $icewind, 'itemSource' => $item), 1, null, array() diff --git a/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php index 940781fc42e4..4a9bb216febe 100644 --- a/tests/lib/share/sharetype/group.php +++ b/tests/lib/share/sharetype/group.php @@ -34,111 +34,228 @@ public function getId() { class Group extends ShareType { + private $itemTargetMachine; private $groupManager; private $userManager; - private $user1; - private $user2; - private $user3; + 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->groupManager, - $this->userManager + $this->instance = new TestGroup('test', new ShareFactory(), $this->itemTargetMachine, + $this->groupManager, $this->userManager ); } - protected function getTestShare() { - $mtgap = $this->getMockBuilder('\OC\User\User') + 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(); - $mtgap->expects($this->any()) + $mtgapUser->expects($this->any()) + ->method('getUID') + ->will($this->returnValue($this->mtgap)); + $mtgapUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Michael Gapczynski')); - $karlitschek = $this->getMockBuilder('\OC\User\User') + ->will($this->returnValue($this->mtgapDisplay)); + $karlitschekUser = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor() ->getMock(); - $karlitschek->expects($this->any()) + $karlitschekUser->expects($this->any()) + ->method('getUID') + ->will($this->returnValue($this->karlitschek)); + $karlitschekUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Frank Karlitschek')); - $icewind = $this->getMockBuilder('\OC\User\User') + ->will($this->returnValue($this->karlitschekDisplay)); + $icewindUser = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor() ->getMock(); - $icewind->expects($this->any()) + $icewindUser->expects($this->any()) + ->method('getUID') + ->will($this->returnValue($this->icewind)); + $icewindUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Robin Appelman')); - $map = array( - array('MTGap', $mtgap), - array('karlitschek', $karlitschek), - array('Icewind', $icewind), + ->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($map)); - $share = new Share(); - $share->setShareTypeId($this->instance->getId()); - $share->setShareOwner('MTGap'); - $share->setShareWith('friends'); - $share->setItemType('test'); - $share->setItemOwner('MTGap'); - $share->setItemSource('23'); - $share->setItemTarget('secrets'); - $share->setPermissions(31); - $share->setShareTime(1370797580); + ->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() { + protected function getSharedTestShare($version) { $share = new Share(); $share->setShareTypeId($this->instance->getId()); - $share->setShareOwner('MTGap'); - $share->setShareOwnerDisplayName('Michael Gapczynski'); - $share->setShareWith('friends'); - $share->setShareWithDisplayName('friends (group)'); $share->setItemType('test'); - $share->setItemOwner('MTGap'); $share->setItemSource('23'); - $share->setItemTarget('secrets'); $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; } - protected function setupTestShares() { - $this->user1 = 'MTGap'; - $this->user2 = 'karlitschek'; - $this->user3 = 'Icewind'; - $this->group1 = 'devs'; - $this->group2 = 'friends'; - - $this->share1 = $this->getTestShare(); - $this->share1->setShareOwner($this->user1); - $this->share1->setShareWith($this->group1); - $this->share1 = $this->instance->share($this->share1); - - $this->share2 = $this->getTestShare(); - $this->share2->setShareOwner($this->user1); - $this->share2->setShareWith($this->group2); - $this->share2 = $this->instance->share($this->share2); - - $this->share3 = $this->getTestShare(); - $this->share3->setShareOwner($this->user3); - $this->share3->setShareWith($this->group1); - $this->share3 = $this->instance->share($this->share3); - - $this->share4 = $this->getTestShare(); - $this->share4->setShareOwner($this->user2); - $this->share4->setShareWith($this->group2); - $this->share4->addParentId($this->share3->getId()); - $this->share4 = $this->instance->share($this->share4); - } - public function testIsValidShare() { $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global'); @@ -294,27 +411,8 @@ public function testIsValidShareWithShareOwnerNotInGroupAndGroupsOnlyPolicy() { \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy); } - public function testShareWithItemTargets() { - $itemTargets = array( - 'Group Item Target', - 'users' => array( - 'tpn' => 'tpn\'s Target', - 'bartv' => 'bartv\'s Target', - ), - ); - $share = $this->getTestShare(); - $share->setItemTarget($itemTargets); - $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 testSetItemTarget() { - $share = $this->getTestShare(); - $share->setItemTarget('Group Item Target'); + $share = $this->getTestShare(3); $share = $this->instance->share($share); $itemTargets = array( 'Group Item Target', @@ -338,6 +436,11 @@ public function testSetItemTarget() { $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() { @@ -352,7 +455,8 @@ public function testGetSharesWithShareWithFilter() { ->method('getUserGroups') ->will($this->returnValue(array($group1))); $filter = array( - 'shareWith' => $this->user3, + 'shareWith' => $this->icewind, + 'isShareWithUser' => true, ); $shares = $this->instance->getShares($filter, null, null); $this->assertCount(1, $shares); @@ -360,12 +464,13 @@ public function testGetSharesWithShareWithFilter() { } public function testGetSharesWithShareWithFilterAndNoGroups() { - $this->setupTestShares();- + $this->setupTestShares(); $this->groupManager->expects($this->once()) ->method('getUserGroups') ->will($this->returnValue(array())); $filter = array( - 'shareWith' => $this->user1, + 'shareWith' => $this->mtgap, + 'isShareWithUser' => true, ); $this->assertEmpty($this->instance->getShares($filter, null, null)); } @@ -552,4 +657,8 @@ public function testSearchForPotentialShareWithsWithLimitOffsetAndGroupsOnlyPoli \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/link.php b/tests/lib/share/sharetype/link.php index baa2b273cf31..b2e4387f8c51 100644 --- a/tests/lib/share/sharetype/link.php +++ b/tests/lib/share/sharetype/link.php @@ -34,99 +34,128 @@ public function getId() { class Link extends ShareType { + private $itemTargetMachine; private $userManager; 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->hasher = $this->getMockBuilder('\PasswordHash') ->disableOriginalConstructor() ->getMock(); - $this->instance = new TestLink('test', new ShareFactory(), $this->userManager, - $this->hasher + $this->instance = new TestLink('test', new ShareFactory(), $this->itemTargetMachine, + $this->userManager, $this->hasher ); } - protected function getTestShare() { - $mtgap = $this->getMockBuilder('\OC\User\User') + 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(); - $mtgap->expects($this->any()) + $mtgapUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Michael Gapczynski')); - $karlitschek = $this->getMockBuilder('\OC\User\User') + ->will($this->returnValue($this->mtgapDisplay)); + $karlitschekUser = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor() ->getMock(); - $karlitschek->expects($this->any()) + $karlitschekUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Frank Karlitschek')); - $icewind = $this->getMockBuilder('\OC\User\User') + ->will($this->returnValue($this->karlitschekDisplay)); + $icewindUser = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor() ->getMock(); - $icewind->expects($this->any()) + $icewindUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Robin Appelman')); + ->will($this->returnValue($this->icewindDisplay)); $map = array( - array('MTGap', $mtgap), - array('karlitschek', $karlitschek), - array('Icewind', $icewind), + array($this->mtgap, $mtgapUser), + array($this->karlitschek, $karlitschekUser), + array($this->icewind, $icewindUser), ); $this->userManager->expects($this->atLeastOnce()) ->method('get') ->will($this->returnValueMap($map)); - $share = new Share(); - $share->setShareTypeId($this->instance->getId()); - $share->setShareOwner('MTGap'); - $share->setShareWith(null); - $share->setItemType('test'); - $share->setItemOwner('MTGap'); - $share->setItemSource('23'); - $share->setItemTarget('secrets'); - $share->setPermissions(31); - $share->setShareTime(1370797580); + switch ($version) { + case 1: + $share->setShareOwner($this->mtgap); + $share->setItemOwner($this->mtgap); + break; + case 2: + $share->setShareOwner($this->mtgap); + $share->setItemOwner($this->mtgap); + break; + case 3: + $share->setShareOwner($this->icewind); + $share->setItemOwner($this->icewind); + break; + case 4: + $share->setShareOwner($this->karlitschek); + $share->setItemOwner($this->karlitschek); + break; + } return $share; } - protected function getSharedTestShare() { - // TODO Fix token + protected function getSharedTestShare($version) { + // TODO Set token $share = new Share(); $share->setShareTypeId($this->instance->getId()); - $share->setShareOwner('MTGap'); - $share->setShareOwnerDisplayName('Michael Gapczynski'); - $share->setShareWith(null); $share->setItemType('test'); - $share->setItemOwner('MTGap'); $share->setItemSource('23'); - $share->setItemTarget('secrets'); + $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); + break; + case 2: + $share->setShareOwner($this->mtgap); + $share->setItemOwner($this->mtgap); + $share->setShareOwnerDisplayName($this->mtgapDisplay); + break; + case 3: + $share->setShareOwner($this->icewind); + $share->setItemOwner($this->icewind); + $share->setShareOwnerDisplayName($this->icewindDisplay); + break; + case 4: + $share->setShareOwner($this->karlitschek); + $share->setItemOwner($this->karlitschek); + $share->setShareOwnerDisplayName($this->karlitschekDisplay); + break; + } return $share; } - protected function setupTestShares() { - $this->user1 = 'MTGap'; - $this->user2 = 'karlitschek'; - $this->user3 = 'Icewind'; - $this->share1 = $this->getTestShare(); - $this->share1->setShareOwner($this->user1); - $this->share1 = $this->instance->share($this->share1); - - $this->share2 = $this->getTestShare(); - $this->share2->setShareOwner($this->user1); - $this->share2 = $this->instance->share($this->share2); - - $this->share3 = $this->getTestShare(); - $this->share3->setShareOwner($this->user3); - $this->share3 = $this->instance->share($this->share3); - - $this->share4 = $this->getTestShare(); - $this->share4->setShareOwner($this->user2); - $this->share4->addParentId($this->share3->getId()); - $this->share4 = $this->instance->share($this->share4); - } - public function testIsValidShare() { $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes'); \OC_Appconfig::setValue('core', 'shareapi_allow_links', 'yes'); @@ -191,7 +220,7 @@ public function testIsValidShareWithLinkSharingDisabled() { } public function testShareWithPassword() { - $share = $this->getTestShare(); + $share = $this->getTestShare(1); $share->setPassword('password'); $this->hasher->expects($this->once()) ->method('HashPassword') @@ -205,7 +234,7 @@ public function testShareWithPassword() { } public function testSetPassword() { - $share = $this->getTestShare(); + $share = $this->getTestShare(2); $share = $this->instance->share($share); $this->hasher->expects($this->once()) ->method('HashPassword') diff --git a/tests/lib/share/sharetype/sharetype.php b/tests/lib/share/sharetype/sharetype.php index a3363d6bc5b2..a97f814933e3 100644 --- a/tests/lib/share/sharetype/sharetype.php +++ b/tests/lib/share/sharetype/sharetype.php @@ -30,30 +30,43 @@ abstract class ShareType extends \PHPUnit_Framework_TestCase { protected $share4; /** - * Get a share with fake data - * @return Share + * 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(); + abstract protected function getTestShare($version); /** * Get the same share as getTestShare, but as expected after being shared - * @return Share + * @param int $version 1-4 Return a unique share for each version number + * @return \OC\Share\Share */ - abstract protected function getSharedTestShare(); + abstract protected function getSharedTestShare($version); /** - * Setup four shares with fake data assigned to their respective class property - * The fourth share has the third share as a parent (even if it doesn't make sense) + * Setup four shares with fake data */ - abstract protected function setupTestShares(); + 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(); - $sharedShare = $this->getSharedTestShare(); + $share = $this->getTestShare(1); + $sharedShare = $this->getSharedTestShare(1); $share = $this->instance->share($share); $this->assertNotNull($share->getId()); $this->assertEquals(array(), $share->getUpdatedProperties()); @@ -64,9 +77,9 @@ public function testShare() { } public function testShareWithParents() { - $share = $this->getTestShare(); + $share = $this->getTestShare(2); $share->setParentIds(array(1, 3)); - $sharedShare = $this->getSharedTestShare(); + $sharedShare = $this->getSharedTestShare(2); $share = $this->instance->share($share); $this->assertNotNull($share->getId()); $this->assertEquals(array(), $share->getUpdatedProperties()); @@ -78,7 +91,7 @@ public function testShareWithParents() { } public function testUnshare() { - $share = $this->getTestShare(); + $share = $this->getTestShare(3); $share = $this->instance->share($share); $this->assertEquals($share, $this->getShareById($share->getId())); $this->instance->unshare($share); @@ -86,7 +99,7 @@ public function testUnshare() { } public function testUpdate() { - $share = $this->getTestShare(); + $share = $this->getTestShare(4); $share = $this->instance->share($share); $share->setPermissions(1); $this->instance->update($share); @@ -95,7 +108,7 @@ public function testUpdate() { } public function testUpdateTwoProperties() { - $share = $this->getTestShare(); + $share = $this->getTestShare(2); $share = $this->instance->share($share); $share->setPermissions(21); $share->setExpirationTime(1370884027); @@ -105,7 +118,7 @@ public function testUpdateTwoProperties() { } public function testSetParentIds() { - $share = $this->getTestShare(); + $share = $this->getTestShare(1); $share->setParentIds(array(1, 2)); $share = $this->instance->share($share); $share->setParentIds(array(2, 3, 4)); @@ -135,6 +148,9 @@ public function testGetSharesWithLimitOffset() { 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(), ); @@ -146,7 +162,7 @@ public function testGetSharesWithParentId() { /** * Get a share from the share type based on id * @param int $id - * @return Share|bool + * @return \OC\Share\Share | bool */ protected function getShareById($id) { $share = $this->instance->getShares(array('id' => $id), 1, null); diff --git a/tests/lib/share/sharetype/user.php b/tests/lib/share/sharetype/user.php index b66c8a71beef..41e58f9b4be2 100644 --- a/tests/lib/share/sharetype/user.php +++ b/tests/lib/share/sharetype/user.php @@ -34,106 +34,139 @@ public function getId() { class User extends ShareType { + private $itemTargetMachine; private $userManager; private $groupManager; - private $user1; - private $user2; - private $user3; + 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->userManager, - $this->groupManager + $this->instance = new TestUser('test', new ShareFactory(), $this->itemTargetMachine, + $this->userManager, $this->groupManager ); } - protected function getTestShare() { - $mtgap = $this->getMockBuilder('\OC\User\User') + 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(); - $mtgap->expects($this->any()) + $mtgapUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Michael Gapczynski')); - $karlitschek = $this->getMockBuilder('\OC\User\User') + ->will($this->returnValue($this->mtgapDisplay)); + $karlitschekUser = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor() ->getMock(); - $karlitschek->expects($this->any()) + $karlitschekUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Frank Karlitschek')); - $icewind = $this->getMockBuilder('\OC\User\User') + ->will($this->returnValue($this->karlitschekDisplay)); + $icewindUser = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor() ->getMock(); - $icewind->expects($this->any()) + $icewindUser->expects($this->any()) ->method('getDisplayName') - ->will($this->returnValue('Robin Appelman')); + ->will($this->returnValue($this->icewindDisplay)); $map = array( - array('MTGap', $mtgap), - array('karlitschek', $karlitschek), - array('Icewind', $icewind), + array($this->mtgap, $mtgapUser), + array($this->karlitschek, $karlitschekUser), + array($this->icewind, $icewindUser), ); $this->userManager->expects($this->atLeastOnce()) ->method('get') ->will($this->returnValueMap($map)); - $share = new Share(); - $share->setShareTypeId($this->instance->getId()); - $share->setShareOwner('MTGap'); - $share->setShareWith('karlitschek'); - $share->setItemType('test'); - $share->setItemOwner('MTGap'); - $share->setItemSource('23'); - $share->setItemTarget('secrets'); - $share->setPermissions(31); - $share->setShareTime(1370797580); + 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() { + protected function getSharedTestShare($version) { $share = new Share(); $share->setShareTypeId($this->instance->getId()); - $share->setShareOwner('MTGap'); - $share->setShareOwnerDisplayName('Michael Gapczynski'); - $share->setShareWith('karlitschek'); - $share->setShareWithDisplayName('Frank Karlitschek'); $share->setItemType('test'); - $share->setItemOwner('MTGap'); $share->setItemSource('23'); - $share->setItemTarget('secrets'); + $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; } - protected function setupTestShares() { - $this->user1 = 'MTGap'; - $this->user2 = 'karlitschek'; - $this->user3 = 'Icewind'; - $this->share1 = $this->getTestShare(); - $this->share1->setShareOwner($this->user1); - $this->share1->setShareWith($this->user2); - $this->share1 = $this->instance->share($this->share1); - - $this->share2 = $this->getTestShare(); - $this->share2->setShareOwner($this->user1); - $this->share2->setShareWith($this->user3); - $this->share2 = $this->instance->share($this->share2); - - $this->share3 = $this->getTestShare(); - $this->share3->setShareOwner($this->user3); - $this->share3->setShareWith($this->user2); - $this->share3 = $this->instance->share($this->share3); - - $this->share4 = $this->getTestShare(); - $this->share4->setShareOwner($this->user2); - $this->share4->setShareWith($this->user1); - $this->share4->addParentId($this->share3->getId()); - $this->share4 = $this->instance->share($this->share4); - } - public function testIsValidShare() { $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); \OC_Appconfig::setValue('core', 'shareapi_share_policy', 'global'); @@ -301,7 +334,7 @@ public function testIsValidShareWithShareOwnerNotInShareWithGroupsAndGroupsOnlyP public function testGetSharesWithFilter() { $this->setupTestShares(); $filter = array( - 'shareWith' => $this->user2, + 'shareWith' => $this->karlitschek, ); $shares = $this->instance->getShares($filter, null, null); $this->assertCount(2, $shares); From 856b15216e645e62f7bf9ee586dd42414fc9174d Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 31 Jul 2013 18:32:57 -0400 Subject: [PATCH 35/85] Fix docs in IShareType --- lib/share/sharetype/isharetype.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/share/sharetype/isharetype.php b/lib/share/sharetype/isharetype.php index d572cbd0a47c..c2d660870725 100644 --- a/lib/share/sharetype/isharetype.php +++ b/lib/share/sharetype/isharetype.php @@ -36,28 +36,28 @@ public function getId(); /** * Check if this share is valid for this share type - * @param Share $share + * @param \OC\Share\Share $share * @return bool - * @throws InvalidShareException + * @throws \OC\Share\Exception\InvalidShareException */ public function isValidShare(Share $share); /** * Insert the share into the database - * @param Share $share - * @return Share + * @param \OC\Share\Share $share + * @return \OC\Share\Share */ public function share(Share $share); /** * Remove the share from the database - * @param Share $share + * @param \OC\Share\Share $share */ public function unshare(Share $share); /** * Update the share's properties in the database - * @param Share $share + * @param \OC\Share\Share $share */ public function update(Share $share); @@ -66,7 +66,7 @@ public function update(Share $share); * @param array $filter A key => value array of share properties * @param int $limit * @param int $offset - * @return Share[] + * @return \OC\Share\Share[] */ public function getShares(array $filter, $limit, $offset); From 13a0fde8f3a00e088aa35689863895a3bb2d12b0 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 31 Jul 2013 21:55:24 -0400 Subject: [PATCH 36/85] Add GroupWatcher --- lib/share/sharetype/groupwatcher.php | 163 ++++++++ tests/lib/share/sharetype/groupwatcher.php | 431 +++++++++++++++++++++ 2 files changed, 594 insertions(+) create mode 100644 lib/share/sharetype/groupwatcher.php create mode 100644 tests/lib/share/sharetype/groupwatcher.php 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/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 From 3427159bb344f1c4eeff8ef9ec4b2f65f250ecce Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 2 Aug 2013 12:10:55 -0400 Subject: [PATCH 37/85] Fix clear query for other database backends --- lib/share/sharetype/common.php | 5 ++--- lib/share/sharetype/group.php | 5 ++--- lib/share/sharetype/link.php | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/share/sharetype/common.php b/lib/share/sharetype/common.php index c81370b8afe9..987319ef3130 100644 --- a/lib/share/sharetype/common.php +++ b/lib/share/sharetype/common.php @@ -174,9 +174,8 @@ public function getShares(array $filter, $limit, $offset) { public function clear() { $sql = 'DELETE FROM '.$this->table.' WHERE `share_type_id` = ?'; \OC_DB::executeAudited($sql, array($this->getId())); - $sql = 'DELETE FROM '.$this->parentsTable.' USING '.$this->parentsTable.' '. - 'LEFT JOIN '.$this->table.' ON '.$this->parentsTable.'.`id` = '.$this->table.'.`id` '. - 'WHERE '.$this->table.'.`id` IS NULL'; + $sql = 'DELETE FROM '.$this->parentsTable.' WHERE '.$this->parentsTable.'.`id` NOT IN '. + ' (SELECT `id` FROM '.$this->table.')'; \OC_DB::executeAudited($sql); } diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index 897ab1a9c015..3b9b54a0829f 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -246,9 +246,8 @@ public function getShares(array $filter, $limit, $offset) { public function clear() { parent::clear(); - $sql = 'DELETE FROM '.$this->groupsTable.' USING '.$this->groupsTable.' '. - 'LEFT JOIN '.$this->table.' ON '.$this->groupsTable.'.`id` = '.$this->table.'.`id` '. - 'WHERE '.$this->table.'.`id` IS NULL'; + $sql = 'DELETE FROM '.$this->groupsTable.' WHERE '.$this->groupsTable.'.`id` NOT IN '. + ' (SELECT `id` FROM '.$this->table.')'; \OC_DB::executeAudited($sql); } diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index a809676fa433..c9d6b9bc3c37 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -164,9 +164,8 @@ public function getShares(array $filter, $limit, $offset) { public function clear() { parent::clear(); - $sql = 'DELETE FROM '.$this->linksTable.' USING '.$this->linksTable.' '. - 'LEFT JOIN '.$this->table.' ON '.$this->linksTable.'.`id` = '.$this->table.'.`id` '. - 'WHERE '.$this->table.'.`id` IS NULL'; + $sql = 'DELETE FROM '.$this->linksTable.' WHERE '.$this->linksTable.'.`id` NOT IN '. + ' (SELECT `id` FROM '.$this->table.')'; \OC_DB::executeAudited($sql); } From d40b0554e5a4be1210a9e9f2142295ef488e17b7 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 3 Aug 2013 10:40:52 -0400 Subject: [PATCH 38/85] Use actual getters and setters for Share object --- lib/share/share.php | 366 +++++++++++++++++++++++++++++++------- tests/lib/share/share.php | 24 +-- 2 files changed, 302 insertions(+), 88 deletions(-) diff --git a/lib/share/share.php b/lib/share/share.php index f0a0f3e5f4c5..e0f20f28cffa 100644 --- a/lib/share/share.php +++ b/lib/share/share.php @@ -28,7 +28,7 @@ * Extend this class to store additional properties * * Adapated from OCA\AppFramework\Db\Entity - * + * Only setters that call markPropertyUpdated are mutable properties */ class Share { @@ -58,32 +58,222 @@ class Share { ); /** - * Get all properties in an array + * 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 toAPI() { - return array( - 'id' => $this->id, - 'parentIds' => $this->parentIds, - 'shareTypeId' => $this->shareTypeId, - 'shareOwner' => $this->shareOwner, - 'shareOwnerDisplayName' => $this->shareOwnerDisplayName, - 'shareWith' => $this->shareWith, - 'shareWithDisplayName' => $this->shareWithDisplayName, - 'itemType' => $this->itemType, - 'itemSource' => $this->itemSource, - 'itemTarget' => $this->itemTarget, - 'itemOwner' => $this->itemOwner, - 'permissions' => $this->permissions, - 'expirationTime' => $this->expirationTime, - 'shareTime' => $this->shareTime, - 'token' => $this->token, - 'password' => $this->password, - ); + 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'); } /** - * Check if the share has create permission + * 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() { @@ -91,7 +281,7 @@ public function isCreatable() { } /** - * Check if the share has read permission + * Check if read permission is granted * @return bool */ public function isReadable() { @@ -99,7 +289,7 @@ public function isReadable() { } /** - * Check if the share has update permission + * Check if update permission is granted * @return bool */ public function isUpdatable() { @@ -107,7 +297,7 @@ public function isUpdatable() { } /** - * Check if the share has delete permission + * Check if delete permission is granted * @return bool */ public function isDeletable() { @@ -115,7 +305,7 @@ public function isDeletable() { } /** - * Check if the share has share permission + * Check if share permission is granted * @return bool */ public function isSharable() { @@ -123,21 +313,94 @@ public function isSharable() { } /** - * Add a reference to a parent share - * @param Share $share + * Get the expiration time + * @return int */ - public function addParentId($id) { - $this->parentIds[] = $id; - $this->markPropertyUpdated('parentIds'); + public function getExpirationTime() { + return $this->expirationTime; } /** - * Remove a reference to a parent share - * @param Share $share + * Set the expiration time + * @param int $expirationTime */ - public function removeParentId($id) { - $this->parentIds = array_diff($this->parentIds, array($id)); - $this->markPropertyUpdated('parentIds'); + 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(), + ); } /** @@ -172,37 +435,6 @@ public static function fromRow(array $row) { return $instance; } - /** - * Each time a setter is called, push the part after set - * into an array: for instance setId will save Id in the - * updated fields array so it can be easily used to create the - * getter method - */ - public function __call($methodName, $args) { - // setters - if (strpos($methodName, 'set') === 0) { - $property = lcfirst(substr($methodName, 3)); - // setters should only work for existing attributes - if (property_exists($this, $property)) { - $this->markPropertyUpdated($property); - $this->$property = $args[0]; - } else { - throw new \BadFunctionCallException($property.' is not a valid property'); - } - // getters - } else if (strpos($methodName, 'get') === 0) { - $property = lcfirst(substr($methodName, 3)); - // getters should only work for existing attributes - if (property_exists($this, $property)) { - return $this->$property; - } else { - throw new \BadFunctionCallException($property.' is not a valid property'); - } - } else { - throw new \BadFunctionCallException($methodName.' does not exist'); - } - } - /** * Mark a property as updated * @param string $property the name of the property diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index 894be8fdd25f..57bf79786dbc 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -172,33 +172,15 @@ public function testGetSetId() { $this->assertEquals($id, $share->getId()); } - public function testCallShouldOnlyWorkForGetterSetter() { - $this->setExpectedException('\BadFunctionCallException'); - $share = new Share(); - $share->something(); - } - - public function testGetterShouldFailIfPropertyNotDefined() { - $this->setExpectedException('\BadFunctionCallException'); - $share = new Share(); - $share->getTest(); - } - - public function testSetterShouldFailIfPropertyNotDefined() { - $this->setExpectedException('\BadFunctionCallException'); - $share = new Share(); - $share->setTest(); - } - public function testSetterMarksPropertyUpdated() { $share = new Share(); - $share->setId(3); - $this->assertContains('id', $share->getUpdatedProperties()); + $share->setParentIds(array(1, 3)); + $this->assertContains('parentIds', $share->getUpdatedProperties()); } public function testResetUpdatedProperties() { $share = new Share(); - $share->setId(3); + $share->setParentIds(array(1, 3)); $share->resetUpdatedProperties(); $this->assertEmpty($share->getUpdatedProperties()); } From f8df6495cc33385e3008819a4103f7899340a6e3 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 3 Aug 2013 12:20:11 -0400 Subject: [PATCH 39/85] Fix link tests --- lib/share/sharetype/link.php | 19 +++++++++++++++++-- tests/lib/share/sharetype/link.php | 28 +++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index c9d6b9bc3c37..1567d4721a81 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -28,6 +28,17 @@ use OC\User\Manager; use PasswordHash; +/** + * Temporary class - waiting for an injectable Util + */ +class TokenMachine { + + public function getToken($length) { + return \OC_Util::generate_random_bytes($length); + } + +} + /** * Controller for shares between a user and the public via a link */ @@ -35,6 +46,7 @@ class Link extends Common { protected $itemTargetMachine; protected $userManager; + protected $tokenMachine; protected $hasher; protected $linkTable; @@ -46,14 +58,17 @@ class Link extends Common { * @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, PasswordHash $hasher + 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`'; } @@ -78,7 +93,7 @@ public function share(Share $share) { $share->setItemTarget($this->itemTargetMachine->getItemTarget($share)); $share = parent::share($share); if ($share) { - $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); + $token = $this->tokenMachine->getToken(self::TOKEN_LENGTH); $password = $this->hashPassword($share->getPassword()); $sql = 'INSERT INTO '.$this->linksTable.' (`id`, `token`, `password`)'. 'VALUES (?, ?, ?)'; diff --git a/tests/lib/share/sharetype/link.php b/tests/lib/share/sharetype/link.php index b2e4387f8c51..9293517a6f9e 100644 --- a/tests/lib/share/sharetype/link.php +++ b/tests/lib/share/sharetype/link.php @@ -36,6 +36,8 @@ class Link extends ShareType { private $itemTargetMachine; private $userManager; + private $tokenMachine; + private $counter; private $hasher; private $mtgap; private $mtgapDisplay; @@ -60,11 +62,15 @@ protected function setUp() { $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->hasher + $this->userManager, $this->tokenMachine, $this->hasher ); } @@ -101,29 +107,41 @@ protected function getTestShare($version) { $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) { - // TODO Set token $share = new Share(); $share->setShareTypeId($this->instance->getId()); $share->setItemType('test'); @@ -136,21 +154,25 @@ protected function getSharedTestShare($version) { $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; @@ -255,7 +277,7 @@ public function testGetSharesWithFilter() { $this->assertContains($this->share2, $shares, '', false, false); $filter = array( - 'shareOwner' => $this->user1, + 'shareOwner' => $this->mtgap, ); $shares = $this->instance->getShares($filter, null, null); $this->assertCount(2, $shares); From a4eb979c2c060e78ed72d522410aa41d4550c2c8 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 5 Aug 2013 18:28:26 -0400 Subject: [PATCH 40/85] Add getItemTypePlural method to ShareBackend for the RESTful API --- lib/share/sharebackend.php | 8 +++++++- tests/lib/share/sharebackend.php | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index 84bf79e3d950..e0f352d95077 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -61,11 +61,17 @@ public function __construct(TimeMachine $timeMachine, array $shareTypes) { } /** - * Get the identifier for the item type this backend handles + * 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 diff --git a/tests/lib/share/sharebackend.php b/tests/lib/share/sharebackend.php index 4e53b559bb8f..0f5a9f6041c3 100644 --- a/tests/lib/share/sharebackend.php +++ b/tests/lib/share/sharebackend.php @@ -32,6 +32,10 @@ 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( From 7fdce9bca4a18d551da139f597b119b642217b25 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 5 Aug 2013 18:32:18 -0400 Subject: [PATCH 41/85] Add Share type to parameter for areValidPermissions in ShareBackend --- lib/share/sharebackend.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/share/sharebackend.php b/lib/share/sharebackend.php index e0f352d95077..6f39009ba72f 100644 --- a/lib/share/sharebackend.php +++ b/lib/share/sharebackend.php @@ -252,7 +252,7 @@ public function isExpired(Share $share) { * You can use PHP's bitwise operators to manipulate the permissions * */ - protected function areValidPermissions($share) { + protected function areValidPermissions(Share $share) { $permissions = $share->getPermissions(); if (!is_int($permissions)) { throw new InvalidPermissionsException('The permissions are not an integer'); From fda99c4a3bd633b2df6b49ca6d5aafbf80b0b857 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 5 Aug 2013 18:34:06 -0400 Subject: [PATCH 42/85] Use getShareBackends method rather than the field in ShareManager --- lib/share/sharemanager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index 39f0278c61b1..788a4f8e8789 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -240,7 +240,7 @@ public function getShareById($id, $itemType = null, $shareTypeId = null) { if (isset($itemType)) { $share = $this->getShares($itemType, $filter, 1); } else { - foreach ($this->shareBackends as $shareBackend) { + foreach ($this->getShareBackends() as $shareBackend) { try { $share = $this->getShares($shareBackend->getItemType(), $filter, 1); if (!empty($share)) { @@ -321,7 +321,7 @@ public function getParents(Share $share) { if (!empty($parentIds)) { $itemType = $share->getItemType(); $parentItemTypes = array($itemType); - foreach ($this->shareBackends as $shareBackend) { + foreach ($this->getShareBackends() as $shareBackend) { if ($shareBackend instanceof CollectionShareBackend && in_array($itemType, $shareBackend->getChildrenItemTypes()) && !in_array($shareBackend->getItemType(), $parentItemTypes) @@ -400,7 +400,7 @@ protected function searchForParents(Share $share) { ); $parents = $this->getShares($itemType, $filter); // Search in collections for parents in case children were reshared - foreach ($this->shareBackends as $shareBackend) { + foreach ($this->getShareBackends() as $shareBackend) { if ($shareBackend instanceof CollectionShareBackend && in_array($itemType, $shareBackend->getChildrenItemTypes()) ) { From aa3c1a09cbd342f93f988914a1a9ab1ba3deb94e Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 5 Aug 2013 19:40:11 -0400 Subject: [PATCH 43/85] Change CollectionShareBackend into an interface --- ...ackend.php => icollectionsharebackend.php} | 35 +++++++------------ lib/share/sharemanager.php | 6 ++-- tests/lib/share/sharemanager.php | 15 ++++++-- 3 files changed, 28 insertions(+), 28 deletions(-) rename lib/share/{collectionsharebackend.php => icollectionsharebackend.php} (55%) diff --git a/lib/share/collectionsharebackend.php b/lib/share/icollectionsharebackend.php similarity index 55% rename from lib/share/collectionsharebackend.php rename to lib/share/icollectionsharebackend.php index c0e1109796ec..a917983d5f4e 100644 --- a/lib/share/collectionsharebackend.php +++ b/lib/share/icollectionsharebackend.php @@ -26,37 +26,26 @@ use OC\Share\TimeMachine; /** - * Backend class that apps extend and register with the ShareManager to share content - * This class should be used if the app has content that can have children that are also shared - * using a different backend class e.g. folders + * 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 class name scope - * - preShare(Share $share) - * - postShare(Share $share) - * - preUnshare(Share $share) - * - postUnshare(Share $share) - * - preUpdate(Share $share) - * - postUpdate(Share $share) + * 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 CollectionShareBackend extends ShareBackend { - - /** - * The constructor - * @param TimeMachine $timeMachine The time() mock - * @param array $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); - } +interface ICollectionShareBackend { /** * Get the identifiers for the children item types of this backend * @return array */ - abstract public function getChildrenItemTypes(); + public function getChildrenItemTypes(); /** * Search for shares of this collection item type that contain the child item source and @@ -65,6 +54,6 @@ abstract public function getChildrenItemTypes(); * @param any $itemSource * @return array */ - abstract public function searchForChildren($shareWith, $itemSource); + public function searchForChildren($shareWith, $itemSource); } \ No newline at end of file diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index 788a4f8e8789..c0783cde3e3e 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -295,7 +295,7 @@ public function getReshares(Share $share) { ); $reshares = $this->getShares($itemType, $filter); $shareBackend = $this->getShareBackend($itemType); - if ($shareBackend instanceof CollectionShareBackend) { + if ($shareBackend instanceof ICollectionShareBackend) { // Find reshares in children item types foreach ($shareBackend->getChildrenItemTypes() as $childItemType) { $childReshares = $this->getShares($childItemType, $filter); @@ -322,7 +322,7 @@ public function getParents(Share $share) { $itemType = $share->getItemType(); $parentItemTypes = array($itemType); foreach ($this->getShareBackends() as $shareBackend) { - if ($shareBackend instanceof CollectionShareBackend + if ($shareBackend instanceof ICollectionShareBackend && in_array($itemType, $shareBackend->getChildrenItemTypes()) && !in_array($shareBackend->getItemType(), $parentItemTypes) ) { @@ -401,7 +401,7 @@ protected function searchForParents(Share $share) { $parents = $this->getShares($itemType, $filter); // Search in collections for parents in case children were reshared foreach ($this->getShareBackends() as $shareBackend) { - if ($shareBackend instanceof CollectionShareBackend + if ($shareBackend instanceof ICollectionShareBackend && in_array($itemType, $shareBackend->getChildrenItemTypes()) ) { $collectionParents = $shareBackend->searchForChildren($shareOwner, $itemSource); diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index c3c3c28f1fda..0dfb5045ae9c 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -36,6 +36,11 @@ public function pIsValidExpirationTimeForParents(Share $share) { } +abstract class CollectionShareBackend extends \OC\Share\ShareBackend + implements \OC\Share\ICollectionShareBackend { + +} + class ShareManager extends \PHPUnit_Framework_TestCase { private $shareBackend; @@ -58,17 +63,23 @@ protected function setUp() { $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('\OC\Share\CollectionShareBackend') + $this->collectionShareBackend = $this->getMockBuilder('\Test\Share\CollectionShareBackend') ->disableOriginalConstructor() - ->setMethods(get_class_methods('\OC\Share\CollectionShareBackend')) + ->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)); From b9ad9ba18fc71f3dddf1fda381bae3f862f1b462 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 6 Aug 2013 12:14:26 -0400 Subject: [PATCH 44/85] Change searchForChildren to searchForParentCollections in ICollectionShareBackend --- lib/share/icollectionsharebackend.php | 11 +++--- lib/share/sharemanager.php | 18 ++++++---- tests/lib/share/sharemanager.php | 50 +++++++++++++++++++-------- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/lib/share/icollectionsharebackend.php b/lib/share/icollectionsharebackend.php index a917983d5f4e..874adc90844d 100644 --- a/lib/share/icollectionsharebackend.php +++ b/lib/share/icollectionsharebackend.php @@ -22,8 +22,6 @@ namespace OC\Share; use OC\Share\Share; -use OC\Share\ShareBackend; -use OC\Share\TimeMachine; /** * This interface should be implemented if a share backend has content that can have children that @@ -49,11 +47,10 @@ public function getChildrenItemTypes(); /** * Search for shares of this collection item type that contain the child item source and - * shared with $shareWith - * @param string $shareWith - * @param any $itemSource - * @return array + * shared with the share owner + * @param \OC\Share\Share $share + * @return \OC\Share\Share[] */ - public function searchForChildren($shareWith, $itemSource); + public function searchForParentCollections(Share $share); } \ No newline at end of file diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index c0783cde3e3e..a83b99dc8479 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -392,11 +392,9 @@ protected function searchForReshares(Share $share) { */ protected function searchForParents(Share $share) { $itemType = $share->getItemType(); - $shareOwner = $share->getShareOwner(); - $itemSource = $share->getItemSource(); $filter = array( - 'shareWith' => $shareOwner, - 'itemSource' => $itemSource, + 'shareWith' => $share->getShareOwner(), + 'itemSource' => $share->getItemSource(), ); $parents = $this->getShares($itemType, $filter); // Search in collections for parents in case children were reshared @@ -404,8 +402,16 @@ protected function searchForParents(Share $share) { if ($shareBackend instanceof ICollectionShareBackend && in_array($itemType, $shareBackend->getChildrenItemTypes()) ) { - $collectionParents = $shareBackend->searchForChildren($shareOwner, $itemSource); - $parents = array_merge($parents, $collectionParents); + $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; diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index 0dfb5045ae9c..de7e416fa7b9 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -466,6 +466,7 @@ public function testShareWithOneParentInCollection() { $jancborchardt = 'jancborchardt'; $danimo = 'danimo'; $dragotin = 'dragotin'; + $group = 'group'; $item = 1; $collectionItem = 2; $share = new Share(); @@ -479,34 +480,53 @@ public function testShareWithOneParentInCollection() { $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('testCollection'); - $parent->setItemSource($collectionItem); - $parent->setPermissions(31); + $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, '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($danimo, $item, array($parent)), + array($share, array($parent1, $parent2)), ); - $collectionMap = array( - array(array('id' => 1), 1, null, array($parent)), + $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('searchForChildren') + ->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)); @@ -613,7 +633,7 @@ public function testShareCollectionWithExistingReshares() { array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare1)), ); $childMap = array( - array($anybodyelse, $item, array($duplicate, $share)), + array($reshare1, array($duplicate, $share)), ); $this->collectionShareBackend->expects($this->atLeastOnce()) ->method('getShares') @@ -623,7 +643,7 @@ public function testShareCollectionWithExistingReshares() { ->with($this->equalTo($share)) ->will($this->returnValue($share)); $this->collectionShareBackend->expects($this->atLeastOnce()) - ->method('searchForChildren') + ->method('searchForParentCollections') ->will($this->returnValueMap($childMap)); $this->collectionShareBackend->expects($this->once()) ->method('update') From cd1f4bf4326a3001089de05c99c33fd070110b39 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 7 Aug 2013 10:08:21 -0400 Subject: [PATCH 45/85] Don't pass table name to insertid for Oracle --- lib/share/sharetype/common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/share/sharetype/common.php b/lib/share/sharetype/common.php index 987319ef3130..5955d3b01377 100644 --- a/lib/share/sharetype/common.php +++ b/lib/share/sharetype/common.php @@ -68,7 +68,7 @@ public function share(Share $share) { $columns = join(',', $columns); $sql = 'INSERT INTO '.$this->table.' ('.$columns.') VALUES ('.$placeholders.')'; $result = \OC_DB::executeAudited($sql, $params); - $id = (int)\OC_DB::insertid($this->table); + $id = (int)\OC_DB::insertid(); $share->setId($id); $share->resetUpdatedProperties(); $this->setParentIds($share); From 7f4fbc516c886cc75e56e922428f93b9917c586c Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 9 Aug 2013 19:36:11 -0400 Subject: [PATCH 46/85] Add addType method to Share from App Framework --- lib/share/share.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/share/share.php b/lib/share/share.php index e0f20f28cffa..2b12aea11635 100644 --- a/lib/share/share.php +++ b/lib/share/share.php @@ -494,4 +494,14 @@ public static function propertyToColumn($property) { 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 From 10c641cc8af9adb830878c677daa2111af103c78 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 9 Aug 2013 19:38:10 -0400 Subject: [PATCH 47/85] Move temp TokenMachine class outside because the autoloader is having trouble finding it --- lib/share/sharetype/link.php | 11 ---------- lib/share/sharetype/tokenmachine.php | 33 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 lib/share/sharetype/tokenmachine.php diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index 1567d4721a81..4a8e0281b555 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -28,17 +28,6 @@ use OC\User\Manager; use PasswordHash; -/** - * Temporary class - waiting for an injectable Util - */ -class TokenMachine { - - public function getToken($length) { - return \OC_Util::generate_random_bytes($length); - } - -} - /** * Controller for shares between a user and the public via a link */ 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 From a3aace4d95bacd9787fd3a260e8705778b986eb5 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 9 Aug 2013 19:39:50 -0400 Subject: [PATCH 48/85] Fix AdvancedShareFactory namespace in share types --- lib/share/sharetype/common.php | 1 + lib/share/sharetype/group.php | 1 + lib/share/sharetype/link.php | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/share/sharetype/common.php b/lib/share/sharetype/common.php index 5955d3b01377..c4602abe3447 100644 --- a/lib/share/sharetype/common.php +++ b/lib/share/sharetype/common.php @@ -23,6 +23,7 @@ use OC\Share\Share; use OC\Share\ShareFactory; +use OC\Share\AdvancedShareFactory; abstract class Common implements IShareType { diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index 3b9b54a0829f..080f8364f0a8 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -23,6 +23,7 @@ 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; diff --git a/lib/share/sharetype/link.php b/lib/share/sharetype/link.php index 4a8e0281b555..feaf67649331 100644 --- a/lib/share/sharetype/link.php +++ b/lib/share/sharetype/link.php @@ -23,6 +23,7 @@ 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; From c6be03f634c03a20f4d96556f940443db8f41313 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 9 Aug 2013 19:41:24 -0400 Subject: [PATCH 49/85] Unset isShareWithUser filter in common share type --- lib/share/sharetype/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/share/sharetype/common.php b/lib/share/sharetype/common.php index c4602abe3447..8e19f788c99a 100644 --- a/lib/share/sharetype/common.php +++ b/lib/share/sharetype/common.php @@ -130,6 +130,7 @@ public function getShares(array $filter, $limit, $offset) { 'shareTypeId' => $this->getId(), 'itemType' => $this->itemType, ); + unset($filter['isShareWithUser']); $filter = array_merge($defaults, $filter); $where = ''; $params = array(); From adeb61f2fd76f9d13f70d65752f3982300991331 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 9 Aug 2013 19:55:54 -0400 Subject: [PATCH 50/85] Initial port of files_sharing app to Share API 2 --- apps/files_sharing/appinfo/app.php | 86 +++- apps/files_sharing/lib/cache.php | 228 ++++++--- apps/files_sharing/lib/permissions.php | 82 ++-- apps/files_sharing/lib/share/file.php | 179 ------- apps/files_sharing/lib/share/fileshare.php | 252 ++++++++++ .../lib/share/filesharebackend.php | 95 ++++ .../lib/share/filesharefactory.php | 79 ++++ .../lib/share/filesharefetcher.php | 253 ++++++++++ .../lib/share/filetargetmachine.php | 44 ++ apps/files_sharing/lib/share/folder.php | 51 -- .../lib/share/foldersharebackend.php | 105 +++++ apps/files_sharing/lib/sharedstorage.php | 437 +++++++++--------- apps/files_sharing/lib/watcher.php | 6 +- core/ajax/share.php | 244 +++++----- lib/files/mount/mount.php | 2 +- lib/public/share.php | 83 +++- 16 files changed, 1518 insertions(+), 708 deletions(-) delete mode 100644 apps/files_sharing/lib/share/file.php create mode 100644 apps/files_sharing/lib/share/fileshare.php create mode 100644 apps/files_sharing/lib/share/filesharebackend.php create mode 100644 apps/files_sharing/lib/share/filesharefactory.php create mode 100644 apps/files_sharing/lib/share/filesharefetcher.php create mode 100644 apps/files_sharing/lib/share/filetargetmachine.php delete mode 100644 apps/files_sharing/lib/share/folder.php create mode 100644 apps/files_sharing/lib/share/foldersharebackend.php diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 9363a5431faa..40abcc32c51b 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -1,18 +1,74 @@ . + */ -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'); \ No newline at end of file +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'; + +// \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'); + +$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); +// 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/lib/cache.php b/apps/files_sharing/lib/cache.php index 2160fe9a393b..a0cc9e1575d4 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,43 +21,44 @@ 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 $numericId; + 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(); + $this->numericId = $cache->getNumericStorageId(); + return array($cache, $internalPath); } - return false; + return array(null, null); } public function getNumericStorageId() { @@ -75,33 +76,73 @@ 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); + $this->fetcher->setETag($etag); } - $data['etag'] = $etag; - return $data; + return array( + 'fileid' => -1, + 'storage' => null, + 'path' => 'files/Shared', + '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 if (is_string($file)) { - if ($cache = $this->getSourceCache($file)) { - return $cache->get($this->files[$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->getMetadata(); + } + } + if (!empty($shares)) { + list($cache, $internalPath) = $this->getSourceCache($file); + if ($cache && $internalPath) { + return $cache->get($internalPath); + } } } 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']); - return $data; + $shares = $this->fetcher->getById($file); + foreach ($shares as $share) { + // Check if we have an exact share for this id + if ($share->getItemSource() === $file) { + return $share->getMetadata(); + } + } + if (!empty($shares)) { + return parent::get($file); + } } return false; } @@ -113,19 +154,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 +189,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 +209,19 @@ 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 === '') { + return -1; + } + $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 +233,7 @@ public function getId($file) { * @return bool */ public function inCache($file) { - if ($file == '') { + if ($file === '') { return true; } return parent::inCache($file); @@ -177,8 +245,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,11 +258,11 @@ 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); + list( , $newInternalPath) = $this->fetcher->resolvePath(dirname($target)); + if ($cache && $oldInternalPath && $newInternalPath) { + $newInternalPath .= '/'.basename($target); + $cache->move($oldInternalPath, $newInternalPath); } } @@ -210,11 +279,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; } @@ -260,8 +330,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 +347,12 @@ 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(); + foreach ($shares as $share) { + $ids[] = $share->getItemSource(); + } + return array_unique($ids); } /** diff --git a/apps/files_sharing/lib/permissions.php b/apps/files_sharing/lib/permissions.php index b6638564cd82..01c8468c4ce6 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..1fc1a4f3db90 --- /dev/null +++ b/apps/files_sharing/lib/share/fileshare.php @@ -0,0 +1,252 @@ +. + */ + +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('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' => 'files/Shared/'.$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..c1ef65c5c8fe --- /dev/null +++ b/apps/files_sharing/lib/share/filesharebackend.php @@ -0,0 +1,95 @@ +. + */ + +namespace OCA\Files\Share; + +use OC\Share\Share; +use OC\Share\ShareBackend; +use OC\Share\Exception\InvalidItemException; +use OC\Share\Exception\InvalidPermissionsException; + +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) { + $path = \OC\Files\Filesystem::getPath($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); + $path = \OC\Files\Filesystem::getPath($share->getItemSource()); + $permissions = 0; + // TODO Move to view + if (\OC\Files\Filesystem::isCreatable($path)) { + $permissions |= \OCP\PERMISSION_CREATE; + } + if (\OC\Files\Filesystem::isReadable($path)) { + $permissions |= \OCP\PERMISSION_READ; + } + if (\OC\Files\Filesystem::isUpdatable($path)) { + $permissions |= \OCP\PERMISSION_UPDATE; + } + if (\OC\Files\Filesystem::isDeletable($path)) { + $permissions |= \OCP\PERMISSION_DELETE; + } + if (\OC\Files\Filesystem::isSharable($path)) { + $permissions |= \OCP\PERMISSION_SHARE; + } + if ($share->getPermissions() & ~$permissions) { + 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..5ffc6e350562 --- /dev/null +++ b/apps/files_sharing/lib/share/filesharefetcher.php @@ -0,0 +1,253 @@ +. + */ + +namespace OCA\Files\Share; + +use OC\Share\ShareManager; + +/** + * Class to retrieve file shares for a user from the ShareManager + * + * These are helper methods used by the shared storage, cache, permissions, etc. + */ +class FileShareFetcher { + + protected $shareManager; + protected $uid; + protected $fileItemType; + protected $folderItemType; + + /** + * The constructor + * @param \OC\Share\ShareManager $shareManager + * @param string $uid + */ + public function __construct(ShareManager $shareManager, $uid) { + $this->shareManager = $shareManager; + $this->uid = $uid; + $this->fileItemType = 'file'; + $this->folderItemType = 'folder'; + } + + /** + * Get all files shares for the user + * @return \OCA\Files\Share\FileShare[] + */ + public function getAll() { + $filter = array( + 'shareWith' => $this->uid, + '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 for the user + * @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() { + return \OCP\Config::getUserValue($this->uid, 'files_sharing', 'etag'); + } + + /** + * Set the ETag of the Shared folder for the user + * @param string $etag + */ + public function setETag($etag) { + \OCP\Config::setUserValue($this->uid, 'files_sharing', 'etag', $etag); + } + + /** + * Get all files shares specified by path + * @param string $path + * @return \OCA\Files\Share\FileShare[] + * + * The returned file shares may not be exact shares for the path, but parent folders + * + */ + public function getByPath($path) { + $shares = array(); + $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( + 'shareWith' => $this->uid, + 'isShareWithUser' => true, + 'itemSource' => $fileId, + ); + $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 shared path to a storage and internal path + * @param string $path + * @return array Consisting of \OC\Files\Storage\Storage and the internal path + */ + 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 path + * @param string $path + * @return int + */ + 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 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) { + $filter = array( + 'shareWith' => $this->uid, + 'isShareWithUser' => true, + ); + 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..f0936c711e04 --- /dev/null +++ b/apps/files_sharing/lib/share/filetargetmachine.php @@ -0,0 +1,44 @@ +. + */ + +namespace OCA\Files\Share; + +use OC\Share\Share; +use OC\Share\ItemTargetMachine; +use OC\User\User; + +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) { + $path = \OC\Files\Filesystem::getPath($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..d85efa7b7ca4 --- /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 = $share->getItemSource(); + while ($fileId !== -1) { + $fileId = $this->getParentFolderId($fileId); + $filter['itemSource'] = $fileId; + $parents = array_merge($parents, $this->getShares($filter)); + } + 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 5c23a9eb0d0a..7bc9cb5a87bb 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,151 @@ 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(); +class Shared extends Common { - public function __construct($arguments) { - $this->sharedFolder = $arguments['sharedFolder']; - } - - 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, $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 +177,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 +229,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 +297,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 +306,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 +339,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 +363,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\FREE_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\FREE_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/watcher.php b/apps/files_sharing/lib/watcher.php index e67d1ee9086f..2b8ba5c25761 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/core/ajax/share.php b/core/ajax/share.php index bdcb61284ecd..9a8ee26fe372 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,25 +62,61 @@ 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'; } - $return = OCP\Share::unshare($_POST['itemType'], $_POST['itemSource'], $_POST['shareType'], $shareWith); - ($return) ? OC_JSON::success() : OC_JSON::error(); + $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(); + } + 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': @@ -126,7 +170,8 @@ switch ($_GET['fetch']) { case 'getItemsSharedStatuses': if (isset($_GET['itemType'])) { - $return = OCP\Share::getItemsShared($_GET['itemType'], OCP\Share::FORMAT_STATUSES); + // $return = OCP\Share::getItemsShared($_GET['itemType'], OCP\Share::FORMAT_STATUSES); + $return = array(); is_array($return) ? OC_JSON::success(array('data' => $return)) : OC_JSON::error(); } break; @@ -135,105 +180,82 @@ && isset($_GET['itemSource']) && isset($_GET['checkReshare']) && isset($_GET['checkShares'])) { - if ($_GET['checkReshare'] == 'true') { - $reshare = OCP\Share::getItemSharedWithBySource( - $_GET['itemType'], - $_GET['itemSource'], - OCP\Share::FORMAT_NONE, - null, - true - ); - } else { - $reshare = false; - } + // if ($_GET['checkReshare'] == 'true') { + // $reshare = OCP\Share::getItemSharedWithBySource( + // $_GET['itemType'], + // $_GET['itemSource'], + // OCP\Share::FORMAT_NONE, + // null, + // true + // ); + // } else { + $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; + } + $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(), + ); + } } 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/lib/files/mount/mount.php b/lib/files/mount/mount.php index 17b0055ee846..914defd3a257 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/public/share.php b/lib/public/share.php index 63645e6fa34b..c23a53480de3 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,53 @@ 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'); + } 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; + // } + + // public static function update() { + // $shareManager = self::getShareManager(); + // if ($shareManager) { + // $updater = new \OC\Share\Updater($shareManager, new \OC\Log()); + // $updater->updateAll(); + // } + // } + /** + * @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 +143,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 +158,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 +176,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 +279,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 +293,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 +307,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 +321,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 +334,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 +349,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 +512,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 @@ -1288,8 +1343,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, @@ -1299,15 +1352,8 @@ 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) { - throw new \Exception($error); - } - if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { @@ -1383,8 +1429,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, @@ -1394,15 +1438,8 @@ 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) { - throw new \Exception($error); - } - if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { From 1020cecc3b86c6884bb7e1c384fbbe533f3d4d3c Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 19 Aug 2013 10:37:06 -0400 Subject: [PATCH 51/85] Check if method exists for fromParams and fromRow constructors in Share --- lib/share/share.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/share/share.php b/lib/share/share.php index 2b12aea11635..510ef073b4e5 100644 --- a/lib/share/share.php +++ b/lib/share/share.php @@ -412,8 +412,10 @@ public function toAPI() { public static function fromParams(array $params) { $instance = new static(); foreach ($params as $property => $value) { - $method = 'set'.ucfirst($property); - $instance->$method($value); + $setter = 'set'.ucfirst($property); + if (method_exists($instance, $setter)) { + $instance->$setter($value); + } } return $instance; } @@ -426,11 +428,13 @@ public static function fromRow(array $row) { $instance = new static(); foreach ($row as $column => $value) { $property = $instance::columnToProperty($column); - if (isset($value) && isset($instance->propertyTypes[$property])) { - settype($value, $instance->propertyTypes[$property]); + $setter = 'set'.ucfirst($property); + if (method_exists($instance, $setter)) { + if (isset($value) && isset($instance->propertyTypes[$property])) { + settype($value, $instance->propertyTypes[$property]); + } + $instance->$setter($value); } - $method = 'set'.ucfirst($property); - $instance->$method($value); } return $instance; } From b8c2a7418d0b5f8641a0fc5e166e525b19b94aaf Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 19 Aug 2013 10:38:50 -0400 Subject: [PATCH 52/85] Add updater for old shares --- lib/share/updater.php | 120 ++++++++++++++++++++++++++++++++++++++++++ lib/updater.php | 9 ++++ 2 files changed, 129 insertions(+) create mode 100644 lib/share/updater.php diff --git a/lib/share/updater.php b/lib/share/updater.php new file mode 100644 index 000000000000..917492af2984 --- /dev/null +++ b/lib/share/updater.php @@ -0,0 +1,120 @@ +. + */ + +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; + + /** + * 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() { + $this->logger->notice('Started update of shares to Share API 2'); + $sql = 'SELECT `id`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. + '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS `share_time`, '. + '`expiration` AS `expiration_time`, `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'); + } + + /** + * Update the share specified by the $row + * @param array $row + */ + protected function updateShare($row) { + $id = $row['id']; + $token = null; + $password = null; + unset($row['id']); + 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'; + $token = $row['token']; + if (isset($row['share_with'])) { + $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; + } + unset($row['share_type']); + if (isset($row['file_source'])) { + $row['item_source'] = $row['file_source']; + } + unset($row['file_source']); + settype($row['permissions'], 'int'); + settype($row['share_time'], 'int'); + if (isset($row['expiration_time'])) { + $date = new DateTime($row['expiration_time']); + $row['expiration_time'] = $date->getTimeStamp(); + } + try { + $share = Share::fromRow($row); + $this->shareManager->share($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, $id)); + } + } catch (Exception $exception) { + $this->logger->error('Unable to update share with id: '.$id.' '. + 'because of an exception: '.$exception->getMessage(), array('app' => 'core') + ); + } + } + } + +} \ 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'); } From 191db11555bb945fbd7c992ae811071acdd754c8 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 19 Aug 2013 12:10:48 -0400 Subject: [PATCH 53/85] Bump version --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util.php b/lib/util.php index 971c76e51a61..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, 06); + return array(5, 80, 07); } /** From 35092a168d97729306d8db90b227bdc6f732d9f5 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 20 Aug 2013 13:44:01 -0400 Subject: [PATCH 54/85] Emit old sharing hooks --- lib/public/share.php | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/lib/public/share.php b/lib/public/share.php index c23a53480de3..0bcd2ef9a6c3 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -78,6 +78,7 @@ public static function getShareManager() { self::$shareManager = new ShareManager(); \OC_Util::addScript('core', 'share'); \OC_Util::addStyle('core', 'share'); + self::setupHooks(); } else { self::$shareManager = null; } @@ -111,6 +112,78 @@ public static function getShareManager() { // } // } + /** + * Emit old hooks for backwards compatibility + */ + public static function setupHooks() { + $shareManager = self::getShareManager(); + if ($shareManager) { + self::$shareManager->listen('\OC\Share', 'preShare', function($share) { + \OC_Hook::emit('OCP\Share', 'pre_shared', self::getHookArray($share)); + }); + self::$shareManager->listen('\OC\Share', 'postShare', function($share) { + \OC_Hook::emit('OCP\Share', 'post_shared', self::getHookArray($share)); + }); + self::$shareManager->listen('\OC\Share', 'preUnshare', function($share) { + $params = self::getHookArray($share); + $params['itemParent'] = $params['parent']; + \OC_Hook::emit('OCP\Share', 'pre_unshare', $params); + }); + self::$shareManager->listen('\OC\Share', 'postUnshare', function($share) { + $params = self::getHookArray($share); + $params['itemParent'] = $params['parent']; + \OC_Hook::emit('OCP\Share', 'post_unshare', $params); + }); + self::$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') { + $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; + } + $parentIds = $share->getParentIds(); + return array( + 'itemType' => $share->getItemType(), + 'itemSource' => $share->getItemSource(), + 'itemTarget' => $itemTarget, + 'parent' => reset($parentIds), + '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 From 9988d390dbfad3a183745ca9b0f35b921d55a260 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 20 Aug 2013 13:44:51 -0400 Subject: [PATCH 55/85] Port files_encryption to Share API 2 --- apps/files_encryption/lib/util.php | 59 ++++++++++++- apps/files_encryption/tests/share.php | 115 ++++++++++++++++++++++---- 2 files changed, 154 insertions(+), 20 deletions(-) diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index b8d686234939..4a7ba850e268 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,61 @@ 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; + $shareManager = \OCP\Share::getShareManager(); + if ($shareManager) { + $view = new \OC\Files\View('/' . $user . '/files/'); + $meta = $view->getFileInfo(\OC\Files\Filesystem::normalizePath($path)); + $fileId = -1; + if ($meta !== false) { + $fileId = $meta['fileid']; + $cache = new \OC\Files\Cache\Cache($meta['storage']); + } + if ($meta['mimetype'] === 'httpd/unix-directory') { + $itemType = 'folder'; + } else { + $itemType = 'file'; + } + $filter = array(); + while ($fileId !== -1) { + $filter['itemSource'] = $fileId; + $shares = $shareManager->getShares($itemType, $filter); + foreach ($shares as $share) { + $shareTypeId = $share->getShareTypeId(); + if ($shareTypeId === 'user') { + $users[] = $share->getShareWith(); + } else if ($shareTypeId === 'group') { + $usersInGroup = \OC_Group::usersInGroup($share->getShareWith()); + $users = array_merge($users, $usersInGroup); + } else if ($shareTypeId === 'link') { + $public = true; + } + } + $meta = $cache->get((int)$fileId); + if ($meta !== false) { + $fileId = (int)$meta['parent']; + } else { + $fileId = -1; + } + } + } + if ($includeOwner) { + $users[] = $user; + } + return array('users' => array_unique($users), 'public' => $public); + } + private function getUserWithAccessToMountPoint($users, $groups) { $result = array(); if (in_array('all', $users)) { @@ -1605,7 +1660,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 59d4adc6fee7..1e49ebf5bc5f 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -32,6 +32,7 @@ require_once realpath(dirname(__FILE__) . '/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( From 7d7aebde4c7254945d906c84203ea3b005fa346d Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 20 Aug 2013 17:41:40 -0400 Subject: [PATCH 56/85] Add tests for FileShareFecther --- .../lib/share/filesharefetcher.php | 1 + .../lib/share/foldersharebackend.php | 4 +- apps/files_sharing/tests/filesharefetcher.php | 319 ++++++++++++++++++ 3 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 apps/files_sharing/tests/filesharefetcher.php diff --git a/apps/files_sharing/lib/share/filesharefetcher.php b/apps/files_sharing/lib/share/filesharefetcher.php index 5ffc6e350562..d83761ffb727 100644 --- a/apps/files_sharing/lib/share/filesharefetcher.php +++ b/apps/files_sharing/lib/share/filesharefetcher.php @@ -240,6 +240,7 @@ protected function getParentFolders($fileId) { 'shareWith' => $this->uid, 'isShareWithUser' => true, ); + $fileId = $folderShareBackend->getParentFolderId($fileId); while ($fileId !== -1) { $filter['itemSource'] = $fileId; $folderShares = $this->shareManager->getShares($this->folderItemType, $filter); diff --git a/apps/files_sharing/lib/share/foldersharebackend.php b/apps/files_sharing/lib/share/foldersharebackend.php index d85efa7b7ca4..a9e2ec73edce 100644 --- a/apps/files_sharing/lib/share/foldersharebackend.php +++ b/apps/files_sharing/lib/share/foldersharebackend.php @@ -78,11 +78,11 @@ public function searchForParentCollections(Share $share) { 'isShareWithUser' => true, ); // Loop through parent folders and check if they are shared - $fileId = $share->getItemSource(); + $fileId = $this->getParentFolderId($share->getItemSource()); while ($fileId !== -1) { - $fileId = $this->getParentFolderId($fileId); $filter['itemSource'] = $fileId; $parents = array_merge($parents, $this->getShares($filter)); + $fileId = $this->getParentFolderId($fileId); } return $parents; } diff --git a/apps/files_sharing/tests/filesharefetcher.php b/apps/files_sharing/tests/filesharefetcher.php new file mode 100644 index 000000000000..66c78bcb6609 --- /dev/null +++ b/apps/files_sharing/tests/filesharefetcher.php @@ -0,0 +1,319 @@ +. + */ + +namespace Test\Share; + +use OCA\Files\Share\FileShare; + +class FileShareFetcher extends \PHPUnit_Framework_TestCase { + + protected $matt; + protected $shareManager; + protected $folderShareBackend; + protected $fetcher; + + protected function setUp() { + $this->matt = 'MTRichards'; + $this->shareManager = $this->getMockBuilder('\OC\Share\ShareManager') + ->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->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('shareWith' => $this->matt, 'isShareWithUser' => true, + 'itemSource' => 79), 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('shareWith' => $this->matt, 'isShareWithUser' => true, + 'itemSource' => 80), null, null, array() + ), + array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true, + 'itemSource' => 80), 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('shareWith' => $this->matt, 'isShareWithUser' => true, + 'itemSource' => 72), 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('shareWith' => $this->matt, 'isShareWithUser' => true, + 'itemSource' => 80), null, null, array() + ), + array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true, + 'itemSource' => 80), 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)); + } + +} \ No newline at end of file From 3d4099609692c3f0463328df8506cabdaaf6640a Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 21 Aug 2013 09:32:02 -0400 Subject: [PATCH 57/85] Revert initial permissions change --- core/js/share.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/js/share.js b/core/js/share.js index e7fb26d0ed8f..123e2d2ea0f6 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(''); From 53ce1297e96f1bb8ef1d75d587b21c3c6f5cad9a Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 21 Aug 2013 10:22:01 -0400 Subject: [PATCH 58/85] Fix share updater for files --- apps/files_sharing/lib/share/filesharebackend.php | 2 ++ lib/share/updater.php | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/apps/files_sharing/lib/share/filesharebackend.php b/apps/files_sharing/lib/share/filesharebackend.php index c1ef65c5c8fe..cf5a4af99a0f 100644 --- a/apps/files_sharing/lib/share/filesharebackend.php +++ b/apps/files_sharing/lib/share/filesharebackend.php @@ -52,6 +52,7 @@ public function getItemTypePlural() { * @return bool */ protected function isValidItem(Share $share) { + \OC\Files\Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); $path = \OC\Files\Filesystem::getPath($share->getItemSource()); if (!isset($path)) { throw new InvalidItemException('The file does not exist in the filesystem'); @@ -68,6 +69,7 @@ protected function isValidItem(Share $share) { */ protected function areValidPermissions(Share $share) { parent::areValidPermissions($share); + \OC\Files\Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); $path = \OC\Files\Filesystem::getPath($share->getItemSource()); $permissions = 0; // TODO Move to view diff --git a/lib/share/updater.php b/lib/share/updater.php index 917492af2984..f822b0c3b5b9 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -95,6 +95,10 @@ protected function updateShare($row) { } unset($row['file_source']); settype($row['permissions'], 'int'); + if ($row['item_type'] === 'file') { + // Remove Create permission from files + $row['permissions'] &= ~4; + } settype($row['share_time'], 'int'); if (isset($row['expiration_time'])) { $date = new DateTime($row['expiration_time']); From c4aebcbad1a4c2570b2b24b763453f0cf108dd87 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 21 Aug 2013 10:52:43 -0400 Subject: [PATCH 59/85] Perform update only once --- lib/share/updater.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/share/updater.php b/lib/share/updater.php index f822b0c3b5b9..0f5d4ad0cd29 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -48,15 +48,19 @@ public function __construct(ShareManager $shareManager, Log $logger) { * Update all shares */ public function updateAll() { - $this->logger->notice('Started update of shares to Share API 2'); - $sql = 'SELECT `id`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. - '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS `share_time`, '. - '`expiration` AS `expiration_time`, `token` FROM `*PREFIX*share`'; - $result = \OC_DB::executeAudited($sql); - while ($row = $result->fetchRow()) { - $this->updateShare($row); + $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`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. + '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS '. + '`share_time`, `expiration` AS `expiration_time`, `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'); } - $this->logger->notice('Finished update of shares to Share API 2'); } /** From 75efb7e9318eee1cdbe3decf69cd3d101c254398 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:54:58 -0400 Subject: [PATCH 60/85] Smarter share updater to handle reshares --- lib/share/updater.php | 147 +++++++++++++++++++++++++++++++++++------- 1 file changed, 125 insertions(+), 22 deletions(-) diff --git a/lib/share/updater.php b/lib/share/updater.php index 0f5d4ad0cd29..81f501f450f5 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -33,6 +33,7 @@ class Updater { private $shareManager; private $logger; private $shareTypeGroupUserUnique = 2; + private $updatedShares; /** * The constructor @@ -51,10 +52,11 @@ 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`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. - '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS '. - '`share_time`, `expiration` AS `expiration_time`, `token` FROM `*PREFIX*share`'; + $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); + $updated = array(); while ($row = $result->fetchRow()) { $this->updateShare($row); } @@ -66,12 +68,71 @@ public function updateAll() { /** * Update the share specified by the $row * @param array $row + * @return \OC\Share\Share | false */ protected function updateShare($row) { $id = $row['id']; - $token = null; - $password = null; + 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 @@ -82,18 +143,19 @@ protected function updateShare($row) { $row['share_type_id'] = 'group'; } else if ($row['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { $row['share_type_id'] = 'link'; - $token = $row['token']; if (isset($row['share_with'])) { - $password = $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; + 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']; } @@ -103,26 +165,67 @@ protected function updateShare($row) { // 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_time'])) { - $date = new DateTime($row['expiration_time']); + if (isset($row['expiration'])) { + $date = new DateTime($row['expiration']); $row['expiration_time'] = $date->getTimeStamp(); } - try { - $share = Share::fromRow($row); - $this->shareManager->share($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, $id)); + 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; } - } catch (Exception $exception) { - $this->logger->error('Unable to update share with id: '.$id.' '. - 'because of an exception: '.$exception->getMessage(), array('app' => 'core') - ); } } + return $parentRows; } } \ No newline at end of file From 1b0109fbe29bbe0eadc03ce88bd42214a3338a81 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:57:04 -0400 Subject: [PATCH 61/85] Be more careful with variables in getHookArray --- lib/public/share.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/public/share.php b/lib/public/share.php index 0bcd2ef9a6c3..acb913127602 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -156,7 +156,9 @@ public static function setupHooks() { public static function getHookArray($share) { $itemTarget = $share->getItemTarget(); if ($share->getShareTypeId() === 'group') { - $itemTarget = reset($itemTarget); + if (is_array($itemTarget)) { + $itemTarget = reset($itemTarget); + } } $shareType = null; $shareTypeId = $share->getShareTypeId(); @@ -167,12 +169,16 @@ public static function getHookArray($share) { } 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' => reset($parentIds), + 'parent' => $parent, 'shareType' => $shareType, 'shareWith' => $share->getShareWith(), 'uidOwner' => $share->getShareOwner(), From f2598394f1b83d6761878dfa36dab84f483d585d Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:57:34 -0400 Subject: [PATCH 62/85] Fix searchForParents --- lib/share/sharemanager.php | 1 + tests/lib/share/sharemanager.php | 54 +++++++++++++++++--------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index a83b99dc8479..aede75fb954d 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -394,6 +394,7 @@ protected function searchForParents(Share $share) { $itemType = $share->getItemType(); $filter = array( 'shareWith' => $share->getShareOwner(), + 'isShareWithUser' => true, 'itemSource' => $share->getItemSource(), ); $parents = $this->getShares($itemType, $filter); diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index de7e416fa7b9..8968c51296b1 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -144,8 +144,8 @@ public function testShareWithOneParent() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, - array($parent) + 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, @@ -189,8 +189,8 @@ public function testShareWithOneParentAndResharingDisabled() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $blizzz, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $blizzz, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -230,8 +230,8 @@ public function testShareWithOneParentWithoutSharePermission() { $parent->setItemSource($item); $parent->setPermissions(15); $map = array( - array(array('shareWith' => $blizzz, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $blizzz, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -270,8 +270,8 @@ public function testShareWithOneParentAndReshareBackToOwner() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -309,8 +309,8 @@ public function testShareWithOneParentAndReshareWithSamePeople() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -362,8 +362,8 @@ public function testShareWithTwoParents() { $parent2->setItemSource($item); $parent2->setPermissions(31); $map = array( - array(array('shareWith' => $anybodyelse, 'itemSource' => $item), null, null, - array($parent1, $parent2) + 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)), @@ -431,13 +431,14 @@ public function testShareWithExistingReshares() { $updatedReshare = clone $reshare; $updatedReshare->addParentId(3); $map = array( - array(array('shareWith' => $mtgap, 'itemSource' => $item), null, null, 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, 'itemSource' => $item), null, null, - array($duplicate, $share) + array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true, + 'itemSource' => $item), null, null, array($duplicate, $share) ), array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare)), ); @@ -499,7 +500,8 @@ public function testShareWithOneParentInCollection() { $parent2->setItemSource($collectionItem); $parent2->setPermissions(31); $sharesMap = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, 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) @@ -610,25 +612,25 @@ public function testShareCollectionWithExistingReshares() { $reshare3->resetUpdatedProperties(); $updatedReshare3 = clone $reshare3; $collectionMap = array( - array(array('shareWith' => $mtgap, 'itemSource' => $collectionItem), null, null, - 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, 'itemSource' => $collectionItem), null, null, - array($duplicate, $share) + array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true, + 'itemSource' => $collectionItem), null, null, array($duplicate, $share) ), - array(array('shareWith' => $dragotin, 'itemSource' => $collectionItem), null, null, - array($duplicate) + 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, 'itemSource' => $item), null, null, - array() + array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true, + 'itemSource' => $item), null, null, array() ), array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare1)), ); @@ -1281,8 +1283,8 @@ public function testUpdateResharesWithSharePermissionAdded() { array($parent1, $parent2) ), array(array('parentId' => 5), null, null, array($reshare1, $reshare2)), - array(array('shareWith' => $DeepDiver, 'itemSource' => $item), null, null, - array($parent1, $parent2) + 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)), From 6d8da59e63552e302ab73d284f12e3af73e4c9f6 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:59:44 -0400 Subject: [PATCH 63/85] Remove unused variable --- lib/share/updater.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/share/updater.php b/lib/share/updater.php index 81f501f450f5..56070dfb4eb2 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -56,7 +56,6 @@ public function updateAll() { '`item_source`, `file_source`, `permissions`, `stime`, `expiration`, `token` '. 'FROM `*PREFIX*share`'; $result = \OC_DB::executeAudited($sql); - $updated = array(); while ($row = $result->fetchRow()) { $this->updateShare($row); } From ff2bcecf1ae3cbbe4777f9bff61d226f136be100 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 20 Aug 2013 13:44:01 -0400 Subject: [PATCH 64/85] Emit old sharing hooks Conflicts: lib/public/share.php --- lib/public/share.php | 111 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/lib/public/share.php b/lib/public/share.php index 63645e6fa34b..7120609baa18 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -63,7 +63,118 @@ 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) { + self::$shareManager->listen('\OC\Share', 'preShare', function($share) { + \OC_Hook::emit('OCP\Share', 'pre_shared', self::getHookArray($share)); + }); + self::$shareManager->listen('\OC\Share', 'postShare', function($share) { + \OC_Hook::emit('OCP\Share', 'post_shared', self::getHookArray($share)); + }); + self::$shareManager->listen('\OC\Share', 'preUnshare', function($share) { + $params = self::getHookArray($share); + $params['itemParent'] = $params['parent']; + \OC_Hook::emit('OCP\Share', 'pre_unshare', $params); + }); + self::$shareManager->listen('\OC\Share', 'postUnshare', function($share) { + $params = self::getHookArray($share); + $params['itemParent'] = $params['parent']; + \OC_Hook::emit('OCP\Share', 'post_unshare', $params); + }); + self::$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') { + $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; + } + $parentIds = $share->getParentIds(); + return array( + 'itemType' => $share->getItemType(), + 'itemSource' => $share->getItemSource(), + 'itemTarget' => $itemTarget, + 'parent' => reset($parentIds), + '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 From bd26e0a2b596bea9fd725586949bd4dc12cc77ba Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 21 Aug 2013 10:52:43 -0400 Subject: [PATCH 65/85] Perform update only once --- lib/share/updater.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/share/updater.php b/lib/share/updater.php index 917492af2984..dcb31f397d89 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -48,15 +48,19 @@ public function __construct(ShareManager $shareManager, Log $logger) { * Update all shares */ public function updateAll() { - $this->logger->notice('Started update of shares to Share API 2'); - $sql = 'SELECT `id`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. - '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS `share_time`, '. - '`expiration` AS `expiration_time`, `token` FROM `*PREFIX*share`'; - $result = \OC_DB::executeAudited($sql); - while ($row = $result->fetchRow()) { - $this->updateShare($row); + $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`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. + '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS '. + '`share_time`, `expiration` AS `expiration_time`, `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'); } - $this->logger->notice('Finished update of shares to Share API 2'); } /** From 1321158825bd6789fc120e3c467cd609b3e0b002 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:54:58 -0400 Subject: [PATCH 66/85] Smarter share updater to handle reshares Conflicts: lib/share/updater.php --- lib/share/updater.php | 151 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 129 insertions(+), 22 deletions(-) diff --git a/lib/share/updater.php b/lib/share/updater.php index dcb31f397d89..81f501f450f5 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -33,6 +33,7 @@ class Updater { private $shareManager; private $logger; private $shareTypeGroupUserUnique = 2; + private $updatedShares; /** * The constructor @@ -51,10 +52,11 @@ 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`, `share_type`, `share_with`, `uid_owner` AS `share_owner`, '. - '`item_type`, `item_source`, `file_source`, `permissions`, `stime` AS '. - '`share_time`, `expiration` AS `expiration_time`, `token` FROM `*PREFIX*share`'; + $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); + $updated = array(); while ($row = $result->fetchRow()) { $this->updateShare($row); } @@ -66,12 +68,71 @@ public function updateAll() { /** * Update the share specified by the $row * @param array $row + * @return \OC\Share\Share | false */ protected function updateShare($row) { $id = $row['id']; - $token = null; - $password = null; + 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 @@ -82,43 +143,89 @@ protected function updateShare($row) { $row['share_type_id'] = 'group'; } else if ($row['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { $row['share_type_id'] = 'link'; - $token = $row['token']; if (isset($row['share_with'])) { - $password = $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; + 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_time'])) { - $date = new DateTime($row['expiration_time']); + if (isset($row['expiration'])) { + $date = new DateTime($row['expiration']); $row['expiration_time'] = $date->getTimeStamp(); } - try { - $share = Share::fromRow($row); - $this->shareManager->share($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, $id)); + 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; } - } catch (Exception $exception) { - $this->logger->error('Unable to update share with id: '.$id.' '. - 'because of an exception: '.$exception->getMessage(), array('app' => 'core') - ); } } + return $parentRows; } } \ No newline at end of file From 40da889db2aa6d9e802aeaa1d1e001b6d6f6da73 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:57:04 -0400 Subject: [PATCH 67/85] Be more careful with variables in getHookArray --- lib/public/share.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/public/share.php b/lib/public/share.php index 7120609baa18..af4aa2a1eeb6 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -145,7 +145,9 @@ public static function setupHooks() { public static function getHookArray($share) { $itemTarget = $share->getItemTarget(); if ($share->getShareTypeId() === 'group') { - $itemTarget = reset($itemTarget); + if (is_array($itemTarget)) { + $itemTarget = reset($itemTarget); + } } $shareType = null; $shareTypeId = $share->getShareTypeId(); @@ -156,12 +158,16 @@ public static function getHookArray($share) { } 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' => reset($parentIds), + 'parent' => $parent, 'shareType' => $shareType, 'shareWith' => $share->getShareWith(), 'uidOwner' => $share->getShareOwner(), From bd1399f3c8ad56a7926c59e53e24360e4fc88f4f Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:57:34 -0400 Subject: [PATCH 68/85] Fix searchForParents --- lib/share/sharemanager.php | 1 + tests/lib/share/sharemanager.php | 54 +++++++++++++++++--------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/lib/share/sharemanager.php b/lib/share/sharemanager.php index a83b99dc8479..aede75fb954d 100644 --- a/lib/share/sharemanager.php +++ b/lib/share/sharemanager.php @@ -394,6 +394,7 @@ protected function searchForParents(Share $share) { $itemType = $share->getItemType(); $filter = array( 'shareWith' => $share->getShareOwner(), + 'isShareWithUser' => true, 'itemSource' => $share->getItemSource(), ); $parents = $this->getShares($itemType, $filter); diff --git a/tests/lib/share/sharemanager.php b/tests/lib/share/sharemanager.php index de7e416fa7b9..8968c51296b1 100644 --- a/tests/lib/share/sharemanager.php +++ b/tests/lib/share/sharemanager.php @@ -144,8 +144,8 @@ public function testShareWithOneParent() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, - array($parent) + 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, @@ -189,8 +189,8 @@ public function testShareWithOneParentAndResharingDisabled() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $blizzz, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $blizzz, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -230,8 +230,8 @@ public function testShareWithOneParentWithoutSharePermission() { $parent->setItemSource($item); $parent->setPermissions(15); $map = array( - array(array('shareWith' => $blizzz, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $blizzz, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -270,8 +270,8 @@ public function testShareWithOneParentAndReshareBackToOwner() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -309,8 +309,8 @@ public function testShareWithOneParentAndReshareWithSamePeople() { $parent->setItemSource($item); $parent->setPermissions(31); $map = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, - array($parent) + array(array('shareWith' => $danimo, 'isShareWithUser' => true, 'itemSource' => $item), + null, null, array($parent) ), ); $this->shareBackend->expects($this->once()) @@ -362,8 +362,8 @@ public function testShareWithTwoParents() { $parent2->setItemSource($item); $parent2->setPermissions(31); $map = array( - array(array('shareWith' => $anybodyelse, 'itemSource' => $item), null, null, - array($parent1, $parent2) + 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)), @@ -431,13 +431,14 @@ public function testShareWithExistingReshares() { $updatedReshare = clone $reshare; $updatedReshare->addParentId(3); $map = array( - array(array('shareWith' => $mtgap, 'itemSource' => $item), null, null, 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, 'itemSource' => $item), null, null, - array($duplicate, $share) + array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true, + 'itemSource' => $item), null, null, array($duplicate, $share) ), array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare)), ); @@ -499,7 +500,8 @@ public function testShareWithOneParentInCollection() { $parent2->setItemSource($collectionItem); $parent2->setPermissions(31); $sharesMap = array( - array(array('shareWith' => $danimo, 'itemSource' => $item), null, null, 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) @@ -610,25 +612,25 @@ public function testShareCollectionWithExistingReshares() { $reshare3->resetUpdatedProperties(); $updatedReshare3 = clone $reshare3; $collectionMap = array( - array(array('shareWith' => $mtgap, 'itemSource' => $collectionItem), null, null, - 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, 'itemSource' => $collectionItem), null, null, - array($duplicate, $share) + array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true, + 'itemSource' => $collectionItem), null, null, array($duplicate, $share) ), - array(array('shareWith' => $dragotin, 'itemSource' => $collectionItem), null, null, - array($duplicate) + 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, 'itemSource' => $item), null, null, - array() + array(array('shareWith' => $anybodyelse, 'isShareWithUser' => true, + 'itemSource' => $item), null, null, array() ), array(array('id' => 2, 'shareTypeId' => 'user'), 1, null, array($reshare1)), ); @@ -1281,8 +1283,8 @@ public function testUpdateResharesWithSharePermissionAdded() { array($parent1, $parent2) ), array(array('parentId' => 5), null, null, array($reshare1, $reshare2)), - array(array('shareWith' => $DeepDiver, 'itemSource' => $item), null, null, - array($parent1, $parent2) + 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)), From 95623574710b5fcee715a850261438e233a7f247 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 15:59:44 -0400 Subject: [PATCH 69/85] Remove unused variable --- lib/share/updater.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/share/updater.php b/lib/share/updater.php index 81f501f450f5..56070dfb4eb2 100644 --- a/lib/share/updater.php +++ b/lib/share/updater.php @@ -56,7 +56,6 @@ public function updateAll() { '`item_source`, `file_source`, `permissions`, `stime`, `expiration`, `token` '. 'FROM `*PREFIX*share`'; $result = \OC_DB::executeAudited($sql); - $updated = array(); while ($row = $result->fetchRow()) { $this->updateShare($row); } From 018a64b8edb2439c5d1887c2d39b3d23858499f6 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Thu, 22 Aug 2013 17:58:48 -0400 Subject: [PATCH 70/85] Always use search method through Group Manager, fixes #4201 --- lib/share/sharetype/group.php | 11 +++++----- tests/lib/share/sharetype/group.php | 32 ++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lib/share/sharetype/group.php b/lib/share/sharetype/group.php index 080f8364f0a8..d23f8b9eee60 100644 --- a/lib/share/sharetype/group.php +++ b/lib/share/sharetype/group.php @@ -259,12 +259,11 @@ public function searchForPotentialShareWiths($shareOwner, $pattern, $limit, $off if ($sharingPolicy === 'groups_only') { $shareOwnerUser = $this->userManager->get($shareOwner); if ($shareOwnerUser) { - $result = $this->groupManager->getUserGroups($shareOwnerUser); - foreach ($result as $group) { - if (stripos($group->getGID(), $pattern) !== false) { - $groups[] = $group; - } - } + $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 { diff --git a/tests/lib/share/sharetype/group.php b/tests/lib/share/sharetype/group.php index 4a9bb216febe..17771d45bd26 100644 --- a/tests/lib/share/sharetype/group.php +++ b/tests/lib/share/sharetype/group.php @@ -580,17 +580,23 @@ public function testSearchForPotentialShareWithsWithGroupsOnlyPolicy() { ->getMock(); $group3->expects($this->any()) ->method('getGID') - ->will($this->returnValue('bargroup3')); + ->will($this->returnValue('foogroup3')); $group4 = $this->getMockBuilder('\OC\Group\Group') ->disableOriginalConstructor() ->getMock(); $group4->expects($this->any()) ->method('getGID') - ->will($this->returnValue('foogroup3')); + ->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, $group3, $group4))); + ->will($this->returnValue(array($group1, $group2, $group4))); $shareWiths = $this->instance->searchForPotentialShareWiths('user2', 'foo', null, null); $this->assertCount(3, $shareWiths); $this->assertContains(array( @@ -600,8 +606,8 @@ public function testSearchForPotentialShareWithsWithGroupsOnlyPolicy() { 'shareWith' => 'foogroup2', 'shareWithDisplayName' => 'foogroup2 (group)'), $shareWiths); $this->assertContains(array( - 'shareWith' => 'foogroup3', - 'shareWithDisplayName' => 'foogroup3 (group)'), $shareWiths); + 'shareWith' => 'foogroup4', + 'shareWithDisplayName' => 'foogroup4 (group)'), $shareWiths); \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy); } @@ -634,25 +640,31 @@ public function testSearchForPotentialShareWithsWithLimitOffsetAndGroupsOnlyPoli ->getMock(); $group3->expects($this->any()) ->method('getGID') - ->will($this->returnValue('bargroup3')); + ->will($this->returnValue('foogroup3')); $group4 = $this->getMockBuilder('\OC\Group\Group') ->disableOriginalConstructor() ->getMock(); $group4->expects($this->any()) ->method('getGID') - ->will($this->returnValue('foogroup3')); + ->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, $group3, $group4))); + ->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' => 'foogroup3', - 'shareWithDisplayName' => 'foogroup3 (group)'), $shareWiths); + 'shareWith' => 'foogroup4', + 'shareWithDisplayName' => 'foogroup4 (group)'), $shareWiths); \OC_Appconfig::setValue('core', 'shareapi_share_policy', $sharingPolicy); } From 0871b68867b1c959813c1362e1aa9da6c1ca27d8 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 23 Aug 2013 20:37:24 -0400 Subject: [PATCH 71/85] Port public links to Share API 2 --- apps/files/ajax/upload.php | 65 ++--- apps/files_sharing/public.php | 440 +++++++++++++++++----------------- 2 files changed, 256 insertions(+), 249 deletions(-) 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_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 From d3553d41964a368eda944be93164aa36bc912fe6 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 24 Aug 2013 16:28:19 -0400 Subject: [PATCH 72/85] Add getPermissions to filesystem methods --- .../lib/share/filesharebackend.php | 28 ++++--------------- lib/files/filesystem.php | 4 +++ lib/files/view.php | 4 +++ 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/apps/files_sharing/lib/share/filesharebackend.php b/apps/files_sharing/lib/share/filesharebackend.php index cf5a4af99a0f..172724b8844b 100644 --- a/apps/files_sharing/lib/share/filesharebackend.php +++ b/apps/files_sharing/lib/share/filesharebackend.php @@ -25,6 +25,7 @@ use OC\Share\ShareBackend; use OC\Share\Exception\InvalidItemException; use OC\Share\Exception\InvalidPermissionsException; +use OC\Files\Filesystem; class FileShareBackend extends ShareBackend { @@ -52,8 +53,8 @@ public function getItemTypePlural() { * @return bool */ protected function isValidItem(Share $share) { - \OC\Files\Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); - $path = \OC\Files\Filesystem::getPath($share->getItemSource()); + Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); + $path = Filesystem::getPath($share->getItemSource()); if (!isset($path)) { throw new InvalidItemException('The file does not exist in the filesystem'); } @@ -69,26 +70,9 @@ protected function isValidItem(Share $share) { */ protected function areValidPermissions(Share $share) { parent::areValidPermissions($share); - \OC\Files\Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); - $path = \OC\Files\Filesystem::getPath($share->getItemSource()); - $permissions = 0; - // TODO Move to view - if (\OC\Files\Filesystem::isCreatable($path)) { - $permissions |= \OCP\PERMISSION_CREATE; - } - if (\OC\Files\Filesystem::isReadable($path)) { - $permissions |= \OCP\PERMISSION_READ; - } - if (\OC\Files\Filesystem::isUpdatable($path)) { - $permissions |= \OCP\PERMISSION_UPDATE; - } - if (\OC\Files\Filesystem::isDeletable($path)) { - $permissions |= \OCP\PERMISSION_DELETE; - } - if (\OC\Files\Filesystem::isSharable($path)) { - $permissions |= \OCP\PERMISSION_SHARE; - } - if ($share->getPermissions() & ~$permissions) { + Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); + $path = Filesystem::getPath($share->getItemSource()); + if ($share->getPermissions() & ~Filesystem::getPermissions($path)) { throw new InvalidPermissionsException('The permissions are not valid for the file'); } return true; 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/view.php b/lib/files/view.php index c9727fe49841..3d610fe80454 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; From 13df4ccac254a376b32aeedccf94201d47e2ccca Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 24 Aug 2013 16:38:27 -0400 Subject: [PATCH 73/85] Make sure filesystem is initialized in FileTargetMachine --- apps/files_sharing/lib/share/filetargetmachine.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/files_sharing/lib/share/filetargetmachine.php b/apps/files_sharing/lib/share/filetargetmachine.php index f0936c711e04..b8299592c57c 100644 --- a/apps/files_sharing/lib/share/filetargetmachine.php +++ b/apps/files_sharing/lib/share/filetargetmachine.php @@ -24,6 +24,7 @@ use OC\Share\Share; use OC\Share\ItemTargetMachine; use OC\User\User; +use OC\Files\Filesystem; class FileTargetMachine extends ItemTargetMachine { @@ -37,7 +38,8 @@ class FileTargetMachine extends ItemTargetMachine { * */ public function getItemTarget(Share $share, User $user = null) { - $path = \OC\Files\Filesystem::getPath($share->getItemSource()); + Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); + $path = Filesystem::getPath($share->getItemSource()); return basename($path); } From 02ace95eb4afbfc5fc3daa3dada43e4c0c3c8ac3 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sun, 25 Aug 2013 20:10:07 -0400 Subject: [PATCH 74/85] New implementation for getPath method so shared file paths will be returned --- apps/files_sharing/lib/cache.php | 52 +++++++++++++--------- apps/files_sharing/lib/share/fileshare.php | 2 +- lib/files/cache/cache.php | 10 ++--- lib/files/view.php | 22 ++++----- 4 files changed, 50 insertions(+), 36 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 6ca65c8e37ac..e9746e1c1656 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -106,7 +106,7 @@ public function get($file) { return array( 'fileid' => -1, 'storage' => null, - 'path' => 'files/Shared', + 'path' => '', 'parent' => -1, 'name' => 'Shared', 'mimetype' => 'httpd/unix-directory', @@ -118,30 +118,42 @@ public function get($file) { 'unencrypted_size' => $unencryptedSize, 'etag' => $etag, ); - } else if (is_string($file)) { - $shares = $this->fetcher->getByPath($file); + } else { + $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 - if ($share->getItemTarget() === $file) { - return $share->getMetadata(); + // 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(); } } - if (!empty($shares)) { - list($cache, $internalPath) = $this->getSourceCache($file); - if ($cache && $internalPath) { - return $cache->get($internalPath); + 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 { - $shares = $this->fetcher->getById($file); - foreach ($shares as $share) { - // Check if we have an exact share for this id - if ($share->getItemSource() === $file) { - return $share->getMetadata(); + return $data; + } 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; } - } - if (!empty($shares)) { - return parent::get($file); } } return false; diff --git a/apps/files_sharing/lib/share/fileshare.php b/apps/files_sharing/lib/share/fileshare.php index 1fc1a4f3db90..d8a0edde4a07 100644 --- a/apps/files_sharing/lib/share/fileshare.php +++ b/apps/files_sharing/lib/share/fileshare.php @@ -235,7 +235,7 @@ public function getMetadata() { return array( 'fileid' => $this->getItemSource(), 'storage' => $this->getStorage(), - 'path' => 'files/Shared/'.$this->getItemTarget(), + 'path' => $this->getItemTarget(), 'parent' => $this->getParent(), 'name' => basename($this->getItemTarget()), 'mimetype' => $this->getMimetype(), 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/view.php b/lib/files/view.php index 3d610fe80454..a5538ba2318b 100644 --- a/lib/files/view.php +++ b/lib/files/view.php @@ -1030,23 +1030,25 @@ 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->getAll(); 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; } + } From 0b296aee5ea316094b2172c20de4adc419f457ea Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Mon, 26 Aug 2013 14:25:35 -0400 Subject: [PATCH 75/85] Fix shared cache move method and add tests for shared cache --- apps/files_sharing/lib/cache.php | 47 +- apps/files_sharing/tests/lib/cache.php | 517 ++++++++++++++++++ .../{ => lib/share}/filesharefetcher.php | 0 3 files changed, 538 insertions(+), 26 deletions(-) create mode 100644 apps/files_sharing/tests/lib/cache.php rename apps/files_sharing/tests/{ => lib/share}/filesharefetcher.php (100%) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index e9746e1c1656..b9db912076fd 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -32,7 +32,6 @@ class SharedCache extends Cache { private $storage; private $storageId; - private $numericId; private $fetcher; /** @@ -55,18 +54,13 @@ protected function getSourceCache($path) { if ($storage && $internalPath) { $cache = $storage->getCache(); $this->storageId = $storage->getId(); - $this->numericId = $cache->getNumericStorageId(); return array($cache, $internalPath); } return array(null, null); } public function getNumericStorageId() { - if (isset($this->numericId)) { - return $this->numericId; - } else { - return false; - } + return null; } /** @@ -139,7 +133,6 @@ public function get($file) { if ($data['storage_mtime'] === 0) { $data['storage_mtime'] = $data['mtime']; } - return $data; } else if (!empty($shares)) { $share = reset($shares); $folder = $share->getItemTarget(); @@ -152,9 +145,9 @@ public function get($file) { } if ($data) { $data['path'] = $folder.substr($data['path'], strlen($share->getPath())); - return $data; } } + return $data; } return false; } @@ -221,19 +214,18 @@ public function put($file, array $data) { * @return int */ public function getId($file) { - if ($file === '') { - return -1; - } - $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(); + 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); } - } - list($cache, $internalPath) = $this->getSourceCache($file); - if ($cache && $internalPath) { - return $cache->getId($internalPath); } return -1; } @@ -271,10 +263,13 @@ public function remove($file) { */ public function move($source, $target) { list($cache, $oldInternalPath) = $this->getSourceCache($source); - list( , $newInternalPath) = $this->fetcher->resolvePath(dirname($target)); - if ($cache && $oldInternalPath && $newInternalPath) { - $newInternalPath .= '/'.basename($target); - $cache->move($oldInternalPath, $newInternalPath); + 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); + } } } @@ -380,4 +375,4 @@ public function getIncomplete() { return false; } -} +} \ 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/filesharefetcher.php b/apps/files_sharing/tests/lib/share/filesharefetcher.php similarity index 100% rename from apps/files_sharing/tests/filesharefetcher.php rename to apps/files_sharing/tests/lib/share/filesharefetcher.php From cdcd3f31eca8395881fe7bc67f2b0658dbcbcb2e Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 13:11:14 -0400 Subject: [PATCH 76/85] Allow switching of UID in FileShareFetcher and add getUsersSharedWith methods --- .../lib/share/filesharefetcher.php | 185 +++++++++++++----- apps/files_sharing/lib/sharedstorage.php | 4 +- .../tests/lib/share/filesharefetcher.php | 101 ++++++++-- 3 files changed, 229 insertions(+), 61 deletions(-) diff --git a/apps/files_sharing/lib/share/filesharefetcher.php b/apps/files_sharing/lib/share/filesharefetcher.php index d83761ffb727..0e2838ffc66c 100644 --- a/apps/files_sharing/lib/share/filesharefetcher.php +++ b/apps/files_sharing/lib/share/filesharefetcher.php @@ -22,15 +22,17 @@ namespace OCA\Files\Share; use OC\Share\ShareManager; +use OC\Group\Manager; /** - * Class to retrieve file shares for a user from the ShareManager + * 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; @@ -38,31 +40,54 @@ class FileShareFetcher { /** * The constructor * @param \OC\Share\ShareManager $shareManager - * @param string $uid + * @param \OC\Group\Manager $groupManager + * @param string $uid (optional) */ - public function __construct(ShareManager $shareManager, $uid) { + public function __construct(ShareManager $shareManager, Manager $groupManager, $uid = null) { $this->shareManager = $shareManager; - $this->uid = $uid; + $this->groupManager = $groupManager; + $this->setUID($uid); $this->fileItemType = 'file'; $this->folderItemType = 'folder'; } /** - * Get all files shares for the user + * 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( - 'shareWith' => $this->uid, - 'isShareWithUser' => true, - ); + $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 for the user + * Get all permissions of all shared files * @return array With file ids as keys and permissions as values */ public function getAllPermissions() { @@ -74,7 +99,10 @@ public function getAllPermissions() { * @return string */ public function getETag() { - return \OCP\Config::getUserValue($this->uid, 'files_sharing', 'etag'); + $uid = $this->getUID(); + if (isset($uid)) { + return \OCP\Config::getUserValue($uid, 'files_sharing', 'etag'); + } } /** @@ -82,46 +110,53 @@ public function getETag() { * @param string $etag */ public function setETag($etag) { - \OCP\Config::setUserValue($this->uid, 'files_sharing', 'etag', $etag); + $uid = $this->getUID(); + if (isset($uid)) { + \OCP\Config::setUserValue($uid, 'files_sharing', 'etag', $etag); + } } /** - * Get all files shares specified by path + * 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(); - $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)) { + $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); - $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); + $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; @@ -133,14 +168,17 @@ public function getByPath($path) { * @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( - 'shareWith' => $this->uid, - 'isShareWithUser' => true, '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 @@ -150,9 +188,12 @@ public function getById($fileId) { } /** - * Resolve a shared path to a storage and internal path + * 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); @@ -179,9 +220,12 @@ public function resolvePath($path) { } /** - * Get permissions for a shared file specified by path + * 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); @@ -206,6 +250,52 @@ public function getPermissionsById($fileId) { 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 @@ -236,10 +326,11 @@ protected function getParentFolders($fileId) { $shares = array(); $folderShareBackend = $this->shareManager->getShareBackend($this->folderItemType); if ($folderShareBackend) { - $filter = array( - 'shareWith' => $this->uid, - 'isShareWithUser' => true, - ); + $uid = $this->getUID(); + if (isset($uid)) { + $filter['shareWith'] = $uid; + $filter['isShareWithUser'] = true; + } $fileId = $folderShareBackend->getParentFolderId($fileId); while ($fileId !== -1) { $filter['itemSource'] = $fileId; diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php index 682acc637b22..5250f994912d 100644 --- a/apps/files_sharing/lib/sharedstorage.php +++ b/apps/files_sharing/lib/sharedstorage.php @@ -52,7 +52,9 @@ public function __construct($params) { public static function setup($params) { if (isset($params['user']) && isset($params['user_dir'])) { $shareManager = \OCP\Share::getShareManager(); - $fetcher = new FileShareFetcher($shareManager, $params['user']); + $fetcher = new FileShareFetcher($shareManager, \OC_Group::getManager(), + $params['user'] + ); \OC\Files\Filesystem::mount('\OC\Files\Storage\Shared', array('fetcher' => $fetcher), $params['user_dir'].'/Shared/' ); diff --git a/apps/files_sharing/tests/lib/share/filesharefetcher.php b/apps/files_sharing/tests/lib/share/filesharefetcher.php index 66c78bcb6609..a75e55bc236e 100644 --- a/apps/files_sharing/tests/lib/share/filesharefetcher.php +++ b/apps/files_sharing/tests/lib/share/filesharefetcher.php @@ -27,6 +27,7 @@ class FileShareFetcher extends \PHPUnit_Framework_TestCase { protected $matt; protected $shareManager; + protected $groupManager; protected $folderShareBackend; protected $fetcher; @@ -35,6 +36,9 @@ protected function setUp() { $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(); @@ -42,7 +46,9 @@ protected function setUp() { ->method('getShareBackend') ->with($this->equalTo('folder')) ->will($this->returnValue($this->folderShareBackend)); - $this->fetcher = new \OCA\Files\Share\FileShareFetcher($this->shareManager, $this->matt); + $this->fetcher = new \OCA\Files\Share\FileShareFetcher($this->shareManager, + $this->groupManager, $this->matt + ); } public function testGetAll() { @@ -171,8 +177,8 @@ public function testGetByIdWithFile() { $share->setItemType('file'); $share->setItemSource(79); $map = array( - array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true, - 'itemSource' => 79), null, null, array($share) + array('file', array('itemSource' => 79, 'shareWith' => $this->matt, + 'isShareWithUser' => true), null, null, array($share) ), ); $this->shareManager->expects($this->once()) @@ -191,11 +197,11 @@ public function testGetByIdWithFolder() { $share->setItemType('folder'); $share->setItemSource(80); $map = array( - array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true, - 'itemSource' => 80), null, null, array() + array('file', array('itemSource' => 80, 'shareWith' => $this->matt, + 'isShareWithUser' => true), null, null, array() ), - array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true, - 'itemSource' => 80), null, null, array($share) + array('folder', array('itemSource' => 80, 'shareWith' => $this->matt, + 'isShareWithUser' => true), null, null, array($share) ), ); $this->shareManager->expects($this->exactly(2)) @@ -220,8 +226,8 @@ public function testGetByIdWithParentFolders() { $share3->setItemType('folder'); $share3->setItemSource(4); $map = array( - array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true, - 'itemSource' => 72), null, null, array($share1) + 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) @@ -289,11 +295,11 @@ public function testGetPermissionsById() { $share2->setItemSource(80); $share2->setPermissions(5); $map = array( - array('file', array('shareWith' => $this->matt, 'isShareWithUser' => true, - 'itemSource' => 80), null, null, array() + array('file', array('itemSource' => 80, 'shareWith' => $this->matt, + 'isShareWithUser' => true), null, null, array() ), - array('folder', array('shareWith' => $this->matt, 'isShareWithUser' => true, - 'itemSource' => 80), null, null, array($share1, $share2) + array('folder', array('itemSource' => 80, 'shareWith' => $this->matt, + 'isShareWithUser' => true), null, null, array($share1, $share2) ), ); $this->shareManager->expects($this->exactly(2)) @@ -316,4 +322,73 @@ public function testGetPermissionsByIdWithNoShares() { $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 From 1a786b4fd8d9b97da66cae7c4b783f3892fcd5f8 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 13:51:56 -0400 Subject: [PATCH 77/85] Cast item source to int for now since current share ajax file doesn't respect variable types --- apps/files_sharing/lib/share/filesharebackend.php | 4 ++-- apps/files_sharing/lib/share/filetargetmachine.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/files_sharing/lib/share/filesharebackend.php b/apps/files_sharing/lib/share/filesharebackend.php index 172724b8844b..d8af85be2a76 100644 --- a/apps/files_sharing/lib/share/filesharebackend.php +++ b/apps/files_sharing/lib/share/filesharebackend.php @@ -54,7 +54,7 @@ public function getItemTypePlural() { */ protected function isValidItem(Share $share) { Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); - $path = Filesystem::getPath($share->getItemSource()); + $path = Filesystem::getPath((int)$share->getItemSource()); if (!isset($path)) { throw new InvalidItemException('The file does not exist in the filesystem'); } @@ -71,7 +71,7 @@ protected function isValidItem(Share $share) { protected function areValidPermissions(Share $share) { parent::areValidPermissions($share); Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); - $path = Filesystem::getPath($share->getItemSource()); + $path = Filesystem::getPath((int)$share->getItemSource()); if ($share->getPermissions() & ~Filesystem::getPermissions($path)) { throw new InvalidPermissionsException('The permissions are not valid for the file'); } diff --git a/apps/files_sharing/lib/share/filetargetmachine.php b/apps/files_sharing/lib/share/filetargetmachine.php index b8299592c57c..f47b97170f5e 100644 --- a/apps/files_sharing/lib/share/filetargetmachine.php +++ b/apps/files_sharing/lib/share/filetargetmachine.php @@ -39,7 +39,7 @@ class FileTargetMachine extends ItemTargetMachine { */ public function getItemTarget(Share $share, User $user = null) { Filesystem::init($share->getShareOwner(), '/'.$share->getShareOwner().'/files'); - $path = Filesystem::getPath($share->getItemSource()); + $path = Filesystem::getPath((int)$share->getItemSource()); return basename($path); } From 03921fccc22e070cb3699c5a519bf51580f842d0 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 14:34:49 -0400 Subject: [PATCH 78/85] Filter mounts for View's getPath --- lib/files/view.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/files/view.php b/lib/files/view.php index a5538ba2318b..54387f82832a 100644 --- a/lib/files/view.php +++ b/lib/files/view.php @@ -1037,7 +1037,8 @@ public function getETag($path) { */ public function getPath($id) { $mountManager = Filesystem::getMountManager(); - $mounts = $mountManager->getAll(); + $mounts = $mountManager->findIn($this->getRoot()); + $mounts[] = $mountManager->find($this->getRoot()); foreach ($mounts as $mount) { $cache = $mount->getStorage()->getCache(); $data = $cache->get($id); From e7333e718409280992a956e69c07baebdd0a4898 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 14:41:56 -0400 Subject: [PATCH 79/85] Port SharedUpdater since we are still using the root Shared folder --- apps/files_sharing/appinfo/app.php | 7 +- apps/files_sharing/lib/updater.php | 141 +++++++++++++++++------------ 2 files changed, 87 insertions(+), 61 deletions(-) diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 40abcc32c51b..f9572b64546a 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -31,10 +31,6 @@ OC::$CLASSPATH['OC\Files\Cache\SharedUpdater'] = 'files_sharing/lib/updater.php'; OC::$CLASSPATH['OC\Files\Cache\SharedWatcher'] = 'files_sharing/lib/watcher.php'; -// \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'); - $shareManager = \OCP\Share::getShareManager(); $timeMachine = new \OC\Share\TimeMachine(); $fileShareFactory = new \OCA\Files\Share\FileShareFactory(); @@ -69,6 +65,9 @@ $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/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 From 039a163a0d209be17b8be19eec8613a8e876723c Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 19:27:18 -0400 Subject: [PATCH 80/85] Change variable name in setupHooks --- lib/public/share.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/public/share.php b/lib/public/share.php index 0f54ec92bb2b..268d2c725033 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -110,23 +110,23 @@ public static function getShareManager() { public static function setupHooks() { $shareManager = self::getShareManager(); if ($shareManager) { - self::$shareManager->listen('\OC\Share', 'preShare', function($share) { + $shareManager->listen('\OC\Share', 'preShare', function($share) { \OC_Hook::emit('OCP\Share', 'pre_shared', self::getHookArray($share)); }); - self::$shareManager->listen('\OC\Share', 'postShare', function($share) { + $shareManager->listen('\OC\Share', 'postShare', function($share) { \OC_Hook::emit('OCP\Share', 'post_shared', self::getHookArray($share)); }); - self::$shareManager->listen('\OC\Share', 'preUnshare', function($share) { + $shareManager->listen('\OC\Share', 'preUnshare', function($share) { $params = self::getHookArray($share); $params['itemParent'] = $params['parent']; \OC_Hook::emit('OCP\Share', 'pre_unshare', $params); }); - self::$shareManager->listen('\OC\Share', 'postUnshare', function($share) { + $shareManager->listen('\OC\Share', 'postUnshare', function($share) { $params = self::getHookArray($share); $params['itemParent'] = $params['parent']; \OC_Hook::emit('OCP\Share', 'post_unshare', $params); }); - self::$shareManager->listen('\OC\Share', 'postUpdate', function($share) { + $shareManager->listen('\OC\Share', 'postUpdate', function($share) { $properties = $share->getUpdatedProperties(); if (isset($properties['permissions'])) { $itemType = $share->getItemType(); @@ -1524,7 +1524,7 @@ private static function put($itemType, $itemSource, $shareType, $shareWith, $uid if ($run === false) { throw new \Exception($error); } - + if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { From 0252093ffd6ffa26dca5eea50d517563dad7af48 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 21:19:44 -0400 Subject: [PATCH 81/85] Tape together the share ajax file a little more --- apps/files_sharing/js/share.js | 1 + core/ajax/share.php | 103 ++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 15 deletions(-) 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/core/ajax/share.php b/core/ajax/share.php index 9a8ee26fe372..b25646fc9d5c 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -121,8 +121,26 @@ 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': @@ -170,9 +188,35 @@ switch ($_GET['fetch']) { case 'getItemsSharedStatuses': if (isset($_GET['itemType'])) { - // $return = OCP\Share::getItemsShared($_GET['itemType'], OCP\Share::FORMAT_STATUSES); - $return = array(); - 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') { + $mounts = \OC\Files\Filesystem::getMountByNumericId($share->getStorage()); + $view = \OC\Files\Filesystem::getView(); + foreach ($mounts as $mount) { + $fullPath = $mount->getMountPoint().$share->getPath(); + if (!is_null($path = $view->getRelativePath($fullPath))) { + $statuses[$share->getItemSource()]['path'] = $path; + break; + } + } + } + } + } catch (Exception $exception) { + OC_JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($exception->getMessage())))); + } + OC_JSON::success(array('data' => $statuses)); } break; case 'getItem': @@ -180,17 +224,41 @@ && isset($_GET['itemSource']) && isset($_GET['checkReshare']) && isset($_GET['checkShares'])) { - // if ($_GET['checkReshare'] == 'true') { - // $reshare = OCP\Share::getItemSharedWithBySource( - // $_GET['itemType'], - // $_GET['itemSource'], - // OCP\Share::FORMAT_NONE, - // null, - // true - // ); - // } else { + if ($_GET['checkReshare'] == '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 = array(); - // } + } if ($_GET['checkShares'] == 'true') { $filter = array( 'shareOwner' => \OCP\User::getUser(), @@ -207,6 +275,10 @@ } 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(), @@ -214,6 +286,7 @@ 'permissions' => $share->getPermissions(), 'share_with_displayname' => $share->getShareWithDisplayName(), 'displayname_owner' => $share->getShareOwnerDisplayName(), + 'expiration' => $expiration, ); } } else { From 2c36f6e2778d9ce9e0a7eef9ac43d616f16d25b6 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 21:23:58 -0400 Subject: [PATCH 82/85] Use the FileShareFetcher for encryption's getUsersSharingFile method --- apps/files_encryption/lib/util.php | 52 +++++++++++------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 4a7ba850e268..27dff50f7621 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1191,47 +1191,33 @@ public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId public function getUsersSharingFile($path, $user, $includeOwner = false) { $users = array(); $public = false; - $shareManager = \OCP\Share::getShareManager(); - if ($shareManager) { - $view = new \OC\Files\View('/' . $user . '/files/'); - $meta = $view->getFileInfo(\OC\Files\Filesystem::normalizePath($path)); - $fileId = -1; - if ($meta !== false) { - $fileId = $meta['fileid']; - $cache = new \OC\Files\Cache\Cache($meta['storage']); - } - if ($meta['mimetype'] === 'httpd/unix-directory') { - $itemType = 'folder'; - } else { - $itemType = 'file'; - } - $filter = array(); - while ($fileId !== -1) { - $filter['itemSource'] = $fileId; - $shares = $shareManager->getShares($itemType, $filter); + $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) { - $shareTypeId = $share->getShareTypeId(); - if ($shareTypeId === 'user') { - $users[] = $share->getShareWith(); - } else if ($shareTypeId === 'group') { - $usersInGroup = \OC_Group::usersInGroup($share->getShareWith()); - $users = array_merge($users, $usersInGroup); - } else if ($shareTypeId === 'link') { + if ($share->getShareTypeId() === 'link') { $public = true; + break; } } - $meta = $cache->get((int)$fileId); - if ($meta !== false) { - $fileId = (int)$meta['parent']; + $users = $fetcher->getUsersSharedWith($shares); + if ($includeOwner) { + if (!in_array($user, $users)) { + $users[] = $user; + } } else { - $fileId = -1; + $users = array_diff($users, array($user)); } } } - if ($includeOwner) { - $users[] = $user; - } - return array('users' => array_unique($users), 'public' => $public); + return array('users' => $users, 'public' => $public); } private function getUserWithAccessToMountPoint($users, $groups) { From 91ba33e2263f05645b8306d4e9f378fdac30b65b Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Tue, 27 Aug 2013 21:29:44 -0400 Subject: [PATCH 83/85] Use safer getPath option --- core/ajax/share.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/core/ajax/share.php b/core/ajax/share.php index b25646fc9d5c..468b16e2733c 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -202,15 +202,7 @@ } $itemType = $share->getItemType(); if ($itemType === 'file' || $itemType == 'folder') { - $mounts = \OC\Files\Filesystem::getMountByNumericId($share->getStorage()); - $view = \OC\Files\Filesystem::getView(); - foreach ($mounts as $mount) { - $fullPath = $mount->getMountPoint().$share->getPath(); - if (!is_null($path = $view->getRelativePath($fullPath))) { - $statuses[$share->getItemSource()]['path'] = $path; - break; - } - } + $statuses[$share->getItemSource()]['path'] = \OC\Files\Filesystem::getPath($share->getItemSource()); } } } catch (Exception $exception) { From bc251933367603592644cd6f3848df9335618773 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 28 Aug 2013 10:16:12 -0400 Subject: [PATCH 84/85] Add break in SharedCache's get method --- apps/files_sharing/lib/cache.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index b9db912076fd..3c0544f0c2d3 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -125,6 +125,7 @@ public function get($file) { || is_int($file) && $share->getItemSource() === $file ) { $data = $share->getMetadata(); + break; } } if ($data) { From dc91e45c40ad23e3b0b9f0f698a01216966823eb Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Wed, 28 Aug 2013 21:03:09 -0400 Subject: [PATCH 85/85] Implement search methods for SharedCache, fixes #4516 --- apps/files_sharing/lib/cache.php | 129 ++++++++++++++++++--- apps/files_sharing/lib/share/fileshare.php | 2 + 2 files changed, 113 insertions(+), 18 deletions(-) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 3c0544f0c2d3..9fa8f9329a9f 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -304,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(); } /** @@ -357,10 +361,18 @@ public function calculateFolderSize($path) { public function getAll() { $ids = array(); $shares = $this->fetcher->getAll(); + $folderMimetypeId = (int)$this->getMimetypeId('httpd/unix-directory'); foreach ($shares as $share) { - $ids[] = $share->getItemSource(); + $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_unique($ids); + return array_values($ids); } /** @@ -376,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/share/fileshare.php b/apps/files_sharing/lib/share/fileshare.php index d8a0edde4a07..16413019d3de 100644 --- a/apps/files_sharing/lib/share/fileshare.php +++ b/apps/files_sharing/lib/share/fileshare.php @@ -45,6 +45,8 @@ 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');