From d258ade35e0fe80d347b4ac661f25c9224fb87cc Mon Sep 17 00:00:00 2001 From: eduardo Date: Sat, 4 Jan 2014 19:23:25 -0200 Subject: Fix PostgreSQL port configuration on install --- lib/private/setup/postgresql.php | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php index 89d328ada19..b5e3d5f8970 100644 --- a/lib/private/setup/postgresql.php +++ b/lib/private/setup/postgresql.php @@ -10,13 +10,21 @@ class PostgreSQL extends AbstractDatabase { $e_user = addslashes($this->dbuser); $e_password = addslashes($this->dbpassword); + // Eduardo: 04/01/2013 + // Fix database with port connection + if(strpos($e_host, ':')) { + list($e_host, $port)=explode(':', $e_host, 2); + } else { + $port=false; + } + //check if the database user has admin rights - $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'"; + $connection_string = "host='$e_host' dbname=postgres user='$e_user' port='$port' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) { // Try if we can connect to the DB with the specified name $e_dbname = addslashes($this->dbname); - $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) @@ -63,7 +71,15 @@ class PostgreSQL extends AbstractDatabase { $e_user = addslashes($this->dbuser); $e_password = addslashes($this->dbpassword); - $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; + // Eduardo: 04/01/2013 + // Fix database with port connection + if(strpos($e_host, ':')) { + list($e_host, $port)=explode(':', $e_host, 2); + } else { + $port=false; + } + + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) { throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), -- cgit v1.2.3 From 569851fa0ea5367d84c411cdb8a6f8fafff695da Mon Sep 17 00:00:00 2001 From: eduardo Date: Sun, 5 Jan 2014 12:38:54 -0200 Subject: Add tabs to conformance with owncloud code standards --- lib/private/setup/postgresql.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php index b5e3d5f8970..dc1df115d93 100644 --- a/lib/private/setup/postgresql.php +++ b/lib/private/setup/postgresql.php @@ -10,8 +10,8 @@ class PostgreSQL extends AbstractDatabase { $e_user = addslashes($this->dbuser); $e_password = addslashes($this->dbpassword); - // Eduardo: 04/01/2013 - // Fix database with port connection + // Eduardo: 04/01/2013 + // Fix database with port connection if(strpos($e_host, ':')) { list($e_host, $port)=explode(':', $e_host, 2); } else { @@ -71,8 +71,8 @@ class PostgreSQL extends AbstractDatabase { $e_user = addslashes($this->dbuser); $e_password = addslashes($this->dbpassword); - // Eduardo: 04/01/2013 - // Fix database with port connection + // Eduardo: 04/01/2013 + // Fix database with port connection if(strpos($e_host, ':')) { list($e_host, $port)=explode(':', $e_host, 2); } else { -- cgit v1.2.3 From 938ece1a3fda68102f9ce2a02dddff882b1da6ff Mon Sep 17 00:00:00 2001 From: eduardo Date: Wed, 8 Jan 2014 00:15:08 -0200 Subject: Remove name from code --- lib/private/setup/postgresql.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php index dc1df115d93..6065cee80c8 100644 --- a/lib/private/setup/postgresql.php +++ b/lib/private/setup/postgresql.php @@ -10,7 +10,6 @@ class PostgreSQL extends AbstractDatabase { $e_user = addslashes($this->dbuser); $e_password = addslashes($this->dbpassword); - // Eduardo: 04/01/2013 // Fix database with port connection if(strpos($e_host, ':')) { list($e_host, $port)=explode(':', $e_host, 2); @@ -71,7 +70,6 @@ class PostgreSQL extends AbstractDatabase { $e_user = addslashes($this->dbuser); $e_password = addslashes($this->dbpassword); - // Eduardo: 04/01/2013 // Fix database with port connection if(strpos($e_host, ':')) { list($e_host, $port)=explode(':', $e_host, 2); -- cgit v1.2.3 From 428d2b6e0fcc687e6cca7c73263eacf7d460192f Mon Sep 17 00:00:00 2001 From: eduardo Date: Wed, 8 Jan 2014 00:16:37 -0200 Subject: Remove unused spaces --- lib/private/setup/postgresql.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/setup/postgresql.php b/lib/private/setup/postgresql.php index 6065cee80c8..4d0c9b52a4d 100644 --- a/lib/private/setup/postgresql.php +++ b/lib/private/setup/postgresql.php @@ -23,7 +23,7 @@ class PostgreSQL extends AbstractDatabase { if(!$connection) { // Try if we can connect to the DB with the specified name $e_dbname = addslashes($this->dbname); - $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) @@ -77,7 +77,7 @@ class PostgreSQL extends AbstractDatabase { $port=false; } - $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) { throw new \DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), -- cgit v1.2.3 From 0db5fead8e9d4cfe410841ab4c4562987f2844a6 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 6 Feb 2014 10:04:18 +0100 Subject: remove some more global variable $RUNTIME_NOAPPS --- console.php | 1 - core/ajax/update.php | 1 - lib/base.php | 5 ----- lib/private/util.php | 4 +--- public.php | 1 - remote.php | 1 - status.php | 2 -- 7 files changed, 1 insertion(+), 14 deletions(-) (limited to 'lib/private') diff --git a/console.php b/console.php index 25b8b312539..fc6957062be 100644 --- a/console.php +++ b/console.php @@ -8,7 +8,6 @@ use Symfony\Component\Console\Application; -$RUNTIME_NOAPPS = true; require_once 'lib/base.php'; // Don't do anything if ownCloud has not been installed yet diff --git a/core/ajax/update.php b/core/ajax/update.php index d6af84e95b1..99e8f275316 100644 --- a/core/ajax/update.php +++ b/core/ajax/update.php @@ -1,6 +1,5 @@ Date: Thu, 6 Feb 2014 11:34:27 +0100 Subject: Within OC:init() the minimum set of apps is loaded - which is filesystem, authentication and logging --- apps/files/appinfo/remote.php | 6 ------ core/command/user/report.php | 3 +-- lib/base.php | 15 ++++----------- lib/private/user.php | 2 -- 4 files changed, 5 insertions(+), 21 deletions(-) (limited to 'lib/private') diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php index ef22fe92188..8d762d4e880 100644 --- a/apps/files/appinfo/remote.php +++ b/apps/files/appinfo/remote.php @@ -22,12 +22,6 @@ * License along with this library. If not, see . * */ -// load needed apps -$RUNTIME_APPTYPES = array('filesystem', 'authentication', 'logging'); - -OC_App::loadApps($RUNTIME_APPTYPES); - -OC_Util::obEnd(); // Backends $authBackend = new OC_Connector_Sabre_Auth(); diff --git a/core/command/user/report.php b/core/command/user/report.php index f95ba251bcc..d6b7abacabc 100644 --- a/core/command/user/report.php +++ b/core/command/user/report.php @@ -48,7 +48,6 @@ class Report extends Command { } private function countUsers() { - \OC_App::loadApps(array('authentication')); $userManager = \OC::$server->getUserManager(); return $userManager->countUsers(); } @@ -58,4 +57,4 @@ class Report extends Command { $userDirectories = $dataview->getDirectoryContent('/', 'httpd/unix-directory'); return count($userDirectories); } -} \ No newline at end of file +} diff --git a/lib/base.php b/lib/base.php index 18adfd31204..fb7baf86a59 100644 --- a/lib/base.php +++ b/lib/base.php @@ -567,15 +567,9 @@ class OC { OC_User::logout(); } - // Load Apps - // This includes plugins for users and filesystems as well - global $RUNTIME_APPTYPES; + // Load minimum set of apps - which is filesystem, authentication and logging if (!self::checkUpgrade(false)) { - if ($RUNTIME_APPTYPES) { - OC_App::loadApps($RUNTIME_APPTYPES); - } else { - OC_App::loadApps(); - } + OC_App::loadApps(array('filesystem', 'authentication', 'logging')); } //setup extra user backends @@ -866,7 +860,7 @@ class OC { ) { return false; } - OC_App::loadApps(array('authentication')); + if (defined("DEBUG") && DEBUG) { OC_Log::write('core', 'Trying to login from cookie', OC_Log::DEBUG); } @@ -938,7 +932,7 @@ class OC { ) { return false; } - OC_App::loadApps(array('authentication')); + if (OC_User::login($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"])) { //OC_Log::write('core',"Logged in with HTTP Authentication", OC_Log::DEBUG); OC_User::unsetMagicInCookie(); @@ -967,4 +961,3 @@ if (!function_exists('get_temp_dir')) { } OC::init(); - diff --git a/lib/private/user.php b/lib/private/user.php index 98ebebbe5c1..11f96aabf74 100644 --- a/lib/private/user.php +++ b/lib/private/user.php @@ -317,8 +317,6 @@ class OC_User { */ public static function isLoggedIn() { if (\OC::$session->get('user_id') && self::$incognitoMode === false) { - OC_App::loadApps(array('authentication')); - self::setupBackends(); return self::userExists(\OC::$session->get('user_id')); } return false; -- cgit v1.2.3 From fc01a13811f5da395f1a9ed1171f15f5fffcb71e Mon Sep 17 00:00:00 2001 From: kondou Date: Wed, 12 Feb 2014 22:35:49 +0100 Subject: Fix imagerotate and move loadFromBase64() one up. imagerotate() with third parameter being -1 does not seem to work in PHP 5.5 loadFromBase64() one up, so debug-logs aren't spammed (as much) with urlencoded base64-data from loadFromFile() debug output. --- lib/private/image.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index 91a9f91e1d6..0b99bf23f6e 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -346,7 +346,7 @@ class OC_Image { break; } if($rotate) { - $res = imagerotate($this->resource, $rotate, -1); + $res = imagerotate($this->resource, $rotate, 0); if($res) { if(imagealphablending($res, true)) { if(imagesavealpha($res, true)) { @@ -381,10 +381,10 @@ class OC_Image { } elseif(in_array(get_resource_type($imageRef), array('file', 'stream'))) { return $this->loadFromFileHandle($imageRef); } - } elseif($this->loadFromFile($imageRef) !== false) { - return $this->resource; } elseif($this->loadFromBase64($imageRef) !== false) { return $this->resource; + } elseif($this->loadFromFile($imageRef) !== false) { + return $this->resource; } elseif($this->loadFromData($imageRef) !== false) { return $this->resource; } else { @@ -415,7 +415,6 @@ class OC_Image { public function loadFromFile($imagePath=false) { // exif_imagetype throws "read error!" if file is less than 12 byte if(!@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) { - // Debug output disabled because this method is tried before loadFromBase64? OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: ' . (string) urlencode($imagePath), OC_Log::DEBUG); return false; } -- cgit v1.2.3 From 2f1a24eee74d0bf7bf5d734d1abd99a7bc68052c Mon Sep 17 00:00:00 2001 From: tomneedham Date: Tue, 18 Feb 2014 09:50:46 +0000 Subject: Add displayname for admins --- lib/private/ocs/cloud.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/ocs/cloud.php b/lib/private/ocs/cloud.php index cbbf3b626f5..784a5b0869e 100644 --- a/lib/private/ocs/cloud.php +++ b/lib/private/ocs/cloud.php @@ -61,17 +61,25 @@ class OC_OCS_Cloud { * the user from whom the information will be returned */ public static function getUser($parameters) { + $return = array(); // Check if they are viewing information on themselves if($parameters['userid'] === OC_User::getUser()) { // Self lookup $storage = OC_Helper::getStorageInfo('/'); - $quota = array( + $return['quota'] = array( 'free' => $storage['free'], 'used' => $storage['used'], 'total' => $storage['total'], 'relative' => $storage['relative'], ); - return new OC_OCS_Result(array('quota' => $quota)); + } + if(OC_User::isAdminUser(OC_User::getUser()) + || OC_Subadmin::isUserAccessible(OC_User::getUser(), $parameters['userid'])) { + // Is an admin/subadmin so can see display name + $return['displayname'] = OC_User::getDisplayName($parameters['userid']); + } + if(count($return)) { + return new OC_OCS_Result($return); } else { // No permission to view this user data return new OC_OCS_Result(null, 997); -- cgit v1.2.3 From df38d4ef1a591bd5b1aaa476b6240eac0a059a8e Mon Sep 17 00:00:00 2001 From: tomneedham Date: Tue, 18 Feb 2014 10:36:18 +0000 Subject: Return 101 if user doesnt exist --- lib/private/ocs/cloud.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/ocs/cloud.php b/lib/private/ocs/cloud.php index 784a5b0869e..06d6a8eb4b0 100644 --- a/lib/private/ocs/cloud.php +++ b/lib/private/ocs/cloud.php @@ -75,8 +75,12 @@ class OC_OCS_Cloud { } if(OC_User::isAdminUser(OC_User::getUser()) || OC_Subadmin::isUserAccessible(OC_User::getUser(), $parameters['userid'])) { - // Is an admin/subadmin so can see display name - $return['displayname'] = OC_User::getDisplayName($parameters['userid']); + if(OC_User::userExists($parameters['userid'])) { + // Is an admin/subadmin so can see display name + $return['displayname'] = OC_User::getDisplayName($parameters['userid']); + } else { + return new OC_OCS_Result(null, 101); + } } if(count($return)) { return new OC_OCS_Result($return); -- cgit v1.2.3 From 76aa4714cf5f32abf8ac329b37adc98cc4741e08 Mon Sep 17 00:00:00 2001 From: Joshua Medeiros Date: Sun, 2 Feb 2014 21:46:09 -0500 Subject: Recursive mkdir fixes #7047 --- lib/private/files/storage/mappedlocal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php index 1bab3489a28..026f6ec895e 100644 --- a/lib/private/files/storage/mappedlocal.php +++ b/lib/private/files/storage/mappedlocal.php @@ -31,7 +31,7 @@ class MappedLocal extends \OC\Files\Storage\Common{ return 'local::'.$this->datadir; } public function mkdir($path) { - return @mkdir($this->buildPath($path)); + return @mkdir($this->buildPath($path), 0777, true); } public function rmdir($path) { try { -- cgit v1.2.3 From d1c392d9adc28f17ef90eb3e515f9622159c64b9 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 20 Feb 2014 15:36:30 +0100 Subject: Also make "regular" local storage's mkdir recursive --- lib/private/files/storage/local.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index a62230bdba5..0f906ec55b4 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -35,7 +35,7 @@ if (\OC_Util::runningOnWindows()) { } public function mkdir($path) { - return @mkdir($this->datadir . $path); + return @mkdir($this->datadir . $path, 0777, true); } public function rmdir($path) { -- cgit v1.2.3 From 43b1d81f77df987ad4118bafbdef14d9bd4f016d Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Fri, 21 Feb 2014 13:45:57 +0100 Subject: Use 'command -v' to detect whether and where software is installed (instead of 'which') --- apps/files_external/lib/config.php | 2 +- lib/private/installer.php | 2 +- lib/private/preview/movies.php | 2 +- lib/private/preview/office-cl.php | 4 ++-- lib/private/preview/office.php | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'lib/private') diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index b2109e5eacd..9bc06bbbccc 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -438,7 +438,7 @@ class OC_Mount_Config { */ public static function checksmbclient() { if(function_exists('shell_exec')) { - $output=shell_exec('which smbclient 2> /dev/null'); + $output=shell_exec('command -v smbclient 2> /dev/null'); return !empty($output); }else{ return false; diff --git a/lib/private/installer.php b/lib/private/installer.php index 11633a4d4a1..64e8e3a5e7a 100644 --- a/lib/private/installer.php +++ b/lib/private/installer.php @@ -464,7 +464,7 @@ class OC_Installer{ // is the code checker enabled? if(OC_Config::getValue('appcodechecker', true)) { // check if grep is installed - $grep = exec('which grep'); + $grep = exec('command -v grep'); if($grep=='') { OC_Log::write('core', 'grep not installed. So checking the code of the app "'.$appname.'" was not possible', diff --git a/lib/private/preview/movies.php b/lib/private/preview/movies.php index 71cd3bae057..7e0ff51ad2e 100644 --- a/lib/private/preview/movies.php +++ b/lib/private/preview/movies.php @@ -9,7 +9,7 @@ namespace OC\Preview; function findBinaryPath($program) { - exec('which ' . escapeshellarg($program) . ' 2> /dev/null', $output, $returnCode); + exec('command -v ' . escapeshellarg($program) . ' 2> /dev/null', $output, $returnCode); if ($returnCode === 0 && count($output) > 0) { return escapeshellcmd($output[0]); } diff --git a/lib/private/preview/office-cl.php b/lib/private/preview/office-cl.php index b11fed13ba1..6e4d4321eb7 100644 --- a/lib/private/preview/office-cl.php +++ b/lib/private/preview/office-cl.php @@ -64,12 +64,12 @@ if (!\OC_Util::runningOnWindows()) { $cmd = \OC_Config::getValue('preview_libreoffice_path', null); } - $whichLibreOffice = shell_exec('which libreoffice'); + $whichLibreOffice = shell_exec('command -v libreoffice'); if($cmd === '' && !empty($whichLibreOffice)) { $cmd = 'libreoffice'; } - $whichOpenOffice = shell_exec('which openoffice'); + $whichOpenOffice = shell_exec('command -v openoffice'); if($cmd === '' && !empty($whichOpenOffice)) { $cmd = 'openoffice'; } diff --git a/lib/private/preview/office.php b/lib/private/preview/office.php index 02bb22e9b94..131bc9a0dc4 100644 --- a/lib/private/preview/office.php +++ b/lib/private/preview/office.php @@ -11,9 +11,9 @@ if (extension_loaded('imagick') && count(@\Imagick::queryFormats("PDF")) === 1) // LibreOffice preview is currently not supported on Windows if (!\OC_Util::runningOnWindows()) { - $whichLibreOffice = ($isShellExecEnabled ? shell_exec('which libreoffice') : ''); + $whichLibreOffice = ($isShellExecEnabled ? shell_exec('command -v libreoffice') : ''); $isLibreOfficeAvailable = !empty($whichLibreOffice); - $whichOpenOffice = ($isShellExecEnabled ? shell_exec('which libreoffice') : ''); + $whichOpenOffice = ($isShellExecEnabled ? shell_exec('command -v libreoffice') : ''); $isOpenOfficeAvailable = !empty($whichOpenOffice); //let's see if there is libreoffice or openoffice on this machine if($isShellExecEnabled && ($isLibreOfficeAvailable || $isOpenOfficeAvailable || is_string(\OC_Config::getValue('preview_libreoffice_path', null)))) { -- cgit v1.2.3 From bc49c6be04d78740d9b7cb100debcb6641559d39 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 26 Feb 2014 14:29:13 +0100 Subject: Manually triger the filecache update hooks before any other hook --- apps/files/appinfo/app.php | 7 ------- lib/private/files/view.php | 20 ++++++++++++++++++++ tests/lib/files/cache/updater.php | 5 ----- 3 files changed, 20 insertions(+), 12 deletions(-) (limited to 'lib/private') diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php index 909baca92ea..15a29133789 100644 --- a/apps/files/appinfo/app.php +++ b/apps/files/appinfo/app.php @@ -12,13 +12,6 @@ OCP\App::addNavigationEntry(array("id" => "files_index", OC_Search::registerProvider('OC_Search_Provider_File'); -// cache hooks must be connected before all other apps. -// since 'files' is always loaded first the hooks need to be connected here -\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook'); -\OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook'); -\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook'); -\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); - \OCP\BackgroundJob::addRegularTask('\OC\Files\Cache\BackgroundWatcher', 'checkNext'); $templateManager = OC_Helper::getFileTemplateManager(); diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 2dbbf5b88c9..a76115a816e 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -25,6 +25,8 @@ namespace OC\Files; +use OC\Files\Cache\Updater; + class View { private $fakeRoot = ''; private $internal_path_cache = array(); @@ -433,6 +435,7 @@ class View { } if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { // if it was a rename from a part file to a regular file it was a write and not a rename operation + Updater::writeHook(array('path' => $this->getHookPath($path2))); \OC_Hook::emit( Filesystem::CLASSNAME, Filesystem::signal_post_write, @@ -441,6 +444,10 @@ class View { ) ); } elseif ($this->shouldEmitHooks() && $result !== false) { + Updater::renameHook(array( + 'oldpath' => $this->getHookPath($path1), + 'newpath' => $this->getHookPath($path2) + )); \OC_Hook::emit( Filesystem::CLASSNAME, Filesystem::signal_post_rename, @@ -741,7 +748,10 @@ class View { } /** + * @param string[] $hooks * @param string $path + * @param bool $post + * @return bool */ private function runHooks($hooks, $path, $post = false) { $path = $this->getHookPath($path); @@ -749,6 +759,16 @@ class View { $run = true; if ($this->shouldEmitHooks($path)) { foreach ($hooks as $hook) { + // manually triger updater hooks to ensure they are called first + if ($post) { + if ($hook == 'write') { + Updater::writeHook(array('path' => $path)); + } elseif ($hook == 'touch') { + Updater::touchHook(array('path' => $path)); + } else if ($hook == 'delete') { + Updater::deleteHook(array('path' => $path)); + } + } if ($hook != 'read') { \OC_Hook::emit( Filesystem::CLASSNAME, diff --git a/tests/lib/files/cache/updater.php b/tests/lib/files/cache/updater.php index 48986149a73..1c4c965af0b 100644 --- a/tests/lib/files/cache/updater.php +++ b/tests/lib/files/cache/updater.php @@ -65,11 +65,6 @@ class Updater extends \PHPUnit_Framework_TestCase { Filesystem::mount($this->storage, array(), '/' . self::$user . '/files'); \OC_Hook::clear('OC_Filesystem'); - - \OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook'); - \OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook'); - \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); - \OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook'); } public function tearDown() { -- cgit v1.2.3 From ab850b961dd576a4caf7c2269d8559fdbe6d62e6 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 26 Feb 2014 23:56:46 +0100 Subject: remove unused code and fix wrong variable names - some PHPDoc updated --- lib/private/image.php | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index 17caaa012f5..da32aa4760f 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -41,8 +41,7 @@ class OC_Image { // exif_imagetype throws "read error!" if file is less than 12 byte if (filesize($filePath) > 11) { $imageType = exif_imagetype($filePath); - } - else { + } else { $imageType = false; } return $imageType ? image_type_to_mime_type($imageType) : ''; @@ -50,7 +49,7 @@ class OC_Image { /** * @brief Constructor. - * @param $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function. + * @param string|resource $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function. * @returns bool False on error */ public function __construct($imageRef = null) { @@ -115,13 +114,11 @@ class OC_Image { case 3: case 4: // Not tested return $this->width(); - break; case 5: // Not tested case 6: case 7: // Not tested case 8: return $this->height(); - break; } return $this->width(); } @@ -140,13 +137,11 @@ class OC_Image { case 3: case 4: // Not tested return $this->height(); - break; case 5: // Not tested case 6: case 7: // Not tested case 8: return $this->width(); - break; } return $this->height(); } @@ -197,7 +192,6 @@ class OC_Image { return false; } - $retVal = false; switch($this->imageType) { case IMAGETYPE_GIF: $retVal = imagegif($this->resource, $filePath); @@ -264,8 +258,8 @@ class OC_Image { } /** - * @returns Returns a base64 encoded string suitable for embedding in a VCard. - */ + * @return string - base64 encoded, which is suitable for embedding in a VCard. + */ function __toString() { return base64_encode($this->data()); } @@ -307,43 +301,33 @@ class OC_Image { $o = $this->getOrientation(); OC_Log::write('core', 'OC_Image->fixOrientation() Orientation: '.$o, OC_Log::DEBUG); $rotate = 0; - $flip = false; switch($o) { case -1: return false; //Nothing to fix - break; case 1: $rotate = 0; - $flip = false; break; case 2: // Not tested $rotate = 0; - $flip = true; break; case 3: $rotate = 180; - $flip = false; break; case 4: // Not tested $rotate = 180; - $flip = true; break; case 5: // Not tested $rotate = 90; - $flip = true; break; case 6: //$rotate = 90; $rotate = 270; - $flip = false; break; case 7: // Not tested $rotate = 270; - $flip = true; break; case 8: $rotate = 90; - $flip = false; break; } if($rotate) { @@ -367,6 +351,7 @@ class OC_Image { return false; } } + return false; } /** @@ -599,9 +584,9 @@ class OC_Image { $meta['imagesize'] = $meta['filesize'] - $meta['offset']; // in rare cases filesize is equal to offset so we need to read physical size if ($meta['imagesize'] < 1) { - $meta['imagesize'] = @filesize($filename) - $meta['offset']; + $meta['imagesize'] = @filesize($fileName) - $meta['offset']; if ($meta['imagesize'] < 1) { - trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING); + trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $fileName . '!', E_USER_WARNING); return false; } } @@ -947,7 +932,7 @@ if ( ! function_exists( 'imagebmp') ) { $index = imagecolorat($im, $i, $j); if ($index !== $lastIndex || $sameNum > 255) { if ($sameNum != 0) { - $bmpData .= chr($same_num) . chr($lastIndex); + $bmpData .= chr($sameNum) . chr($lastIndex); } $lastIndex = $index; $sameNum = 1; -- cgit v1.2.3 From 8282cfff044cb88ddc6901c091fe0e29d837a9a4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 27 Feb 2014 13:15:18 +0100 Subject: Cache the fileinfo in OC\Preview --- lib/private/preview.php | 241 +++++++++++++++++++++++++----------------------- 1 file changed, 126 insertions(+), 115 deletions(-) (limited to 'lib/private') diff --git a/lib/private/preview.php b/lib/private/preview.php index 80fd003ed8d..798a1322b03 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -52,6 +52,11 @@ class Preview { static private $providers = array(); static private $registeredProviders = array(); + /** + * @var \OCP\Files\FileInfo + */ + protected $info; + /** * @brief check if thumbnail or bigger version of thumbnail of file is cached * @param string $user userid - if no user is given, OC_User::getUser will be used @@ -61,12 +66,12 @@ class Preview { * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image * @param bool $scalingUp Disable/Enable upscaling of previews * @return mixed (bool / string) - * false if thumbnail does not exist - * path to thumbnail if thumbnail exists - */ - public function __construct($user='', $root='/', $file='', $maxX=1, $maxY=1, $scalingUp=true) { + * false if thumbnail does not exist + * path to thumbnail if thumbnail exists + */ + public function __construct($user = '', $root = '/', $file = '', $maxX = 1, $maxY = 1, $scalingUp = true) { //init fileviews - if($user === ''){ + if ($user === '') { $user = \OC_User::getUser(); } $this->fileView = new \OC\Files\View('/' . $user . '/' . $root); @@ -86,11 +91,11 @@ class Preview { $this->preview = null; //check if there are preview backends - if(empty(self::$providers)) { + if (empty(self::$providers)) { self::initProviders(); } - if(empty(self::$providers)) { + if (empty(self::$providers)) { \OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR); throw new \Exception('No preview providers'); } @@ -99,15 +104,15 @@ class Preview { /** * @brief returns the path of the file you want a thumbnail from * @return string - */ - public function getFile() { + */ + public function getFile() { return $this->file; } /** * @brief returns the max width of the preview * @return integer - */ + */ public function getMaxX() { return $this->maxX; } @@ -115,7 +120,7 @@ class Preview { /** * @brief returns the max height of the preview * @return integer - */ + */ public function getMaxY() { return $this->maxY; } @@ -123,7 +128,7 @@ class Preview { /** * @brief returns whether or not scalingup is enabled * @return bool - */ + */ public function getScalingUp() { return $this->scalingup; } @@ -131,7 +136,7 @@ class Preview { /** * @brief returns the name of the thumbnailfolder * @return string - */ + */ public function getThumbnailsFolder() { return self::THUMBNAILS_FOLDER; } @@ -139,7 +144,7 @@ class Preview { /** * @brief returns the max scale factor * @return string - */ + */ public function getMaxScaleFactor() { return $this->maxScaleFactor; } @@ -147,7 +152,7 @@ class Preview { /** * @brief returns the max width set in ownCloud's config * @return string - */ + */ public function getConfigMaxX() { return $this->configMaxX; } @@ -155,20 +160,28 @@ class Preview { /** * @brief returns the max height set in ownCloud's config * @return string - */ + */ public function getConfigMaxY() { return $this->configMaxY; } + protected function getFileInfo() { + if (!$this->info) { + $this->info = $this->fileView->getFileInfo($this->file); + } + return $this->info; + } + /** * @brief set the path of the file you want a thumbnail from * @param string $file * @return $this - */ + */ public function setFile($file) { $this->file = $file; + $this->info = null; if ($file !== '') { - $this->mimetype = $this->fileView->getMimeType($this->file); + $this->mimetype = $this->getFileInfo()->getMimetype(); } return $this; } @@ -185,14 +198,14 @@ class Preview { * @brief set the the max width of the preview * @param int $maxX * @return $this - */ - public function setMaxX($maxX=1) { - if($maxX <= 0) { + */ + public function setMaxX($maxX = 1) { + if ($maxX <= 0) { throw new \Exception('Cannot set width of 0 or smaller!'); } $configMaxX = $this->getConfigMaxX(); - if(!is_null($configMaxX)) { - if($maxX > $configMaxX) { + if (!is_null($configMaxX)) { + if ($maxX > $configMaxX) { \OC_Log::write('core', 'maxX reduced from ' . $maxX . ' to ' . $configMaxX, \OC_Log::DEBUG); $maxX = $configMaxX; } @@ -205,14 +218,14 @@ class Preview { * @brief set the the max height of the preview * @param int $maxY * @return $this - */ - public function setMaxY($maxY=1) { - if($maxY <= 0) { + */ + public function setMaxY($maxY = 1) { + if ($maxY <= 0) { throw new \Exception('Cannot set height of 0 or smaller!'); } $configMaxY = $this->getConfigMaxY(); - if(!is_null($configMaxY)) { - if($maxY > $configMaxY) { + if (!is_null($configMaxY)) { + if ($maxY > $configMaxY) { \OC_Log::write('core', 'maxX reduced from ' . $maxY . ' to ' . $configMaxY, \OC_Log::DEBUG); $maxY = $configMaxY; } @@ -225,9 +238,9 @@ class Preview { * @brief set whether or not scalingup is enabled * @param bool $scalingUp * @return $this - */ + */ public function setScalingup($scalingUp) { - if($this->getMaxScaleFactor() === 1) { + if ($this->getMaxScaleFactor() === 1) { $scalingUp = false; } $this->scalingup = $scalingUp; @@ -237,15 +250,15 @@ class Preview { /** * @brief check if all parameters are valid * @return bool - */ + */ public function isFileValid() { $file = $this->getFile(); - if($file === '') { + if ($file === '') { \OC_Log::write('core', 'No filename passed', \OC_Log::DEBUG); return false; } - if(!$this->fileView->file_exists($file)) { + if (!$this->fileView->file_exists($file)) { \OC_Log::write('core', 'File:"' . $file . '" not found', \OC_Log::DEBUG); return false; } @@ -256,40 +269,38 @@ class Preview { /** * @brief deletes previews of a file with specific x and y * @return bool - */ + */ public function deletePreview() { $file = $this->getFile(); - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; + $fileInfo = $this->getFileInfo($file); + $fileId = $fileInfo->getId(); $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/' . $this->getMaxX() . '-' . $this->getMaxY() . '.png'; - $this->userView->unlink($previewPath); - return !$this->userView->file_exists($previewPath); + return $this->userView->unlink($previewPath); } /** * @brief deletes all previews of a file * @return bool - */ + */ public function deleteAllPreviews() { $file = $this->getFile(); - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; + $fileInfo = $this->getFileInfo($file); + $fileId = $fileInfo->getId(); $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; $this->userView->deleteAll($previewPath); - $this->userView->rmdir($previewPath); - return !$this->userView->is_dir($previewPath); + return $this->userView->rmdir($previewPath); } /** * @brief check if thumbnail or bigger version of thumbnail of file is cached * @return mixed (bool / string) - * false if thumbnail does not exist - * path to thumbnail if thumbnail exists - */ + * false if thumbnail does not exist + * path to thumbnail if thumbnail exists + */ private function isCached() { $file = $this->getFile(); $maxX = $this->getMaxX(); @@ -297,75 +308,75 @@ class Preview { $scalingUp = $this->getScalingUp(); $maxScaleFactor = $this->getMaxScaleFactor(); - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; + $fileInfo = $this->getFileInfo($file); + $fileId = $fileInfo->getId(); - if(is_null($fileId)) { + if (is_null($fileId)) { return false; } $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; - if(!$this->userView->is_dir($previewPath)) { + if (!$this->userView->is_dir($previewPath)) { return false; } //does a preview with the wanted height and width already exist? - if($this->userView->file_exists($previewPath . $maxX . '-' . $maxY . '.png')) { + if ($this->userView->file_exists($previewPath . $maxX . '-' . $maxY . '.png')) { return $previewPath . $maxX . '-' . $maxY . '.png'; } - $wantedAspectRatio = (float) ($maxX / $maxY); + $wantedAspectRatio = (float)($maxX / $maxY); //array for usable cached thumbnails $possibleThumbnails = array(); $allThumbnails = $this->userView->getDirectoryContent($previewPath); - foreach($allThumbnails as $thumbnail) { + foreach ($allThumbnails as $thumbnail) { $name = rtrim($thumbnail['name'], '.png'); $size = explode('-', $name); - $x = (int) $size[0]; - $y = (int) $size[1]; + $x = (int)$size[0]; + $y = (int)$size[1]; - $aspectRatio = (float) ($x / $y); - if($aspectRatio !== $wantedAspectRatio) { + $aspectRatio = (float)($x / $y); + if ($aspectRatio !== $wantedAspectRatio) { continue; } - if($x < $maxX || $y < $maxY) { - if($scalingUp) { + if ($x < $maxX || $y < $maxY) { + if ($scalingUp) { $scalefactor = $maxX / $x; - if($scalefactor > $maxScaleFactor) { + if ($scalefactor > $maxScaleFactor) { continue; } - }else{ + } else { continue; } } $possibleThumbnails[$x] = $thumbnail['path']; } - if(count($possibleThumbnails) === 0) { + if (count($possibleThumbnails) === 0) { return false; } - if(count($possibleThumbnails) === 1) { + if (count($possibleThumbnails) === 1) { return current($possibleThumbnails); } ksort($possibleThumbnails); - if(key(reset($possibleThumbnails)) > $maxX) { + if (key(reset($possibleThumbnails)) > $maxX) { return current(reset($possibleThumbnails)); } - if(key(end($possibleThumbnails)) < $maxX) { + if (key(end($possibleThumbnails)) < $maxX) { return current(end($possibleThumbnails)); } - foreach($possibleThumbnails as $width => $path) { - if($width < $maxX) { + foreach ($possibleThumbnails as $width => $path) { + if ($width < $maxX) { continue; - }else{ + } else { return $path; } } @@ -374,9 +385,9 @@ class Preview { /** * @brief return a preview of a file * @return \OC_Image - */ + */ public function getPreview() { - if(!is_null($this->preview) && $this->preview->valid()){ + if (!is_null($this->preview) && $this->preview->valid()) { return $this->preview; } @@ -386,22 +397,22 @@ class Preview { $maxY = $this->getMaxY(); $scalingUp = $this->getScalingUp(); - $fileInfo = $this->fileView->getFileInfo($file); - $fileId = $fileInfo['fileid']; + $fileInfo = $this->getFileInfo($file); + $fileId = $fileInfo->getId(); $cached = $this->isCached(); - if($cached) { + if ($cached) { $image = new \OC_Image($this->userView->file_get_contents($cached, 'r')); $this->preview = $image->valid() ? $image : null; $this->resizeAndCrop(); } - if(is_null($this->preview)) { + if (is_null($this->preview)) { $preview = null; - foreach(self::$providers as $supportedMimetype => $provider) { - if(!preg_match($supportedMimetype, $this->mimetype)) { + foreach (self::$providers as $supportedMimetype => $provider) { + if (!preg_match($supportedMimetype, $this->mimetype)) { continue; } @@ -409,7 +420,7 @@ class Preview { $preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingUp, $this->fileView); - if(!($preview instanceof \OC_Image)) { + if (!($preview instanceof \OC_Image)) { continue; } @@ -419,11 +430,11 @@ class Preview { $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; $cachePath = $previewPath . $maxX . '-' . $maxY . '.png'; - if($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) { + if ($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) { $this->userView->mkdir($this->getThumbnailsFolder() . '/'); } - if($this->userView->is_dir($previewPath) === false) { + if ($this->userView->is_dir($previewPath) === false) { $this->userView->mkdir($previewPath); } @@ -433,7 +444,7 @@ class Preview { } } - if(is_null($this->preview)) { + if (is_null($this->preview)) { $this->preview = new \OC_Image(); } @@ -443,10 +454,10 @@ class Preview { /** * @brief show preview * @return void - */ + */ public function showPreview() { \OCP\Response::enableCaching(3600 * 24); // 24 hours - if(is_null($this->preview)) { + if (is_null($this->preview)) { $this->getPreview(); } $this->preview->show(); @@ -456,7 +467,7 @@ class Preview { /** * @brief show preview * @return void - */ + */ public function show() { $this->showPreview(); return; @@ -465,7 +476,7 @@ class Preview { /** * @brief resize, crop and fix orientation * @return void - */ + */ private function resizeAndCrop() { $image = $this->preview; $x = $this->getMaxX(); @@ -473,17 +484,17 @@ class Preview { $scalingUp = $this->getScalingUp(); $maxscalefactor = $this->getMaxScaleFactor(); - if(!($image instanceof \OC_Image)) { + if (!($image instanceof \OC_Image)) { \OC_Log::write('core', '$this->preview is not an instance of OC_Image', \OC_Log::DEBUG); return; } $image->fixOrientation(); - $realx = (int) $image->width(); - $realy = (int) $image->height(); + $realx = (int)$image->width(); + $realy = (int)$image->height(); - if($x === $realx && $y === $realy) { + if ($x === $realx && $y === $realy) { $this->preview = $image; return; } @@ -491,36 +502,36 @@ class Preview { $factorX = $x / $realx; $factorY = $y / $realy; - if($factorX >= $factorY) { + if ($factorX >= $factorY) { $factor = $factorX; - }else{ + } else { $factor = $factorY; } - if($scalingUp === false) { - if($factor > 1) { + if ($scalingUp === false) { + if ($factor > 1) { $factor = 1; } } - if(!is_null($maxscalefactor)) { - if($factor > $maxscalefactor) { + if (!is_null($maxscalefactor)) { + if ($factor > $maxscalefactor) { \OC_Log::write('core', 'scalefactor reduced from ' . $factor . ' to ' . $maxscalefactor, \OC_Log::DEBUG); $factor = $maxscalefactor; } } - $newXsize = (int) ($realx * $factor); - $newYsize = (int) ($realy * $factor); + $newXsize = (int)($realx * $factor); + $newYsize = (int)($realy * $factor); $image->preciseResize($newXsize, $newYsize); - if($newXsize === $x && $newYsize === $y) { + if ($newXsize === $x && $newYsize === $y) { $this->preview = $image; return; } - if($newXsize >= $x && $newYsize >= $y) { + if ($newXsize >= $x && $newYsize >= $y) { $cropX = floor(abs($x - $newXsize) * 0.5); //don't crop previews on the Y axis, this sucks if it's a document. //$cropY = floor(abs($y - $newYsize) * 0.5); @@ -532,19 +543,19 @@ class Preview { return; } - if($newXsize < $x || $newYsize < $y) { - if($newXsize > $x) { + if ($newXsize < $x || $newYsize < $y) { + if ($newXsize > $x) { $cropX = floor(($newXsize - $x) * 0.5); $image->crop($cropX, 0, $x, $newYsize); } - if($newYsize > $y) { + if ($newYsize > $y) { $cropY = floor(($newYsize - $y) * 0.5); $image->crop(0, $cropY, $newXsize, $y); } - $newXsize = (int) $image->width(); - $newYsize = (int) $image->height(); + $newXsize = (int)$image->width(); + $newYsize = (int)$image->height(); //create transparent background layer $backgroundlayer = imagecreatetruecolor($x, $y); @@ -573,8 +584,8 @@ class Preview { * @param array $options * @return void */ - public static function registerProvider($class, $options=array()) { - self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); + public static function registerProvider($class, $options = array()) { + self::$registeredProviders[] = array('class' => $class, 'options' => $options); } /** @@ -582,19 +593,19 @@ class Preview { * @return void */ private static function initProviders() { - if(!\OC_Config::getValue('enable_previews', true)) { + if (!\OC_Config::getValue('enable_previews', true)) { $provider = new Preview\Unknown(array()); self::$providers = array($provider->getMimeType() => $provider); return; } - if(count(self::$providers)>0) { + if (count(self::$providers) > 0) { return; } - foreach(self::$registeredProviders as $provider) { - $class=$provider['class']; - $options=$provider['options']; + foreach (self::$registeredProviders as $provider) { + $class = $provider['class']; + $options = $provider['options']; $object = new $class($options); @@ -611,7 +622,7 @@ class Preview { public static function post_delete($args) { $path = $args['path']; - if(substr($path, 0, 1) === '/') { + if (substr($path, 0, 1) === '/') { $path = substr($path, 1); } $preview = new Preview(\OC_User::getUser(), 'files/', $path); @@ -622,19 +633,19 @@ class Preview { * @param string $mimetype */ public static function isMimeSupported($mimetype) { - if(!\OC_Config::getValue('enable_previews', true)) { + if (!\OC_Config::getValue('enable_previews', true)) { return false; } //check if there are preview backends - if(empty(self::$providers)) { + if (empty(self::$providers)) { self::initProviders(); } //remove last element because it has the mimetype * $providers = array_slice(self::$providers, 0, -1); - foreach($providers as $supportedMimetype => $provider) { - if(preg_match($supportedMimetype, $mimetype)) { + foreach ($providers as $supportedMimetype => $provider) { + if (preg_match($supportedMimetype, $mimetype)) { return true; } } -- cgit v1.2.3 From 7c92e2e3ad9555746aca7df38431a56bc4aced83 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 27 Feb 2014 14:04:19 +0100 Subject: Update rawlist to work with new fileinfo object --- apps/files/ajax/rawlist.php | 59 +++++++++++++++++++--------------------- lib/private/files/filesystem.php | 2 +- 2 files changed, 29 insertions(+), 32 deletions(-) (limited to 'lib/private') diff --git a/apps/files/ajax/rawlist.php b/apps/files/ajax/rawlist.php index 40da32b223a..89c21a172fc 100644 --- a/apps/files/ajax/rawlist.php +++ b/apps/files/ajax/rawlist.php @@ -1,12 +1,12 @@ getPreviewManager()->isMimeSupported($file['mimetype']); - $file["date"] = OCP\Util::formatDate($file["mtime"]); - $file['mimetype_icon'] = \OCA\Files\Helper::determineIcon($file); - $files[] = $file; - } +if ($mimetypes && !in_array('httpd/unix-directory', $mimetypes)) { + $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir, 'httpd/unix-directory')); } if (is_array($mimetypes) && count($mimetypes)) { foreach ($mimetypes as $mimetype) { - foreach( \OC\Files\Filesystem::getDirectoryContent( $dir, $mimetype ) as $file ) { - $file['directory'] = $dir; - $file['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file['mimetype']); - $file["date"] = OCP\Util::formatDate($file["mtime"]); - $file['mimetype_icon'] = \OCA\Files\Helper::determineIcon($file); - $files[] = $file; - } + $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir, $mimetype)); } } else { - foreach( \OC\Files\Filesystem::getDirectoryContent( $dir ) as $file ) { - $file['directory'] = $dir; - $file['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file['mimetype']); - $file["date"] = OCP\Util::formatDate($file["mtime"]); - $file['mimetype_icon'] = \OCA\Files\Helper::determineIcon($file); - $files[] = $file; - } + $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir)); +} + +$result = array(); +foreach ($files as $file) { + $fileData = array(); + $fileData['directory'] = $dir; + $fileData['name'] = $file->getName(); + $fileData['type'] = $file->getType(); + $fileData['path'] = $file['path']; + $fileData['id'] = $file->getId(); + $fileData['size'] = $file->getSize(); + $fileData['mtime'] = $file->getMtime(); + $fileData['mimetype'] = $file->getMimetype(); + $fileData['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file->getMimetype()); + $fileData["date"] = OCP\Util::formatDate($file->getMtime()); + $fileData['mimetype_icon'] = \OCA\Files\Helper::determineIcon($file); + $result[] = $fileData; } // Sort by name -usort($files, function ($a, $b) { - if ($a['name'] === $b['name']) { - return 0; - } - return ($a['name'] < $b['name']) ? -1 : 1; -}); +usort($result, array('\OCA\Files\Helper', 'fileCmp')); -OC_JSON::success(array('data' => $files)); +OC_JSON::success(array('data' => $result)); diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 7f7b6f7f468..6478854eae8 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -761,7 +761,7 @@ class Filesystem { * * @param string $directory path under datadirectory * @param string $mimetype_filter limit returned content to this mimetype or mimepart - * @return array + * @return \OC\Files\FileInfo[] */ public static function getDirectoryContent($directory, $mimetype_filter = '') { return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter); -- cgit v1.2.3 From 49b331be39162bbca738cadfedd6042028613b94 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Thu, 27 Feb 2014 14:39:16 +0100 Subject: add BMP mimetype for BMP previews --- lib/private/mimetypes.list.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/private') diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index 9bd07b89023..a216414c9dd 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -31,6 +31,7 @@ return array( 'bash' => 'text/x-shellscript', 'blend' => 'application/x-blender', 'bin' => 'application/x-bin', + 'bmp' => 'image/bmp', 'cb7' => 'application/x-cbr', 'cba' => 'application/x-cbr', 'cbr' => 'application/x-cbr', -- cgit v1.2.3 From 4c4bb70cb67fb20739ec48fc2d06400485413dda Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Fri, 28 Feb 2014 11:14:18 +0100 Subject: CSS is now loaded directly instead via PHP 269f24cf9617397aaf501b27ec1af2c8e3154cf8 was not changed in setup.php which prevented loading of CSS files in some environments (e.g. my local setup) for apps. --- lib/private/setup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/setup.php b/lib/private/setup.php index 3906204bda3..0d5bf424b33 100644 --- a/lib/private/setup.php +++ b/lib/private/setup.php @@ -147,7 +147,7 @@ class OC_Setup { $content.= "RewriteRule ^.well-known/host-meta /public.php?service=host-meta [QSA,L]\n"; $content.= "RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]\n"; $content.= "RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]\n"; - $content.= "RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]\n"; + $content.= "RewriteRule ^apps/([^/]*)/(.*\.(php))$ index.php?app=$1&getfile=$2 [QSA,L]\n"; $content.= "RewriteRule ^remote/(.*) remote.php [QSA,L]\n"; $content.= "\n"; $content.= "\n"; -- cgit v1.2.3 From 3ff12ef4eca82325a6e4f1244a12597174e07192 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 28 Feb 2014 14:21:33 +0100 Subject: Also send explicit cache hooks when calling file_put_contents with a resource --- lib/private/files/view.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/private') diff --git a/lib/private/files/view.php b/lib/private/files/view.php index a76115a816e..975b5d00099 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -310,6 +310,9 @@ class View { fclose($target); fclose($data); if ($this->shouldEmitHooks($path) && $result !== false) { + Updater::writeHook(array( + 'path' => $this->getHookPath($path) + )); if (!$exists) { \OC_Hook::emit( Filesystem::CLASSNAME, -- cgit v1.2.3 From da386aad5950235d6d1089f18b5ef4260057d78e Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 28 Feb 2014 14:23:07 +0100 Subject: Allow re-using already known fileinfo when calculating folder sizes --- apps/files_sharing/lib/cache.php | 3 ++- lib/private/files/cache/cache.php | 12 ++++++++---- lib/private/files/cache/homecache.php | 13 ++++++++++--- lib/private/files/cache/scanner.php | 8 +++++--- lib/private/files/cache/updater.php | 4 ++-- 5 files changed, 27 insertions(+), 13 deletions(-) (limited to 'lib/private') diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 4b0da0b002d..579780dcd2b 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -354,9 +354,10 @@ class Shared_Cache extends Cache { * get the size of a folder and set it in the cache * * @param string $path + * @param array $entry (optional) meta data of the folder * @return int */ - public function calculateFolderSize($path) { + public function calculateFolderSize($path, $entry = null) { if ($cache = $this->getSourceCache($path)) { return $cache->calculateFolderSize($this->files[$path]); } diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 9b18257088c..d886fd0fe76 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -498,9 +498,10 @@ class Cache { * update the folder size and the size of all parent folders * * @param string|boolean $path + * @param array $data (optional) meta data of the folder */ - public function correctFolderSize($path) { - $this->calculateFolderSize($path); + public function correctFolderSize($path, $data = null) { + $this->calculateFolderSize($path, $data); if ($path !== '') { $parent = dirname($path); if ($parent === '.' or $parent === '/') { @@ -514,11 +515,14 @@ class Cache { * get the size of a folder and set it in the cache * * @param string $path + * @param array $entry (optional) meta data of the folder * @return int */ - public function calculateFolderSize($path) { + public function calculateFolderSize($path, $entry = null) { $totalSize = 0; - $entry = $this->get($path); + if (is_null($entry)) { + $entry = $this->get($path); + } if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { $id = $entry['fileid']; $sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2, ' . diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index a7c310a3782..fad39a7fdad 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -13,15 +13,21 @@ class HomeCache extends Cache { * get the size of a folder and set it in the cache * * @param string $path + * @param array $entry (optional) meta data of the folder * @return int */ - public function calculateFolderSize($path) { + public function calculateFolderSize($path, $entry = null) { if ($path !== '/' and $path !== '' and $path !== 'files') { - return parent::calculateFolderSize($path); + return parent::calculateFolderSize($path, $entry); + } elseif ($path === '' or $path === '/') { + // since the size of / isn't used (the size of /files is used instead) there is no use in calculating it + return 0; } $totalSize = 0; - $entry = $this->get($path); + if (is_null($entry)) { + $entry = $this->get($path); + } if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { $id = $entry['fileid']; $sql = 'SELECT SUM(`size`) FROM `*PREFIX*filecache` ' . @@ -40,6 +46,7 @@ class HomeCache extends Cache { /** * @param string $path + * @return array */ public function get($path) { $data = parent::get($path); diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index 92a4c01841b..ee6a828f7cc 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -173,14 +173,16 @@ class Scanner extends BasicEmitter { * @param string $path * @param bool $recursive * @param int $reuse - * @return int the size of the scanned folder or -1 if the size is unknown at this stage + * @return array with the meta data of the scanned file or folder */ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { if ($reuse === -1) { $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : 0; } - $this->scanFile($path, $reuse); - return $this->scanChildren($path, $recursive, $reuse); + $data = $this->scanFile($path, $reuse); + $size = $this->scanChildren($path, $recursive, $reuse); + $data['size'] = $size; + return $data; } /** diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index 7a45b9e9e96..666d5dd7fe5 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -38,8 +38,8 @@ class Updater { if ($storage) { $cache = $storage->getCache($internalPath); $scanner = $storage->getScanner($internalPath); - $scanner->scan($internalPath, Scanner::SCAN_SHALLOW); - $cache->correctFolderSize($internalPath); + $data = $scanner->scan($internalPath, Scanner::SCAN_SHALLOW); + $cache->correctFolderSize($internalPath, $data); self::correctFolder($path, $storage->filemtime($internalPath)); self::correctParentStorageMtime($storage, $internalPath); } -- cgit v1.2.3 From 4ab7f58745dd7583163f5f56804774c19b750b57 Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Fri, 28 Feb 2014 11:15:49 -0500 Subject: replace spaces in download link without encoding entire URL --- lib/private/app.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/private') diff --git a/lib/private/app.php b/lib/private/app.php index 048d4d4aeb1..cc3a0025283 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -218,6 +218,8 @@ class OC_App{ }else{ $appdata=OC_OCSClient::getApplication($app); $download=OC_OCSClient::getApplicationDownload($app, 1); + // Replace spaces in download link without encoding entire URL + $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']); if(isset($download['downloadlink']) and $download['downloadlink']!='') { $info = array('source'=>'http', 'href'=>$download['downloadlink'], 'appdata'=>$appdata); $app=OC_Installer::installApp($info); -- cgit v1.2.3 From 195bdff91fc55bf4d2c80ff7d978d74e6efac7a8 Mon Sep 17 00:00:00 2001 From: Myles McNamara Date: Fri, 28 Feb 2014 11:19:19 -0500 Subject: move replace to inside isset --- lib/private/app.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/app.php b/lib/private/app.php index cc3a0025283..58bf67c1d47 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -218,9 +218,9 @@ class OC_App{ }else{ $appdata=OC_OCSClient::getApplication($app); $download=OC_OCSClient::getApplicationDownload($app, 1); - // Replace spaces in download link without encoding entire URL - $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']); if(isset($download['downloadlink']) and $download['downloadlink']!='') { + // Replace spaces in download link without encoding entire URL + $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']); $info = array('source'=>'http', 'href'=>$download['downloadlink'], 'appdata'=>$appdata); $app=OC_Installer::installApp($info); } -- cgit v1.2.3 From 5d5306175f5dd272bead7161f3dd1054cf73dcd0 Mon Sep 17 00:00:00 2001 From: kondou Date: Sat, 1 Mar 2014 03:38:35 +0100 Subject: Fix some docstrings in l10n.php --- lib/private/l10n.php | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'lib/private') diff --git a/lib/private/l10n.php b/lib/private/l10n.php index ad979a92870..197b2d6791b 100644 --- a/lib/private/l10n.php +++ b/lib/private/l10n.php @@ -73,8 +73,8 @@ class OC_L10N implements \OCP\IL10N { /** * get an L10N instance - * @param $app string - * @param $lang string|null + * @param string $app + * @param string|null $lang * @return OC_L10N */ public static function get($app, $lang=null) { @@ -87,8 +87,8 @@ class OC_L10N implements \OCP\IL10N { /** * @brief The constructor - * @param $app string app requesting l10n - * @param $lang string default: null Language + * @param string $app app requesting l10n + * @param string $lang default: null Language * @returns OC_L10N-Object * * If language is not set, the constructor tries to find the right @@ -237,7 +237,7 @@ class OC_L10N implements \OCP\IL10N { /** * @brief Translating - * @param $text String The text we need a translation for + * @param string $text The text we need a translation for * @param array $parameters default:array() Parameters for sprintf * @return \OC_L10N_String Translation or the same text * @@ -250,9 +250,9 @@ class OC_L10N implements \OCP\IL10N { /** * @brief Translating - * @param $text_singular String the string to translate for exactly one object - * @param $text_plural String the string to translate for n objects - * @param $count Integer Number of objects + * @param string $text_singular the string to translate for exactly one object + * @param string $text_plural the string to translate for n objects + * @param integer $count Number of objects * @param array $parameters default:array() Parameters for sprintf * @return \OC_L10N_String Translation or the same text * @@ -351,7 +351,7 @@ class OC_L10N implements \OCP\IL10N { /** * @brief Localization - * @param $type Type of localization + * @param string $type Type of localization * @param $params parameters for this localization * @returns String or false * @@ -406,7 +406,7 @@ class OC_L10N implements \OCP\IL10N { /** * @brief Choose a language - * @param $texts Associative Array with possible strings + * @param array $text Associative Array with possible strings * @returns String * * $text is an array 'de' => 'hallo welt', 'en' => 'hello world', ... @@ -421,7 +421,7 @@ class OC_L10N implements \OCP\IL10N { /** * @brief find the best language - * @param $app Array or string, details below + * @param array|string $app details below * @returns string language * * If $app is an array, ownCloud assumes that these are the available @@ -494,7 +494,7 @@ class OC_L10N implements \OCP\IL10N { /** * @brief find the l10n directory - * @param $app App that needs to be translated + * @param string $app App that needs to be translated * @returns directory */ protected static function findI18nDir($app) { @@ -514,7 +514,7 @@ class OC_L10N implements \OCP\IL10N { /** * @brief find all available languages for an app - * @param $app App that needs to be translated + * @param string $app App that needs to be translated * @returns array an array of available languages */ public static function findAvailableLanguages($app=null) { @@ -533,7 +533,9 @@ class OC_L10N implements \OCP\IL10N { } /** + * @param string $app * @param string $lang + * @returns bool */ public static function languageExists($app, $lang) { if ($lang == 'en') {//english is always available -- cgit v1.2.3 From 1291303c5a312fad9f01fbaf22cc21e3b9b3675d Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sun, 2 Mar 2014 22:30:24 +0100 Subject: Replace OC.Router.generate() with OC.generateUrl() --- apps/files/js/filelist.js | 4 +- apps/files/js/files.js | 4 +- apps/files_sharing/appinfo/routes.php | 1 + core/js/jquery.avatar.js | 41 +++++++++--------- core/js/js.js | 31 +++++++++++--- core/js/router.js | 81 ----------------------------------- core/js/tags.js | 18 ++++---- core/routes.php | 2 - lib/base.php | 1 - lib/private/router.php | 24 ----------- settings/js/admin.js | 2 +- settings/js/personal.js | 10 ++--- settings/js/users.js | 5 ++- settings/routes.php | 2 + 14 files changed, 72 insertions(+), 154 deletions(-) delete mode 100644 core/js/router.js (limited to 'lib/private') diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 550c10dba3e..c3c7f4c2b9b 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -137,7 +137,9 @@ window.FileList={ var download_url = null; if (!param.download_url) { - download_url = OC.Router.generate('download', { file: $('#dir').val()+'/'+name }); + download_url = OC.generateUrl( + '/download{file}', + { file: $('#dir').val()+'/'+name }); } else { download_url = param.download_url; } diff --git a/apps/files/js/files.js b/apps/files/js/files.js index f4546120702..c93862e85d8 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -780,9 +780,9 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { if ( $('#isPublic').length ) { urlSpec.t = $('#dirToken').val(); - previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec); + previewURL = OC.generateUrl('/publicpreview.png?') + $.param(urlSpec); } else { - previewURL = OC.Router.generate('core_ajax_preview', urlSpec); + previewURL = OC.generateUrl('/core/preview.png?') + $.param(urlSpec); } previewURL = previewURL.replace('(', '%28'); previewURL = previewURL.replace(')', '%29'); diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php index 3469829b6f7..9417a6eeb89 100644 --- a/apps/files_sharing/appinfo/routes.php +++ b/apps/files_sharing/appinfo/routes.php @@ -1,4 +1,5 @@ create('core_ajax_public_preview', '/publicpreview.png')->action( function() { require_once __DIR__ . '/../ajax/publicpreview.php'; diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js index 02a40c088b4..381c42d9dbb 100644 --- a/core/js/jquery.avatar.js +++ b/core/js/jquery.avatar.js @@ -75,31 +75,32 @@ var $div = this; - OC.Router.registerLoadedCallback(function() { - var url = OC.Router.generate('core_avatar_get', {user: user, size: size})+'?requesttoken='+oc_requesttoken; - $.get(url, function(result) { - if (typeof(result) === 'object') { - if (!hidedefault) { - if (result.data && result.data.displayname) { - $div.imageplaceholder(user, result.data.displayname); - } else { - $div.imageplaceholder(user); - } + var url = OC.generateUrl( + '/avatar/{user}/{size}?requesttoken={requesttoken}', + {user: user, size: size, requesttoken: oc_requesttoken}); + + $.get(url, function(result) { + if (typeof(result) === 'object') { + if (!hidedefault) { + if (result.data && result.data.displayname) { + $div.imageplaceholder(user, result.data.displayname); } else { - $div.hide(); + $div.imageplaceholder(user); } } else { - $div.show(); - if (ie8fix === true) { - $div.html(''); - } else { - $div.html(''); - } + $div.hide(); } - if(typeof callback === 'function') { - callback(); + } else { + $div.show(); + if (ie8fix === true) { + $div.html(''); + } else { + $div.html(''); } - }); + } + if(typeof callback === 'function') { + callback(); + } }); }; }(jQuery)); diff --git a/core/js/js.js b/core/js/js.js index 21ccee0f1d5..80d83dc07f9 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -194,6 +194,27 @@ var OC={ linkToRemoteBase:function(service) { return OC.webroot + '/remote.php/' + service; }, + + generateUrl: function(url, params) { + var _build = function (text, vars) { + return text.replace(/{([^{}]*)}/g, + function (a, b) { + var r = vars[b]; + return typeof r === 'string' || typeof r === 'number' ? r : a; + } + ); + }; + if (url.charAt(0) !== '/') { + url = '/' + url; + + } + return OC.webroot + '/index.php' + _build(url, params); + }, + + linkToRoute:function(route) { + return OC.webroot + '/index.php/' + route; + }, + /** * @brief Creates an absolute url for remote use * @param string $service id @@ -791,12 +812,10 @@ function initCore() { if (interval < 60) { interval = 60; } - OC.Router.registerLoadedCallback(function(){ - var url = OC.Router.generate('heartbeat'); - setInterval(function(){ - $.post(url); - }, interval * 1000); - }); + var url = OC.linkToRoute('heartbeat'); + setInterval(function(){ + $.post(url); + }, interval * 1000); } // session heartbeat (defaults to enabled) diff --git a/core/js/router.js b/core/js/router.js deleted file mode 100644 index e6ef54a1864..00000000000 --- a/core/js/router.js +++ /dev/null @@ -1,81 +0,0 @@ -OC.router_base_url = OC.webroot + '/index.php'; -OC.Router = { - // register your ajax requests to load after the loading of the routes - // has finished. otherwise you face problems with race conditions - registerLoadedCallback: function(callback){ - if (!this.routes_request){ - return; - } - this.routes_request.done(callback); - }, - routes_request: !window.TESTING && $.ajax(OC.router_base_url + '/core/routes.json', { - dataType: 'json', - success: function(jsondata) { - if (jsondata.status === 'success') { - OC.Router.routes = jsondata.data; - } - } - }), - generate:function(name, opt_params) { - if (!('routes' in this)) { - if(this.routes_request.state() != 'resolved') { - console.warn('To avoid race conditions, please register a callback');// wait - } - } - if (!(name in this.routes)) { - throw new Error('The route "' + name + '" does not exist.'); - } - var route = this.routes[name]; - var params = opt_params || {}; - var unusedParams = $.extend(true, {}, params); - var url = ''; - var optional = true; - $(route.tokens).each(function(i, token) { - if ('text' === token[0]) { - url = token[1] + url; - optional = false; - - return; - } - - if ('variable' === token[0]) { - if (false === optional || !(token[3] in route.defaults) - || ((token[3] in params) && params[token[3]] != route.defaults[token[3]])) { - var value; - if (token[3] in params) { - value = params[token[3]]; - delete unusedParams[token[3]]; - } else if (token[3] in route.defaults) { - value = route.defaults[token[3]]; - } else if (optional) { - return; - } else { - throw new Error('The route "' + name + '" requires the parameter "' + token[3] + '".'); - } - - var empty = true === value || false === value || '' === value; - - if (!empty || !optional) { - url = token[1] + encodeURIComponent(value).replace(/%2F/g, '/') + url; - } - - optional = false; - } - - return; - } - - throw new Error('The token type "' + token[0] + '" is not supported.'); - }); - if (url === '') { - url = '/'; - } - - unusedParams = $.param(unusedParams); - if (unusedParams.length > 0) { - url += '?'+unusedParams; - } - - return OC.router_base_url + url; - } -} diff --git a/core/js/tags.js b/core/js/tags.js index bc6d7b4e071..bc2b42bf5ff 100644 --- a/core/js/tags.js +++ b/core/js/tags.js @@ -69,7 +69,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_ids_for_tag', {type: type}); + url = OC.generateUrl('/tags/{type}/ids', {type: type}); $.getJSON(url, {tag: tag}, function(response) { if(response.status === 'success') { defer.resolve(response.ids); @@ -90,7 +90,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_favorites', {type: type}); + url = OC.generateUrl('/tags/{type}/favorites', {type: type}); $.getJSON(url, function(response) { if(response.status === 'success') { defer.resolve(response.ids); @@ -111,7 +111,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_tags', {type: type}); + url = OC.generateUrl('/tags/{type}', {type: type}); $.getJSON(url, function(response) { if(response.status === 'success') { defer.resolve(response.tags); @@ -133,7 +133,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_tag', {type: type, id: id}); + url = OC.generateUrl('/tags/{type}/tag/{id}/', {type: type, id: id}); $.post(url, {tag: tag}, function(response) { if(response.status === 'success') { defer.resolve(response); @@ -157,7 +157,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_untag', {type: type, id: id}); + url = OC.generateUrl('/tags/{type}/untag/{id}/', {type: type, id: id}); $.post(url, {tag: tag}, function(response) { if(response.status === 'success') { defer.resolve(response); @@ -181,7 +181,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_favorite', {type: type, id: id}); + url = OC.generateUrl('/tags/{type}/favorite/{id}/', {type: type, id: id}); $.post(url, function(response) { if(response.status === 'success') { defer.resolve(response); @@ -205,7 +205,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_unfavorite', {type: type, id: id}); + url = OC.generateUrl('/tags/{type}/unfavorite/{id}/', {type: type, id: id}); $.post(url, function(response) { if(response.status === 'success') { defer.resolve(); @@ -229,7 +229,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_add', {type: type}); + url = OC.generateUrl('/tags/{type}/add', {type: type}); $.post(url,{tag:tag}, function(response) { if(typeof cb == 'function') { cb(response); @@ -256,7 +256,7 @@ OC.Tags= { type = type ? type : this.type; var defer = $.Deferred(), self = this, - url = OC.Router.generate('core_tags_delete', {type: type}); + url = OC.generateUrl('/tags/{type}/delete', {type: type}); if(!tags || !tags.length) { throw new Error(t('core', 'No tags selected for deletion.')); } diff --git a/core/routes.php b/core/routes.php index aea788bdc6b..76cf03c3673 100644 --- a/core/routes.php +++ b/core/routes.php @@ -65,8 +65,6 @@ $this->create('core_tags_delete', '/tags/{type}/delete') $this->create('js_config', '/core/js/oc.js') ->actionInclude('core/js/config.php'); // Routing -$this->create('core_ajax_routes', '/core/routes.json') - ->action('OC_Router', 'JSRoutes'); $this->create('core_ajax_preview', '/core/preview.png') ->actionInclude('core/ajax/preview.php'); $this->create('core_lostpassword_index', '/lostpassword/') diff --git a/lib/base.php b/lib/base.php index 49cbb1279d1..7703e83ec2e 100644 --- a/lib/base.php +++ b/lib/base.php @@ -316,7 +316,6 @@ class OC { OC_Util::addScript("config"); //OC_Util::addScript( "multiselect" ); OC_Util::addScript('search', 'result'); - OC_Util::addScript('router'); OC_Util::addScript("oc-requesttoken"); // avatars diff --git a/lib/private/router.php b/lib/private/router.php index 19c1e4473ec..918e3b13206 100644 --- a/lib/private/router.php +++ b/lib/private/router.php @@ -158,28 +158,4 @@ class OC_Router { return $this->getGenerator()->generate($name, $parameters, $absolute); } - /** - * Generate JSON response for routing in javascript - */ - public static function JSRoutes() - { - $router = OC::getRouter(); - - $etag = $router->getCacheKey(); - OC_Response::enableCaching(); - OC_Response::setETagHeader($etag); - - $root = $router->getCollection('root'); - $routes = array(); - foreach($root->all() as $name => $route) { - $compiled_route = $route->compile(); - $defaults = $route->getDefaults(); - unset($defaults['action']); - $routes[$name] = array( - 'tokens' => $compiled_route->getTokens(), - 'defaults' => $defaults, - ); - } - OCP\JSON::success ( array( 'data' => $routes ) ); - } } diff --git a/settings/js/admin.js b/settings/js/admin.js index 5ea6a5af2df..cfb1cb788d0 100644 --- a/settings/js/admin.js +++ b/settings/js/admin.js @@ -64,7 +64,7 @@ $(document).ready(function(){ $('#mail_settings').change(function(){ OC.msg.startSaving('#mail_settings .msg'); var post = $( "#mail_settings" ).serialize(); - $.post(OC.Router.generate('settings_mail_settings'), post, function(data){ + $.post(OC.generateUrl('/settings/admin/mailsettings'), post, function(data){ OC.msg.finishedSaving('#mail_settings .msg', data); }); }); diff --git a/settings/js/personal.js b/settings/js/personal.js index 98bfe7132d4..7a4257f1c97 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -67,7 +67,7 @@ function showAvatarCropper() { $cropper.prepend(""); $cropperImage = $('#cropper img'); - $cropperImage.attr('src', OC.Router.generate('core_avatar_get_tmp')+'?requesttoken='+oc_requesttoken+'#'+Math.floor(Math.random()*1000)); + $cropperImage.attr('src', OC.generateUrl('/avatar/tmp')+'?requesttoken='+oc_requesttoken+'#'+Math.floor(Math.random()*1000)); // Looks weird, but on('load', ...) doesn't work in IE8 $cropperImage.ready(function(){ @@ -95,7 +95,7 @@ function sendCropData() { w: cropperdata.w, h: cropperdata.h }; - $.post(OC.Router.generate('core_avatar_post_cropped'), {crop: data}, avatarResponseHandler); + $.post(OC.generateUrl('/avatar/cropped'), {crop: data}, avatarResponseHandler); } function saveCoords(c) { @@ -132,7 +132,7 @@ $(document).ready(function(){ $('#passwordchanged').hide(); $('#passworderror').hide(); // Ajax foo - $.post(OC.Router.generate('settings_personal_changepassword'), post, function(data){ + $.post(OC.generateUrl('/settings/personal/changepassword'), post, function(data){ if( data.status === "success" ){ $('#pass1').val(''); $('#pass2').val(''); @@ -243,7 +243,7 @@ $(document).ready(function(){ OC.dialogs.filepicker( t('settings', "Select a profile picture"), function(path){ - $.post(OC.Router.generate('core_avatar_post'), {path: path}, avatarResponseHandler); + $.post(OC.generateUrl('/avatar/'), {path: path}, avatarResponseHandler); }, false, ["image/png", "image/jpeg"] @@ -253,7 +253,7 @@ $(document).ready(function(){ $('#removeavatar').click(function(){ $.ajax({ type: 'DELETE', - url: OC.Router.generate('core_avatar_delete'), + url: OC.generateUrl('/avatar/'), success: function(msg) { updateAvatar(true); } diff --git a/settings/js/users.js b/settings/js/users.js index 160d0a8d9d2..6b5447c7674 100644 --- a/settings/js/users.js +++ b/settings/js/users.js @@ -225,7 +225,8 @@ var UserList = { } $('table+.loading').css('visibility', 'visible'); UserList.updating = true; - $.get(OC.Router.generate('settings_ajax_userlist', { offset: UserList.offset, limit: UserList.usersToLoad }), function (result) { + var query = $.param({ offset: UserList.offset, limit: UserList.usersToLoad }); + $.get(OC.generateUrl('/settings/ajax/userlist') + query, function (result) { var loadedUsers = 0; var trs = []; if (result.status === 'success') { @@ -401,7 +402,7 @@ $(document).ready(function () { if ($(this).val().length > 0) { var recoveryPasswordVal = $('input:password[id="recoveryPassword"]').val(); $.post( - OC.Router.generate('settings_users_changepassword'), + OC.generateUrl('/settings/users/changepassword'), {username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal}, function (result) { if (result.status != 'success') { diff --git a/settings/routes.php b/settings/routes.php index 64f7122f0cf..7d94f130088 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -6,6 +6,8 @@ * See the COPYING-README file. */ +/** @var $this OC_Router */ + // Settings pages $this->create('settings_help', '/settings/help') ->actionInclude('settings/help.php'); -- cgit v1.2.3 From b8d0fc94949e6e28b9fcb603deec9759e55cb6a3 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 3 Mar 2014 12:43:22 +0100 Subject: make mail notification header color themable --- core/templates/mail.php | 4 ++-- lib/private/defaults.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/core/templates/mail.php b/core/templates/mail.php index c46fd6ab805..854240a976f 100644 --- a/core/templates/mail.php +++ b/core/templates/mail.php @@ -2,8 +2,8 @@ - - + diff --git a/lib/private/defaults.php b/lib/private/defaults.php index 59630cda5c0..79be211b82f 100644 --- a/lib/private/defaults.php +++ b/lib/private/defaults.php @@ -21,6 +21,7 @@ class OC_Defaults { private $defaultDocBaseUrl; private $defaultSlogan; private $defaultLogoClaim; + private $defaultMailHeaderColor; function __construct() { $this->l = OC_L10N::get('core'); @@ -33,6 +34,7 @@ class OC_Defaults { $this->defaultDocBaseUrl = "http://doc.owncloud.org"; $this->defaultSlogan = $this->l->t("web services under your control"); $this->defaultLogoClaim = ""; + $this->defaultMailHeaderColor = "#1d2d44"; /* header color of mail notifications */ if (class_exists("OC_Theme")) { $this->theme = new OC_Theme(); @@ -181,4 +183,16 @@ class OC_Defaults { return $this->getDocBaseUrl() . '/server/6.0/go.php?to=' . $key; } + /** + * Returns mail header color + * @return mail header color + */ + public function getMailHeaderColor() { + if ($this->themeExist('getMailHeaderColor')) { + return $this->theme->getMailHeaderColor(); + } else { + return $this->defaultMailHeaderColor; + } + } + } -- cgit v1.2.3 From c87658fedab5073642848b2db0e8707dc2b5cff4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 3 Mar 2014 12:56:08 +0100 Subject: Fix updater when getFileInfo fails --- lib/private/files/cache/updater.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index 7a45b9e9e96..f6ea914bf62 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -119,6 +119,9 @@ class Updater { if ($uid != \OCP\User::getUser()) { $info = \OC\Files\Filesystem::getFileInfo($filename); + if (!$info) { + return array($uid, '/files/' . $filename); + } $ownerView = new \OC\Files\View('/' . $uid . '/files'); $filename = $ownerView->getPath($info['fileid']); } @@ -150,7 +153,7 @@ class Updater { $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath))); if ($realPath !== '') { $realPath = dirname($realPath); - if($realPath === DIRECTORY_SEPARATOR ) { + if ($realPath === DIRECTORY_SEPARATOR) { $realPath = ""; } // check storage for parent in case we change the storage in this step -- cgit v1.2.3 From 79ae3c4527b492bee76b2951ca14e8259147b181 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 3 Mar 2014 11:31:46 +0100 Subject: Allow XML entity loader for MDB2 schema loader Forward port of 762b0d9 from stable6 to master --- lib/private/db/mdb2schemareader.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/private') diff --git a/lib/private/db/mdb2schemareader.php b/lib/private/db/mdb2schemareader.php index f9a76786c3e..1c16d03eab2 100644 --- a/lib/private/db/mdb2schemareader.php +++ b/lib/private/db/mdb2schemareader.php @@ -41,7 +41,9 @@ class MDB2SchemaReader { */ public function loadSchemaFromFile($file) { $schema = new \Doctrine\DBAL\Schema\Schema(); + $loadEntities = libxml_disable_entity_loader(false); $xml = simplexml_load_file($file); + libxml_disable_entity_loader($loadEntities); foreach ($xml->children() as $child) { /** * @var \SimpleXMLElement $child -- cgit v1.2.3 From 06c6163265bf10e7aa84c2621d58323b3ad94963 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 3 Mar 2014 16:48:28 +0100 Subject: Check if fields we need are actually set to prevent errors --- lib/private/files/cache/cache.php | 4 ++-- lib/private/files/cache/scanner.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index d886fd0fe76..abc11e76470 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -520,7 +520,7 @@ class Cache { */ public function calculateFolderSize($path, $entry = null) { $totalSize = 0; - if (is_null($entry)) { + if (is_null($entry) or !isset($entry['fileid'])) { $entry = $this->get($path); } if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { @@ -544,7 +544,7 @@ class Cache { if ($entry['size'] !== $totalSize) { $update['size'] = $totalSize; } - if ($entry['unencrypted_size'] !== $unencryptedSum) { + if (!isset($entry['unencrypted_size']) or $entry['unencrypted_size'] !== $unencryptedSum) { $update['unencrypted_size'] = $unencryptedSum; } if (count($update) > 0) { diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index ee6a828f7cc..79159724d16 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -155,7 +155,7 @@ class Scanner extends BasicEmitter { } } if (!empty($newData)) { - $this->cache->put($file, $newData); + $data['fileid'] = $this->cache->put($file, $newData); $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', array($file, $this->storageId)); \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', array('path' => $file, 'storage' => $this->storageId)); } -- cgit v1.2.3 From 5e3b6f1fd9f3ba07031cb1cc1757d9ae94bebba6 Mon Sep 17 00:00:00 2001 From: kondou Date: Mon, 3 Mar 2014 17:32:29 +0100 Subject: Fix some more docstrings --- lib/private/config.php | 2 +- lib/private/template/base.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/config.php b/lib/private/config.php index 3649da84973..56f47256134 100644 --- a/lib/private/config.php +++ b/lib/private/config.php @@ -77,7 +77,7 @@ class Config { /** * @brief Gets a value from config.php * @param string $key key - * @param string|null $default = null default value + * @param array|bool|string|null $default = null default value * @return string the value or $default * * This function gets the value from config.php. If it does not exist, diff --git a/lib/private/template/base.php b/lib/private/template/base.php index 232a29939cc..7aa0cb4a956 100644 --- a/lib/private/template/base.php +++ b/lib/private/template/base.php @@ -61,7 +61,7 @@ class Base { /** * @brief Assign variables * @param string $key key - * @param string $value value + * @param array|bool|integer|string $value value * @return bool * * This function assigns a variable. It can be accessed via $_[$key] in -- cgit v1.2.3 From a8c67dc675d21c6c8167c6477157a07d372bc410 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 4 Mar 2014 15:44:58 +0100 Subject: Add caching for getLocalFile on remote storages --- apps/files_external/lib/webdav.php | 193 +++++++++++++++++------------------ lib/private/files/storage/common.php | 24 ++++- 2 files changed, 116 insertions(+), 101 deletions(-) (limited to 'lib/private') diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 9afe73aebd7..279ae716935 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -8,7 +8,7 @@ namespace OC\Files\Storage; -class DAV extends \OC\Files\Storage\Common{ +class DAV extends \OC\Files\Storage\Common { private $password; private $user; private $host; @@ -21,7 +21,7 @@ class DAV extends \OC\Files\Storage\Common{ */ private $client; - private static $tempFiles=array(); + private static $tempFiles = array(); public function __construct($params) { if (isset($params['host']) && isset($params['user']) && isset($params['password'])) { @@ -29,9 +29,9 @@ class DAV extends \OC\Files\Storage\Common{ //remove leading http[s], will be generated in createBaseUri() if (substr($host, 0, 8) == "https://") $host = substr($host, 8); else if (substr($host, 0, 7) == "http://") $host = substr($host, 7); - $this->host=$host; - $this->user=$params['user']; - $this->password=$params['password']; + $this->host = $host; + $this->user = $params['user']; + $this->password = $params['password']; if (isset($params['secure'])) { if (is_string($params['secure'])) { $this->secure = ($params['secure'] === 'true'); @@ -42,25 +42,25 @@ class DAV extends \OC\Files\Storage\Common{ $this->secure = false; } if ($this->secure === true) { - $certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt'; + $certPath = \OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt'; if (file_exists($certPath)) { - $this->certPath=$certPath; + $this->certPath = $certPath; } } - $this->root=isset($params['root'])?$params['root']:'/'; - if ( ! $this->root || $this->root[0]!='/') { - $this->root='/'.$this->root; + $this->root = isset($params['root']) ? $params['root'] : '/'; + if (!$this->root || $this->root[0] != '/') { + $this->root = '/' . $this->root; } - if (substr($this->root, -1, 1)!='/') { - $this->root.='/'; + if (substr($this->root, -1, 1) != '/') { + $this->root .= '/'; } } else { throw new \Exception(); } } - private function init(){ - if($this->ready) { + private function init() { + if ($this->ready) { return; } $this->ready = true; @@ -78,28 +78,28 @@ class DAV extends \OC\Files\Storage\Common{ } } - public function getId(){ + public function getId() { return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; } protected function createBaseUri() { - $baseUri='http'; + $baseUri = 'http'; if ($this->secure) { - $baseUri.='s'; + $baseUri .= 's'; } - $baseUri.='://'.$this->host.$this->root; + $baseUri .= '://' . $this->host . $this->root; return $baseUri; } public function mkdir($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); return $this->simpleResponse('MKCOL', $path, null, 201); } public function rmdir($path) { $this->init(); - $path=$this->cleanPath($path) . '/'; + $path = $this->cleanPath($path) . '/'; // FIXME: some WebDAV impl return 403 when trying to DELETE // a non-empty folder return $this->simpleResponse('DELETE', $path, null, 204); @@ -107,35 +107,35 @@ class DAV extends \OC\Files\Storage\Common{ public function opendir($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array(), 1); - $id=md5('webdav'.$this->root.$path); + $response = $this->client->propfind($this->encodePath($path), array(), 1); + $id = md5('webdav' . $this->root . $path); $content = array(); - $files=array_keys($response); - array_shift($files);//the first entry is the current directory + $files = array_keys($response); + array_shift($files); //the first entry is the current directory foreach ($files as $file) { $file = urldecode(basename($file)); - $content[]=$file; + $content[] = $file; } \OC\Files\Stream\Dir::register($id, $content); - return opendir('fakedir://'.$id); - } catch(\Exception $e) { + return opendir('fakedir://' . $id); + } catch (\Exception $e) { return false; } } public function filetype($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype')); + $response = $this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype')); $responseType = array(); if (isset($response["{DAV:}resourcetype"])) { - $responseType=$response["{DAV:}resourcetype"]->resourceType; + $responseType = $response["{DAV:}resourcetype"]->resourceType; } - return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; - } catch(\Exception $e) { + return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file'; + } catch (\Exception $e) { error_log($e->getMessage()); \OCP\Util::writeLog("webdav client", \OCP\Util::sanitizeHTML($e->getMessage()), \OCP\Util::ERROR); return false; @@ -144,11 +144,11 @@ class DAV extends \OC\Files\Storage\Common{ public function file_exists($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { $this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype')); - return true;//no 404 exception - } catch(\Exception $e) { + return true; //no 404 exception + } catch (\Exception $e) { return false; } } @@ -160,34 +160,34 @@ class DAV extends \OC\Files\Storage\Common{ public function fopen($path, $mode) { $this->init(); - $path=$this->cleanPath($path); - switch($mode) { + $path = $this->cleanPath($path); + switch ($mode) { case 'r': case 'rb': - if ( ! $this->file_exists($path)) { + if (!$this->file_exists($path)) { return false; } //straight up curl instead of sabredav here, sabredav put's the entire get result in memory $curl = curl_init(); $fp = fopen('php://temp', 'r+'); - curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password); - curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$this->encodePath($path)); + curl_setopt($curl, CURLOPT_USERPWD, $this->user . ':' . $this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri() . $this->encodePath($path)); curl_setopt($curl, CURLOPT_FILE, $fp); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); if ($this->secure === true) { curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); - if($this->certPath){ + if ($this->certPath) { curl_setopt($curl, CURLOPT_CAINFO, $this->certPath); } } - - curl_exec ($curl); + + curl_exec($curl); $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($statusCode !== 200) { \OCP\Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, \OCP\Util::ERROR); } - curl_close ($curl); + curl_close($curl); rewind($fp); return $fp; case 'w': @@ -203,18 +203,19 @@ class DAV extends \OC\Files\Storage\Common{ case 'c': case 'c+': //emulate these - if (strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); + if (strrpos($path, '.') !== false) { + $ext = substr($path, strrpos($path, '.')); } else { - $ext=''; + $ext = ''; } - $tmpFile = \OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - if($this->file_exists($path)) { - $this->getFile($path, $tmpFile); + if ($this->file_exists($path)) { + $tmpFile = $this->getCachedFile($path); + } else { + $tmpFile = \OCP\Files::tmpFile($ext); } - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); + self::$tempFiles[$tmpFile] = $path; + return fopen('close://' . $tmpFile, $mode); } } @@ -227,32 +228,31 @@ class DAV extends \OC\Files\Storage\Common{ public function free_space($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes')); + $response = $this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes')); if (isset($response['{DAV:}quota-available-bytes'])) { return (int)$response['{DAV:}quota-available-bytes']; } else { return \OC\Files\SPACE_UNKNOWN; } - } catch(\Exception $e) { + } catch (\Exception $e) { return \OC\Files\SPACE_UNKNOWN; } } - public function touch($path, $mtime=null) { + public function touch($path, $mtime = null) { $this->init(); if (is_null($mtime)) { - $mtime=time(); + $mtime = time(); } - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); // if file exists, update the mtime, else create a new empty file if ($this->file_exists($path)) { try { $this->client->proppatch($this->encodePath($path), array('{DAV:}lastmodified' => $mtime)); - } - catch (\Sabre_DAV_Exception_NotImplemented $e) { + } catch (\Sabre_DAV_Exception_NotImplemented $e) { return false; } } else { @@ -261,23 +261,13 @@ class DAV extends \OC\Files\Storage\Common{ return true; } - /** - * @param string $path - * @param string $target - */ - public function getFile($path, $target) { - $this->init(); - $source=$this->fopen($path, 'r'); - file_put_contents($target, $source); - } - - public function uploadFile($path, $target) { + protected function uploadFile($path, $target) { $this->init(); - $source=fopen($path, 'r'); + $source = fopen($path, 'r'); $curl = curl_init(); - curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password); - curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $target)); + curl_setopt($curl, CURLOPT_USERPWD, $this->user . ':' . $this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri() . str_replace(' ', '%20', $target)); curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); @@ -285,26 +275,29 @@ class DAV extends \OC\Files\Storage\Common{ if ($this->secure === true) { curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); - if($this->certPath){ + if ($this->certPath) { curl_setopt($curl, CURLOPT_CAINFO, $this->certPath); } } - curl_exec ($curl); + curl_exec($curl); $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($statusCode !== 200) { \OCP\Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, \OCP\Util::ERROR); } - curl_close ($curl); + curl_close($curl); + $this->removeCachedFile($target); } public function rename($path1, $path2) { $this->init(); $path1 = $this->encodePath($this->cleanPath($path1)); - $path2 = $this->createBaseUri().$this->encodePath($this->cleanPath($path2)); + $path2 = $this->createBaseUri() . $this->encodePath($this->cleanPath($path2)); try { - $this->client->request('MOVE', $path1, null, array('Destination'=>$path2)); + $this->client->request('MOVE', $path1, null, array('Destination' => $path2)); + $this->removeCachedFile($path1); + $this->removeCachedFile($path2); return true; - } catch(\Exception $e) { + } catch (\Exception $e) { return false; } } @@ -312,47 +305,48 @@ class DAV extends \OC\Files\Storage\Common{ public function copy($path1, $path2) { $this->init(); $path1 = $this->encodePath($this->cleanPath($path1)); - $path2 = $this->createBaseUri().$this->encodePath($this->cleanPath($path2)); + $path2 = $this->createBaseUri() . $this->encodePath($this->cleanPath($path2)); try { - $this->client->request('COPY', $path1, null, array('Destination'=>$path2)); + $this->client->request('COPY', $path1, null, array('Destination' => $path2)); + $this->removeCachedFile($path2); return true; - } catch(\Exception $e) { + } catch (\Exception $e) { return false; } } public function stat($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { $response = $this->client->propfind($this->encodePath($path), array('{DAV:}getlastmodified', '{DAV:}getcontentlength')); return array( - 'mtime'=>strtotime($response['{DAV:}getlastmodified']), - 'size'=>(int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, + 'mtime' => strtotime($response['{DAV:}getlastmodified']), + 'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, ); - } catch(\Exception $e) { + } catch (\Exception $e) { return array(); } } public function getMimeType($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array('{DAV:}getcontenttype', '{DAV:}resourcetype')); + $response = $this->client->propfind($this->encodePath($path), array('{DAV:}getcontenttype', '{DAV:}resourcetype')); $responseType = array(); if (isset($response["{DAV:}resourcetype"])) { - $responseType=$response["{DAV:}resourcetype"]->resourceType; + $responseType = $response["{DAV:}resourcetype"]->resourceType; } - $type=(count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; - if ($type=='dir') { + $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file'; + if ($type == 'dir') { return 'httpd/unix-directory'; } elseif (isset($response['{DAV:}getcontenttype'])) { return $response['{DAV:}getcontenttype']; } else { return false; } - } catch(\Exception $e) { + } catch (\Exception $e) { return false; } } @@ -368,6 +362,7 @@ class DAV extends \OC\Files\Storage\Common{ /** * URL encodes the given path but keeps the slashes + * * @param string $path to encode * @return string encoded path */ @@ -382,11 +377,11 @@ class DAV extends \OC\Files\Storage\Common{ * @param integer $expected */ private function simpleResponse($method, $path, $body, $expected) { - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->request($method, $this->encodePath($path), $body); - return $response['statusCode']==$expected; - } catch(\Exception $e) { + $response = $this->client->request($method, $this->encodePath($path), $body); + return $response['statusCode'] == $expected; + } catch (\Exception $e) { return false; } } diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 9e826dd6192..3c078d7b1b4 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -27,6 +27,11 @@ abstract class Common implements \OC\Files\Storage\Storage { protected $watcher; protected $storageCache; + /** + * @var string[] + */ + protected $cachedFiles = array(); + public function __construct($parameters) { } @@ -122,11 +127,13 @@ abstract class Common implements \OC\Files\Storage\Storage { public function file_put_contents($path, $data) { $handle = $this->fopen($path, "w"); + $this->removeCachedFile($path); return fwrite($handle, $data); } public function rename($path1, $path2) { if ($this->copy($path1, $path2)) { + $this->removeCachedFile($path1); return $this->unlink($path1); } else { return false; @@ -137,6 +144,7 @@ abstract class Common implements \OC\Files\Storage\Storage { $source = $this->fopen($path1, 'r'); $target = $this->fopen($path2, 'w'); list($count, $result) = \OC_Helper::streamCopy($source, $target); + $this->removeCachedFile($path2); return $result; } @@ -162,13 +170,14 @@ abstract class Common implements \OC\Files\Storage\Storage { } public function getLocalFile($path) { - return $this->toTmpFile($path); + return $this->getCachedFile($path); } /** * @param string $path + * @return string */ - private function toTmpFile($path) { //no longer in the storage api, still useful here + protected function toTmpFile($path) { //no longer in the storage api, still useful here $source = $this->fopen($path, 'r'); if (!$source) { return false; @@ -352,4 +361,15 @@ abstract class Common implements \OC\Files\Storage\Storage { // default, which is not local return false; } + + protected function getCachedFile($path) { + if (!isset($this->cachedFiles[$path])) { + $this->cachedFiles[$path] = $this->toTmpFile($path); + } + return $this->cachedFiles[$path]; + } + + protected function removeCachedFile($path) { + unset($this->cachedFiles[$path]); + } } -- cgit v1.2.3 From 2e73c957e5b3ae4030e41520088fb078354ae8b1 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 4 Mar 2014 16:42:40 +0100 Subject: don't allow to create a file or folder named 'Shared' in the root folder, also exclude all combinations of lower and upper case letters --- apps/files/ajax/move.php | 2 +- apps/files/js/file-upload.js | 34 ++++++++++++++--------------- apps/files/js/filelist.js | 9 +++----- apps/files/js/files.js | 7 ++++-- apps/files/tests/js/filesSpec.js | 35 ++++++++++++++++++++++++++++++ lib/private/connector/sabre/directory.php | 4 ++-- lib/private/connector/sabre/objecttree.php | 3 +++ 7 files changed, 66 insertions(+), 28 deletions(-) (limited to 'lib/private') diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php index 93063e52eb0..04a260265c2 100644 --- a/apps/files/ajax/move.php +++ b/apps/files/ajax/move.php @@ -18,7 +18,7 @@ if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) { exit; } -if ($dir != '' || $file != 'Shared') { +if ($target != '' || strtolower($file) != 'shared') { $targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file); $sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file); if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) { diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index f962a7044a8..aa85644cefb 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -82,7 +82,7 @@ OC.Upload = { */ isProcessing:function() { var count = 0; - + jQuery.each(this._uploads,function(i, data) { if (data.state() === 'pending') { count++; @@ -208,13 +208,13 @@ $(document).ready(function() { add: function(e, data) { OC.Upload.log('add', e, data); var that = $(this); - + // we need to collect all data upload objects before starting the upload so we can check their existence // and set individual conflict actions. unfortunately there is only one variable that we can use to identify // the selection a data upload is part of, so we have to collect them in data.originalFiles // turning singleFileUploads off is not an option because we want to gracefully handle server errors like // already exists - + // create a container where we can store the data objects if ( ! data.originalFiles.selection ) { // initialize selection and remember number of files to upload @@ -225,34 +225,34 @@ $(document).ready(function() { }; } var selection = data.originalFiles.selection; - + // add uploads if ( selection.uploads.length < selection.filesToUpload ) { // remember upload selection.uploads.push(data); } - + //examine file var file = data.files[0]; try { // FIXME: not so elegant... need to refactor that method to return a value - Files.isFileNameValid(file.name); + Files.isFileNameValid(file.name, FileList.getCurrentDirectory()); } catch (errorMessage) { data.textStatus = 'invalidcharacters'; data.errorThrown = errorMessage; } - + if (file.type === '' && file.size === 4096) { data.textStatus = 'dirorzero'; data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes', {filename: file.name} ); } - + // add size selection.totalBytes += file.size; - + // check PHP upload limit if (selection.totalBytes > $('#upload_limit').val()) { data.textStatus = 'sizeexceedlimit'; @@ -270,7 +270,7 @@ $(document).ready(function() { 'size2': humanFileSize($('#free_space').val()) }); } - + // end upload for whole selection on error if (data.errorThrown) { // trigger fileupload fail @@ -281,12 +281,12 @@ $(document).ready(function() { // check existing files when all is collected if ( selection.uploads.length >= selection.filesToUpload ) { - + //remove our selection hack: delete data.originalFiles.selection; var callbacks = { - + onNoConflicts: function (selection) { $.each(selection.uploads, function(i, upload) { upload.submit(); @@ -309,7 +309,7 @@ $(document).ready(function() { }; OC.Upload.checkExistingFiles(selection, callbacks); - + } return true; // continue adding files @@ -439,7 +439,7 @@ $(document).ready(function() { }); fileupload.on('fileuploadstop', function(e, data) { OC.Upload.log('progress handle fileuploadstop', e, data); - + $('#uploadprogresswrapper input.stop').fadeOut(); $('#uploadprogressbar').fadeOut(); Files.updateStorageStatistics(); @@ -531,7 +531,7 @@ $(document).ready(function() { if ($(this).children('p').length === 0) { return; } - + $('#new .error').tipsy('hide'); $('#new li').each(function(i,element) { @@ -545,7 +545,7 @@ $(document).ready(function() { var text=$(this).children('p').text(); $(this).data('text',text); $(this).children('p').remove(); - + // add input field var form = $('
'); var input = $(''); @@ -562,7 +562,7 @@ $(document).ready(function() { throw t('files', 'URL cannot be empty'); } else if (type !== 'web' && !Files.isFileNameValid(filename)) { // Files.isFileNameValid(filename) throws an exception itself - } else if ($('#dir').val() === '/' && filename === 'Shared') { + } else if (FileList.getCurrentDirectory() === '/' && filename.toLowerCase() === 'shared') { throw t('files', 'In the home folder \'Shared\' is a reserved filename'); } else if (FileList.inList(filename)) { throw t('files', '{new_name} already exists', {new_name: filename}); diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 550c10dba3e..020ee275b7d 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -419,15 +419,12 @@ window.FileList={ len = input.val().length; } input.selectRange(0, len); - var checkInput = function () { var filename = input.val(); if (filename !== oldname) { - if (!Files.isFileNameValid(filename)) { - // Files.isFileNameValid(filename) throws an exception itself - } else if($('#dir').val() === '/' && filename === 'Shared') { - throw t('files','In the home folder \'Shared\' is a reserved filename'); - } else if (FileList.inList(filename)) { + // Files.isFileNameValid(filename) throws an exception itself + Files.isFileNameValid(filename, FileList.getCurrentDirectory()); + if (FileList.inList(filename)) { throw t('files', '{new_name} already exists', {new_name: filename}); } } diff --git a/apps/files/js/files.js b/apps/files/js/files.js index f4546120702..48e5771ae8a 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -87,9 +87,12 @@ var Files = { * Throws a string exception with an error message if * the file name is not valid */ - isFileNameValid: function (name) { + isFileNameValid: function (name, root) { var trimmedName = name.trim(); - if (trimmedName === '.' || trimmedName === '..') { + if (trimmedName === '.' + || trimmedName === '..' + || (root === '/' && trimmedName.toLowerCase() === 'shared')) + { throw t('files', '"{name}" is an invalid file name.', {name: name}); } else if (trimmedName.length === 0) { throw t('files', 'File name cannot be empty.'); diff --git a/apps/files/tests/js/filesSpec.js b/apps/files/tests/js/filesSpec.js index 018c8ef0f3c..95bf87e03ec 100644 --- a/apps/files/tests/js/filesSpec.js +++ b/apps/files/tests/js/filesSpec.js @@ -48,6 +48,41 @@ describe('Files tests', function() { expect(error).toEqual(false); } }); + it('Validates correct file names do not create Shared folder in root', function() { + // create shared file in subfolder + var error = false; + try { + expect(Files.isFileNameValid('shared', '/foo')).toEqual(true); + expect(Files.isFileNameValid('Shared', '/foo')).toEqual(true); + } + catch (e) { + error = e; + } + expect(error).toEqual(false); + + // create shared file in root + var threwException = false; + try { + Files.isFileNameValid('Shared', '/'); + console.error('Invalid file name not detected'); + } + catch (e) { + threwException = true; + } + expect(threwException).toEqual(true); + + // create shared file in root + var threwException = false; + try { + Files.isFileNameValid('shared', '/'); + console.error('Invalid file name not detected'); + } + catch (e) { + threwException = true; + } + expect(threwException).toEqual(true); + + }); it('Detects invalid file names', function() { var fileNames = [ '', diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php index 02d1a9f4ba2..3ed9e94d69b 100644 --- a/lib/private/connector/sabre/directory.php +++ b/lib/private/connector/sabre/directory.php @@ -50,7 +50,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa */ public function createFile($name, $data = null) { - if ($name === 'Shared' && empty($this->path)) { + if (strtolower($name) === 'shared' && empty($this->path)) { throw new \Sabre_DAV_Exception_Forbidden(); } @@ -86,7 +86,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa */ public function createDirectory($name) { - if ($name === 'Shared' && empty($this->path)) { + if (strtolower($name) === 'shared' && empty($this->path)) { throw new \Sabre_DAV_Exception_Forbidden(); } diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index d2fa425b22c..accf020daa2 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -94,6 +94,9 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { } if ($sourceDir !== $destinationDir) { // for a full move we need update privileges on sourcePath and sourceDir as well as destinationDir + if (ltrim($destinationDir, '/') === '' && strtolower($sourceNode->getName()) === 'shared') { + throw new \Sabre_DAV_Exception_Forbidden(); + } if (!$fs->isUpdatable($sourceDir)) { throw new \Sabre_DAV_Exception_Forbidden(); } -- cgit v1.2.3 From bdb96b9af85256f9b3f8663ccf6d27b3d1330918 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Wed, 5 Mar 2014 13:20:50 +0100 Subject: fix issue with spamming logging files when loading cached thumbnail --- lib/private/preview.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/preview.php b/lib/private/preview.php index 798a1322b03..b0d91fd5680 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -403,7 +403,9 @@ class Preview { $cached = $this->isCached(); if ($cached) { - $image = new \OC_Image($this->userView->file_get_contents($cached, 'r')); + $stream = $this->userView->fopen($cached, 'r'); + $image = new \OC_Image(); + $image->loadFromFileHandle($stream); $this->preview = $image->valid() ? $image : null; $this->resizeAndCrop(); } -- cgit v1.2.3 From 32a5d51fa6cdbf437342f028fce6e91b53ece16f Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Wed, 5 Mar 2014 15:37:26 +0100 Subject: add fclose, fixes issue from bdb96b9af85256f9b3f8663ccf6d27b3d1330918 --- lib/private/preview.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/private') diff --git a/lib/private/preview.php b/lib/private/preview.php index b0d91fd5680..74051fbc2a3 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -408,6 +408,7 @@ class Preview { $image->loadFromFileHandle($stream); $this->preview = $image->valid() ? $image : null; $this->resizeAndCrop(); + fclose($stream); } if (is_null($this->preview)) { -- cgit v1.2.3 From dbf83aada2f8dae509d17b947ecce6a4d09f8174 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Wed, 5 Mar 2014 15:53:12 +0100 Subject: fix issue with Non-static method Imagick ../..; @ doesn't seem to work in this case --- lib/private/preview/office.php | 35 ++++++++++++++----------- lib/private/preview/pdf.php | 49 ++++++++++++++++++++--------------- lib/private/preview/svg.php | 58 +++++++++++++++++++++++------------------- 3 files changed, 80 insertions(+), 62 deletions(-) (limited to 'lib/private') diff --git a/lib/private/preview/office.php b/lib/private/preview/office.php index 02bb22e9b94..269e1dad74e 100644 --- a/lib/private/preview/office.php +++ b/lib/private/preview/office.php @@ -6,24 +6,29 @@ * See the COPYING-README file. */ //both, libreoffice backend and php fallback, need imagick -if (extension_loaded('imagick') && count(@\Imagick::queryFormats("PDF")) === 1) { - $isShellExecEnabled = \OC_Helper::is_function_enabled('shell_exec'); +if (extension_loaded('imagick')) { - // LibreOffice preview is currently not supported on Windows - if (!\OC_Util::runningOnWindows()) { - $whichLibreOffice = ($isShellExecEnabled ? shell_exec('which libreoffice') : ''); - $isLibreOfficeAvailable = !empty($whichLibreOffice); - $whichOpenOffice = ($isShellExecEnabled ? shell_exec('which libreoffice') : ''); - $isOpenOfficeAvailable = !empty($whichOpenOffice); - //let's see if there is libreoffice or openoffice on this machine - if($isShellExecEnabled && ($isLibreOfficeAvailable || $isOpenOfficeAvailable || is_string(\OC_Config::getValue('preview_libreoffice_path', null)))) { - require_once('office-cl.php'); - }else{ + $checkImagick = new Imagick(); + + if(count($checkImagick->queryFormats('PDF')) === 1) { + $isShellExecEnabled = \OC_Helper::is_function_enabled('shell_exec'); + + // LibreOffice preview is currently not supported on Windows + if (!\OC_Util::runningOnWindows()) { + $whichLibreOffice = ($isShellExecEnabled ? shell_exec('which libreoffice') : ''); + $isLibreOfficeAvailable = !empty($whichLibreOffice); + $whichOpenOffice = ($isShellExecEnabled ? shell_exec('which libreoffice') : ''); + $isOpenOfficeAvailable = !empty($whichOpenOffice); + //let's see if there is libreoffice or openoffice on this machine + if($isShellExecEnabled && ($isLibreOfficeAvailable || $isOpenOfficeAvailable || is_string(\OC_Config::getValue('preview_libreoffice_path', null)))) { + require_once('office-cl.php'); + }else{ + //in case there isn't, use our fallback + require_once('office-fallback.php'); + } + } else { //in case there isn't, use our fallback require_once('office-fallback.php'); } - } else { - //in case there isn't, use our fallback - require_once('office-fallback.php'); } } diff --git a/lib/private/preview/pdf.php b/lib/private/preview/pdf.php index d390b4fc677..064a5a3b3d1 100644 --- a/lib/private/preview/pdf.php +++ b/lib/private/preview/pdf.php @@ -7,34 +7,41 @@ */ namespace OC\Preview; -if (extension_loaded('imagick') && count(@\Imagick::queryFormats("PDF")) === 1) { +use Imagick; - class PDF extends Provider { +if (extension_loaded('imagick')) { - public function getMimeType() { - return '/application\/pdf/'; - } + $checkImagick = new Imagick(); + + if(count($checkImagick->queryFormats('PDF')) === 1) { - public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { - $tmpPath = $fileview->toTmpFile($path); + class PDF extends Provider { - //create imagick object from pdf - try{ - $pdf = new \imagick($tmpPath . '[0]'); - $pdf->setImageFormat('jpg'); - } catch (\Exception $e) { - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; + public function getMimeType() { + return '/application\/pdf/'; } - unlink($tmpPath); + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $tmpPath = $fileview->toTmpFile($path); + + //create imagick object from pdf + try{ + $pdf = new Imagick($tmpPath . '[0]'); + $pdf->setImageFormat('jpg'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + unlink($tmpPath); - //new image object - $image = new \OC_Image($pdf); - //check if image object is valid - return $image->valid() ? $image : false; + //new image object + $image = new \OC_Image($pdf); + //check if image object is valid + return $image->valid() ? $image : false; + } } - } - \OC\Preview::registerProvider('OC\Preview\PDF'); + \OC\Preview::registerProvider('OC\Preview\PDF'); + } } diff --git a/lib/private/preview/svg.php b/lib/private/preview/svg.php index 9a73fff9467..505122fddbf 100644 --- a/lib/private/preview/svg.php +++ b/lib/private/preview/svg.php @@ -7,40 +7,46 @@ */ namespace OC\Preview; -if (extension_loaded('imagick') && count(@\Imagick::queryFormats("SVG")) === 1) { +use Imagick; - class SVG extends Provider { +if (extension_loaded('imagick')) { - public function getMimeType() { - return '/image\/svg\+xml/'; - } + $checkImagick = new Imagick(); - public function getThumbnail($path,$maxX,$maxY,$scalingup,$fileview) { - try{ - $svg = new \Imagick(); - $svg->setBackgroundColor(new \ImagickPixel('transparent')); + if(count($checkImagick->queryFormats('SVG')) === 1) { - $content = stream_get_contents($fileview->fopen($path, 'r')); - if(substr($content, 0, 5) !== '' . $content; - } + class SVG extends Provider { - $svg->readImageBlob($content); - $svg->setImageFormat('png32'); - } catch (\Exception $e) { - \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); - return false; + public function getMimeType() { + return '/image\/svg\+xml/'; } + public function getThumbnail($path,$maxX,$maxY,$scalingup,$fileview) { + try{ + $svg = new Imagick(); + $svg->setBackgroundColor(new \ImagickPixel('transparent')); + + $content = stream_get_contents($fileview->fopen($path, 'r')); + if(substr($content, 0, 5) !== '' . $content; + } + + $svg->readImageBlob($content); + $svg->setImageFormat('png32'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } - //new image object - $image = new \OC_Image(); - $image->loadFromData($svg); - //check if image object is valid - return $image->valid() ? $image : false; - } - } - \OC\Preview::registerProvider('OC\Preview\SVG'); + //new image object + $image = new \OC_Image(); + $image->loadFromData($svg); + //check if image object is valid + return $image->valid() ? $image : false; + } + } + \OC\Preview::registerProvider('OC\Preview\SVG'); + } } \ No newline at end of file -- cgit v1.2.3 From 421cff00bdb6441b1639c83ed68dc1cbe196e333 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 5 Mar 2014 15:02:05 +0100 Subject: Show warning page when accessing server from an untrusted domain Added early check for the requested domain host and show a warning page if the domain is not trusted. --- lib/base.php | 16 +++++++++++ lib/private/request.php | 70 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 16 deletions(-) (limited to 'lib/private') diff --git a/lib/base.php b/lib/base.php index 351b91b7dfa..82612a18771 100644 --- a/lib/base.php +++ b/lib/base.php @@ -694,6 +694,22 @@ class OC { exit(); } + $host = OC_Request::insecureServerHost(); + // if the host passed in headers isn't trusted + if (!OC::$CLI + // overwritehost is always trusted + && OC_Request::getOverwriteHost() === null + && !OC_Request::isTrustedDomain($host)) { + + header('HTTP/1.1 400 Bad Request'); + header('Status: 400 Bad Request'); + OC_Template::printErrorPage( + 'You are accessing the server from an untrusted domain.', + 'Please contact your administrator' + ); + return; + } + $request = OC_Request::getPathInfo(); if (substr($request, -3) !== '.js') { // we need these files during the upgrade self::checkMaintenanceMode(); diff --git a/lib/private/request.php b/lib/private/request.php index afd3fda4f2d..fb387e83e3a 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -25,49 +25,87 @@ class OC_Request { } /** - * @brief Checks whether a domain is considered as trusted. This is used to prevent Host Header Poisoning. + * @brief Checks whether a domain is considered as trusted from the list + * of trusted domains. If no trusted domains have been configured, returns + * true. + * This is used to prevent Host Header Poisoning. * @param string $host - * @return bool + * @return bool true if the given domain is trusted or if no trusted domains + * have been configured */ public static function isTrustedDomain($domain) { - $trustedList = \OC_Config::getValue('trusted_domains', array('')); + $trustedList = \OC_Config::getValue('trusted_domains', array()); + if (empty($trustedList)) { + return true; + } return in_array($domain, $trustedList); } /** - * @brief Returns the server host + * @brief Returns the unverified server host from the headers without checking + * whether it is a trusted domain * @returns string the server host * * Returns the server host, even if the website uses one or more * reverse proxies */ - public static function serverHost() { - if(OC::$CLI) { - return 'localhost'; - } - if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { - return OC_Config::getValue('overwritehost'); - } + public static function insecureServerHost() { + $host = null; if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); - } - else{ + } else { $host = $_SERVER['HTTP_X_FORWARDED_HOST']; } } else { if (isset($_SERVER['HTTP_HOST'])) { $host = $_SERVER['HTTP_HOST']; - } - else if (isset($_SERVER['SERVER_NAME'])) { + } else if (isset($_SERVER['SERVER_NAME'])) { $host = $_SERVER['SERVER_NAME']; } } + return $host; + } + + /** + * Returns the overwritehost setting from the config if set and + * if the overwrite condition is met + * @return overwritehost value or null if not defined or the defined condition + * isn't met + */ + public static function getOverwriteHost() { + if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { + return OC_Config::getValue('overwritehost'); + } + return null; + } + + /** + * @brief Returns the server host from the headers, or the first configured + * trusted domain if the host isn't in the trusted list + * @returns string the server host + * + * Returns the server host, even if the website uses one or more + * reverse proxies + */ + public static function serverHost() { + if(OC::$CLI) { + return 'localhost'; + } + + // overwritehost is always trusted + $host = self::getOverwriteHost(); + if ($host !== null) { + return $host; + } + + // get the host from the headers + $host = self::insecureServerHost(); // Verify that the host is a trusted domain if the trusted domains // are defined // If no trusted domain is provided the first trusted domain is returned - if(self::isTrustedDomain($host) || \OC_Config::getValue('trusted_domains', "") === "") { + if (self::isTrustedDomain($host)) { return $host; } else { $trustedList = \OC_Config::getValue('trusted_domains', array('')); -- cgit v1.2.3 From f8fe2753b125c6882019d1ba2c2db661b0bdcbf2 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 5 Mar 2014 15:41:28 +0100 Subject: Added localhost as trusted domain --- lib/private/request.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/private') diff --git a/lib/private/request.php b/lib/private/request.php index fb387e83e3a..347d77b3724 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -13,6 +13,8 @@ class OC_Request { const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#'; const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#'; + const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost)(:[0-9]+|)$/'; + /** * @brief Check overwrite condition * @param string $type @@ -38,6 +40,9 @@ class OC_Request { if (empty($trustedList)) { return true; } + if (preg_match(self::REGEX_LOCALHOST, $domain) === 1) { + return true; + } return in_array($domain, $trustedList); } -- cgit v1.2.3 From 9136e6ad3028040b91685fc94e8fccd29c9b9210 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 5 Mar 2014 17:04:45 +0100 Subject: Fixed X-Forwarded-Host parsing --- lib/private/request.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/request.php b/lib/private/request.php index 347d77b3724..8041c4f0048 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -58,7 +58,8 @@ class OC_Request { $host = null; if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { - $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); + $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); + $host = trim(current($parts)); } else { $host = $_SERVER['HTTP_X_FORWARDED_HOST']; } -- cgit v1.2.3 From 0dcac65aa1eb14adc4d3693b6a2c99cbf6ea2425 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 6 Mar 2014 13:50:53 +0100 Subject: Fixed upload issue when free space is not known --- apps/files/js/file-upload.js | 4 +++- lib/private/helper.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index b9c4dc941f7..b7b8f6fdeb6 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -206,6 +206,7 @@ OC.Upload = { add: function(e, data) { OC.Upload.log('add', e, data); var that = $(this); + var freeSpace; // we need to collect all data upload objects before starting the upload so we can check their existence // and set individual conflict actions. unfortunately there is only one variable that we can use to identify @@ -261,7 +262,8 @@ OC.Upload = { } // check free space - if (selection.totalBytes > $('#free_space').val()) { + freeSpace = $('#free_space').val(); + if (freeSpace >= 0 && selection.totalBytes > freeSpace) { data.textStatus = 'notenoughspace'; data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', { 'size1': humanFileSize(selection.totalBytes), diff --git a/lib/private/helper.php b/lib/private/helper.php index d8c4650f666..b9956d5ec1c 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -839,7 +839,7 @@ class OC_Helper { * @return int number of bytes representing */ public static function maxUploadFilesize($dir, $freeSpace = null) { - if (is_null($freeSpace)){ + if (is_null($freeSpace) || $freeSpace < 0){ $freeSpace = self::freeSpace($dir); } return min($freeSpace, self::uploadLimit()); -- cgit v1.2.3 From 895fc0fa26ee5a1e9dbadb09736dbb56cad0c6e8 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 6 Mar 2014 14:23:27 +0100 Subject: Fix check if fileinfo is valid --- lib/private/files/view.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 975b5d00099..f06c2fcd66c 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -843,7 +843,7 @@ class View { $data = $cache->get($internalPath); } - if ($data and $data['fileid']) { + if ($data and isset($data['fileid'])) { if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') { //add the sizes of other mountpoints to the folder $mountPoints = Filesystem::getMountPoints($path); -- cgit v1.2.3 From 242cbb802a980f47f4f5038154069768327e1487 Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Thu, 6 Mar 2014 18:19:58 +0300 Subject: Reset time of last update feed polling --- lib/private/updater.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/private') diff --git a/lib/private/updater.php b/lib/private/updater.php index f05d5038b76..94f7ea34cba 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -134,6 +134,8 @@ class Updater extends BasicEmitter { $repair = new Repair(); $repair->run(); + //Invalidate update feed + \OC_Appconfig::setValue('core', 'lastupdatedat', 0); \OC_Config::setValue('maintenance', false); $this->emit('\OC\Updater', 'maintenanceEnd'); } -- cgit v1.2.3 From ceb5b918d750f39ddb3d8a4575be9bf42096cbc1 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 6 Mar 2014 23:56:11 +0100 Subject: Add \OC:: to URLGenerator::getAbsoluteURL() --- lib/private/urlgenerator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php index 60da34f2d6e..aa06d6fca11 100644 --- a/lib/private/urlgenerator.php +++ b/lib/private/urlgenerator.php @@ -148,6 +148,7 @@ class URLGenerator implements IURLGenerator { */ public function getAbsoluteURL($url) { $separator = $url[0] === '/' ? '' : '/'; - return \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . $separator . $url; + + return \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost(). \OC::$WEBROOT . $separator . $url; } } -- cgit v1.2.3 From 7f24d42ca5f70e5ed48cf800f0a8f134b9445d2e Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 7 Mar 2014 11:00:22 +0100 Subject: Propagate unencrypted_size up to the file cache root --- lib/private/files/cache/homecache.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index a7c310a3782..2af5b03c6e1 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -24,15 +24,20 @@ class HomeCache extends Cache { $entry = $this->get($path); if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { $id = $entry['fileid']; - $sql = 'SELECT SUM(`size`) FROM `*PREFIX*filecache` ' . + $sql = 'SELECT SUM(`size`) AS f1, ' . + 'SUM(`unencrypted_size`) AS f2 FROM `*PREFIX*filecache` ' . 'WHERE `parent` = ? AND `storage` = ? AND `size` >= 0'; $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { - list($sum) = array_values($row); + list($sum, $unencryptedSum) = array_values($row); $totalSize = (int)$sum; + $unencryptedSize = (int)$unencryptedSum; if ($entry['size'] !== $totalSize) { $this->update($id, array('size' => $totalSize)); } + if ($entry['unencrypted_size'] !== $unencryptedSize) { + $this->update($id, array('unencrypted_size' => $unencryptedSize)); + } } } return $totalSize; -- cgit v1.2.3 From 65f52fee4f333cc31591a265c2d5b4c0ed0d7016 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 7 Mar 2014 14:52:44 +0100 Subject: Fix FileInfo->getType errors --- lib/private/files/fileinfo.php | 9 ++++++++- lib/public/files/fileinfo.php | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index 2dbdd80a26b..a9e64fe1533 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -53,6 +53,9 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { } public function offsetGet($offset) { + if ($offset === 'type') { + return $this->getType(); + } return $this->data[$offset]; } @@ -144,7 +147,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return \OCP\Files\FileInfo::TYPE_FILE | \OCP\Files\FileInfo::TYPE_FOLDER */ public function getType() { - return $this->data['type']; + if (isset($this->data['type'])) { + return $this->data['type']; + } else { + return $this->getMimetype() === 'httpd/unix-directory' ? self::TYPE_FOLDER : self::TYPE_FILE; + } } public function getData(){ diff --git a/lib/public/files/fileinfo.php b/lib/public/files/fileinfo.php index 68ce45d3fa1..37162e09336 100644 --- a/lib/public/files/fileinfo.php +++ b/lib/public/files/fileinfo.php @@ -9,7 +9,7 @@ namespace OCP\Files; interface FileInfo { const TYPE_FILE = 'file'; - const TYPE_FOLDER = 'folder'; + const TYPE_FOLDER = 'dir'; /** * Get the Etag of the file or folder -- cgit v1.2.3 From 48d63a6278078d164774fd182f03ebba5e3c77ad Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 7 Mar 2014 11:25:29 +0100 Subject: Return unencrypted_size of folder when queried This fixes the "used space" to be based on the unencrypted size, not encrypted size, to be consistent with how quota/space is handled when encryption is enabled --- apps/files_encryption/lib/proxy.php | 7 +++++++ apps/files_encryption/tests/proxy.php | 20 ++++++++++++++++++++ lib/private/files/storage/wrapper/quota.php | 5 +++++ tests/lib/files/storage/wrapper/quota.php | 16 ++++++++++++++++ 4 files changed, 48 insertions(+) (limited to 'lib/private') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index a2d42c22c13..b7e1599c1fe 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -340,6 +340,13 @@ class Proxy extends \OC_FileProxy { // if path is a folder do nothing if ($view->is_dir($path)) { + $proxyState = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + $fileInfo = $view->getFileInfo($path); + \OC_FileProxy::$enabled = $proxyState; + if ($fileInfo['unencrypted_size'] > 0) { + return $fileInfo['unencrypted_size']; + } return $size; } diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php index 51cc0b795e3..647ee955eb1 100644 --- a/apps/files_encryption/tests/proxy.php +++ b/apps/files_encryption/tests/proxy.php @@ -112,4 +112,24 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase { } + function testPostFileSizeWithDirectory() { + + $this->view->file_put_contents($this->filename, $this->data); + + \OC_FileProxy::$enabled = false; + + // get root size, must match the file's unencrypted size + $unencryptedSize = $this->view->filesize(''); + + \OC_FileProxy::$enabled = true; + + $encryptedSize = $this->view->filesize(''); + + $this->assertTrue($encryptedSize !== $unencryptedSize); + + // cleanup + $this->view->unlink($this->filename); + + } + } diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index 26c952e694a..ea612735477 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -36,6 +36,11 @@ class Quota extends Wrapper { $cache = $this->getCache(); $data = $cache->get($path); if (is_array($data) and isset($data['size'])) { + if (isset($data['unencrypted_size']) + && $data['unencrypted_size'] > 0 + ) { + return $data['unencrypted_size']; + } return $data['size']; } else { return \OC\Files\SPACE_NOT_COMPUTED; diff --git a/tests/lib/files/storage/wrapper/quota.php b/tests/lib/files/storage/wrapper/quota.php index 43eae78415d..bd2c69a7396 100644 --- a/tests/lib/files/storage/wrapper/quota.php +++ b/tests/lib/files/storage/wrapper/quota.php @@ -53,6 +53,22 @@ class Quota extends \Test\Files\Storage\Storage { $this->assertEquals(9, $instance->free_space('')); } + public function testFreeSpaceWithUsedSpace() { + $instance = $this->getLimitedStorage(9); + $instance->getCache()->put( + '', array('size' => 3, 'unencrypted_size' => 0) + ); + $this->assertEquals(6, $instance->free_space('')); + } + + public function testFreeSpaceWithUsedSpaceAndEncryption() { + $instance = $this->getLimitedStorage(9); + $instance->getCache()->put( + '', array('size' => 7, 'unencrypted_size' => 3) + ); + $this->assertEquals(6, $instance->free_space('')); + } + public function testFWriteNotEnoughSpace() { $instance = $this->getLimitedStorage(9); $stream = $instance->fopen('foo', 'w+'); -- cgit v1.2.3 From 51165a1a04a8a97a5d7ac684b0588a86c01a0018 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 7 Mar 2014 15:16:35 +0100 Subject: Check if value exists before returning --- lib/private/files/fileinfo.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index a9e64fe1533..d6940f50bf1 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -55,8 +55,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function offsetGet($offset) { if ($offset === 'type') { return $this->getType(); + } elseif (isset($this->data[$offset])) { + return $this->data[$offset]; + } else { + return null; } - return $this->data[$offset]; } /** @@ -154,7 +157,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { } } - public function getData(){ + public function getData() { return $this->data; } -- cgit v1.2.3 From 0d90b90d9402cbcab4037efc913728cdeb4eadbd Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 7 Mar 2014 20:00:34 +0100 Subject: we first shall check if the current session is valid - otherwise the session-id will be regenerated on login via basic auth --- lib/private/api.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'lib/private') diff --git a/lib/private/api.php b/lib/private/api.php index 3f96196e6df..e9d31242e3a 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -270,7 +270,19 @@ class OC_API { * @return string|false (username, or false on failure) */ private static function loginUser(){ - // basic auth + + // reuse existing login + $loggedIn = OC_User::isLoggedIn(); + $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false; + if ($loggedIn === true && $ocsApiRequest) { + + // initialize the user's filesystem + \OC_Util::setUpFS(\OC_User::getUser()); + + return OC_User::getUser(); + } + + // basic auth $authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : ''; $authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; $return = OC_User::login($authUser, $authPw); @@ -283,17 +295,6 @@ class OC_API { return $authUser; } - // reuse existing login - $loggedIn = OC_User::isLoggedIn(); - $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false; - if ($loggedIn === true && $ocsApiRequest) { - - // initialize the user's filesystem - \OC_Util::setUpFS(\OC_User::getUser()); - - return OC_User::getUser(); - } - return false; } -- cgit v1.2.3 From 25f523680ac1ed46470ea40277e578fd35ec02a7 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 7 Mar 2014 20:06:06 +0100 Subject: fixing ident --- lib/private/api.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'lib/private') diff --git a/lib/private/api.php b/lib/private/api.php index e9d31242e3a..1537cc11dd0 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -271,18 +271,18 @@ class OC_API { */ private static function loginUser(){ - // reuse existing login - $loggedIn = OC_User::isLoggedIn(); - $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false; - if ($loggedIn === true && $ocsApiRequest) { + // reuse existing login + $loggedIn = OC_User::isLoggedIn(); + $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false; + if ($loggedIn === true && $ocsApiRequest) { - // initialize the user's filesystem - \OC_Util::setUpFS(\OC_User::getUser()); + // initialize the user's filesystem + \OC_Util::setUpFS(\OC_User::getUser()); - return OC_User::getUser(); - } + return OC_User::getUser(); + } - // basic auth + // basic auth $authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : ''; $authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; $return = OC_User::login($authUser, $authPw); -- cgit v1.2.3 From 8ab7d18a6a2b023527d2eef63099e2834c46ec97 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 10 Mar 2014 14:04:58 +0100 Subject: Move the router classes to a namespace and expose it with a public interface --- apps/files_sharing/appinfo/routes.php | 2 +- lib/base.php | 14 +- lib/private/appframework/routing/routeconfig.php | 7 +- lib/private/route.php | 124 -------------- lib/private/route/route.php | 132 +++++++++++++++ lib/private/route/router.php | 202 +++++++++++++++++++++++ lib/private/router.php | 161 ------------------ lib/private/server.php | 15 ++ lib/public/appframework/app.php | 2 +- lib/public/iservercontainer.php | 6 + lib/public/route/iroute.php | 79 +++++++++ lib/public/route/irouter.php | 71 ++++++++ tests/lib/appframework/routing/RoutingTest.php | 8 +- 13 files changed, 517 insertions(+), 306 deletions(-) delete mode 100644 lib/private/route.php create mode 100644 lib/private/route/route.php create mode 100644 lib/private/route/router.php delete mode 100644 lib/private/router.php create mode 100644 lib/public/route/iroute.php create mode 100644 lib/public/route/irouter.php (limited to 'lib/private') diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php index 9417a6eeb89..06e454b7d77 100644 --- a/apps/files_sharing/appinfo/routes.php +++ b/apps/files_sharing/appinfo/routes.php @@ -1,5 +1,5 @@ create('core_ajax_public_preview', '/publicpreview.png')->action( function() { require_once __DIR__ . '/../ajax/publicpreview.php'; diff --git a/lib/base.php b/lib/base.php index 86ee5349828..d49dd958310 100644 --- a/lib/base.php +++ b/lib/base.php @@ -73,11 +73,6 @@ class OC { */ public static $CLI = false; - /** - * @var OC_Router - */ - protected static $router = null; - /** * @var \OC\Session\Session */ @@ -388,15 +383,10 @@ class OC { } /** - * @return OC_Router + * @return \OCP\Route\IRouter */ public static function getRouter() { - if (!isset(OC::$router)) { - OC::$router = new OC_Router(); - OC::$router->loadRoutes(); - } - - return OC::$router; + return self::$server->getRouter(); } diff --git a/lib/private/appframework/routing/routeconfig.php b/lib/private/appframework/routing/routeconfig.php index 716358444a2..35bee75cc4d 100644 --- a/lib/private/appframework/routing/routeconfig.php +++ b/lib/private/appframework/routing/routeconfig.php @@ -23,6 +23,7 @@ namespace OC\AppFramework\routing; use OC\AppFramework\DependencyInjection\DIContainer; +use OCP\Route\IRouter; /** * Class RouteConfig @@ -36,10 +37,10 @@ class RouteConfig { /** * @param \OC\AppFramework\DependencyInjection\DIContainer $container - * @param \OC_Router $router + * @param \OCP\Route\IRouter $router * @internal param $appName */ - public function __construct(DIContainer $container, \OC_Router $router, $routes) { + public function __construct(DIContainer $container, IRouter $router, $routes) { $this->routes = $routes; $this->container = $container; $this->router = $router; @@ -47,7 +48,7 @@ class RouteConfig { } /** - * The routes and resource will be registered to the \OC_Router + * The routes and resource will be registered to the \OCP\Route\IRouter */ public function register() { diff --git a/lib/private/route.php b/lib/private/route.php deleted file mode 100644 index fb7da456b62..00000000000 --- a/lib/private/route.php +++ /dev/null @@ -1,124 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -use Symfony\Component\Routing\Route; - -class OC_Route extends Route { - /** - * Specify the method when this route is to be used - * - * @param string $method HTTP method (uppercase) - */ - public function method($method) { - $this->setRequirement('_method', strtoupper($method)); - return $this; - } - - /** - * Specify POST as the method to use with this route - */ - public function post() { - $this->method('POST'); - return $this; - } - - /** - * Specify GET as the method to use with this route - */ - public function get() { - $this->method('GET'); - return $this; - } - - /** - * Specify PUT as the method to use with this route - */ - public function put() { - $this->method('PUT'); - return $this; - } - - /** - * Specify DELETE as the method to use with this route - */ - public function delete() { - $this->method('DELETE'); - return $this; - } - - /** - * Specify PATCH as the method to use with this route - */ - public function patch() { - $this->method('PATCH'); - return $this; - } - - /** - * Defaults to use for this route - * - * @param array $defaults The defaults - */ - public function defaults($defaults) { - $action = $this->getDefault('action'); - $this->setDefaults($defaults); - if (isset($defaults['action'])) { - $action = $defaults['action']; - } - $this->action($action); - return $this; - } - - /** - * Requirements for this route - * - * @param array $requirements The requirements - */ - public function requirements($requirements) { - $method = $this->getRequirement('_method'); - $this->setRequirements($requirements); - if (isset($requirements['_method'])) { - $method = $requirements['_method']; - } - if ($method) { - $this->method($method); - } - return $this; - } - - /** - * The action to execute when this route matches - * @param string|callable $class the class or a callable - * @param string $function the function to use with the class - * - * This function is called with $class set to a callable or - * to the class with $function - */ - public function action($class, $function = null) { - $action = array($class, $function); - if (is_null($function)) { - $action = $class; - } - $this->setDefault('action', $action); - return $this; - } - - /** - * The action to execute when this route matches, includes a file like - * it is called directly - * @param $file - */ - public function actionInclude($file) { - $function = create_function('$param', - 'unset($param["_route"]);' - .'$_GET=array_merge($_GET, $param);' - .'unset($param);' - .'require_once "'.$file.'";'); - $this->action($function); - } -} diff --git a/lib/private/route/route.php b/lib/private/route/route.php new file mode 100644 index 00000000000..6ade9ec15f6 --- /dev/null +++ b/lib/private/route/route.php @@ -0,0 +1,132 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Route; + +use OCP\Route\IRoute; +use Symfony\Component\Routing\Route as SymfonyRoute; + +class Route extends SymfonyRoute implements IRoute { + /** + * Specify the method when this route is to be used + * + * @param string $method HTTP method (uppercase) + * @return \OC\Route\Route + */ + public function method($method) { + $this->setRequirement('_method', strtoupper($method)); + return $this; + } + + /** + * Specify POST as the method to use with this route + */ + public function post() { + $this->method('POST'); + return $this; + } + + /** + * Specify GET as the method to use with this route + */ + public function get() { + $this->method('GET'); + return $this; + } + + /** + * Specify PUT as the method to use with this route + */ + public function put() { + $this->method('PUT'); + return $this; + } + + /** + * Specify DELETE as the method to use with this route + */ + public function delete() { + $this->method('DELETE'); + return $this; + } + + /** + * Specify PATCH as the method to use with this route + */ + public function patch() { + $this->method('PATCH'); + return $this; + } + + /** + * Defaults to use for this route + * + * @param array $defaults The defaults + * @return \OC\Route\Route + */ + public function defaults($defaults) { + $action = $this->getDefault('action'); + $this->setDefaults($defaults); + if (isset($defaults['action'])) { + $action = $defaults['action']; + } + $this->action($action); + return $this; + } + + /** + * Requirements for this route + * + * @param array $requirements The requirements + * @return \OC\Route\Route + */ + public function requirements($requirements) { + $method = $this->getRequirement('_method'); + $this->setRequirements($requirements); + if (isset($requirements['_method'])) { + $method = $requirements['_method']; + } + if ($method) { + $this->method($method); + } + return $this; + } + + /** + * The action to execute when this route matches + * + * @param string|callable $class the class or a callable + * @param string $function the function to use with the class + * @return \OC\Route\Route + * + * This function is called with $class set to a callable or + * to the class with $function + */ + public function action($class, $function = null) { + $action = array($class, $function); + if (is_null($function)) { + $action = $class; + } + $this->setDefault('action', $action); + return $this; + } + + /** + * The action to execute when this route matches, includes a file like + * it is called directly + * @param $file + */ + public function actionInclude($file) { + $function = create_function('$param', + 'unset($param["_route"]);' + .'$_GET=array_merge($_GET, $param);' + .'unset($param);' + .'require_once "'.$file.'";'); + $this->action($function); + } +} diff --git a/lib/private/route/router.php b/lib/private/route/router.php new file mode 100644 index 00000000000..60ba5878401 --- /dev/null +++ b/lib/private/route/router.php @@ -0,0 +1,202 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Route; + +use OCP\Route\IRouter; +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; + +class Router implements IRouter { + /** + * @var \Symfony\Component\Routing\RouteCollection[] + */ + protected $collections = array(); + + /** + * @var \Symfony\Component\Routing\RouteCollection + */ + protected $collection = null; + + /** + * @var \Symfony\Component\Routing\RouteCollection + */ + protected $root = null; + + /** + * @var \Symfony\Component\Routing\Generator\UrlGenerator + */ + protected $generator = null; + + /** + * @var string[] + */ + protected $routingFiles; + + /** + * @var string + */ + protected $cacheKey; + + protected $loaded = false; + + public function __construct() { + $baseUrl = \OC_Helper::linkTo('', 'index.php'); + if (!\OC::$CLI) { + $method = $_SERVER['REQUEST_METHOD']; + } else { + $method = 'GET'; + } + $host = \OC_Request::serverHost(); + $schema = \OC_Request::serverProtocol(); + $this->context = new RequestContext($baseUrl, $method, $host, $schema); + // TODO cache + $this->root = $this->getCollection('root'); + } + + /** + * Get the files to load the routes from + * + * @return string[] + */ + public function getRoutingFiles() { + if (!isset($this->routingFiles)) { + $this->routingFiles = array(); + foreach (\OC_APP::getEnabledApps() as $app) { + $file = \OC_App::getAppPath($app) . '/appinfo/routes.php'; + if (file_exists($file)) { + $this->routingFiles[$app] = $file; + } + } + } + return $this->routingFiles; + } + + public function getCacheKey() { + if (!isset($this->cacheKey)) { + $files = $this->getRoutingFiles(); + $files[] = 'settings/routes.php'; + $files[] = 'core/routes.php'; + $files[] = 'ocs/routes.php'; + $this->cacheKey = \OC_Cache::generateCacheKeyFromFiles($files); + } + return $this->cacheKey; + } + + /** + * loads the api routes + */ + public function loadRoutes() { + if ($this->loaded) { + return; + } + $this->loaded = true; + foreach ($this->getRoutingFiles() as $app => $file) { + $this->useCollection($app); + require_once $file; + $collection = $this->getCollection($app); + $collection->addPrefix('/apps/' . $app); + $this->root->addCollection($collection); + } + $this->useCollection('root'); + require_once 'settings/routes.php'; + require_once 'core/routes.php'; + + // include ocs routes + require_once 'ocs/routes.php'; + $collection = $this->getCollection('ocs'); + $collection->addPrefix('/ocs'); + $this->root->addCollection($collection); + } + + /** + * @param string $name + * @return \Symfony\Component\Routing\RouteCollection + */ + protected function getCollection($name) { + if (!isset($this->collections[$name])) { + $this->collections[$name] = new RouteCollection(); + } + return $this->collections[$name]; + } + + /** + * Sets the collection to use for adding routes + * + * @param string $name Name of the collection to use. + */ + public function useCollection($name) { + $this->collection = $this->getCollection($name); + } + + /** + * Create a \OC\Route\Route. + * + * @param string $name Name of the route to create. + * @param string $pattern The pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + * @return \OC\Route\Route + */ + public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { + $route = new Route($pattern, $defaults, $requirements); + $this->collection->add($name, $route); + return $route; + } + + /** + * Find the route matching $url. + * + * @param string $url The url to find + * @throws \Exception + */ + public function match($url) { + $matcher = new UrlMatcher($this->root, $this->context); + $parameters = $matcher->match($url); + if (isset($parameters['action'])) { + $action = $parameters['action']; + if (!is_callable($action)) { + var_dump($action); + throw new \Exception('not a callable action'); + } + unset($parameters['action']); + call_user_func($action, $parameters); + } elseif (isset($parameters['file'])) { + include $parameters['file']; + } else { + throw new \Exception('no action available'); + } + } + + /** + * Get the url generator + * + */ + public function getGenerator() { + if (null !== $this->generator) { + return $this->generator; + } + + return $this->generator = new UrlGenerator($this->root, $this->context); + } + + /** + * Generate url based on $name and $parameters + * + * @param string $name Name of the route to use. + * @param array $parameters Parameters for the route + * @param bool $absolute + * @return string + */ + public function generate($name, $parameters = array(), $absolute = false) { + return $this->getGenerator()->generate($name, $parameters, $absolute); + } + +} diff --git a/lib/private/router.php b/lib/private/router.php deleted file mode 100644 index 918e3b13206..00000000000 --- a/lib/private/router.php +++ /dev/null @@ -1,161 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -use Symfony\Component\Routing\Matcher\UrlMatcher; -use Symfony\Component\Routing\Generator\UrlGenerator; -use Symfony\Component\Routing\RequestContext; -use Symfony\Component\Routing\RouteCollection; -//use Symfony\Component\Routing\Route; - -class OC_Router { - protected $collections = array(); - protected $collection = null; - protected $root = null; - - protected $generator = null; - protected $routing_files; - protected $cache_key; - - public function __construct() { - $baseUrl = OC_Helper::linkTo('', 'index.php'); - if ( !OC::$CLI) { - $method = $_SERVER['REQUEST_METHOD']; - }else{ - $method = 'GET'; - } - $host = OC_Request::serverHost(); - $schema = OC_Request::serverProtocol(); - $this->context = new RequestContext($baseUrl, $method, $host, $schema); - // TODO cache - $this->root = $this->getCollection('root'); - } - - public function getRoutingFiles() { - if (!isset($this->routing_files)) { - $this->routing_files = array(); - foreach(OC_APP::getEnabledApps() as $app) { - $file = OC_App::getAppPath($app).'/appinfo/routes.php'; - if(file_exists($file)) { - $this->routing_files[$app] = $file; - } - } - } - return $this->routing_files; - } - - public function getCacheKey() { - if (!isset($this->cache_key)) { - $files = $this->getRoutingFiles(); - $files[] = 'settings/routes.php'; - $files[] = 'core/routes.php'; - $files[] = 'ocs/routes.php'; - $this->cache_key = OC_Cache::generateCacheKeyFromFiles($files); - } - return $this->cache_key; - } - - /** - * loads the api routes - */ - public function loadRoutes() { - foreach($this->getRoutingFiles() as $app => $file) { - $this->useCollection($app); - require_once $file; - $collection = $this->getCollection($app); - $collection->addPrefix('/apps/'.$app); - $this->root->addCollection($collection); - } - $this->useCollection('root'); - require_once 'settings/routes.php'; - require_once 'core/routes.php'; - - // include ocs routes - require_once 'ocs/routes.php'; - $collection = $this->getCollection('ocs'); - $collection->addPrefix('/ocs'); - $this->root->addCollection($collection); - } - - protected function getCollection($name) { - if (!isset($this->collections[$name])) { - $this->collections[$name] = new RouteCollection(); - } - return $this->collections[$name]; - } - - /** - * Sets the collection to use for adding routes - * - * @param string $name Name of the colletion to use. - */ - public function useCollection($name) { - $this->collection = $this->getCollection($name); - } - - /** - * Create a OC_Route. - * - * @param string $name Name of the route to create. - * @param string $pattern The pattern to match - * @param array $defaults An array of default parameter values - * @param array $requirements An array of requirements for parameters (regexes) - */ - public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { - $route = new OC_Route($pattern, $defaults, $requirements); - $this->collection->add($name, $route); - return $route; - } - - /** - * Find the route matching $url. - * - * @param string $url The url to find - */ - public function match($url) { - $matcher = new UrlMatcher($this->root, $this->context); - $parameters = $matcher->match($url); - if (isset($parameters['action'])) { - $action = $parameters['action']; - if (!is_callable($action)) { - var_dump($action); - throw new Exception('not a callable action'); - } - unset($parameters['action']); - call_user_func($action, $parameters); - } elseif (isset($parameters['file'])) { - include $parameters['file']; - } else { - throw new Exception('no action available'); - } - } - - /** - * Get the url generator - * - */ - public function getGenerator() - { - if (null !== $this->generator) { - return $this->generator; - } - - return $this->generator = new UrlGenerator($this->root, $this->context); - } - - /** - * Generate url based on $name and $parameters - * - * @param string $name Name of the route to use. - * @param array $parameters Parameters for the route - */ - public function generate($name, $parameters = array(), $absolute = false) - { - return $this->getGenerator()->generate($name, $parameters, $absolute); - } - -} diff --git a/lib/private/server.php b/lib/private/server.php index 7696fc207fd..8c9ea39c562 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -158,6 +158,10 @@ class Server extends SimpleContainer implements IServerContainer { $config = $c->getConfig(); return new \OC\BackgroundJob\JobList($c->getDatabaseConnection(), $config); }); + $this->registerService('Router', function ($c){ + $router = new \OC\Route\Router(); + return $router; + }); } /** @@ -364,4 +368,15 @@ class Server extends SimpleContainer implements IServerContainer { function getJobList(){ return $this->query('JobList'); } + + /** + * Returns a router for generating and matching urls + * + * @return \OCP\Route\IRouter + */ + function getRouter(){ + $router = $this->query('Router'); + $router->loadRoutes(); + return $router; + } } diff --git a/lib/public/appframework/app.php b/lib/public/appframework/app.php index 90150245c41..21612327879 100644 --- a/lib/public/appframework/app.php +++ b/lib/public/appframework/app.php @@ -67,7 +67,7 @@ class App { * $a = new TasksApp(); * $a->registerRoutes($this, $routes); * - * @param \OC_Router $router + * @param \OCP\Route\IRouter $router * @param array $routes */ public function registerRoutes($router, $routes) { diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 5fb51f9ecd5..dc3aff663d4 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -190,4 +190,10 @@ interface IServerContainer { */ function getJobList(); + /** + * Returns a router for generating and matching urls + * + * @return \OCP\Route\IRouter + */ + function getRouter(); } diff --git a/lib/public/route/iroute.php b/lib/public/route/iroute.php new file mode 100644 index 00000000000..66fdb841821 --- /dev/null +++ b/lib/public/route/iroute.php @@ -0,0 +1,79 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OCP\Route; + +interface IRoute { + /** + * Specify PATCH as the method to use with this route + */ + public function patch(); + + /** + * Specify the method when this route is to be used + * + * @param string $method HTTP method (uppercase) + * @return \OCP\Route\IRoute + */ + public function method($method); + + /** + * The action to execute when this route matches, includes a file like + * it is called directly + * + * @param $file + */ + public function actionInclude($file); + + /** + * Specify GET as the method to use with this route + */ + public function get(); + + /** + * Specify POST as the method to use with this route + */ + public function post(); + + /** + * Specify DELETE as the method to use with this route + */ + public function delete(); + + /** + * The action to execute when this route matches + * + * @param string|callable $class the class or a callable + * @param string $function the function to use with the class + * @return \OCP\Route\IRoute + * + * This function is called with $class set to a callable or + * to the class with $function + */ + public function action($class, $function = null); + + /** + * Defaults to use for this route + * + * @param array $defaults The defaults + * @return \OCP\Route\IRoute + */ + public function defaults($defaults); + + /** + * Requirements for this route + * + * @param array $requirements The requirements + * @return \OCP\Route\IRoute + */ + public function requirements($requirements); + + /** + * Specify PUT as the method to use with this route + */ + public function put(); +} diff --git a/lib/public/route/irouter.php b/lib/public/route/irouter.php new file mode 100644 index 00000000000..deb01bca9b9 --- /dev/null +++ b/lib/public/route/irouter.php @@ -0,0 +1,71 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Route; + +interface IRouter { + + public function __construct(); + + /** + * Get the files to load the routes from + * + * @return string[] + */ + public function getRoutingFiles(); + + public function getCacheKey(); + + /** + * loads the api routes + */ + public function loadRoutes(); + + /** + * Sets the collection to use for adding routes + * + * @param string $name Name of the collection to use. + */ + public function useCollection($name); + + /** + * Create a \OCP\Route\IRoute. + * + * @param string $name Name of the route to create. + * @param string $pattern The pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + * @return \OCP\Route\IRoute + */ + public function create($name, $pattern, array $defaults = array(), array $requirements = array()); + + /** + * Find the route matching $url. + * + * @param string $url The url to find + * @throws \Exception + */ + public function match($url); + + /** + * Get the url generator + * + */ + public function getGenerator(); + + /** + * Generate url based on $name and $parameters + * + * @param string $name Name of the route to use. + * @param array $parameters Parameters for the route + * @param bool $absolute + * @return string + */ + public function generate($name, $parameters = array(), $absolute = false); + +} diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php index d0244cf2511..9f2675bf0b4 100644 --- a/tests/lib/appframework/routing/RoutingTest.php +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -46,7 +46,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase )); // router mock - $router = $this->getMock("\OC_Router", array('create')); + $router = $this->getMock("\OC\Route\Router", array('create')); // load route configuration $container = new DIContainer('app1'); @@ -91,7 +91,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase $route = $this->mockRoute($verb, $controllerName, $actionName); // router mock - $router = $this->getMock("\OC_Router", array('create')); + $router = $this->getMock("\OC\Route\Router", array('create')); // we expect create to be called once: $router @@ -116,7 +116,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName) { // router mock - $router = $this->getMock("\OC_Router", array('create')); + $router = $this->getMock("\OC\Route\Router", array('create')); // route mocks $indexRoute = $this->mockRoute('GET', $controllerName, 'index'); @@ -174,7 +174,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase private function mockRoute($verb, $controllerName, $actionName) { $container = new DIContainer('app1'); - $route = $this->getMock("\OC_Route", array('method', 'action'), array(), '', false); + $route = $this->getMock("\OC\Route\Route", array('method', 'action'), array(), '', false); $route ->expects($this->exactly(1)) ->method('method') -- cgit v1.2.3 From 26793e1f943012937776324698855108dd5352ba Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 10 Mar 2014 14:06:47 +0100 Subject: switch OC::getRouter usages to OC::$server->getRouter --- lib/base.php | 10 +--------- lib/private/api.php | 4 ++-- lib/private/urlgenerator.php | 2 +- ocs/v1.php | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) (limited to 'lib/private') diff --git a/lib/base.php b/lib/base.php index d49dd958310..4bc6c4329c4 100644 --- a/lib/base.php +++ b/lib/base.php @@ -382,14 +382,6 @@ class OC { return OC_Config::getValue('session_lifetime', 60 * 60 * 24); } - /** - * @return \OCP\Route\IRouter - */ - public static function getRouter() { - return self::$server->getRouter(); - } - - public static function loadAppClassPaths() { foreach (OC_APP::getEnabledApps() as $app) { $file = OC_App::getAppPath($app) . '/appinfo/classpath.php'; @@ -714,7 +706,7 @@ class OC { OC_App::loadApps(); } self::checkSingleUserMode(); - OC::getRouter()->match(OC_Request::getRawPathInfo()); + OC::$server->getRouter()->match(OC_Request::getRawPathInfo()); return; } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) { //header('HTTP/1.0 404 Not Found'); diff --git a/lib/private/api.php b/lib/private/api.php index 3f96196e6df..cde24f78a55 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -65,8 +65,8 @@ class OC_API { $name = strtolower($method).$url; $name = str_replace(array('/', '{', '}'), '_', $name); if(!isset(self::$actions[$name])) { - OC::getRouter()->useCollection('ocs'); - OC::getRouter()->create($name, $url) + OC::$server->getRouter()->useCollection('ocs'); + OC::$server->getRouter()->create($name, $url) ->method($method) ->defaults($defaults) ->requirements($requirements) diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php index 60da34f2d6e..44b46ef6700 100644 --- a/lib/private/urlgenerator.php +++ b/lib/private/urlgenerator.php @@ -39,7 +39,7 @@ class URLGenerator implements IURLGenerator { * Returns a url to the given app and file. */ public function linkToRoute($route, $parameters = array()) { - $urlLinkTo = \OC::getRouter()->generate($route, $parameters); + $urlLinkTo = \OC::$server->getRouter()->generate($route, $parameters); return $urlLinkTo; } diff --git a/ocs/v1.php b/ocs/v1.php index 1c7d1c89768..3da72e65f1c 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -26,7 +26,7 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\MethodNotAllowedException; try { - OC::getRouter()->match('/ocs'.OC_Request::getRawPathInfo()); + OC::$server->getRouter()->match('/ocs'.OC_Request::getRawPathInfo()); } catch (ResourceNotFoundException $e) { OC_OCS::notFound(); } catch (MethodNotAllowedException $e) { -- cgit v1.2.3 From 73a1ece7533b9d90305e11052947809b91850184 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 10 Mar 2014 14:21:12 +0100 Subject: adding an explicit close method to class session - write operations (set and remove) being called after close() will throw an exception --- lib/private/session/internal.php | 2 +- lib/private/session/memory.php | 8 ++++++++ lib/private/session/session.php | 6 ++++++ lib/public/isession.php | 5 +++++ 4 files changed, 20 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php index a7c9e2fdefd..d589932d425 100644 --- a/lib/private/session/internal.php +++ b/lib/private/session/internal.php @@ -27,7 +27,7 @@ class Internal extends Memory { public function __destruct() { $_SESSION = array_merge($_SESSION, $this->data); - session_write_close(); + \OC::$session->close(); } /** diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php index 1b9ac452575..1562c2ce037 100644 --- a/lib/private/session/memory.php +++ b/lib/private/session/memory.php @@ -28,6 +28,7 @@ class Memory extends Session { * @param integer $value */ public function set($key, $value) { + $this->validateSession(); $this->data[$key] = $value; } @@ -54,10 +55,17 @@ class Memory extends Session { * @param string $key */ public function remove($key) { + $this->validateSession(); unset($this->data[$key]); } public function clear() { $this->data = array(); } + + private function validateSession() { + if ($this->sessionClosed) { + throw new \Exception('Session has been closed - no further changes to the session as allowed'); + } + } } diff --git a/lib/private/session/session.php b/lib/private/session/session.php index fe160faa267..5c18f3e495d 100644 --- a/lib/private/session/session.php +++ b/lib/private/session/session.php @@ -49,4 +49,10 @@ abstract class Session implements \ArrayAccess, ISession { public function offsetUnset($offset) { $this->remove($offset); } + + protected $sessionClosed = false; + + public function close() { + $this->sessionClosed = true; + } } diff --git a/lib/public/isession.php b/lib/public/isession.php index 20da712cda3..dc5719625cc 100644 --- a/lib/public/isession.php +++ b/lib/public/isession.php @@ -75,4 +75,9 @@ interface ISession { */ public function clear(); + /** + * Close the session and release the lock + */ + public function close(); + } -- cgit v1.2.3 From f0603a971d49f7143471123a2a255fc9632a45c5 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 10 Mar 2014 14:40:36 +0100 Subject: close the session for all DAV calls right after authentication - no need to write to the session afterwards --- lib/private/connector/sabre/auth.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/connector/sabre/auth.php b/lib/private/connector/sabre/auth.php index 0c84fa6b757..5577273df8c 100644 --- a/lib/private/connector/sabre/auth.php +++ b/lib/private/connector/sabre/auth.php @@ -73,6 +73,20 @@ class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic { */ public function authenticate(Sabre_DAV_Server $server, $realm) { + $result = $this->auth($server, $realm); + + // close the session - right after authentication there is not need to write to the session any more + \OC::$session->close(); + + return $result; + } + + /** + * @param Sabre_DAV_Server $server + * @param $realm + * @return bool + */ + private function auth(Sabre_DAV_Server $server, $realm) { if (OC_User::handleApacheAuth() || OC_User::isLoggedIn()) { $user = OC_User::getUser(); OC_Util::setupFS($user); @@ -81,5 +95,5 @@ class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic { } return parent::authenticate($server, $realm); - } + } } -- cgit v1.2.3 From 4562909a2021be795b89cb7fcf6f244d7f6a8204 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 25 Feb 2014 21:35:54 +0100 Subject: get trash size from file cache --- apps/files_trashbin/appinfo/database.xml | 4 +- apps/files_trashbin/appinfo/update.php | 2 +- apps/files_trashbin/appinfo/version | 2 +- apps/files_trashbin/lib/trashbin.php | 79 +++----------------------------- lib/private/files/cache/homecache.php | 2 +- 5 files changed, 11 insertions(+), 78 deletions(-) (limited to 'lib/private') diff --git a/apps/files_trashbin/appinfo/database.xml b/apps/files_trashbin/appinfo/database.xml index d08c3469b02..db104ee9298 100644 --- a/apps/files_trashbin/appinfo/database.xml +++ b/apps/files_trashbin/appinfo/database.xml @@ -49,7 +49,7 @@ type text - true + false 4 @@ -57,7 +57,7 @@ mime text - true + false 255 diff --git a/apps/files_trashbin/appinfo/update.php b/apps/files_trashbin/appinfo/update.php index 0ca232668d7..ca7b87a8681 100644 --- a/apps/files_trashbin/appinfo/update.php +++ b/apps/files_trashbin/appinfo/update.php @@ -2,7 +2,7 @@ $installedVersion=OCP\Config::getAppValue('files_trashbin', 'installed_version'); -if (version_compare($installedVersion, '0.4', '<')) { +if (version_compare($installedVersion, '0.6', '<')) { //size of the trash bin could be incorrect, remove it for all users to //enforce a recalculation during next usage. $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trashsize`'); diff --git a/apps/files_trashbin/appinfo/version b/apps/files_trashbin/appinfo/version index 2eb3c4fe4ee..5a2a5806df6 100644 --- a/apps/files_trashbin/appinfo/version +++ b/apps/files_trashbin/appinfo/version @@ -1 +1 @@ -0.5 +0.6 diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php index 3933395c298..f6816b2b4c2 100644 --- a/apps/files_trashbin/lib/trashbin.php +++ b/apps/files_trashbin/lib/trashbin.php @@ -112,9 +112,6 @@ class Trashbin { $timestamp = time(); $userTrashSize = self::getTrashbinSize($user); - if ($userTrashSize === false || $userTrashSize < 0) { - $userTrashSize = self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin')); - } // disable proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; @@ -146,17 +143,12 @@ class Trashbin { $userTrashSize += $size; $userTrashSize -= self::expire($userTrashSize, $user); - self::setTrashbinSize($user, $userTrashSize); // if owner !== user we also need to update the owners trash size if($owner !== $user) { $ownerTrashSize = self::getTrashbinSize($owner); - if ($ownerTrashSize === false || $ownerTrashSize < 0) { - $ownerTrashSize = self::calculateSize(new \OC\Files\View('/' . $owner . '/files_trashbin')); - } $ownerTrashSize += $size; $ownerTrashSize -= self::expire($ownerTrashSize, $owner); - self::setTrashbinSize($owner, $ownerTrashSize); } } @@ -317,10 +309,6 @@ class Trashbin { $user = \OCP\User::getUser(); $view = new \OC\Files\View('/' . $user); - $trashbinSize = self::getTrashbinSize($user); - if ($trashbinSize === false || $trashbinSize < 0) { - $trashbinSize = self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin')); - } $location = ''; if ($timestamp) { $query = \OC_DB::prepare('SELECT `location` FROM `*PREFIX*files_trash`' @@ -361,22 +349,15 @@ class Trashbin { $view->chroot($fakeRoot); \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', array('filePath' => \OC\Files\Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename), 'trashPath' => \OC\Files\Filesystem::normalizePath($file))); - if ($view->is_dir($target)) { - $trashbinSize -= self::calculateSize(new \OC\Files\View('/' . $user . '/' . $target)); - } else { - $trashbinSize -= $view->filesize($target); - } - $trashbinSize -= self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp); - $trashbinSize -= self::restoreEncryptionKeys($view, $file, $filename, $uniqueFilename, $location, $timestamp); + self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp); + self::restoreEncryptionKeys($view, $file, $filename, $uniqueFilename, $location, $timestamp); if ($timestamp) { $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?'); $query->execute(array($user, $filename, $timestamp)); } - self::setTrashbinSize($user, $trashbinSize); - // enable proxy \OC_FileProxy::$enabled = $proxyStatus; @@ -399,10 +380,8 @@ class Trashbin { * @param $location location if file * @param $timestamp deleteion time * - * @return size of restored versions */ private static function restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp) { - $size = 0; if (\OCP\App::isEnabled('files_versions')) { // disable proxy to prevent recursive calls @@ -423,15 +402,12 @@ class Trashbin { } if ($view->is_dir('/files_trashbin/versions/' . $file)) { - $size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . 'files_trashbin/versions/' . $file)); $rootView->rename(\OC\Files\Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath)); } else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp)) { foreach ($versions as $v) { if ($timestamp) { - $size += $view->filesize('files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp); $rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v); } else { - $size += $view->filesize('files_trashbin/versions/' . $versionedFile . '.v' . $v); $rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v, $owner . '/files_versions/' . $ownerPath . '.v' . $v); } } @@ -440,7 +416,6 @@ class Trashbin { // enable proxy \OC_FileProxy::$enabled = $proxyStatus; } - return $size; } /** @@ -453,11 +428,9 @@ class Trashbin { * @param $location location of file * @param $timestamp deleteion time * - * @return size of restored encrypted file */ private static function restoreEncryptionKeys($view, $file, $filename, $uniqueFilename, $location, $timestamp) { // Take care of encryption keys TODO! Get '.key' in file between file name and delete date (also for permanent delete!) - $size = 0; if (\OCP\App::isEnabled('files_encryption')) { $user = \OCP\User::getUser(); $rootView = new \OC\Files\View('/'); @@ -502,18 +475,15 @@ class Trashbin { if ($rootView->is_dir($keyfile)) { // handle keyfiles - $size += self::calculateSize(new \OC\Files\View($keyfile)); $rootView->rename($keyfile, $baseDir . '/keyfiles/' . $ownerPath); // handle share-keys if ($timestamp) { $sharekey .= '.d' . $timestamp; } - $size += self::calculateSize(new \OC\Files\View($sharekey)); $rootView->rename($sharekey, $baseDir . '/share-keys/' . $ownerPath); } else { // handle keyfiles - $size += $rootView->filesize($keyfile); $rootView->rename($keyfile, $baseDir . '/keyfiles/' . $ownerPath . '.key'); // handle share-keys @@ -522,8 +492,6 @@ class Trashbin { $ownerShareKey .= '.d' . $timestamp; } - $size += $rootView->filesize($ownerShareKey); - // move only owners key $rootView->rename($ownerShareKey, $baseDir . '/share-keys/' . $ownerPath . '.' . $user . '.shareKey'); @@ -550,7 +518,6 @@ class Trashbin { // enable proxy \OC_FileProxy::$enabled = $proxyStatus; } - return $size; } /** @@ -560,7 +527,6 @@ class Trashbin { $user = \OCP\User::getUser(); $view = new \OC\Files\View('/' . $user); $view->deleteAll('files_trashbin'); - self::setTrashbinSize($user, 0); $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?'); $query->execute(array($user)); @@ -581,11 +547,6 @@ class Trashbin { $view = new \OC\Files\View('/' . $user); $size = 0; - $trashbinSize = self::getTrashbinSize($user); - if ($trashbinSize === false || $trashbinSize < 0) { - $trashbinSize = self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin')); - } - if ($timestamp) { $query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?'); $query->execute(array($user, $filename, $timestamp)); @@ -604,8 +565,6 @@ class Trashbin { } $view->unlink('/files_trashbin/files/' . $file); \OC_Hook::emit('\OCP\Trashbin', 'delete', array('path' => '/files_trashbin/files/' . $file)); - $trashbinSize -= $size; - self::setTrashbinSize($user, $trashbinSize); return $size; } @@ -751,17 +710,10 @@ class Trashbin { $size = self::getTrashbinSize($user); - if ($size === false || $size < 0) { - $size = self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin')); - } - $freeSpace = self::calculateFreeSpace($size); if ($freeSpace < 0) { - $newSize = $size - self::expire($size, $user); - if ($newSize !== $size) { - self::setTrashbinSize($user, $newSize); - } + self::expire($size, $user); } } @@ -938,28 +890,9 @@ class Trashbin { * @return mixed trash bin size or false if no trash bin size is stored */ private static function getTrashbinSize($user) { - $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*files_trashsize` WHERE `user`=?'); - $result = $query->execute(array($user))->fetchAll(); - - if ($result) { - return (int)$result[0]['size']; - } - return false; - } - - /** - * write to the database how much space is in use for the trash bin - * - * @param $user owner of the trash bin - * @param $size size of the trash bin - */ - private static function setTrashbinSize($user, $size) { - if (self::getTrashbinSize($user) === false) { - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*files_trashsize` (`size`, `user`) VALUES (?, ?)'); - } else { - $query = \OC_DB::prepare('UPDATE `*PREFIX*files_trashsize` SET `size`=? WHERE `user`=?'); - } - $query->execute(array($size, $user)); + $view = new \OC\Files\View('/' . $user); + $fileInfo = $view->getFileInfo('/files_trashbin'); + return $fileInfo['size']; } /** diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index a7c310a3782..a35e4d5e1b9 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -16,7 +16,7 @@ class HomeCache extends Cache { * @return int */ public function calculateFolderSize($path) { - if ($path !== '/' and $path !== '' and $path !== 'files') { + if ($path !== '/' and $path !== '' and $path !== 'files' and $path !== 'files_trashbin') { return parent::calculateFolderSize($path); } -- cgit v1.2.3 From a074adb2af2a72a5f122435bece7b8f5c2850ca4 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 10 Mar 2014 15:36:20 +0100 Subject: fix close() implementation in \OC\Session\Internal --- lib/private/session/internal.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php index d589932d425..9d3b9cb81ba 100644 --- a/lib/private/session/internal.php +++ b/lib/private/session/internal.php @@ -26,8 +26,7 @@ class Internal extends Memory { } public function __destruct() { - $_SESSION = array_merge($_SESSION, $this->data); - \OC::$session->close(); + $this->close(); } /** @@ -47,4 +46,12 @@ class Internal extends Memory { @session_start(); $this->data = $_SESSION = array(); } + + public function close() { + $_SESSION = array_merge($_SESSION, $this->data); + session_write_close(); + + parent::close(); + } + } -- cgit v1.2.3 From 9fe5033f1ec1737eae9402008c5228e5fe60f9bc Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 10 Mar 2014 17:15:19 +0100 Subject: PHPDoc updated --- lib/private/session/memory.php | 5 +++++ lib/private/session/session.php | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php index 1562c2ce037..8434b6000e5 100644 --- a/lib/private/session/memory.php +++ b/lib/private/session/memory.php @@ -63,6 +63,11 @@ class Memory extends Session { $this->data = array(); } + /** + * In case the session has already been locked an exception will be thrown + * + * @throws \Exception + */ private function validateSession() { if ($this->sessionClosed) { throw new \Exception('Session has been closed - no further changes to the session as allowed'); diff --git a/lib/private/session/session.php b/lib/private/session/session.php index 5c18f3e495d..6f6c804f384 100644 --- a/lib/private/session/session.php +++ b/lib/private/session/session.php @@ -12,6 +12,11 @@ use OCP\ISession; abstract class Session implements \ArrayAccess, ISession { + /** + * @var bool + */ + protected $sessionClosed = false; + /** * $name serves as a namespace for the session keys * @@ -50,8 +55,9 @@ abstract class Session implements \ArrayAccess, ISession { $this->remove($offset); } - protected $sessionClosed = false; - + /** + * Close the session and release the lock + */ public function close() { $this->sessionClosed = true; } -- cgit v1.2.3 From f4f61f03c9d14eaa16a7a7fcd49f2086dfa56e92 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 10 Mar 2014 17:49:47 +0100 Subject: Disable XML entities when parsing XML --- lib/private/ocsclient.php | 16 ++++++++++++---- lib/private/updater.php | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php index fa6e3fac1bb..68dc2c2d6ec 100644 --- a/lib/private/ocsclient.php +++ b/lib/private/ocsclient.php @@ -72,7 +72,9 @@ class OC_OCSClient{ if($xml==false) { return null; } - $data=simplexml_load_string($xml); + $loadEntities = libxml_disable_entity_loader(true); + $data = simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); $tmp=$data->data; $cats=array(); @@ -117,7 +119,9 @@ class OC_OCSClient{ if($xml==false) { return null; } - $data=simplexml_load_string($xml); + $loadEntities = libxml_disable_entity_loader(true); + $data = simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); $tmp=$data->data->content; for($i = 0; $i < count($tmp); $i++) { @@ -159,7 +163,9 @@ class OC_OCSClient{ OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); return null; } - $data=simplexml_load_string($xml); + $loadEntities = libxml_disable_entity_loader(true); + $data = simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); $tmp=$data->data->content; $app=array(); @@ -200,7 +206,9 @@ class OC_OCSClient{ OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); return null; } - $data=simplexml_load_string($xml); + $loadEntities = libxml_disable_entity_loader(true); + $data = simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); $tmp=$data->data->content; $app=array(); diff --git a/lib/private/updater.php b/lib/private/updater.php index f05d5038b76..292752067bf 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -76,7 +76,9 @@ class Updater extends BasicEmitter { if ($xml == false) { return array(); } + $loadEntities = libxml_disable_entity_loader(true); $data = @simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); $tmp = array(); $tmp['version'] = $data->version; -- cgit v1.2.3 From 010eef95c0c5cebd03b03645d29847638e064bd5 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 10 Mar 2014 15:19:18 +0100 Subject: Fixed total space display when data size exceeds quota The total space display in the personal page now shows the quota value instead of used space when used space exceeds the quota (soft quota). --- lib/private/files/storage/wrapper/quota.php | 7 ++ lib/private/helper.php | 11 ++- tests/lib/helperstorage.php | 113 ++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 tests/lib/helperstorage.php (limited to 'lib/private') diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index 26c952e694a..0e0d5b13104 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -29,6 +29,13 @@ class Quota extends Wrapper { $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : ''; } + /** + * @return quota value + */ + public function getQuota() { + return $this->quota; + } + /** * @param string $path */ diff --git a/lib/private/helper.php b/lib/private/helper.php index b9956d5ec1c..0b1a26bbecd 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -914,13 +914,22 @@ class OC_Helper { if ($used < 0) { $used = 0; } - $free = \OC\Files\Filesystem::free_space($path); + $quota = 0; + // TODO: need a better way to get total space from storage + $storage = $rootInfo->getStorage(); + if ($storage instanceof \OC\Files\Storage\Wrapper\Quota) { + $quota = $storage->getQuota(); + } + $free = $storage->free_space(''); if ($free >= 0) { $total = $free + $used; } else { $total = $free; //either unknown or unlimited } if ($total > 0) { + if ($quota > 0 && $total > $quota) { + $total = $quota; + } // prevent division by zero or error codes (negative values) $relative = round(($used / $total) * 10000) / 100; } else { diff --git a/tests/lib/helperstorage.php b/tests/lib/helperstorage.php new file mode 100644 index 00000000000..010a54e3bb0 --- /dev/null +++ b/tests/lib/helperstorage.php @@ -0,0 +1,113 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Test the storage functions of OC_Helper + */ +class Test_Helper_Storage extends PHPUnit_Framework_TestCase { + private $user; + private $storageMock; + + public function setUp() { + $this->user = 'user_' . uniqid(); + \OC\Files\Filesystem::tearDown(); + \OC\Files\Filesystem::init($this->user, '/' . $this->user . '/files'); + + $this->storageMock = $this->getMock( + '\OC\Files\Storage\Temporary', + array('free_space'), + array('') + ); + + \OC\Files\Filesystem::clearMounts(); + + $this->storageMock->expects($this->once()) + ->method('free_space') + ->will($this->returnValue(12)); + } + + public function tearDown() { + $this->user = null; + + $this->storageMock->getCache()->clear(); + \OC\Files\Filesystem::tearDown(); + } + + /** + * Test getting the storage info + */ + function testGetStorageInfo() { + \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + $this->storageMock->file_put_contents('test.txt', '01234'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(12, $storageInfo['free']); + $this->assertEquals(5, $storageInfo['used']); + $this->assertEquals(17, $storageInfo['total']); + } + + /** + * Test getting the storage info with quota enabled + */ + function testGetStorageInfoWithQuota() { + $this->storageMock->file_put_contents('test.txt', '01234'); + $this->storageMock = new \OC\Files\Storage\Wrapper\Quota( + array( + 'storage' => $this->storageMock, + 'quota' => 7 + ) + ); + \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(2, $storageInfo['free']); + $this->assertEquals(5, $storageInfo['used']); + $this->assertEquals(7, $storageInfo['total']); + } + + /** + * Test getting the storage info when data exceeds quota + */ + function testGetStorageInfoWhenSizeExceedsQuota() { + $this->storageMock->file_put_contents('test.txt', '0123456789'); + $this->storageMock = new \OC\Files\Storage\Wrapper\Quota( + array( + 'storage' => $this->storageMock, + 'quota' => 7 + ) + ); + \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(0, $storageInfo['free']); + $this->assertEquals(10, $storageInfo['used']); + // total = quota + $this->assertEquals(7, $storageInfo['total']); + } + + /** + * Test getting the storage info when the remaining + * free storage space is less than the quota + */ + function testGetStorageInfoWhenFreeSpaceLessThanQuota() { + $this->storageMock->file_put_contents('test.txt', '01234'); + $this->storageMock = new \OC\Files\Storage\Wrapper\Quota( + array( + 'storage' => $this->storageMock, + 'quota' => 18 + ) + ); + \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(12, $storageInfo['free']); + $this->assertEquals(5, $storageInfo['used']); + // total = free + used (because quota > total) + $this->assertEquals(17, $storageInfo['total']); + } +} -- cgit v1.2.3 From f1ecc758f5f6543566ae9970de837e5524cf8bf9 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 10 Mar 2014 21:54:23 +0100 Subject: send an individual email to each recipient --- core/ajax/share.php | 11 +++++++++-- lib/private/share/mailnotifications.php | 23 +++++++++++++---------- 2 files changed, 22 insertions(+), 12 deletions(-) (limited to 'lib/private') diff --git a/core/ajax/share.php b/core/ajax/share.php index 86ee018e388..ca1951ec9ae 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -145,10 +145,17 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo } $result = $mailNotification->sendLinkShareMail($to_address, $file, $link, $expiration); - if($result === true) { + if(empty($result)) { \OCP\JSON::success(); } else { - \OCP\JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($result)))); + $l = OC_L10N::get('core'); + OCP\JSON::error(array( + 'data' => array( + 'message' => $l->t("Couldn't send mail to following users: %s ", + implode(', ', $result) + ) + ) + )); } break; diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php index 360376294cc..45734818731 100644 --- a/lib/private/share/mailnotifications.php +++ b/lib/private/share/mailnotifications.php @@ -97,7 +97,7 @@ class MailNotifications { try { \OCP\Util::sendMail($to, $recipientDisplayName, $subject, $htmlMail, $this->from, $this->senderDisplayName, 1, $alttextMail); } catch (\Exception $e) { - \OCP\Util::writeLog('sharing', "Can't send mail to inform the user abaut an internal share: " . $e->getMessage() , \OCP\Util::ERROR); + \OCP\Util::writeLog('sharing', "Can't send mail to inform the user about an internal share: " . $e->getMessage() , \OCP\Util::ERROR); $noMail[] = $recipientDisplayName; } } @@ -109,23 +109,26 @@ class MailNotifications { /** * @brief inform recipient about public link share * - * @param string recipient recipient email address + * @param string $recipient recipient email address * @param string $filename the shared file * @param string $link the public link * @param int $expiration expiration date (timestamp) - * @return mixed $result true or error message + * @return array $result of failed recipients */ public function sendLinkShareMail($recipient, $filename, $link, $expiration) { $subject = (string)$this->l->t('%s shared »%s« with you', array($this->senderDisplayName, $filename)); list($htmlMail, $alttextMail) = $this->createMailBody($filename, $link, $expiration); - try { - \OCP\Util::sendMail($recipient, $recipient, $subject, $htmlMail, $this->from, $this->senderDisplayName, 1, $alttextMail); - } catch (\Exception $e) { - \OCP\Util::writeLog('sharing', "Can't send mail with public link: " . $e->getMessage(), \OCP\Util::ERROR); - return $e->getMessage(); + $rs = explode(' ', $recipient); + $failed = array(); + foreach ($rs as $r) { + try { + \OCP\Util::sendMail($r, $r, $subject, $htmlMail, $this->from, $this->senderDisplayName, 1, $alttextMail); + } catch (\Exception $e) { + \OCP\Util::writeLog('sharing', "Can't send mail with public link to $r: " . $e->getMessage(), \OCP\Util::ERROR); + $failed[] = $r; + } } - - return true; + return $failed; } /** -- cgit v1.2.3 From 0de43f1fbe20f6cb69d14e8b07efa1e72f852464 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 10 Mar 2014 21:56:37 +0100 Subject: remove magic handling of recipient lists by exploding the string - this functionality is nowhere used this way and nowhere documented - and broken because only $toaddress will be exploded not $toname --- lib/private/mail.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/private/mail.php b/lib/private/mail.php index 90c3e343199..9605290fe57 100644 --- a/lib/private/mail.php +++ b/lib/private/mail.php @@ -72,11 +72,8 @@ class OC_Mail { $mailo->From = $fromaddress; $mailo->FromName = $fromname;; $mailo->Sender = $fromaddress; - $a=explode(' ', $toaddress); try { - foreach($a as $ad) { - $mailo->AddAddress($ad, $toname); - } + $mailo->AddAddress($toaddress, $toname); if($ccaddress<>'') $mailo->AddCC($ccaddress, $ccname); if($bcc<>'') $mailo->AddBCC($bcc); -- cgit v1.2.3 From 7c78368e8b0c4b796a2f01757e50a1428a4ac017 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 12 Mar 2014 00:18:51 +0100 Subject: sanitize fallbackId --- lib/private/eventsource.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/eventsource.php b/lib/private/eventsource.php index 4df0bc2e7cd..5a41ddd8b37 100644 --- a/lib/private/eventsource.php +++ b/lib/private/eventsource.php @@ -63,8 +63,9 @@ class OC_EventSource{ $type=null; } if($this->fallback) { + $fallBackId = OC_Util::sanitizeHTML($this->fallBackId); $response='' . PHP_EOL; + .$fallBackId.',"' . $type . '",' . OCP\JSON::encode($data) . ')' . PHP_EOL; echo $response; }else{ if($type) { -- cgit v1.2.3 From 743addd1e317c760e8b1e4ad7dc149476e4ad282 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 12 Mar 2014 00:35:19 +0100 Subject: set content-type on ocs exceptions --- lib/private/api.php | 33 ++++++++++++++++++++++++++++++--- ocs/v1.php | 3 +++ 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/api.php b/lib/private/api.php index 1537cc11dd0..ccaccda97be 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -116,9 +116,7 @@ class OC_API { ); } $response = self::mergeResponses($responses); - $formats = array('json', 'xml'); - - $format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml'; + $format = self::requestedFormat(); if (self::$logoutRequired) { OC_User::logout(); } @@ -350,4 +348,33 @@ class OC_API { } } + /** + * @return string + */ + public static function requestedFormat() { + $formats = array('json', 'xml'); + + $format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml'; + return $format; + } + + /** + * Based on the requested format the response content type is set + */ + public static function setOcsContentType() { + $format = \OC_API::requestedFormat(); + if ($format === 'xml') { + header('Content-type: text/xml; charset=UTF-8'); + return; + } + + if ($format === 'json') { + header('Content-Type: application/json; charset=utf-8'); + return; + } + + header('Content-Type: application/octet-stream; charset=utf-8'); + } + + } diff --git a/ocs/v1.php b/ocs/v1.php index 1c7d1c89768..9d84f482ef7 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -28,8 +28,11 @@ use Symfony\Component\Routing\Exception\MethodNotAllowedException; try { OC::getRouter()->match('/ocs'.OC_Request::getRawPathInfo()); } catch (ResourceNotFoundException $e) { + OC_API::setContentType(); OC_OCS::notFound(); } catch (MethodNotAllowedException $e) { + setOcsContentType(); + OC_API::setContentType(); OC_Response::setStatus(405); } -- cgit v1.2.3 From 88f6dd7db1b3dc4cb68d3526a35108d196a5e5cb Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 12 Mar 2014 10:00:22 +0100 Subject: fixing method names --- lib/private/api.php | 2 +- ocs/v1.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/api.php b/lib/private/api.php index ccaccda97be..e8e54e375e9 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -361,7 +361,7 @@ class OC_API { /** * Based on the requested format the response content type is set */ - public static function setOcsContentType() { + public static function setContentType() { $format = \OC_API::requestedFormat(); if ($format === 'xml') { header('Content-type: text/xml; charset=UTF-8'); diff --git a/ocs/v1.php b/ocs/v1.php index 9d84f482ef7..4cbc857bbcf 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -31,7 +31,6 @@ try { OC_API::setContentType(); OC_OCS::notFound(); } catch (MethodNotAllowedException $e) { - setOcsContentType(); OC_API::setContentType(); OC_Response::setStatus(405); } -- cgit v1.2.3 From 8048868bd7cc55716127d1c9fa40a0c32db8b901 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 11 Mar 2014 14:21:27 +0100 Subject: use preDelete instead of postDelete hook --- lib/base.php | 5 ++++- lib/private/preview.php | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/base.php b/lib/base.php index 86ee5349828..6ad3a84bcac 100644 --- a/lib/base.php +++ b/lib/base.php @@ -661,7 +661,10 @@ class OC { */ public static function registerPreviewHooks() { OC_Hook::connect('OC_Filesystem', 'post_write', 'OC\Preview', 'post_write'); - OC_Hook::connect('OC_Filesystem', 'delete', 'OC\Preview', 'post_delete'); + OC_Hook::connect('OC_Filesystem', 'preDelete', 'OC\Preview', 'prepare_delete_files'); + OC_Hook::connect('\OCP\Versions', 'preDelete', 'OC\Preview', 'prepare_delete'); + OC_Hook::connect('\OCP\Trashbin', 'preDelete', 'OC\Preview', 'prepare_delete'); + OC_Hook::connect('OC_Filesystem', 'delete', 'OC\Preview', 'post_delete_files'); OC_Hook::connect('\OCP\Versions', 'delete', 'OC\Preview', 'post_delete'); OC_Hook::connect('\OCP\Trashbin', 'delete', 'OC\Preview', 'post_delete'); } diff --git a/lib/private/preview.php b/lib/private/preview.php index 74051fbc2a3..8cef1ade01b 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -42,6 +42,10 @@ class Preview { private $scalingup; private $mimetype; + //filemapper used for deleting previews + // index is path, value is fileinfo + static public $deleteFileMapper = array(); + //preview images object /** * @var \OC_Image @@ -166,7 +170,11 @@ class Preview { } protected function getFileInfo() { - if (!$this->info) { + $absPath = $this->fileView->getAbsolutePath($this->file); + $absPath = Files\Filesystem::normalizePath($absPath); + if(array_key_exists($absPath, self::$deleteFileMapper)) { + $this->info = self::$deleteFileMapper[$absPath]; + } else if (!$this->info) { $this->info = $this->fileView->getFileInfo($this->file); } return $this->info; @@ -623,12 +631,35 @@ class Preview { self::post_delete($args); } - public static function post_delete($args) { + public static function prepare_delete_files($args) { + self::prepare_delete($args, 'files/'); + } + + public static function prepare_delete($args, $prefix='') { $path = $args['path']; if (substr($path, 0, 1) === '/') { $path = substr($path, 1); } - $preview = new Preview(\OC_User::getUser(), 'files/', $path); + + $view = new \OC\Files\View('/' . \OC_User::getUser() . '/' . $prefix); + $info = $view->getFileInfo($path); + + \OC\Preview::$deleteFileMapper = array_merge( + \OC\Preview::$deleteFileMapper, + array( + Files\Filesystem::normalizePath($view->getAbsolutePath($path)) => $info, + ) + ); + } + + public static function post_delete_files($args) { + self::post_delete($args, 'files/'); + } + + public static function post_delete($args, $prefix='') { + $path = Files\Filesystem::normalizePath($args['path']); + + $preview = new Preview(\OC_User::getUser(), $prefix, $path); $preview->deleteAllPreviews(); } -- cgit v1.2.3 From f43833749301a8c8ea605d08897ffbc422c8d560 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Thu, 13 Mar 2014 12:32:02 +0100 Subject: improve validation of getFileInfo in \OC\Preview --- lib/private/preview.php | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'lib/private') diff --git a/lib/private/preview.php b/lib/private/preview.php index 8cef1ade01b..1f797c7e994 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -189,7 +189,10 @@ class Preview { $this->file = $file; $this->info = null; if ($file !== '') { - $this->mimetype = $this->getFileInfo()->getMimetype(); + $this->getFileInfo(); + if($this->info !== null && $this->info !== false) { + $this->mimetype = $this->info->getMimetype(); + } } return $this; } @@ -282,10 +285,13 @@ class Preview { $file = $this->getFile(); $fileInfo = $this->getFileInfo($file); - $fileId = $fileInfo->getId(); + if($fileInfo !== null && $fileInfo !== false) { + $fileId = $fileInfo->getId(); - $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/' . $this->getMaxX() . '-' . $this->getMaxY() . '.png'; - return $this->userView->unlink($previewPath); + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/' . $this->getMaxX() . '-' . $this->getMaxY() . '.png'; + return $this->userView->unlink($previewPath); + } + return false; } /** @@ -296,11 +302,14 @@ class Preview { $file = $this->getFile(); $fileInfo = $this->getFileInfo($file); - $fileId = $fileInfo->getId(); + if($fileInfo !== null && $fileInfo !== false) { + $fileId = $fileInfo->getId(); - $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; - $this->userView->deleteAll($previewPath); - return $this->userView->rmdir($previewPath); + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + $this->userView->deleteAll($previewPath); + return $this->userView->rmdir($previewPath); + } + return false; } /** @@ -406,6 +415,9 @@ class Preview { $scalingUp = $this->getScalingUp(); $fileInfo = $this->getFileInfo($file); + if($fileInfo === null || $fileInfo === false) { + return new \OC_Image(); + } $fileId = $fileInfo->getId(); $cached = $this->isCached(); -- cgit v1.2.3 From 6f96ab3e9093d03088ebd6bde399edf2d1ba2fac Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 14 Mar 2014 11:13:45 +0100 Subject: make it possible to influence output type of \OC_Image --- lib/private/image.php | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index a4a23f0f097..df49bf9848d 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -150,9 +150,12 @@ class OC_Image { * @brief Outputs the image. * @returns bool */ - public function show() { - header('Content-Type: '.$this->mimeType()); - return $this->_output(); + public function show($mimeType=null) { + if($mimeType === null) { + $mimeType = $this->mimeType(); + } + header('Content-Type: '.$mimeType); + return $this->_output(null, $mimeType); } /** @@ -161,20 +164,23 @@ class OC_Image { * @param string $filePath */ - public function save($filePath=null) { + public function save($filePath=null, $mimeType=null) { + if($mimeType === null) { + $mimeType = $this->mimeType(); + } if($filePath === null && $this->filePath === null) { OC_Log::write('core', __METHOD__.'(): called with no path.', OC_Log::ERROR); return false; } elseif($filePath === null && $this->filePath !== null) { $filePath = $this->filePath; } - return $this->_output($filePath); + return $this->_output($filePath, $mimeType); } /** * @brief Outputs/saves the image. */ - private function _output($filePath=null) { + private function _output($filePath=null, $mimeType=null) { if($filePath) { if (!file_exists(dirname($filePath))) mkdir(dirname($filePath), 0777, true); @@ -192,7 +198,34 @@ class OC_Image { return false; } - switch($this->imageType) { + $imageType = null; + if($mimeType !== null) { + switch($mimeType) { + case 'image/gif': + $this->imageType = IMAGETYPE_GIF; + break; + case 'image/jpeg': + case 'image/pjpeg': + $this->imageType = IMAGETYPE_JPEG; + break; + case 'image/png': + $this->imageType = IMAGETYPE_PNG; + break; + case 'image/x-xbitmap': + $this->imageType = IMAGETYPE_XBM; + break; + case 'image/bmp': + $this->imageType = IMAGETYPE_BMP; + break; + default: + $this->imageType = IMAGETYPE_PNG; + break; + } + } else { + $imageType = $this->imageType; + } + + switch($imageType) { case IMAGETYPE_GIF: $retVal = imagegif($this->resource, $filePath); break; -- cgit v1.2.3 From 0c3c75efd5fd2e68d67ac45a63e6226d1b8e822b Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 14 Mar 2014 11:14:09 +0100 Subject: always output a png --- lib/private/preview.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/preview.php b/lib/private/preview.php index 74051fbc2a3..70bfdb6e70a 100755 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -463,7 +463,7 @@ class Preview { if (is_null($this->preview)) { $this->getPreview(); } - $this->preview->show(); + $this->preview->show('image/png'); return; } -- cgit v1.2.3 From 1a116828cf00b434c5d3f5a3948393a714899df9 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 14 Mar 2014 10:48:07 +0100 Subject: Added warning for trusted_domains after CLI upgrade If trusted_domains is not set after a CLI upgrade, show a warning in the output. --- core/command/upgrade.php | 26 ++++++++++++++++++++++++++ lib/private/updater.php | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/core/command/upgrade.php b/core/command/upgrade.php index 128d27aa3db..6e5681b26df 100644 --- a/core/command/upgrade.php +++ b/core/command/upgrade.php @@ -27,6 +27,12 @@ class Upgrade extends Command { ; } + /** + * Execute the upgrade command + * + * @param InputInterface $input input interface + * @param OutputInterface $output output interface + */ protected function execute(InputInterface $input, OutputInterface $output) { global $RUNTIME_NOAPPS; @@ -69,6 +75,9 @@ class Upgrade extends Command { }); $updater->upgrade(); + + $this->postUpgradeCheck($input, $output); + return self::ERROR_SUCCESS; } else if(\OC_Config::getValue('maintenance', false)) { //Possible scenario: ownCloud core is updated but an app failed @@ -84,4 +93,21 @@ class Upgrade extends Command { return self::ERROR_UP_TO_DATE; } } + + /** + * Perform a post upgrade check (specific to the command line tool) + * + * @param InputInterface $input input interface + * @param OutputInterface $output output interface + */ + protected function postUpgradeCheck(InputInterface $input, OutputInterface $output) { + $trustedDomains = \OC_Config::getValue('trusted_domains', array()); + if (empty($trustedDomains)) { + $output->write( + 'The setting "trusted_domains" could not be ' . + 'set automatically by the upgrade script, ' . + 'please set it manually' + ); + } + } } diff --git a/lib/private/updater.php b/lib/private/updater.php index fd2d46a1fac..dd8dc84e804 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -108,7 +108,7 @@ class Updater extends BasicEmitter { /* * START CONFIG CHANGES FOR OLDER VERSIONS */ - if (version_compare($currentVersion, '6.90.1', '<')) { + if (!\OC::$CLI && version_compare($currentVersion, '6.90.1', '<')) { // Add the overwriteHost config if it is not existant // This is added to prevent host header poisoning \OC_Config::setValue('trusted_domains', \OC_Config::getValue('trusted_domains', array(\OC_Request::serverHost()))); -- cgit v1.2.3 From c140010e813480c5d67ec7b7751b0b36a8a3af65 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 14 Mar 2014 11:17:20 +0100 Subject: don't change mimetype of whole image object --- lib/private/image.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index df49bf9848d..d108360b2a8 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -202,23 +202,23 @@ class OC_Image { if($mimeType !== null) { switch($mimeType) { case 'image/gif': - $this->imageType = IMAGETYPE_GIF; + $imageType = IMAGETYPE_GIF; break; case 'image/jpeg': case 'image/pjpeg': - $this->imageType = IMAGETYPE_JPEG; + $imageType = IMAGETYPE_JPEG; break; case 'image/png': - $this->imageType = IMAGETYPE_PNG; + $imageType = IMAGETYPE_PNG; break; case 'image/x-xbitmap': - $this->imageType = IMAGETYPE_XBM; + $imageType = IMAGETYPE_XBM; break; case 'image/bmp': - $this->imageType = IMAGETYPE_BMP; + $imageType = IMAGETYPE_BMP; break; default: - $this->imageType = IMAGETYPE_PNG; + $imageType = IMAGETYPE_PNG; break; } } else { -- cgit v1.2.3 From 3c46dcd7ddde403cdc89abdaabd3879fc71d39b9 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 14 Mar 2014 13:03:18 +0100 Subject: Added .ocdata file to check for data folder validity In environments where the data folder is mount from another partition, it is important to check that the data folder we see is actually the real one. If the mount failed for some reasons, this fix will make ownCloud temporarily unavailable instead of causing unpredictable behavior. --- lib/private/setup.php | 4 ++ lib/private/updater.php | 5 ++ lib/private/util.php | 32 +++++++++++-- tests/lib/utilcheckserver.php | 108 ++++++++++++++++++++++++++++++++++++++++++ tests/testcleanuplistener.php | 1 + 5 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 tests/lib/utilcheckserver.php (limited to 'lib/private') diff --git a/lib/private/setup.php b/lib/private/setup.php index 0d5bf424b33..b1061b3a25b 100644 --- a/lib/private/setup.php +++ b/lib/private/setup.php @@ -106,6 +106,10 @@ class OC_Setup { //guess what this does OC_Installer::installShippedApps(); + // create empty file in data dir, so we can later find + // out that this is indeed an ownCloud data directory + file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.ocdata', ''); + //create htaccess files for apache hosts if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { self::createHtaccess(); diff --git a/lib/private/updater.php b/lib/private/updater.php index fd2d46a1fac..2ca705193cc 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -105,6 +105,11 @@ class Updater extends BasicEmitter { } $this->emit('\OC\Updater', 'maintenanceStart'); + // create empty file in data dir, so we can later find + // out that this is indeed an ownCloud data directory + // (in case it didn't exist before) + file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', ''); + /* * START CONFIG CHANGES FOR OLDER VERSIONS */ diff --git a/lib/private/util.php b/lib/private/util.php index 920161949ae..75e1711b0de 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -290,13 +290,19 @@ class OC_Util { * @return array arrays with error messages and hints */ public static function checkServer() { + $errors = array(); + $CONFIG_DATADIRECTORY = OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data'); + + if (!\OC::needUpgrade() && OC_Config::getValue('installed', false)) { + // this check needs to be done every time + $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY); + } + // Assume that if checkServer() succeeded before in this session, then all is fine. if(\OC::$session->exists('checkServer_suceeded') && \OC::$session->get('checkServer_suceeded')) { - return array(); + return $errors; } - $errors = array(); - $defaults = new \OC_Defaults(); $webServerRestart = false; @@ -341,7 +347,6 @@ class OC_Util { ); } } - $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); // Create root dir. if(!is_dir($CONFIG_DATADIRECTORY)) { $success=@mkdir($CONFIG_DATADIRECTORY); @@ -540,6 +545,25 @@ class OC_Util { return $errors; } + /** + * Check that the data directory exists and is valid by + * checking the existence of the ".ocdata" file. + * + * @param string $dataDirectory data directory path + * @return bool true if the data directory is valid, false otherwise + */ + public static function checkDataDirectoryValidity($dataDirectory) { + $errors = array(); + if (!file_exists($dataDirectory.'/.ocdata')) { + $errors[] = array( + 'error' => 'Data directory (' . $dataDirectory . ') is invalid', + 'hint' => 'Please check that the data directory contains a file' . + ' ".ocdata" in its root.' + ); + } + return $errors; + } + /** * @return void */ diff --git a/tests/lib/utilcheckserver.php b/tests/lib/utilcheckserver.php new file mode 100644 index 00000000000..155d617c4ad --- /dev/null +++ b/tests/lib/utilcheckserver.php @@ -0,0 +1,108 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Tests for server check functions + */ +class Test_Util_CheckServer extends PHPUnit_Framework_TestCase { + + private $datadir; + + public function setUp() { + $this->datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data'); + + file_put_contents($this->datadir . '/.ocdata', ''); + } + + public function tearDown() { + // clean up + @unlink($this->datadir . '/.ocdata'); + } + + /** + * Test that checkServer() returns no errors in the regular case. + */ + public function testCheckServer() { + $result = \OC_Util::checkServer(); + $this->assertEmpty($result); + } + + /** + * Test that checkServer() does not check the data dir validity + * when the server is not installed yet (else the setup cannot + * be run...) + */ + public function testCheckServerSkipDataDirValidityOnSetup() { + // simulate old version that didn't have it + unlink($this->datadir . '/.ocdata'); + + $session = \OC::$server->getSession(); + $oldInstalled = \OC_Config::getValue('installed', false); + + // simulate that the server isn't setup yet + \OC_Config::setValue('installed', false); + + // even though ".ocdata" is missing, the error isn't + // triggered to allow setup to run + $result = \OC_Util::checkServer(); + $this->assertEmpty($result); + + // restore config + \OC_Config::setValue('installed', $oldInstalled); + } + + /** + * Test that checkServer() does not check the data dir validity + * when an upgrade is required (else the upgrade cannot be + * performed...) + */ + public function testCheckServerSkipDataDirValidityOnUpgrade() { + // simulate old version that didn't have it + unlink($this->datadir . '/.ocdata'); + + $session = \OC::$server->getSession(); + $oldCurrentVersion = $session->get('OC_Version'); + $oldInstallVersion = \OC_Config::getValue('version', '0.0.0'); + + // upgrade condition to simulate needUpgrade() === true + $session->set('OC_Version', array(6, 0, 0, 2)); + \OC_Config::setValue('version', '6.0.0.1'); + + // even though ".ocdata" is missing, the error isn't + // triggered to allow for upgrade + $result = \OC_Util::checkServer(); + $this->assertEmpty($result); + + // restore versions + $session->set('OC_Version', $oldCurrentVersion); + \OC_Config::setValue('version', $oldInstallVersion); + } + + /** + * Test that checkDataDirectoryValidity returns no error + * when ".ocdata" is present. + */ + public function testCheckDataDirValidity() { + $result = \OC_Util::checkDataDirectoryValidity($this->datadir); + $this->assertEmpty($result); + } + + /** + * Test that checkDataDirectoryValidity and checkServer + * both return an error when ".ocdata" is missing. + */ + public function testCheckDataDirValidityWhenFileMissing() { + unlink($this->datadir . '/.ocdata'); + $result = \OC_Util::checkDataDirectoryValidity($this->datadir); + $this->assertEquals(1, count($result)); + + $result = \OC_Util::checkServer(); + $this->assertEquals(1, count($result)); + } + +} diff --git a/tests/testcleanuplistener.php b/tests/testcleanuplistener.php index 299a589ef4e..2083ffce67c 100644 --- a/tests/testcleanuplistener.php +++ b/tests/testcleanuplistener.php @@ -83,6 +83,7 @@ class TestCleanupListener implements PHPUnit_Framework_TestListener { $knownEntries = array( 'owncloud.log' => true, 'owncloud.db' => true, + '.ocdata' => true, '..' => true, '.' => true ); -- cgit v1.2.3 From 9dee3772eb3c46a7a23efc83d77da6c5a3aba030 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 14 Mar 2014 18:12:33 +0100 Subject: remove image/pjpeg from OC_Image::_output --- lib/private/image.php | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index d108360b2a8..4aa14be109c 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -205,7 +205,6 @@ class OC_Image { $imageType = IMAGETYPE_GIF; break; case 'image/jpeg': - case 'image/pjpeg': $imageType = IMAGETYPE_JPEG; break; case 'image/png': -- cgit v1.2.3 From 3527adbbe1ab947ca6e6edbba889539eea444915 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 14 Mar 2014 18:19:16 +0100 Subject: OC_Image::_output() - throw exception instead of falling back to png --- lib/private/image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index 4aa14be109c..1cd7399cce1 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -217,7 +217,7 @@ class OC_Image { $imageType = IMAGETYPE_BMP; break; default: - $imageType = IMAGETYPE_PNG; + throw new Exception('\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format'); break; } } else { -- cgit v1.2.3 From b619ff6076f200e2aee62758e1e3ea95df1c4a63 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 14 Mar 2014 13:58:34 +0100 Subject: Return 503 when a config/data dir error exists --- lib/base.php | 1 + lib/private/response.php | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'lib/private') diff --git a/lib/base.php b/lib/base.php index 86ee5349828..5f15189b118 100644 --- a/lib/base.php +++ b/lib/base.php @@ -536,6 +536,7 @@ class OC { echo $error['hint'] . "\n\n"; } } else { + OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE); OC_Template::printGuestPage('', 'error', array('errors' => $errors)); } exit; diff --git a/lib/private/response.php b/lib/private/response.php index 71c538fb311..983c682bf3f 100644 --- a/lib/private/response.php +++ b/lib/private/response.php @@ -12,6 +12,7 @@ class OC_Response { const STATUS_TEMPORARY_REDIRECT = 307; const STATUS_NOT_FOUND = 404; const STATUS_INTERNAL_SERVER_ERROR = 500; + const STATUS_SERVICE_UNAVAILABLE = 503; /** * @brief Enable response caching by sending correct HTTP headers @@ -74,6 +75,9 @@ class OC_Response { case self::STATUS_INTERNAL_SERVER_ERROR; $status = $status . ' Internal Server Error'; break; + case self::STATUS_SERVICE_UNAVAILABLE; + $status = $status . ' Service Unavailable'; + break; } header($protocol.' '.$status); } -- cgit v1.2.3 From 79ba930ef90d3e54c02f62c43f61c190e11fb4ec Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 17 Mar 2014 08:17:56 +0100 Subject: fixing PHPDoc --- lib/private/image.php | 107 +++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 49 deletions(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index 1cd7399cce1..dd041442ed6 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -35,7 +35,7 @@ class OC_Image { /** * @brief Get mime type for an image file. * @param string|null $filepath The path to a local image file. - * @returns string The mime type if the it could be determined, otherwise an empty string. + * @return string The mime type if the it could be determined, otherwise an empty string. */ static public function getMimeTypeForFile($filePath) { // exif_imagetype throws "read error!" if file is less than 12 byte @@ -48,10 +48,11 @@ class OC_Image { } /** - * @brief Constructor. - * @param string|resource $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function. - * @returns bool False on error - */ + * @brief Constructor. + * @param resource|string $imageref The path to a local file, a base64 encoded string or a resource created by + * an imagecreate* function. + * @return \OC_Image False on error + */ public function __construct($imageRef = null) { //OC_Log::write('core',__METHOD__.'(): start', OC_Log::DEBUG); if(!extension_loaded('gd') || !function_exists('gd_info')) { @@ -70,7 +71,7 @@ class OC_Image { /** * @brief Determine whether the object contains an image resource. - * @returns bool + * @return bool */ public function valid() { // apparently you can't name a method 'empty'... return is_resource($this->resource); @@ -78,7 +79,7 @@ class OC_Image { /** * @brief Returns the MIME type of the image or an empty string if no image is loaded. - * @returns int + * @return int */ public function mimeType() { return $this->valid() ? $this->mimeType : ''; @@ -86,7 +87,7 @@ class OC_Image { /** * @brief Returns the width of the image or -1 if no image is loaded. - * @returns int + * @return int */ public function width() { return $this->valid() ? imagesx($this->resource) : -1; @@ -94,7 +95,7 @@ class OC_Image { /** * @brief Returns the height of the image or -1 if no image is loaded. - * @returns int + * @return int */ public function height() { return $this->valid() ? imagesy($this->resource) : -1; @@ -102,7 +103,7 @@ class OC_Image { /** * @brief Returns the width when the image orientation is top-left. - * @returns int + * @return int */ public function widthTopLeft() { $o = $this->getOrientation(); @@ -125,7 +126,7 @@ class OC_Image { /** * @brief Returns the height when the image orientation is top-left. - * @returns int + * @return int */ public function heightTopLeft() { $o = $this->getOrientation(); @@ -147,9 +148,10 @@ class OC_Image { } /** - * @brief Outputs the image. - * @returns bool - */ + * @brief Outputs the image. + * @param string $mimeType + * @return bool + */ public function show($mimeType=null) { if($mimeType === null) { $mimeType = $this->mimeType(); @@ -159,10 +161,11 @@ class OC_Image { } /** - * @brief Saves the image. - * @returns bool - * @param string $filePath - */ + * @brief Saves the image. + * @param string $filePath + * @param string $mimeType + * @return bool + */ public function save($filePath=null, $mimeType=null) { if($mimeType === null) { @@ -178,8 +181,12 @@ class OC_Image { } /** - * @brief Outputs/saves the image. - */ + * @brief Outputs/saves the image. + * @param string $filePath + * @param string $mimeType + * @return bool + * @throws Exception + */ private function _output($filePath=null, $mimeType=null) { if($filePath) { if (!file_exists(dirname($filePath))) @@ -198,7 +205,7 @@ class OC_Image { return false; } - $imageType = null; + $imageType = $this->imageType; if($mimeType !== null) { switch($mimeType) { case 'image/gif': @@ -218,10 +225,7 @@ class OC_Image { break; default: throw new Exception('\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format'); - break; } - } else { - $imageType = $this->imageType; } switch($imageType) { @@ -257,14 +261,14 @@ class OC_Image { } /** - * @returns resource Returns the image resource in any. + * @return resource Returns the image resource in any. */ public function resource() { return $this->resource; } /** - * @returns Returns the raw image data. + * @return string Returns the raw image data. */ function data() { ob_start(); @@ -299,7 +303,7 @@ class OC_Image { /** * (I'm open for suggestions on better method name ;) * @brief Get the orientation based on EXIF data. - * @returns The orientation or -1 if no EXIF data is available. + * @return int The orientation or -1 if no EXIF data is available. */ public function getOrientation() { if(!is_callable('exif_read_data')) { @@ -327,7 +331,7 @@ class OC_Image { /** * (I'm open for suggestions on better method name ;) * @brief Fixes orientation based on EXIF data. - * @returns bool. + * @return bool. */ public function fixOrientation() { $o = $this->getOrientation(); @@ -387,10 +391,10 @@ class OC_Image { } /** - * @brief Loads an image from a local file, a base64 encoded string or a resource created by an imagecreate* function. - * @param $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function or a file resource (file handle ). - * @returns An image resource or false on error - */ + * @brief Loads an image from a local file, a base64 encoded string or a resource created by an imagecreate* function. + * @param resource|string $imageref The path to a local file, a base64 encoded string or a resource created by an imagecreate* function or a file resource (file handle ). + * @return resource|false An image resource or false on error + */ public function load($imageRef) { if(is_resource($imageRef)) { if(get_resource_type($imageRef) == 'gd') { @@ -415,7 +419,7 @@ class OC_Image { * @brief Loads an image from an open file handle. * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again. * @param resource $handle - * @returns An image resource or false on error + * @return An image resource or false on error */ public function loadFromFileHandle($handle) { OC_Log::write('core', __METHOD__.'(): Trying', OC_Log::DEBUG); @@ -427,8 +431,8 @@ class OC_Image { /** * @brief Loads an image from a local file. - * @param $imagePath The path to a local file. - * @returns An image resource or false on error + * @param bool|string $imagePath The path to a local file. + * @return bool|resource An image resource or false on error */ public function loadFromFile($imagePath=false) { // exif_imagetype throws "read error!" if file is less than 12 byte @@ -528,8 +532,8 @@ class OC_Image { /** * @brief Loads an image from a string of data. - * @param $str A string of image data as read from a file. - * @returns An image resource or false on error + * @param string $str A string of image data as read from a file. + * @return bool|resource An image resource or false on error */ public function loadFromData($str) { if(is_resource($str)) { @@ -553,8 +557,8 @@ class OC_Image { /** * @brief Loads an image from a base64 encoded string. - * @param $str A string base64 encoded string of image data. - * @returns An image resource or false on error + * @param string $str A string base64 encoded string of image data. + * @return bool|resource An image resource or false on error */ public function loadFromBase64($str) { if(!is_string($str)) { @@ -583,7 +587,7 @@ class OC_Image { * @param string $fileName

* Path to the BMP image. *

- * @return resource an image resource identifier on success, FALSE on errors. + * @return bool|resource an image resource identifier on success, FALSE on errors. */ private function imagecreatefrombmp($fileName) { if (!($fh = fopen($fileName, 'rb'))) { @@ -722,7 +726,7 @@ class OC_Image { /** * @brief Resizes the image preserving ratio. * @param integer $maxSize The maximum size of either the width or height. - * @returns bool + * @return bool */ public function resize($maxSize) { if(!$this->valid()) { @@ -745,6 +749,11 @@ class OC_Image { return true; } + /** + * @param int $width + * @param int $height + * @return bool + */ public function preciseResize($width, $height) { if (!$this->valid()) { OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR); @@ -780,8 +789,8 @@ class OC_Image { /** * @brief Crops the image to the middle square. If the image is already square it just returns. - * @param int maximum size for the result (optional) - * @returns bool for success or failure + * @param int $size maximum size for the result (optional) + * @return bool for success or failure */ public function centerCrop($size=0) { if(!$this->valid()) { @@ -839,11 +848,11 @@ class OC_Image { /** * @brief Crops the image from point $x$y with dimension $wx$h. - * @param $x Horizontal position - * @param $y Vertical position - * @param $w Width - * @param $h Height - * @returns bool for success or failure + * @param int $x Horizontal position + * @param int $y Vertical position + * @param int $w Width + * @param int $h Height + * @return bool for success or failure */ public function crop($x, $y, $w, $h) { if(!$this->valid()) { @@ -871,7 +880,7 @@ class OC_Image { * @brief Resizes the image to fit within a boundry while preserving ratio. * @param integer $maxWidth * @param integer $maxHeight - * @returns bool + * @return bool */ public function fitIn($maxWidth, $maxHeight) { if(!$this->valid()) { -- cgit v1.2.3 From cd038604d396b7611353041cb8ed033f23fe305b Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 17 Mar 2014 08:40:59 +0100 Subject: unit tests for specific image type output added --- lib/private/image.php | 7 ++++++- tests/lib/image.php | 24 ++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/image.php b/lib/private/image.php index dd041442ed6..c987ce92c3c 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -239,7 +239,12 @@ class OC_Image { $retVal = imagepng($this->resource, $filePath); break; case IMAGETYPE_XBM: - $retVal = imagexbm($this->resource, $filePath); + if (function_exists('imagexbm')) { + $retVal = imagexbm($this->resource, $filePath); + } else { + throw new Exception('\OC_Image::_output(): imagexbm() is not supported.'); + } + break; case IMAGETYPE_WBMP: $retVal = imagewbmp($this->resource, $filePath); diff --git a/tests/lib/image.php b/tests/lib/image.php index 4aba1b0bc61..131a9d86f3e 100644 --- a/tests/lib/image.php +++ b/tests/lib/image.php @@ -8,8 +8,8 @@ class Test_Image extends PHPUnit_Framework_TestCase { public static function tearDownAfterClass() { - unlink(OC::$SERVERROOT.'/tests/data/testimage2.png'); - unlink(OC::$SERVERROOT.'/tests/data/testimage2.jpg'); + @unlink(OC::$SERVERROOT.'/tests/data/testimage2.png'); + @unlink(OC::$SERVERROOT.'/tests/data/testimage2.jpg'); } public function testGetMimeTypeForFile() { @@ -236,4 +236,24 @@ class Test_Image extends PHPUnit_Framework_TestCase { $this->assertEquals(200, $img->width()); $this->assertEquals(200, $img->height()); } + + function convertDataProvider() { + return array( + array( 'image/gif'), + array( 'image/jpeg'), + array( 'image/png'), + ); + } + + /** + * @dataProvider convertDataProvider + */ + public function testConvert($mimeType) { + $img = new \OC_Image(OC::$SERVERROOT.'/tests/data/testimage.png'); + $tempFile = tempnam(sys_get_temp_dir(), 'img-test'); + + $img->save($tempFile, $mimeType); + $actualMimeType = \OC_Image::getMimeTypeForFile($tempFile); + $this->assertEquals($mimeType, $actualMimeType); + } } -- cgit v1.2.3 From 145db370d1e83978d0e575a60d7d61fbe1039cc4 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 17 Mar 2014 12:15:12 +0100 Subject: Correctly round bytes when converted from human readable format Instead of leave two decimal places which is confusing, round the byte values correctly to the closest byte. --- lib/private/helper.php | 4 ++-- tests/lib/helper.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/helper.php b/lib/private/helper.php index 0b1a26bbecd..807fa849637 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -308,7 +308,7 @@ class OC_Helper { /** * @brief Make a computer file size - * @param string $str file size in a fancy format + * @param string $str file size in human readable format * @return int a file size in bytes * * Makes 2kB to 2048. @@ -338,7 +338,7 @@ class OC_Helper { $bytes *= $bytes_array[$matches[1]]; } - $bytes = round($bytes, 2); + $bytes = round($bytes); return $bytes; } diff --git a/tests/lib/helper.php b/tests/lib/helper.php index 4311215795c..0943e6bc1b9 100644 --- a/tests/lib/helper.php +++ b/tests/lib/helper.php @@ -23,6 +23,7 @@ class Test_Helper extends PHPUnit_Framework_TestCase { array('0 B', 0), array('1 kB', 1024), array('9.5 MB', 10000000), + array('1.3 GB', 1395864371), array('465.7 GB', 500000000000), array('454.7 TB', 500000000000000), array('444.1 PB', 500000000000000000), @@ -41,8 +42,9 @@ class Test_Helper extends PHPUnit_Framework_TestCase { return array( array(0.0, "0 B"), array(1024.0, "1 kB"), + array(1395864371.0, '1.3 GB'), array(9961472.0, "9.5 MB"), - array(500041567436.8, "465.7 GB"), + array(500041567437.0, "465.7 GB"), ); } -- cgit v1.2.3 From 166dfbf58bd8944688c0941dfbca052a600faef1 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 17 Mar 2014 12:53:26 +0100 Subject: use a non-recursive chmod on the datadir --- lib/private/helper.php | 29 ----------------------------- lib/private/util.php | 2 +- 2 files changed, 1 insertion(+), 30 deletions(-) (limited to 'lib/private') diff --git a/lib/private/helper.php b/lib/private/helper.php index 0b1a26bbecd..f0129f7c84d 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -343,35 +343,6 @@ class OC_Helper { return $bytes; } - /** - * @brief Recursive editing of file permissions - * @param string $path path to file or folder - * @param int $filemode unix style file permissions - * @return bool - */ - static function chmodr($path, $filemode) { - if (!is_dir($path)) - return chmod($path, $filemode); - $dh = opendir($path); - if(is_resource($dh)) { - while (($file = readdir($dh)) !== false) { - if ($file != '.' && $file != '..') { - $fullpath = $path . '/' . $file; - if (is_link($fullpath)) - return false; - elseif (!is_dir($fullpath) && !@chmod($fullpath, $filemode)) - return false; elseif (!self::chmodr($fullpath, $filemode)) - return false; - } - } - closedir($dh); - } - if (@chmod($path, $filemode)) - return true; - else - return false; - } - /** * @brief Recursive copying of folders * @param string $src source folder diff --git a/lib/private/util.php b/lib/private/util.php index 920161949ae..fc78566e456 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -526,7 +526,7 @@ class OC_Util { .' cannot be listed by other users.'; $perms = substr(decoct(@fileperms($dataDirectory)), -3); if (substr($perms, -1) != '0') { - OC_Helper::chmodr($dataDirectory, 0770); + chmod($dataDirectory, 0770); clearstatcache(); $perms = substr(decoct(@fileperms($dataDirectory)), -3); if (substr($perms, 2, 1) != '0') { -- cgit v1.2.3 From 239069c8386a1a4ec29594d392e8359b8914af47 Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Thu, 6 Mar 2014 22:40:25 +0100 Subject: Use $installedVersion instead of $currentVersion --- lib/private/updater.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/updater.php b/lib/private/updater.php index dd8dc84e804..edde42136e9 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -108,7 +108,7 @@ class Updater extends BasicEmitter { /* * START CONFIG CHANGES FOR OLDER VERSIONS */ - if (!\OC::$CLI && version_compare($currentVersion, '6.90.1', '<')) { + if (!\OC::$CLI && version_compare($installedVersion, '6.90.1', '<')) { // Add the overwriteHost config if it is not existant // This is added to prevent host header poisoning \OC_Config::setValue('trusted_domains', \OC_Config::getValue('trusted_domains', array(\OC_Request::serverHost()))); -- cgit v1.2.3 From 3cd09f2b09e69821b8f938b2c54f9c12dbb303f0 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sat, 15 Mar 2014 13:28:20 +0100 Subject: Added PostgreSQL version warning on upgrade --- lib/private/util.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'lib/private') diff --git a/lib/private/util.php b/lib/private/util.php index fc78566e456..54e04ce4d7a 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -485,12 +485,46 @@ class OC_Util { ); } + $errors = array_merge($errors, self::checkDatabaseVersion()); + // Cache the result of this function \OC::$session->set('checkServer_suceeded', count($errors) == 0); return $errors; } + /** + * Check the database version + * @return array errors array + */ + public static function checkDatabaseVersion() { + $errors = array(); + $dbType = \OC_Config::getValue('dbtype', 'sqlite'); + if ($dbType === 'pgsql') { + // check PostgreSQL version + try { + $result = \OC_DB::executeAudited('SHOW SERVER_VERSION'); + $data = $result->fetchRow(); + if (isset($data['server_version'])) { + $version = $data['server_version']; + if (version_compare($version, '9.0.0', '<')) { + $errors[] = array( + 'error' => 'PostgreSQL >= 9 required', + 'hint' => 'Please upgrade your database version' + ); + } + } + } + catch (\Doctrine\DBAL\DBALException $e){ + $errors[] = array( + 'error' => 'PostgreSQL >= 9 required' + ); + } + } + return $errors; + } + + /** * @brief check if there are still some encrypted files stored * @return boolean -- cgit v1.2.3 From 6bbbf8536f6d5d21eed906c42da1e12118e4112e Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 17 Mar 2014 21:57:10 +0100 Subject: introduce reopen() method to be used for unit test execution only - right after a unit test has been executed the session will be reopened --- lib/private/session/memory.php | 7 +++++++ tests/startsessionlistener.php | 11 ++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'lib/private') diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php index 8434b6000e5..1497c0f8928 100644 --- a/lib/private/session/memory.php +++ b/lib/private/session/memory.php @@ -63,6 +63,13 @@ class Memory extends Session { $this->data = array(); } + /** + * Helper function for PHPUnit execution - don't use in non-test code + */ + public function reopen() { + $this->sessionClosed = false; + } + /** * In case the session has already been locked an exception will be thrown * diff --git a/tests/startsessionlistener.php b/tests/startsessionlistener.php index 7559b8cff65..808a2a2226f 100644 --- a/tests/startsessionlistener.php +++ b/tests/startsessionlistener.php @@ -27,11 +27,12 @@ class StartSessionListener implements PHPUnit_Framework_TestListener { } public function endTest(PHPUnit_Framework_Test $test, $time) { - // new session - \OC::$session = new \OC\Session\Memory(''); - - // load the version - OC_Util::getVersion(); + // reopen the session - only allowed for memory session + if (\OC::$session instanceof \OC\Session\Memory) { + /** @var $session \OC\Session\Memory */ + $session = \OC::$session; + $session->reopen(); + } } public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { -- cgit v1.2.3 From effea790c7200d1a9e5605407dcefc8ab71146b8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 18 Mar 2014 11:44:22 +0100 Subject: redefine reopen() in class \OC\Session\Internal to avoid accidental calls in productive code --- lib/private/session/internal.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/private') diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php index 9d3b9cb81ba..42ec9606dc9 100644 --- a/lib/private/session/internal.php +++ b/lib/private/session/internal.php @@ -54,4 +54,7 @@ class Internal extends Memory { parent::close(); } + public function reopen() { + throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.'); + } } -- cgit v1.2.3 From 6b9ae27b90ee5649fcab2417ebaf14e87559756e Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 18 Mar 2014 17:14:38 +0100 Subject: drop file cache migration OC5 -> OC6 --- apps/files/ajax/upgrade.php | 44 ------- apps/files/index.php | 135 ++++++++++----------- apps/files/js/upgrade.js | 28 ----- apps/files/templates/upgrade.php | 4 - core/ajax/update.php | 9 -- core/command/upgrade.php | 9 -- lib/private/files/cache/legacy.php | 139 --------------------- lib/private/files/cache/upgrade.php | 235 ------------------------------------ lib/private/updater.php | 43 ------- 9 files changed, 62 insertions(+), 584 deletions(-) delete mode 100644 apps/files/ajax/upgrade.php delete mode 100644 apps/files/js/upgrade.js delete mode 100644 apps/files/templates/upgrade.php delete mode 100644 lib/private/files/cache/legacy.php delete mode 100644 lib/private/files/cache/upgrade.php (limited to 'lib/private') diff --git a/apps/files/ajax/upgrade.php b/apps/files/ajax/upgrade.php deleted file mode 100644 index 7237b02c0b0..00000000000 --- a/apps/files/ajax/upgrade.php +++ /dev/null @@ -1,44 +0,0 @@ -hasItems()) { - OC_Hook::connect('\OC\Files\Cache\Upgrade', 'migrate_path', $listener, 'upgradePath'); - - OC_DB::beginTransaction(); - $upgrade = new \OC\Files\Cache\Upgrade($legacy); - $count = $legacy->getCount(); - $eventSource->send('total', $count); - $upgrade->upgradePath('/' . $user . '/files'); - OC_DB::commit(); -} -\OC\Files\Cache\Upgrade::upgradeDone($user); -$eventSource->send('done', true); -$eventSource->close(); - -class UpgradeListener { - /** - * @var OC_EventSource $eventSource - */ - private $eventSource; - - private $count = 0; - private $lastSend = 0; - - public function __construct($eventSource) { - $this->eventSource = $eventSource; - } - - public function upgradePath($path) { - $this->count++; - if ($this->count > ($this->lastSend + 5)) { - $this->lastSend = $this->count; - $this->eventSource->send('count', $this->count); - } - } -} diff --git a/apps/files/index.php b/apps/files/index.php index ad7a2e210ed..c66cd40fb56 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -62,22 +62,17 @@ if ($isIE8 && isset($_GET['dir'])){ $ajaxLoad = false; $files = array(); $user = OC_User::getUser(); -if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache - $needUpgrade = true; -} else { - if ($isIE8){ - // after the redirect above, the URL will have a format - // like "files#?dir=path" which means that no path was given - // (dir is not set). In that specific case, we don't return any - // files because the client will take care of switching the dir - // to the one from the hash, then ajax-load the initial file list - $files = array(); - $ajaxLoad = true; - } - else{ - $files = \OCA\Files\Helper::getFiles($dir); - } - $needUpgrade = false; +if ($isIE8){ + // after the redirect above, the URL will have a format + // like "files#?dir=path" which means that no path was given + // (dir is not set). In that specific case, we don't return any + // files because the client will take care of switching the dir + // to the one from the hash, then ajax-load the initial file list + $files = array(); + $ajaxLoad = true; +} +else{ + $files = \OCA\Files\Helper::getFiles($dir); } $config = \OC::$server->getConfig(); @@ -97,62 +92,56 @@ $breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir $permissions = $dirInfo->getPermissions(); -if ($needUpgrade) { - OCP\Util::addscript('files', 'upgrade'); - $tmpl = new OCP\Template('files', 'upgrade', 'user'); - $tmpl->printPage(); -} else { - // information about storage capacities - $storageInfo=OC_Helper::getStorageInfo($dir); - $freeSpace=$storageInfo['free']; - $uploadLimit=OCP\Util::uploadLimit(); - $maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); - $publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'); - // if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) - $encryptionInitStatus = 2; - if (OC_App::isEnabled('files_encryption')) { - $session = new \OCA\Encryption\Session(new \OC\Files\View('/')); - $encryptionInitStatus = $session->getInitialized(); - } - - $trashEnabled = \OCP\App::isEnabled('files_trashbin'); - $trashEmpty = true; - if ($trashEnabled) { - $trashEmpty = \OCA\Files_Trashbin\Trashbin::isEmpty($user); - } +// information about storage capacities +$storageInfo=OC_Helper::getStorageInfo($dir); +$freeSpace=$storageInfo['free']; +$uploadLimit=OCP\Util::uploadLimit(); +$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); +$publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'); +// if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) +$encryptionInitStatus = 2; +if (OC_App::isEnabled('files_encryption')) { + $session = new \OCA\Encryption\Session(new \OC\Files\View('/')); + $encryptionInitStatus = $session->getInitialized(); +} - $isCreatable = \OC\Files\Filesystem::isCreatable($dir . '/'); - $fileHeader = (!isset($files) or count($files) > 0); - $emptyContent = ($isCreatable and !$fileHeader) or $ajaxLoad; - - OCP\Util::addscript('files', 'fileactions'); - OCP\Util::addscript('files', 'files'); - OCP\Util::addscript('files', 'keyboardshortcuts'); - $tmpl = new OCP\Template('files', 'index', 'user'); - $tmpl->assign('fileList', $list->fetchPage()); - $tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage()); - $tmpl->assign('dir', $dir); - $tmpl->assign('isCreatable', $isCreatable); - $tmpl->assign('permissions', $permissions); - $tmpl->assign('files', $files); - $tmpl->assign('trash', $trashEnabled); - $tmpl->assign('trashEmpty', $trashEmpty); - $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit - $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); - $tmpl->assign('freeSpace', $freeSpace); - $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit - $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); - $tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); - $tmpl->assign('isPublic', false); - $tmpl->assign('publicUploadEnabled', $publicUploadEnabled); - $tmpl->assign("encryptedFiles", \OCP\Util::encryptedFiles()); - $tmpl->assign("mailNotificationEnabled", $config->getAppValue('core', 'shareapi_allow_mail_notification', 'yes')); - $tmpl->assign("allowShareWithLink", $config->getAppValue('core', 'shareapi_allow_links', 'yes')); - $tmpl->assign("encryptionInitStatus", $encryptionInitStatus); - $tmpl->assign('disableSharing', false); - $tmpl->assign('ajaxLoad', $ajaxLoad); - $tmpl->assign('emptyContent', $emptyContent); - $tmpl->assign('fileHeader', $fileHeader); - - $tmpl->printPage(); +$trashEnabled = \OCP\App::isEnabled('files_trashbin'); +$trashEmpty = true; +if ($trashEnabled) { + $trashEmpty = \OCA\Files_Trashbin\Trashbin::isEmpty($user); } + +$isCreatable = \OC\Files\Filesystem::isCreatable($dir . '/'); +$fileHeader = (!isset($files) or count($files) > 0); +$emptyContent = ($isCreatable and !$fileHeader) or $ajaxLoad; + +OCP\Util::addscript('files', 'fileactions'); +OCP\Util::addscript('files', 'files'); +OCP\Util::addscript('files', 'keyboardshortcuts'); +$tmpl = new OCP\Template('files', 'index', 'user'); +$tmpl->assign('fileList', $list->fetchPage()); +$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage()); +$tmpl->assign('dir', $dir); +$tmpl->assign('isCreatable', $isCreatable); +$tmpl->assign('permissions', $permissions); +$tmpl->assign('files', $files); +$tmpl->assign('trash', $trashEnabled); +$tmpl->assign('trashEmpty', $trashEmpty); +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit +$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); +$tmpl->assign('freeSpace', $freeSpace); +$tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit +$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); +$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); +$tmpl->assign('isPublic', false); +$tmpl->assign('publicUploadEnabled', $publicUploadEnabled); +$tmpl->assign("encryptedFiles", \OCP\Util::encryptedFiles()); +$tmpl->assign("mailNotificationEnabled", $config->getAppValue('core', 'shareapi_allow_mail_notification', 'yes')); +$tmpl->assign("allowShareWithLink", $config->getAppValue('core', 'shareapi_allow_links', 'yes')); +$tmpl->assign("encryptionInitStatus", $encryptionInitStatus); +$tmpl->assign('disableSharing', false); +$tmpl->assign('ajaxLoad', $ajaxLoad); +$tmpl->assign('emptyContent', $emptyContent); +$tmpl->assign('fileHeader', $fileHeader); + +$tmpl->printPage(); diff --git a/apps/files/js/upgrade.js b/apps/files/js/upgrade.js deleted file mode 100644 index 714adf824a1..00000000000 --- a/apps/files/js/upgrade.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2014 - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -/* global OC */ -$(document).ready(function () { - var eventSource, total, bar = $('#progressbar'); - console.log('start'); - bar.progressbar({value: 0}); - eventSource = new OC.EventSource(OC.filePath('files', 'ajax', 'upgrade.php')); - eventSource.listen('total', function (count) { - total = count; - console.log(count + ' files needed to be migrated'); - }); - eventSource.listen('count', function (count) { - bar.progressbar({value: (count / total) * 100}); - console.log(count); - }); - eventSource.listen('done', function () { - document.location.reload(); - }); -}); diff --git a/apps/files/templates/upgrade.php b/apps/files/templates/upgrade.php deleted file mode 100644 index e03f086e47d..00000000000 --- a/apps/files/templates/upgrade.php +++ /dev/null @@ -1,4 +0,0 @@ -
- t('Upgrading filesystem cache...'));?> -
-
diff --git a/core/ajax/update.php b/core/ajax/update.php index d6af84e95b1..2a0cbb2036d 100644 --- a/core/ajax/update.php +++ b/core/ajax/update.php @@ -16,15 +16,6 @@ if (OC::checkUpgrade(false)) { $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) { $eventSource->send('success', (string)$l->t('Updated database')); }); - $updater->listen('\OC\Updater', 'filecacheStart', function () use ($eventSource, $l) { - $eventSource->send('success', (string)$l->t('Updating filecache, this may take really long...')); - }); - $updater->listen('\OC\Updater', 'filecacheDone', function () use ($eventSource, $l) { - $eventSource->send('success', (string)$l->t('Updated filecache')); - }); - $updater->listen('\OC\Updater', 'filecacheProgress', function ($out) use ($eventSource, $l) { - $eventSource->send('success', (string)$l->t('... %d%% done ...', array('percent' => $out))); - }); $updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource) { $eventSource->send('failure', $message); $eventSource->close(); diff --git a/core/command/upgrade.php b/core/command/upgrade.php index 6e5681b26df..cfccfb5d2f0 100644 --- a/core/command/upgrade.php +++ b/core/command/upgrade.php @@ -59,15 +59,6 @@ class Upgrade extends Command { $updater->listen('\OC\Updater', 'dbUpgrade', function () use($output) { $output->writeln('Updated database'); }); - $updater->listen('\OC\Updater', 'filecacheStart', function () use($output) { - $output->writeln('Updating filecache, this may take really long...'); - }); - $updater->listen('\OC\Updater', 'filecacheDone', function () use($output) { - $output->writeln('Updated filecache'); - }); - $updater->listen('\OC\Updater', 'filecacheProgress', function ($out) use($output) { - $output->writeln('... ' . $out . '% done ...'); - }); $updater->listen('\OC\Updater', 'failure', function ($message) use($output) { $output->writeln($message); diff --git a/lib/private/files/cache/legacy.php b/lib/private/files/cache/legacy.php deleted file mode 100644 index 4d5f58741e9..00000000000 --- a/lib/private/files/cache/legacy.php +++ /dev/null @@ -1,139 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -/** - * Provide read only support for the old filecache - */ -class Legacy { - private $user; - - private $cacheHasItems = null; - - /** - * @param string $user - */ - public function __construct($user) { - $this->user = $user; - } - - /** - * get the numbers of items in the legacy cache - * - * @return int - */ - function getCount() { - $sql = 'SELECT COUNT(`id`) AS `count` FROM `*PREFIX*fscache` WHERE `user` = ?'; - $result = \OC_DB::executeAudited($sql, array($this->user)); - if ($row = $result->fetchRow()) { - return $row['count']; - } else { - return 0; - } - } - - /** - * check if a legacy cache is present and holds items - * - * @return bool - */ - function hasItems() { - if (!is_null($this->cacheHasItems)) { - return $this->cacheHasItems; - } - try { - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `user` = ?',1); - } catch (\Exception $e) { - $this->cacheHasItems = false; - return false; - } - try { - $result = $query->execute(array($this->user)); - } catch (\Exception $e) { - $this->cacheHasItems = false; - return false; - } - - if ($result === false || property_exists($result, 'error_message_prefix')) { - $this->cacheHasItems = false; - return false; - } - - $this->cacheHasItems = (bool)$result->fetchRow(); - return $this->cacheHasItems; - } - - /** - * get an item from the legacy cache - * - * @param string $path - * @return array - */ - function get($path) { - if (is_numeric($path)) { - $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `id` = ?'; - } else { - $sql = 'SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?'; - } - $result = \OC_DB::executeAudited($sql, array($path)); - $data = $result->fetchRow(); - $data['etag'] = $this->getEtag($data['path'], $data['user']); - return $data; - } - - /** - * Get the ETag for the given path - * - * @param type $path - * @return string - */ - function getEtag($path, $user = null) { - static $query = null; - - $pathDetails = explode('/', $path, 4); - if((!$user) && !isset($pathDetails[1])) { - //no user!? Too odd, return empty string. - return ''; - } else if(!$user) { - //guess user from path, if no user passed. - $user = $pathDetails[1]; - } - - if(!isset($pathDetails[3]) || is_null($pathDetails[3])) { - $relativePath = ''; - } else { - $relativePath = $pathDetails[3]; - } - - if(is_null($query)){ - $query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\''); - } - $result = \OC_DB::executeAudited($query,array($user, '/' . $relativePath)); - if ($row = $result->fetchRow()) { - return trim($row['propertyvalue'], '"'); - } else { - return ''; - } - } - - /** - * get all child items of an item from the legacy cache - * - * @param int $id - * @return array - */ - function getChildren($id) { - $result = \OC_DB::executeAudited('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?', array($id)); - $data = $result->fetchAll(); - foreach ($data as $i => $item) { - $data[$i]['etag'] = $this->getEtag($item['path'], $item['user']); - } - return $data; - } -} diff --git a/lib/private/files/cache/upgrade.php b/lib/private/files/cache/upgrade.php deleted file mode 100644 index e3a46896cbf..00000000000 --- a/lib/private/files/cache/upgrade.php +++ /dev/null @@ -1,235 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\Files\Cache; - -class Upgrade { - /** - * @var Legacy $legacy - */ - private $legacy; - - private $numericIds = array(); - - private $mimeTypeIds = array(); - - /** - * @param Legacy $legacy - */ - public function __construct($legacy) { - $this->legacy = $legacy; - } - - /** - * Preform a upgrade a path and it's childs - * - * @param string $path - * @param bool $mode - */ - function upgradePath($path, $mode = Scanner::SCAN_RECURSIVE) { - if (!$this->legacy->hasItems()) { - return; - } - \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path); - if ($row = $this->legacy->get($path)) { - $data = $this->getNewData($row); - if ($data) { - $this->insert($data); - $this->upgradeChilds($data['id'], $mode); - } - } - } - - /** - * upgrade all child elements of an item - * - * @param int $id - * @param bool $mode - */ - function upgradeChilds($id, $mode = Scanner::SCAN_RECURSIVE) { - $children = $this->legacy->getChildren($id); - foreach ($children as $child) { - $childData = $this->getNewData($child); - \OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $child['path']); - if ($childData) { - $this->insert($childData); - if ($mode == Scanner::SCAN_RECURSIVE) { - $this->upgradeChilds($child['id']); - } - } - } - } - - /** - * insert data into the new cache - * - * @param array $data the data for the new cache - */ - function insert($data) { - static $insertQuery = null; - if(is_null($insertQuery)) { - $insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache` - ( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` ) - VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); - } - if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) { - \OC_DB::executeAudited($insertQuery, array($data['id'], $data['storage'], - $data['path'], $data['path_hash'], $data['parent'], $data['name'], - $data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag'])); - } - } - - /** - * check if an item is already in the new cache - * - * @param string $storage - * @param string $pathHash - * @param string $id - * @return bool - */ - function inCache($storage, $pathHash, $id) { - static $query = null; - if(is_null($query)) { - $query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?'); - } - $result = \OC_DB::executeAudited($query, array($storage, $pathHash, $id)); - return (bool)$result->fetchRow(); - } - - /** - * get the new data array from the old one - * - * @param array $data the data from the old cache - * Example data array - * Array - * ( - * [id] => 418 - * [path] => /tina/files/picture.jpg //relative to datadir - * [path_hash] => 66d4547e372888deed80b24fec9b192b - * [parent] => 234 - * [name] => picture.jpg - * [user] => tina - * [size] => 1265283 - * [ctime] => 1363909709 - * [mtime] => 1363909709 - * [mimetype] => image/jpeg - * [mimepart] => image - * [encrypted] => 0 - * [versioned] => 0 - * [writable] => 1 - * ) - * - * @return array - */ - function getNewData($data) { - //Make sure there is a path, otherwise we can do nothing. - if(!isset($data['path'])) { - return false; - } - $newData = $data; - /** - * @var \OC\Files\Storage\Storage $storage - * @var string $internalPath; - */ - list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']); - if ($storage) { - $newData['etag'] = $data['etag']; - $newData['path_hash'] = md5($internalPath); - $newData['path'] = $internalPath; - $newData['storage'] = $this->getNumericId($storage); - $newData['parent'] = ($internalPath === '') ? -1 : $data['parent']; - $newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ; - $newData['storage_object'] = $storage; - $newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage); - $newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage); - return $newData; - } else { - \OC_Log::write('core', 'Unable to migrate data from old cache for '.$data['path'].' because the storage was not found', \OC_Log::ERROR); - return false; - } - } - - /** - * get the numeric storage id - * - * @param \OC\Files\Storage\Storage $storage - * @return int - */ - function getNumericId($storage) { - $storageId = $storage->getId(); - if (!isset($this->numericIds[$storageId])) { - $cache = $storage->getCache(); - $this->numericIds[$storageId] = $cache->getNumericStorageId(); - } - return $this->numericIds[$storageId]; - } - - /** - * get the numeric id for a mimetype - * - * @param string $mimetype - * @param \OC\Files\Storage\Storage $storage - * @return int - */ - function getMimetypeId($mimetype, $storage) { - if (!isset($this->mimeTypeIds[$mimetype])) { - $cache = new Cache($storage); - $this->mimeTypeIds[$mimetype] = $cache->getMimetypeId($mimetype); - } - return $this->mimeTypeIds[$mimetype]; - } - - /** - * check if a cache upgrade is required for $user - * - * @param string $user - * @return bool - */ - static function needUpgrade($user) { - $cacheVersion = (int)\OCP\Config::getUserValue($user, 'files', 'cache_version', 4); - if ($cacheVersion < 5) { - $legacy = new \OC\Files\Cache\Legacy($user); - if ($legacy->hasItems()) { - return true; - } - self::upgradeDone($user); - } - - return false; - } - - /** - * mark the filecache as upgrade - * - * @param string $user - */ - static function upgradeDone($user) { - \OCP\Config::setUserValue($user, 'files', 'cache_version', 5); - } - - /** - * Does a "silent" upgrade, i.e. without an Event-Source as triggered - * on User-Login via Ajax. This method is called within the regular - * ownCloud upgrade. - * - * @param string $user a User ID - */ - public static function doSilentUpgrade($user) { - if(!self::needUpgrade($user)) { - return; - } - $legacy = new \OC\Files\Cache\Legacy($user); - if ($legacy->hasItems()) { - \OC_DB::beginTransaction(); - $upgrade = new \OC\Files\Cache\Upgrade($legacy); - $upgrade->upgradePath('/' . $user . '/files'); - \OC_DB::commit(); - } - \OC\Files\Cache\Upgrade::upgradeDone($user); - } -} diff --git a/lib/private/updater.php b/lib/private/updater.php index dd8dc84e804..1354f3fd2f8 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -16,9 +16,6 @@ use OC\Hooks\BasicEmitter; * - maintenanceStart() * - maintenanceEnd() * - dbUpgrade() - * - filecacheStart() - * - filecacheProgress(int $percentage) - * - filecacheDone() * - failure(string $message) */ class Updater extends BasicEmitter { @@ -122,9 +119,6 @@ class Updater extends BasicEmitter { \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); $this->emit('\OC\Updater', 'dbUpgrade'); - // do a file cache upgrade for users with files - // this can take loooooooooooooooooooooooong - $this->upgradeFileCache(); } catch (\Exception $exception) { $this->emit('\OC\Updater', 'failure', array($exception->getMessage())); } @@ -142,42 +136,5 @@ class Updater extends BasicEmitter { $this->emit('\OC\Updater', 'maintenanceEnd'); } - private function upgradeFileCache() { - try { - $query = \OC_DB::prepare(' - SELECT DISTINCT `user` - FROM `*PREFIX*fscache` - '); - $result = $query->execute(); - } catch (\Exception $e) { - return; - } - $users = $result->fetchAll(); - if (count($users) == 0) { - return; - } - $step = 100 / count($users); - $percentCompleted = 0; - $lastPercentCompletedOutput = 0; - $startInfoShown = false; - foreach ($users as $userRow) { - $user = $userRow['user']; - \OC\Files\Filesystem::initMountPoints($user); - \OC\Files\Cache\Upgrade::doSilentUpgrade($user); - if (!$startInfoShown) { - //We show it only now, because otherwise Info about upgraded apps - //will appear between this and progress info - $this->emit('\OC\Updater', 'filecacheStart'); - $startInfoShown = true; - } - $percentCompleted += $step; - $out = floor($percentCompleted); - if ($out != $lastPercentCompletedOutput) { - $this->emit('\OC\Updater', 'filecacheProgress', array($out)); - $lastPercentCompletedOutput = $out; - } - } - $this->emit('\OC\Updater', 'filecacheDone'); - } } -- cgit v1.2.3 From 4cb53f77b2e09fa16129700b459e8b4edcd3eb64 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 19 Mar 2014 12:20:48 +0100 Subject: Moved external storage mounting code to files_external app Moved the mounting code for external storage from OC\Filesystem::initMountPoint to files_external using the post_initMountPoints hook --- apps/files_external/appinfo/app.php | 3 +- apps/files_external/lib/config.php | 87 +++++++++++++++++++++++++++++++++++-- lib/private/files/filesystem.php | 70 ----------------------------- 3 files changed, 86 insertions(+), 74 deletions(-) (limited to 'lib/private') diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 5b1cd86a170..0e83660f845 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -25,5 +25,6 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == ' } // connecting hooks -OCP\Util::connectHook( 'OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login' ); +OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); +OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login'); diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 0a68de1cdb1..28761b4862e 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -27,10 +27,10 @@ set_include_path( include('Crypt/AES.php'); /** -* Class to configure the config/mount.php and data/$user/mount.php files + * Class to configure mount.json globally and for users */ -// TODO: make this class non-static class OC_Mount_Config { + // TODO: make this class non-static and give it a proper namespace const MOUNT_TYPE_GLOBAL = 'global'; const MOUNT_TYPE_GROUP = 'group'; @@ -166,6 +166,81 @@ class OC_Mount_Config { return($backends); } + /** + * Init mount points hook + * @param array $data + */ + public static function initMountPointsHook($data) { + $user = $data['user']; + $root = $data['user_dir']; + + $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data"); + $mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json"); + + //move config file to it's new position + if (is_file(\OC::$SERVERROOT . '/config/mount.json')) { + rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file); + } + + // Load system mount points + $mountConfig = self::readData(false); + if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) { + foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) { + $options['options'] = self::decryptPasswords($options['options']); + \OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint); + } + } + if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) { + foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) { + if (\OC_Group::inGroup($user, $group)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + $options['options'] = self::decryptPasswords($options['options']); + \OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + if (isset($mountConfig[self::MOUNT_TYPE_USER])) { + foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) { + if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + $options['options'] = self::decryptPasswords($options['options']); + \OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint); + } + } + } + } + + // Load personal mount points + $mountConfig = self::readData(true); + if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) { + foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) { + $options['options'] = self::decryptPasswords($options['options']); + \OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint); + } + } + } + + /** + * fill in the correct values for $user + * + * @param string $user + * @param string $input + * @return string + */ + private static function setUserVars($user, $input) { + return str_replace('$user', $user, $input); + } + + /** * Get details on each of the external storage backends, used for the mount config UI * Some backends are not available as a personal backend, f.e. Local and such that have @@ -288,12 +363,18 @@ class OC_Mount_Config { return $personal; } + /** + * Test connecting using the given backend configuration + * @param string $class backend class name + * @param array $options backend configuration options + * @return bool true if the connection succeeded, false otherwise + */ private static function getBackendStatus($class, $options) { if (self::$skipTest) { return true; } foreach ($options as &$option) { - $option = str_replace('$user', OCP\User::getUser(), $option); + $option = self::setUserVars(OCP\User::getUser(), $option); } if (class_exists($class)) { try { diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 6478854eae8..c31e0c38180 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -320,81 +320,11 @@ class Filesystem { else { self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user); } - $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data"); - $mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json"); - - //move config file to it's new position - if (is_file(\OC::$SERVERROOT . '/config/mount.json')) { - rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file); - } - // Load system mount points - if (is_file(\OC::$SERVERROOT . '/config/mount.php') or is_file($mount_file)) { - if (is_file($mount_file)) { - $mountConfig = json_decode(file_get_contents($mount_file), true); - } elseif (is_file(\OC::$SERVERROOT . '/config/mount.php')) { - $mountConfig = $parser->parsePHP(file_get_contents(\OC::$SERVERROOT . '/config/mount.php')); - } - if (isset($mountConfig['global'])) { - foreach ($mountConfig['global'] as $mountPoint => $options) { - self::mount($options['class'], $options['options'], $mountPoint); - } - } - if (isset($mountConfig['group'])) { - foreach ($mountConfig['group'] as $group => $mounts) { - if (\OC_Group::inGroup($user, $group)) { - foreach ($mounts as $mountPoint => $options) { - $mountPoint = self::setUserVars($user, $mountPoint); - foreach ($options as &$option) { - $option = self::setUserVars($user, $option); - } - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - } - if (isset($mountConfig['user'])) { - foreach ($mountConfig['user'] as $mountUser => $mounts) { - if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) { - foreach ($mounts as $mountPoint => $options) { - $mountPoint = self::setUserVars($user, $mountPoint); - foreach ($options as &$option) { - $option = self::setUserVars($user, $option); - } - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } - } - } - // Load personal mount points - if (is_file($root . '/mount.php') or is_file($root . '/mount.json')) { - if (is_file($root . '/mount.json')) { - $mountConfig = json_decode(file_get_contents($root . '/mount.json'), true); - } elseif (is_file($root . '/mount.php')) { - $mountConfig = $parser->parsePHP(file_get_contents($root . '/mount.php')); - } - if (isset($mountConfig['user'][$user])) { - foreach ($mountConfig['user'][$user] as $mountPoint => $options) { - self::mount($options['class'], $options['options'], $mountPoint); - } - } - } // Chance to mount for other storages \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root)); } - /** - * fill in the correct values for $user - * - * @param string $user - * @param string $input - * @return string - */ - private static function setUserVars($user, $input) { - return str_replace('$user', $user, $input); - } - /** * get the default filesystem view * -- cgit v1.2.3 From 9abe6b7f87c312154f5c300ebfe3c6c36602ebff Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Wed, 19 Mar 2014 17:45:20 +0100 Subject: Add mimetype for MKV videos This will make oC create previews for MKVs. Test file: http://www.auby.no/files/video_tests/h264_720p_hp_5.1_3mbps_vorbis_styled_and_unstyled_subs_suzumiya.mkv To test this just apply this change and upload the test file, if an preview is generated this change is most likely working as expecting. --- lib/private/mimetypes.list.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/private') diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php index a216414c9dd..91bcf584267 100644 --- a/lib/private/mimetypes.list.php +++ b/lib/private/mimetypes.list.php @@ -77,6 +77,7 @@ return array( 'md' => 'text/markdown', 'mdb' => 'application/msaccess', 'mdwn' => 'text/markdown', + 'mkv' => 'video/x-matroska', 'mobi' => 'application/x-mobipocket-ebook', 'mov' => 'video/quicktime', 'mp3' => 'audio/mpeg', -- cgit v1.2.3 From 66bc0f0848846bce3680b79da4209d42620f1b8d Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 19 Mar 2014 19:07:11 +0100 Subject: Still return quota value when free space is unknown Fixed the quota storage wrapper to correctly return the quota value when the free space is not known (which usually happens when the disk_free_space function is disabled) --- lib/private/files/storage/wrapper/quota.php | 9 ++++++++- tests/lib/files/storage/wrapper/quota.php | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index 32ceba8b196..a878b2c5cf6 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -69,7 +69,14 @@ class Quota extends Wrapper { return \OC\Files\SPACE_NOT_COMPUTED; } else { $free = $this->storage->free_space($path); - return min($free, (max($this->quota - $used, 0))); + $quotaFree = max($this->quota - $used, 0); + // if free space is known + if ($free >= 0) { + $free = min($free, $quotaFree); + } else { + $free = $quotaFree; + } + return $free; } } } diff --git a/tests/lib/files/storage/wrapper/quota.php b/tests/lib/files/storage/wrapper/quota.php index bd2c69a7396..777529fd85e 100644 --- a/tests/lib/files/storage/wrapper/quota.php +++ b/tests/lib/files/storage/wrapper/quota.php @@ -61,6 +61,24 @@ class Quota extends \Test\Files\Storage\Storage { $this->assertEquals(6, $instance->free_space('')); } + public function testFreeSpaceWithUnknownDiskSpace() { + $storage = $this->getMock( + '\OC\Files\Storage\Local', + array('free_space'), + array(array('datadir' => $this->tmpDir)) + ); + $storage->expects($this->any()) + ->method('free_space') + ->will($this->returnValue(-2)); + $storage->getScanner()->scan(''); + + $instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 9)); + $instance->getCache()->put( + '', array('size' => 3, 'unencrypted_size' => 0) + ); + $this->assertEquals(6, $instance->free_space('')); + } + public function testFreeSpaceWithUsedSpaceAndEncryption() { $instance = $this->getLimitedStorage(9); $instance->getCache()->put( -- cgit v1.2.3 From 6de9033d8655f172320fd092916b51b56b0f8080 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 20 Mar 2014 12:31:36 +0100 Subject: Added warning for Mac OS on setup page --- core/setup/controller.php | 21 +++++++++++++++++++++ lib/private/util.php | 11 ++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/core/setup/controller.php b/core/setup/controller.php index 697408cfb57..bb9c9101fe2 100644 --- a/core/setup/controller.php +++ b/core/setup/controller.php @@ -80,6 +80,13 @@ class Controller { return $post; } + /** + * Gathers system information like database type and does + * a few system checks. + * + * @return array of system info, including an "errors" value + * in case of errors/warnings + */ public function getSystemInfo() { $hasSQLite = class_exists('SQLite3'); $hasMySQL = is_callable('mysql_connect'); @@ -122,6 +129,20 @@ class Controller { $htaccessWorking = false; } + if (\OC_Util::runningOnMac()) { + $l10n = \OC_L10N::get('core'); + $themeName = \OC_Util::getTheme(); + $theme = new \OC_Defaults(); + $errors[] = array( + 'error' => $l10n->t( + 'Mac OS X is not supported and %s will not work properly on this platform. ' . + 'Use it at your own risk! ', + $theme->getName() + ), + 'hint' => $l10n->t('For the best results, please consider using a GNU/Linux server instead.') + ); + } + return array( 'hasSQLite' => $hasSQLite, 'hasMySQL' => $hasMySQL, diff --git a/lib/private/util.php b/lib/private/util.php index 70dadb1befd..f72276418ba 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -1085,12 +1085,21 @@ class OC_Util { } /** - * @return bool - well are we running on windows or not + * Checks whether the server is running on Windows + * @return bool true if running on Windows, false otherwise */ public static function runningOnWindows() { return (substr(PHP_OS, 0, 3) === "WIN"); } + /** + * Checks whether the server is running on Mac OS X + * @return bool true if running on Mac OS X, false otherwise + */ + public static function runningOnMac() { + return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN'); + } + /** * Handles the case that there may not be a theme, then check if a "default" * theme exists and take that one -- cgit v1.2.3 From fffe330bbccee617cac6d84d1f4097133de82e44 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 20 Mar 2014 15:32:12 +0100 Subject: Fix parameter order for Storage\Local::hash --- lib/private/files/storage/local.php | 2 +- lib/private/files/storage/mappedlocal.php | 2 +- tests/lib/files/storage/storage.php | 47 +++++++++++++++++++++---------- 3 files changed, 34 insertions(+), 17 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index a62230bdba5..071b12ffbd5 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -256,7 +256,7 @@ if (\OC_Util::runningOnWindows()) { return 0; } - public function hash($path, $type, $raw = false) { + public function hash($type, $path, $raw = false) { return hash_file($type, $this->datadir . $path, $raw); } diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php index 1bab3489a28..cb5ab6902e6 100644 --- a/lib/private/files/storage/mappedlocal.php +++ b/lib/private/files/storage/mappedlocal.php @@ -276,7 +276,7 @@ class MappedLocal extends \OC\Files\Storage\Common{ return 0; } - public function hash($path, $type, $raw=false) { + public function hash($type, $path, $raw=false) { return hash_file($type, $this->buildPath($path), $raw); } diff --git a/tests/lib/files/storage/storage.php b/tests/lib/files/storage/storage.php index f9291758606..f3bfba3feb8 100644 --- a/tests/lib/files/storage/storage.php +++ b/tests/lib/files/storage/storage.php @@ -64,17 +64,17 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { * @dataProvider directoryProvider */ public function testDirectories($directory) { - $this->assertFalse($this->instance->file_exists('/'.$directory)); + $this->assertFalse($this->instance->file_exists('/' . $directory)); - $this->assertTrue($this->instance->mkdir('/'.$directory)); + $this->assertTrue($this->instance->mkdir('/' . $directory)); - $this->assertTrue($this->instance->file_exists('/'.$directory)); - $this->assertTrue($this->instance->is_dir('/'.$directory)); - $this->assertFalse($this->instance->is_file('/'.$directory)); - $this->assertEquals('dir', $this->instance->filetype('/'.$directory)); - $this->assertEquals(0, $this->instance->filesize('/'.$directory)); - $this->assertTrue($this->instance->isReadable('/'.$directory)); - $this->assertTrue($this->instance->isUpdatable('/'.$directory)); + $this->assertTrue($this->instance->file_exists('/' . $directory)); + $this->assertTrue($this->instance->is_dir('/' . $directory)); + $this->assertFalse($this->instance->is_file('/' . $directory)); + $this->assertEquals('dir', $this->instance->filetype('/' . $directory)); + $this->assertEquals(0, $this->instance->filesize('/' . $directory)); + $this->assertTrue($this->instance->isReadable('/' . $directory)); + $this->assertTrue($this->instance->isUpdatable('/' . $directory)); $dh = $this->instance->opendir('/'); $content = array(); @@ -85,13 +85,13 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { } $this->assertEquals(array($directory), $content); - $this->assertFalse($this->instance->mkdir('/'.$directory)); //cant create existing folders - $this->assertTrue($this->instance->rmdir('/'.$directory)); + $this->assertFalse($this->instance->mkdir('/' . $directory)); //cant create existing folders + $this->assertTrue($this->instance->rmdir('/' . $directory)); $this->wait(); - $this->assertFalse($this->instance->file_exists('/'.$directory)); + $this->assertFalse($this->instance->file_exists('/' . $directory)); - $this->assertFalse($this->instance->rmdir('/'.$directory)); //cant remove non existing folders + $this->assertFalse($this->instance->rmdir('/' . $directory)); //cant remove non existing folders $dh = $this->instance->opendir('/'); $content = array(); @@ -103,8 +103,7 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { $this->assertEquals(array(), $content); } - public function directoryProvider() - { + public function directoryProvider() { return array( array('folder'), array(' folder'), @@ -113,6 +112,7 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { array('spéciäl földer'), ); } + /** * test the various uses of file_get_contents and file_put_contents */ @@ -298,4 +298,21 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { $this->assertFalse($this->instance->file_exists('folder/bar')); $this->assertFalse($this->instance->file_exists('folder')); } + + public function hashProvider(){ + return array( + array('Foobar', 'md5'), + array('Foobar', 'sha1'), + array('Foobar', 'sha256'), + ); + } + + /** + * @dataProvider hashProvider + */ + public function testHash($data, $type) { + $this->instance->file_put_contents('hash.txt', $data); + $this->assertEquals(hash($type, $data), $this->instance->hash($type, 'hash.txt')); + $this->assertEquals(hash($type, $data, true), $this->instance->hash($type, 'hash.txt', true)); + } } -- cgit v1.2.3 From 7a8f1389fec7db92e1da4f4d46bf0b2737bd3482 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 21 Mar 2014 13:23:14 +0100 Subject: fix temporary file based common hash --- lib/private/files/storage/common.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 3c078d7b1b4..2b697141515 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -160,8 +160,7 @@ abstract class Common implements \OC\Files\Storage\Storage { public function hash($type, $path, $raw = false) { $tmpFile = $this->getLocalFile($path); - $hash = hash($type, $tmpFile, $raw); - unlink($tmpFile); + $hash = hash_file($type, $tmpFile, $raw); return $hash; } -- cgit v1.2.3 From a25b86a30e34204f9a67e3231b1975f7aaf527af Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 24 Mar 2014 11:54:44 +0100 Subject: Log exception when PostgreSQL version check failed --- lib/private/util.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/util.php b/lib/private/util.php index 54e04ce4d7a..d039d9f6a96 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -516,8 +516,10 @@ class OC_Util { } } catch (\Doctrine\DBAL\DBALException $e){ + \OCP\Util::logException('core', $e); $errors[] = array( - 'error' => 'PostgreSQL >= 9 required' + 'error' => 'Error occurred while checking PostgreSQL version', + 'hint' => 'Please make sure you have PostgreSQL >= 9 or check the logs for more information about the error' ); } } -- cgit v1.2.3 From 10c9b8eb996bcabbe4ef40c51248fd6fca70814a Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 20 Mar 2014 16:15:18 +0100 Subject: Cache folder is now configurable When using an external cache folder, it is automatically mounted in FileSystem::initFileSystem so that any app can use it transparently by creating a view on the "/$user/cache" directory. --- config/config.sample.php | 13 +++++++++++-- lib/private/cache/file.php | 15 ++++++++------- lib/private/files/filesystem.php | 36 ++++++++++++++++++++++++++++++++++++ lib/private/forbiddenexception.php | 16 ++++++++++++++++ 4 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 lib/private/forbiddenexception.php (limited to 'lib/private') diff --git a/config/config.sample.php b/config/config.sample.php index 987a866e49b..f8e216d1e26 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -273,6 +273,15 @@ $CONFIG = array( /* all css and js files will be served by the web server statically in one js file and ons css file*/ 'asset-pipeline.enabled' => false, - /* where mount.json file should be stored, defaults to data/mount.json */ - 'mount_file' => '', +/* where mount.json file should be stored, defaults to data/mount.json */ +'mount_file' => '', + +/* + * Location of the cache folder, defaults to "data/$user/cache" where "$user" is the current user. + * + * When specified, the format will change to "$cache_path/$user" where "$cache_path" is the configured + * cache directory and "$user" is the user. + * + */ +'cache_path' => '' ); diff --git a/lib/private/cache/file.php b/lib/private/cache/file.php index 8a6ef39f61b..be6805a9a57 100644 --- a/lib/private/cache/file.php +++ b/lib/private/cache/file.php @@ -1,6 +1,7 @@ + * Copyright (c) 2014 Vincent Petry * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. @@ -10,22 +11,22 @@ namespace OC\Cache; class File { protected $storage; + + /** + * Returns the cache storage for the logged in user + * @return cache storage + */ protected function getStorage() { if (isset($this->storage)) { return $this->storage; } if(\OC_User::isLoggedIn()) { \OC\Files\Filesystem::initMountPoints(\OC_User::getUser()); - $subdir = 'cache'; - $view = new \OC\Files\View('/' . \OC_User::getUser()); - if(!$view->file_exists($subdir)) { - $view->mkdir($subdir); - } - $this->storage = new \OC\Files\View('/' . \OC_User::getUser().'/'.$subdir); + $this->storage = new \OC\Files\View('/' . \OC_User::getUser() . '/cache'); return $this->storage; }else{ \OC_Log::write('core', 'Can\'t get cache storage, user not logged in', \OC_Log::ERROR); - return false; + throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in'); } } diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index c31e0c38180..56bafc7e974 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -321,10 +321,46 @@ class Filesystem { self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user); } + self::mountCacheDir($user); + // Chance to mount for other storages \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root)); } + /** + * Mounts the cache directory + * @param string $user user name + */ + private static function mountCacheDir($user) { + $cacheBaseDir = \OC_Config::getValue('cache_path', ''); + if ($cacheBaseDir === '') { + // use local cache dir relative to the user's home + $subdir = 'cache'; + $view = new \OC\Files\View('/' . $user); + if(!$view->file_exists($subdir)) { + $view->mkdir($subdir); + } + } else { + $cacheDir = rtrim($cacheBaseDir, '/') . '/' . $user; + if (!file_exists($cacheDir)) { + mkdir($cacheDir, 0770, true); + } + // mount external cache dir to "/$user/cache" mount point + self::mount('\OC\Files\Storage\Local', array('datadir' => $cacheDir), '/' . $user . '/cache'); + } + } + + /** + * fill in the correct values for $user + * + * @param string $user + * @param string $input + * @return string + */ + private static function setUserVars($user, $input) { + return str_replace('$user', $user, $input); + } + /** * get the default filesystem view * diff --git a/lib/private/forbiddenexception.php b/lib/private/forbiddenexception.php new file mode 100644 index 00000000000..14a4cd14984 --- /dev/null +++ b/lib/private/forbiddenexception.php @@ -0,0 +1,16 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +/** + * Exception thrown whenever access to a resource has + * been forbidden or whenever a user isn't authenticated. + */ +class ForbiddenException extends \Exception { +} -- cgit v1.2.3 From fb7f3008d33cb123f8b6931f6edf8697913b355a Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 24 Mar 2014 13:46:31 +0100 Subject: idn have to be converted before being used --- lib/private/mail.php | 17 +++++++++++++++++ tests/lib/mail.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/lib/mail.php (limited to 'lib/private') diff --git a/lib/private/mail.php b/lib/private/mail.php index 9605290fe57..f691fda979d 100644 --- a/lib/private/mail.php +++ b/lib/private/mail.php @@ -73,6 +73,7 @@ class OC_Mail { $mailo->FromName = $fromname;; $mailo->Sender = $fromaddress; try { + $toaddress = self::buildAsciiEmail($toaddress); $mailo->AddAddress($toaddress, $toname); if($ccaddress<>'') $mailo->AddCC($ccaddress, $ccname); @@ -125,6 +126,22 @@ class OC_Mail { * @return bool */ public static function ValidateAddress($emailAddress) { + $emailAddress = self::buildAsciiEmail($emailAddress); return PHPMailer::ValidateAddress($emailAddress); } + + /** + * IDN domains will be properly converted to ascii domains. + * + * @param string $emailAddress + * @return string + */ + public static function buildAsciiEmail($emailAddress) { + + list($name, $domain) = explode('@', $emailAddress, 2); + $domain = idn_to_ascii($domain); + + return "$name@$domain"; + } + } diff --git a/tests/lib/mail.php b/tests/lib/mail.php new file mode 100644 index 00000000000..a88a9d797ae --- /dev/null +++ b/tests/lib/mail.php @@ -0,0 +1,30 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Mail extends PHPUnit_Framework_TestCase { + + /** + * @dataProvider buildAsciiEmailProvider + * @param $expected + * @param $address + */ + public function testBuildAsciiEmail($expected, $address) { + $actual = \OC_Mail::buildAsciiEmail($address); + $this->assertEquals($expected, $actual); + } + + function buildAsciiEmailProvider() { + return array( + array('info@example.com', 'info@example.com'), + array('info@xn--cjr6vy5ejyai80u.com', 'info@國際化域名.com'), + array('info@xn--mller-kva.de', 'info@müller.de'), + array('info@xn--mller-kva.xn--mller-kva.de', 'info@müller.müller.de'), + ); + } + +} -- cgit v1.2.3 From 0d0aac6fffb2da47054ed19eae835aa7d9904692 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 24 Mar 2014 14:55:03 +0100 Subject: Load the routes when matching or generating a route instead of when creating the router --- lib/private/route/router.php | 2 ++ lib/private/server.php | 16 +++++++++++----- lib/public/route/irouter.php | 2 -- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index 60ba5878401..806bbf51abf 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -158,6 +158,7 @@ class Router implements IRouter { * @throws \Exception */ public function match($url) { + $this->loadRoutes(); $matcher = new UrlMatcher($this->root, $this->context); $parameters = $matcher->match($url); if (isset($parameters['action'])) { @@ -196,6 +197,7 @@ class Router implements IRouter { * @return string */ public function generate($name, $parameters = array(), $absolute = false) { + $this->loadRoutes(); return $this->getGenerator()->generate($name, $parameters, $absolute); } diff --git a/lib/private/server.php b/lib/private/server.php index 8c9ea39c562..5c83f3ef495 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -159,7 +159,15 @@ class Server extends SimpleContainer implements IServerContainer { return new \OC\BackgroundJob\JobList($c->getDatabaseConnection(), $config); }); $this->registerService('Router', function ($c){ - $router = new \OC\Route\Router(); + /** + * @var Server $c + */ + $cacheFactory = $c->getMemCacheFactory(); + if ($cacheFactory->isAvailable()) { + $router = new \OC\Route\CachingRouter($cacheFactory->create('route')); + } else { + $router = new \OC\Route\Router(); + } return $router; }); } @@ -327,7 +335,7 @@ class Server extends SimpleContainer implements IServerContainer { /** * Returns an \OCP\CacheFactory instance * - * @return \OCP\CacheFactory + * @return \OCP\ICacheFactory */ function getMemCacheFactory() { return $this->query('MemCacheFactory'); @@ -375,8 +383,6 @@ class Server extends SimpleContainer implements IServerContainer { * @return \OCP\Route\IRouter */ function getRouter(){ - $router = $this->query('Router'); - $router->loadRoutes(); - return $router; + return $this->query('Router'); } } diff --git a/lib/public/route/irouter.php b/lib/public/route/irouter.php index d6b0750ba6f..df397bc8758 100644 --- a/lib/public/route/irouter.php +++ b/lib/public/route/irouter.php @@ -10,8 +10,6 @@ namespace OCP\Route; interface IRouter { - public function __construct(); - /** * Get the files to load the routes from * -- cgit v1.2.3 From 3eb5898f7b8f8b836b15dcb9c9a9213d7edbda96 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 24 Mar 2014 15:35:07 +0100 Subject: use \OC_Mail::validateAddress() to validate the email address - fixes #7862 --- lib/private/mail.php | 2 +- lib/public/util.php | 2 +- settings/ajax/lostpassword.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/mail.php b/lib/private/mail.php index f691fda979d..79f51609631 100644 --- a/lib/private/mail.php +++ b/lib/private/mail.php @@ -125,7 +125,7 @@ class OC_Mail { * @param string $emailAddress a given email address to be validated * @return bool */ - public static function ValidateAddress($emailAddress) { + public static function validateAddress($emailAddress) { $emailAddress = self::buildAsciiEmail($emailAddress); return PHPMailer::ValidateAddress($emailAddress); } diff --git a/lib/public/util.php b/lib/public/util.php index 5cc7f0f4676..f02213f2446 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -266,7 +266,7 @@ class Util { $host_name = \OC_Config::getValue('mail_domain', $host_name); $defaultEmailAddress = $user_part.'@'.$host_name; - if (\OC_Mail::ValidateAddress($defaultEmailAddress)) { + if (\OC_Mail::validateAddress($defaultEmailAddress)) { return $defaultEmailAddress; } diff --git a/settings/ajax/lostpassword.php b/settings/ajax/lostpassword.php index b5f47bbceab..88c2bee6142 100644 --- a/settings/ajax/lostpassword.php +++ b/settings/ajax/lostpassword.php @@ -6,7 +6,7 @@ OCP\JSON::callCheck(); $l=OC_L10N::get('core'); // Get data -if( isset( $_POST['email'] ) && filter_var( $_POST['email'], FILTER_VALIDATE_EMAIL) ) { +if( isset( $_POST['email'] ) && OC_Mail::validateAddress($_POST['email']) ) { $email=trim($_POST['email']); OC_Preferences::setValue(OC_User::getUser(), 'settings', 'email', $email); OC_JSON::success(array("data" => array( "message" => $l->t("Email saved") ))); -- cgit v1.2.3 From f17674fef281da097838c22c71e14698f842a2db Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 24 Mar 2014 15:41:46 +0100 Subject: Only load routes from the apps we need --- lib/private/route/router.php | 50 ++++++++++++++++++++++++++++++++------------ lib/public/route/irouter.php | 2 +- 2 files changed, 38 insertions(+), 14 deletions(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index 806bbf51abf..28c27b601c1 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -47,6 +47,8 @@ class Router implements IRouter { protected $loaded = false; + protected $loadedApps = array(); + public function __construct() { $baseUrl = \OC_Helper::linkTo('', 'index.php'); if (!\OC::$CLI) { @@ -93,27 +95,44 @@ class Router implements IRouter { /** * loads the api routes */ - public function loadRoutes() { + public function loadRoutes($app = null) { if ($this->loaded) { return; } - $this->loaded = true; - foreach ($this->getRoutingFiles() as $app => $file) { + if (is_null($app)) { + $this->loaded = true; + $routingFiles = $this->getRoutingFiles(); + } else { + if (isset($this->loadedApps[$app])) { + return; + } + $this->loadedApps[$app] = true; + $file = \OC_App::getAppPath($app) . '/appinfo/routes.php'; + if (file_exists($file)) { + $routingFiles = array($file); + } else { + $routingFiles = array(); + } + } + foreach ($routingFiles as $app => $file) { $this->useCollection($app); require_once $file; $collection = $this->getCollection($app); $collection->addPrefix('/apps/' . $app); $this->root->addCollection($collection); } - $this->useCollection('root'); - require_once 'settings/routes.php'; - require_once 'core/routes.php'; - - // include ocs routes - require_once 'ocs/routes.php'; - $collection = $this->getCollection('ocs'); - $collection->addPrefix('/ocs'); - $this->root->addCollection($collection); + if (!isset($this->loadedApps['core'])) { + $this->loadedApps['core'] = true; + $this->useCollection('root'); + require_once 'settings/routes.php'; + require_once 'core/routes.php'; + + // include ocs routes + require_once 'ocs/routes.php'; + $collection = $this->getCollection('ocs'); + $collection->addPrefix('/ocs'); + $this->root->addCollection($collection); + } } /** @@ -158,7 +177,12 @@ class Router implements IRouter { * @throws \Exception */ public function match($url) { - $this->loadRoutes(); + if (substr($url, 0, 6) === '/apps/') { + list(, , $app,) = explode('/', $url, 4); + $this->loadRoutes($app); + } else { + $this->loadRoutes(); + } $matcher = new UrlMatcher($this->root, $this->context); $parameters = $matcher->match($url); if (isset($parameters['action'])) { diff --git a/lib/public/route/irouter.php b/lib/public/route/irouter.php index df397bc8758..125cd29e81b 100644 --- a/lib/public/route/irouter.php +++ b/lib/public/route/irouter.php @@ -22,7 +22,7 @@ interface IRouter { /** * loads the api routes */ - public function loadRoutes(); + public function loadRoutes($app = null); /** * Sets the collection to use for adding routes -- cgit v1.2.3 From 0e1cb001b64f45597300282d41965aeff3d11188 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 24 Mar 2014 15:42:21 +0100 Subject: Cache generated urls for routes --- lib/private/route/cachingrouter.php | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 lib/private/route/cachingrouter.php (limited to 'lib/private') diff --git a/lib/private/route/cachingrouter.php b/lib/private/route/cachingrouter.php new file mode 100644 index 00000000000..ad25372391f --- /dev/null +++ b/lib/private/route/cachingrouter.php @@ -0,0 +1,43 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Route; + +class CachingRouter extends Router { + /** + * @var \OCP\ICache + */ + protected $cache; + + /** + * @param \OCP\ICache $cache + */ + public function __construct($cache) { + $this->cache = $cache; + parent::__construct(); + } + + /** + * Generate url based on $name and $parameters + * + * @param string $name Name of the route to use. + * @param array $parameters Parameters for the route + * @param bool $absolute + * @return string + */ + public function generate($name, $parameters = array(), $absolute = false) { + $key = $name . json_encode($parameters) . $absolute; + if ($this->cache->hasKey($key)) { + return $this->cache->get($key); + } else { + $url = parent::generate($name, $parameters, $absolute); + $this->cache->set($key, $url, 3600); + return $url; + } + } +} -- cgit v1.2.3 From 9e89ad07c64cba95093bc40a44daf54621275e15 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 24 Mar 2014 16:20:53 +0100 Subject: Only load core routes when matching a core route --- lib/private/route/router.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index 28c27b601c1..a0e701d391a 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -106,15 +106,15 @@ class Router implements IRouter { if (isset($this->loadedApps[$app])) { return; } - $this->loadedApps[$app] = true; $file = \OC_App::getAppPath($app) . '/appinfo/routes.php'; if (file_exists($file)) { - $routingFiles = array($file); + $routingFiles[$app] = array($file); } else { $routingFiles = array(); } } foreach ($routingFiles as $app => $file) { + $this->loadedApps[$app] = true; $this->useCollection($app); require_once $file; $collection = $this->getCollection($app); @@ -171,7 +171,7 @@ class Router implements IRouter { } /** - * Find the route matching $url. + * Find the route matching $url * * @param string $url The url to find * @throws \Exception @@ -180,6 +180,8 @@ class Router implements IRouter { if (substr($url, 0, 6) === '/apps/') { list(, , $app,) = explode('/', $url, 4); $this->loadRoutes($app); + } else if(substr($url, 0, 6) === '/core/') { + $this->loadRoutes('core'); } else { $this->loadRoutes(); } -- cgit v1.2.3 From c17f415356ef9a8145de6403cb40af203d6c574e Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 25 Mar 2014 13:42:47 +0100 Subject: Only load core routes for ocs and settings --- lib/private/route/router.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index a0e701d391a..8b2c9e72f20 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -178,9 +178,10 @@ class Router implements IRouter { */ public function match($url) { if (substr($url, 0, 6) === '/apps/') { + // empty string / 'apps' / $app / rest of the route list(, , $app,) = explode('/', $url, 4); $this->loadRoutes($app); - } else if(substr($url, 0, 6) === '/core/') { + } else if(substr($url, 0, 6) === '/core/' or substr($url, 0, 5) === '/ocs/' or substr($url, 0, 10) === '/settings/') { $this->loadRoutes('core'); } else { $this->loadRoutes(); -- cgit v1.2.3 From e1d3d0e9486f8816d9e180b5231e66af7211fba6 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 25 Mar 2014 14:04:18 +0100 Subject: fix incorect array --- lib/private/route/router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index 8b2c9e72f20..a9fad7bc292 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -108,7 +108,7 @@ class Router implements IRouter { } $file = \OC_App::getAppPath($app) . '/appinfo/routes.php'; if (file_exists($file)) { - $routingFiles[$app] = array($file); + $routingFiles = array($app => $file); } else { $routingFiles = array(); } -- cgit v1.2.3 From d75c3d5f9ab0f0c7a65a1d497311117ccdc981cd Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 25 Mar 2014 14:28:30 +0100 Subject: Fix routes getting lost when loading app routes twice --- lib/private/route/router.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index a9fad7bc292..bad74c925fa 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -114,12 +114,14 @@ class Router implements IRouter { } } foreach ($routingFiles as $app => $file) { - $this->loadedApps[$app] = true; - $this->useCollection($app); - require_once $file; - $collection = $this->getCollection($app); - $collection->addPrefix('/apps/' . $app); - $this->root->addCollection($collection); + if (!$this->loadedApps[$app]) { + $this->loadedApps[$app] = true; + $this->useCollection($app); + require_once $file; + $collection = $this->getCollection($app); + $collection->addPrefix('/apps/' . $app); + $this->root->addCollection($collection); + } } if (!isset($this->loadedApps['core'])) { $this->loadedApps['core'] = true; @@ -181,7 +183,7 @@ class Router implements IRouter { // empty string / 'apps' / $app / rest of the route list(, , $app,) = explode('/', $url, 4); $this->loadRoutes($app); - } else if(substr($url, 0, 6) === '/core/' or substr($url, 0, 5) === '/ocs/' or substr($url, 0, 10) === '/settings/') { + } else if (substr($url, 0, 6) === '/core/' or substr($url, 0, 5) === '/ocs/' or substr($url, 0, 10) === '/settings/') { $this->loadRoutes('core'); } else { $this->loadRoutes(); -- cgit v1.2.3 From 8b6d1d3bf2b31c13417bbac0ede6bc319877bf61 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 18 Feb 2014 12:37:32 +0100 Subject: added private share api --- lib/private/share/share.php | 1886 +++++++++++++++++++++++++++++++++++++++++++ lib/public/share.php | 1705 ++------------------------------------ 2 files changed, 1944 insertions(+), 1647 deletions(-) create mode 100644 lib/private/share/share.php (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php new file mode 100644 index 00000000000..b44d362672b --- /dev/null +++ b/lib/private/share/share.php @@ -0,0 +1,1886 @@ + + * 2014 Bjoern Schiessle + * + * 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; + +/** + * 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 Share { + + const SHARE_TYPE_USER = 0; + const SHARE_TYPE_GROUP = 1; + const SHARE_TYPE_LINK = 3; + const SHARE_TYPE_EMAIL = 4; + const SHARE_TYPE_CONTACT = 5; + const SHARE_TYPE_REMOTE = 6; + + /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask + * Construct permissions for share() and setPermissions with Or (|) e.g. + * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE + * + * Check if permission is granted with And (&) e.g. Check if delete is + * granted: if ($permissions & PERMISSION_DELETE) + * + * Remove permissions with And (&) and Not (~) e.g. Remove the update + * permission: $permissions &= ~PERMISSION_UPDATE + * + * Apps are required to handle permissions on their own, this class only + * stores and manages the permissions of shares + * @see lib/public/constants.php + */ + + const FORMAT_NONE = -1; + const FORMAT_STATUSES = -2; + const FORMAT_SOURCES = -3; + + const TOKEN_LENGTH = 32; // see db_structure.xml + + private static $shareTypeUserAndGroups = -1; + private static $shareTypeGroupUserUnique = 2; + private static $backends = array(); + private static $backendTypes = array(); + private static $isResharingAllowed; + + /** + * Register a sharing backend class that implements OCP\Share_Backend for an item type + * @param string Item type + * @param string Backend class + * @param string (optional) Depends on item type + * @param array (optional) List of supported file extensions if this item type depends on files + * @return Returns true if backend is registered or false if error + */ + public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) { + if (self::isEnabled()) { + if (!isset(self::$backendTypes[$itemType])) { + self::$backendTypes[$itemType] = array( + 'class' => $class, + 'collectionOf' => $collectionOf, + 'supportedFileExtensions' => $supportedFileExtensions + ); + if(count(self::$backendTypes) === 1) { + \OC_Util::addScript('core', 'share'); + \OC_Util::addStyle('core', 'share'); + } + return true; + } + \OC_Log::write('OCP\Share', + 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class'] + .' is already registered for '.$itemType, + \OC_Log::WARN); + } + return false; + } + + /** + * Check if the Share API is enabled + * @return Returns true if enabled or false + * + * The Share API is enabled by default if not configured + */ + public static function isEnabled() { + if (\OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes') == 'yes') { + return true; + } + return false; + } + + /** + * Prepare a path to be passed to DB as file_target + * @param string $path path + * @return string Prepared path + */ + public static function prepFileTarget( $path ) { + + // Paths in DB are stored with leading slashes, so add one if necessary + if ( substr( $path, 0, 1 ) !== '/' ) { + + $path = '/' . $path; + + } + + return $path; + + } + + /** + * 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 static function getUsersSharingFile($path, $user, $includeOwner = false) { + + $shares = array(); + $publicShare = false; + $source = -1; + $cache = false; + + $view = new \OC\Files\View('/' . $user . '/files'); + if ($view->file_exists($path)) { + $meta = $view->getFileInfo($path); + } else { + // if the file doesn't exists yet we start with the parent folder + $meta = $view->getFileInfo(dirname($path)); + } + + if($meta !== false) { + $source = $meta['fileid']; + $cache = new \OC\Files\Cache\Cache($meta['storage']); + } + + while ($source !== -1) { + + // Fetch all shares with another user + $query = \OC_DB::prepare( + 'SELECT `share_with` + FROM + `*PREFIX*share` + WHERE + `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')' + ); + + $result = $query->execute(array($source, self::SHARE_TYPE_USER)); + + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + } else { + while ($row = $result->fetchRow()) { + $shares[] = $row['share_with']; + } + } + // We also need to take group shares into account + + $query = \OC_DB::prepare( + 'SELECT `share_with` + FROM + `*PREFIX*share` + WHERE + `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')' + ); + + $result = $query->execute(array($source, self::SHARE_TYPE_GROUP)); + + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + } else { + while ($row = $result->fetchRow()) { + $usersInGroup = \OC_Group::usersInGroup($row['share_with']); + $shares = array_merge($shares, $usersInGroup); + } + } + + //check for public link shares + if (!$publicShare) { + $query = \OC_DB::prepare( + 'SELECT `share_with` + FROM + `*PREFIX*share` + WHERE + `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')' + ); + + $result = $query->execute(array($source, self::SHARE_TYPE_LINK)); + + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + } else { + if ($result->fetchRow()) { + $publicShare = true; + } + } + } + + // let's get the parent for the next round + $meta = $cache->get((int)$source); + if($meta !== false) { + $source = (int)$meta['parent']; + } else { + $source = -1; + } + } + // Include owner in list of users, if requested + if ($includeOwner) { + $shares[] = $user; + } + + return array("users" => array_unique($shares), "public" => $publicShare); + } + + /** + * 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 + * @param mixed Parameters (optional) + * @param int Number of items to return (optional) Returns all by default + * @param bool include collections (optional) + * @return Return depends on format + */ + public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE, + $parameters = null, $limit = -1, $includeCollections = false) { + return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, + $parameters, $limit, $includeCollections); + } + + /** + * Get the item of item type shared with the current user + * @param string $itemType + * @param string $itemTarget + * @param int $format (optional) Format type must be defined by the backend + * @param mixed Parameters (optional) + * @param bool include collections (optional) + * @return Return depends on format + */ + public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE, + $parameters = null, $includeCollections = false) { + return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, + $parameters, 1, $includeCollections); + } + + /** + * Get the item of item type shared with a given user by source + * @param string $itemType + * @param string $itemSource + * @param string $user User user to whom the item was shared + * @return array Return list of items with file_target, permissions and expiration + */ + public static function getItemSharedWithUser($itemType, $itemSource, $user) { + + $shares = array(); + + // first check if there is a db entry for the specific user + $query = \OC_DB::prepare( + 'SELECT `file_target`, `permissions`, `expiration` + FROM + `*PREFIX*share` + WHERE + `item_source` = ? AND `item_type` = ? AND `share_with` = ?' + ); + + $result = \OC_DB::executeAudited($query, array($itemSource, $itemType, $user)); + + while ($row = $result->fetchRow()) { + $shares[] = $row; + } + + //if didn't found a result than let's look for a group share. + if(empty($shares)) { + $groups = \OC_Group::getUserGroups($user); + + $query = \OC_DB::prepare( + 'SELECT `file_target`, `permissions`, `expiration` + FROM + `*PREFIX*share` + WHERE + `item_source` = ? AND `item_type` = ? AND `share_with` in (?)' + ); + + $result = \OC_DB::executeAudited($query, array($itemSource, $itemType, implode(',', $groups))); + + while ($row = $result->fetchRow()) { + $shares[] = $row; + } + } + + return $shares; + + } + + /** + * Get the item of item type shared with the current user by source + * @param string Item type + * @param string Item source + * @param int Format (optional) Format type must be defined by the backend + * @param mixed Parameters + * @param bool include collections + * @return Return depends on format + */ + public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, + $parameters = null, $includeCollections = false) { + return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, + $parameters, 1, $includeCollections, true); + } + + /** + * Get the item of item type shared by a link + * @param string Item type + * @param string Item source + * @param string Owner of link + * @return Item + */ + public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) { + return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, + null, 1); + } + + /** + * Based on the given token the share information will be returned - password protected shares will be verified + * @param string $token + * @return array | bool false will be returned in case the token is unknown or unauthorized + */ + public static function getShareByToken($token, $checkPasswordProtection = true) { + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1); + $result = $query->execute(array($token)); + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', token=' . $token, \OC_Log::ERROR); + } + $row = $result->fetchRow(); + if ($row === false) { + return false; + } + if (is_array($row) and self::expireItem($row)) { + return false; + } + + // password protected shares need to be authenticated + if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) { + return false; + } + + return $row; + } + + /** + * resolves reshares down to the last real share + * @param $linkItem + * @return $fileOwner + */ + public static function resolveReShare($linkItem) + { + if (isset($linkItem['parent'])) { + $parent = $linkItem['parent']; + while (isset($parent)) { + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1); + $item = $query->execute(array($parent))->fetchRow(); + if (isset($item['parent'])) { + $parent = $item['parent']; + } else { + return $item; + } + } + } + return $linkItem; + } + + + /** + * Get the shared items of item type owned by the current user + * @param string Item type + * @param int Format (optional) Format type must be defined by the backend + * @param mixed Parameters + * @param int Number of items to return (optional) Returns all by default + * @param bool include collections + * @return Return depends on format + */ + public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null, + $limit = -1, $includeCollections = false) { + return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format, + $parameters, $limit, $includeCollections); + } + + /** + * Get the shared item of item type owned by the current user + * @param string Item type + * @param string Item source + * @param int Format (optional) Format type must be defined by the backend + * @param mixed Parameters + * @param bool include collections + * @return Return depends on format + */ + public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, + $parameters = null, $includeCollections = false) { + return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format, + $parameters, -1, $includeCollections); + } + + /** + * Get all users an item is shared with + * @param string Item type + * @param string Item source + * @param string Owner + * @param bool Include collections + * @praram bool check expire date + * @return Return array of users + */ + public static function getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections = false, $checkExpireDate = true) { + + $users = array(); + $items = self::getItems($itemType, $itemSource, null, null, $uidOwner, self::FORMAT_NONE, null, -1, $includeCollections, false, $checkExpireDate); + if ($items) { + foreach ($items as $item) { + if ((int)$item['share_type'] === self::SHARE_TYPE_USER) { + $users[] = $item['share_with']; + } else if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) { + $users = array_merge($users, \OC_Group::usersInGroup($item['share_with'])); + } + } + } + return $users; + } + + /** + * Share an item with a user, group, or via private link + * @param string $itemType + * @param string $itemSource + * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string $shareWith User or group the item is being shared with + * @param int $permissions CRUDS + * @param null $itemSourceName + * @throws \Exception + * @internal param \OCP\Item $string type + * @internal param \OCP\Item $string source + * @internal param \OCP\SHARE_TYPE_USER $int , SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @internal param \OCP\User $string or group the item is being shared with + * @internal param \OCP\CRUDS $int permissions + * @return bool|string Returns true on success or false on failure, Returns token on success for links + */ + public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null) { + $uidOwner = \OC_User::getUser(); + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); + + if (is_null($itemSourceName)) { + $itemSourceName = $itemSource; + } + + // Verify share type and sharing conditions are met + if ($shareType === self::SHARE_TYPE_USER) { + if ($shareWith == $uidOwner) { + $message = 'Sharing '.$itemSourceName.' failed, because the user '.$shareWith.' is the item owner'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + if (!\OC_User::userExists($shareWith)) { + $message = 'Sharing '.$itemSourceName.' failed, because the user '.$shareWith.' does not exist'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + if ($sharingPolicy == 'groups_only') { + $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith)); + if (empty($inGroup)) { + $message = 'Sharing '.$itemSourceName.' failed, because the user ' + .$shareWith.' is not a member of any groups that '.$uidOwner.' is a member of'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } + // Check if the item source is already shared with the user, either from the same owner or a different user + if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, + $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { + // Only allow the same share to occur again if it is the same + // owner and is not a user share, this use case is for increasing + // permissions for a specific user + if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { + $message = 'Sharing '.$itemSourceName.' failed, because this item is already shared with '.$shareWith; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } + } else if ($shareType === self::SHARE_TYPE_GROUP) { + if (!\OC_Group::groupExists($shareWith)) { + $message = 'Sharing '.$itemSourceName.' failed, because the group '.$shareWith.' does not exist'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + if ($sharingPolicy == 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) { + $message = 'Sharing '.$itemSourceName.' failed, because ' + .$uidOwner.' is not a member of the group '.$shareWith; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + // Check if the item source is already shared with the group, either from the same owner or a different user + // The check for each user in the group is done inside the put() function + if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, + null, self::FORMAT_NONE, null, 1, true, true)) { + // Only allow the same share to occur again if it is the same + // owner and is not a group share, this use case is for increasing + // permissions for a specific user + if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { + $message = 'Sharing '.$itemSourceName.' failed, because this item is already shared with '.$shareWith; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } + // Convert share with into an array with the keys group and users + $group = $shareWith; + $shareWith = array(); + $shareWith['group'] = $group; + $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner)); + } else if ($shareType === self::SHARE_TYPE_LINK) { + if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') { + // when updating a link share + if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, + $uidOwner, self::FORMAT_NONE, null, 1)) { + // remember old token + $oldToken = $checkExists['token']; + $oldPermissions = $checkExists['permissions']; + //delete the old share + self::delete($checkExists['id']); + } + + // Generate hash of password - same method as user passwords + if (isset($shareWith)) { + $forcePortable = (CRYPT_BLOWFISH != 1); + $hasher = new \PasswordHash(8, $forcePortable); + $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', '')); + } else { + // reuse the already set password, but only if we change permissions + // otherwise the user disabled the password protection + if ($checkExists && (int)$permissions !== (int)$oldPermissions) { + $shareWith = $checkExists['share_with']; + } + } + + // Generate token + if (isset($oldToken)) { + $token = $oldToken; + } else { + $token = \OC_Util::generateRandomBytes(self::TOKEN_LENGTH); + } + $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, + null, $token, $itemSourceName); + if ($result) { + return $token; + } else { + return false; + } + } + $message = 'Sharing '.$itemSourceName.' failed, because sharing with links is not allowed'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + return false; + } else { + // Future share types need to include their own conditions + $message = 'Share type '.$shareType.' is not valid for '.$itemSource; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + // Put the item into the database + return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName); + } + + /** + * Unshare an item from a user, group, or delete a private link + * @param string Item type + * @param string Item source + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string User or group the item is being shared with + * @return Returns true on success or false on failure + */ + public static function unshare($itemType, $itemSource, $shareType, $shareWith) { + if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), + self::FORMAT_NONE, null, 1)) { + self::unshareItem($item); + return true; + } + return false; + } + + /** + * Unshare an item from all users, groups, and remove all links + * @param string Item type + * @param string Item source + * @return Returns true on success or false on failure + */ + public static function unshareAll($itemType, $itemSource) { + // Get all of the owners of shares of this item. + $query = \OC_DB::prepare( 'SELECT `uid_owner` from `*PREFIX*share` WHERE `item_type`=? AND `item_source`=?' ); + $result = $query->execute(array($itemType, $itemSource)); + $shares = array(); + // Add each owner's shares to the array of all shares for this item. + while ($row = $result->fetchRow()) { + $shares = array_merge($shares, self::getItems($itemType, $itemSource, null, null, $row['uid_owner'])); + } + if (!empty($shares)) { + // Pass all the vars we have for now, they may be useful + $hookParams = array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shares' => $shares, + ); + \OC_Hook::emit('OCP\Share', 'pre_unshareAll', $hookParams); + foreach ($shares as $share) { + self::unshareItem($share); + } + \OC_Hook::emit('OCP\Share', 'post_unshareAll', $hookParams); + return true; + } + return false; + } + + /** + * Unshare an item shared with the current user + * @param string Item type + * @param string Item target + * @return Returns true on success or false on failure + * + * Unsharing from self is not allowed for items inside collections + */ + public static function unshareFromSelf($itemType, $itemTarget) { + if ($item = self::getItemSharedWith($itemType, $itemTarget)) { + if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) { + // Insert an extra row for the group share and set permission + // to 0 to prevent it from showing up for the user + $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 (?,?,?,?,?,?,?,?,?,?,?)'); + $query->execute(array($item['item_type'], $item['item_source'], $item['item_target'], + $item['id'], self::$shareTypeGroupUserUnique, + \OC_User::getUser(), $item['uid_owner'], 0, $item['stime'], $item['file_source'], + $item['file_target'])); + \OC_DB::insertid('*PREFIX*share'); + // Delete all reshares by this user of the group share + self::delete($item['id'], true, \OC_User::getUser()); + } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) { + // Set permission to 0 to prevent it from showing up for the user + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?'); + $query->execute(array(0, $item['id'])); + self::delete($item['id'], true); + } else { + self::delete($item['id']); + } + return true; + } + return false; + } + /** + * sent status if users got informed by mail about share + * @param string $itemType + * @param string $itemSource + * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param bool $status + */ + public static function setSendMailStatus($itemType, $itemSource, $shareType, $status) { + $status = $status ? 1 : 0; + + $query = \OC_DB::prepare( + 'UPDATE `*PREFIX*share` + SET `mail_send` = ? + WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ?'); + + $result = $query->execute(array($status, $itemType, $itemSource, $shareType)); + + if($result === false) { + \OC_Log::write('OCP\Share', 'Couldn\'t set send mail status', \OC_Log::ERROR); + } + } + + /** + * Set the permissions of an item for a specific user or group + * @param string Item type + * @param string Item source + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string User or group the item is being shared with + * @param int CRUDS permissions + * @return Returns true on success or false on failure + */ + public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) { + if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, + \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) { + // Check if this item is a reshare and verify that the permissions + // granted don't exceed the parent shared item + if (isset($item['parent'])) { + $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $result = $query->execute(array($item['parent']))->fetchRow(); + if (~(int)$result['permissions'] & $permissions) { + $message = 'Setting permissions for '.$itemSource.' failed,' + .' because the permissions exceed permissions granted to '.\OC_User::getUser(); + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?'); + $query->execute(array($permissions, $item['id'])); + if ($itemType === 'file' || $itemType === 'folder') { + \OC_Hook::emit('OCP\Share', 'post_update_permissions', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + 'uidOwner' => \OC_User::getUser(), + 'permissions' => $permissions, + 'path' => $item['path'], + )); + } + // Check if permissions were removed + if ($item['permissions'] & ~$permissions) { + // If share permission is removed all reshares must be deleted + if (($item['permissions'] & \OCP\PERMISSION_SHARE) && (~$permissions & \OCP\PERMISSION_SHARE)) { + self::delete($item['id'], true); + } else { + $ids = array(); + $parents = array($item['id']); + while (!empty($parents)) { + $parents = "'".implode("','", $parents)."'"; + $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`' + .' WHERE `parent` IN ('.$parents.')'); + $result = $query->execute(); + // Reset parents array, only go through loop again if + // items are found that need permissions removed + $parents = array(); + while ($item = $result->fetchRow()) { + // Check if permissions need to be removed + if ($item['permissions'] & ~$permissions) { + // Add to list of items that need permissions removed + $ids[] = $item['id']; + $parents[] = $item['id']; + } + } + } + // Remove the permissions for all reshares of this item + if (!empty($ids)) { + $ids = "'".implode("','", $ids)."'"; + // TODO this should be done with Doctrine platform objects + if (\OC_Config::getValue( "dbtype") === 'oci') { + $andOp = 'BITAND(`permissions`, ?)'; + } else { + $andOp = '`permissions` & ?'; + } + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp + .' WHERE `id` IN ('.$ids.')'); + $query->execute(array($permissions)); + } + } + } + return true; + } + $message = 'Setting permissions for '.$itemSource.' failed, because the item was not found'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + + /** + * Set expiration date for a share + * @param string $itemType + * @param string $itemSource + * @param string $date expiration date + * @return \OCP\Share_Backend + */ + public static function setExpirationDate($itemType, $itemSource, $date) { + if ($items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), + self::FORMAT_NONE, null, -1, false)) { + if (!empty($items)) { + if ($date == '') { + $date = null; + } else { + $date = new \DateTime($date); + } + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `id` = ?'); + $query->bindValue(1, $date, 'datetime'); + foreach ($items as $item) { + $query->bindValue(2, (int) $item['id']); + $query->execute(); + } + return true; + } + } + return false; + } + + /** + * Checks whether a share has expired, calls unshareItem() if yes. + * @param array $item Share data (usually database row) + * @return bool True if item was expired, false otherwise. + */ + protected static function expireItem(array $item) { + if (!empty($item['expiration'])) { + $now = new \DateTime(); + $expires = new \DateTime($item['expiration']); + if ($now > $expires) { + self::unshareItem($item); + return true; + } + } + return false; + } + + /** + * Unshares a share given a share data array + * @param array $item Share data (usually database row) + * @return null + */ + protected static function unshareItem(array $item) { + // Pass all the vars we have for now, they may be useful + $hookParams = array( + 'itemType' => $item['item_type'], + 'itemSource' => $item['item_source'], + 'shareType' => $item['share_type'], + 'shareWith' => $item['share_with'], + 'itemParent' => $item['parent'], + 'uidOwner' => $item['uid_owner'], + ); + + \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams + array( + 'fileSource' => $item['file_source'], + )); + self::delete($item['id']); + \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams); + } + + /** + * Get the backend class for the specified item type + * @param string $itemType + * @return \OCP\Share_Backend + */ + public static function getBackend($itemType) { + if (isset(self::$backends[$itemType])) { + return self::$backends[$itemType]; + } else if (isset(self::$backendTypes[$itemType]['class'])) { + $class = self::$backendTypes[$itemType]['class']; + if (class_exists($class)) { + self::$backends[$itemType] = new $class; + if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) { + $message = 'Sharing backend '.$class.' must implement the interface OCP\Share_Backend'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + return self::$backends[$itemType]; + } else { + $message = 'Sharing backend '.$class.' not found'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } + $message = 'Sharing backend for '.$itemType.' not found'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + + /** + * Check if resharing is allowed + * @return Returns true if allowed or false + * + * Resharing is allowed by default if not configured + */ + private static function isResharingAllowed() { + if (!isset(self::$isResharingAllowed)) { + if (\OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') { + self::$isResharingAllowed = true; + } else { + self::$isResharingAllowed = false; + } + } + return self::$isResharingAllowed; + } + + /** + * Get a list of collection item types for the specified item type + * @param string Item type + * @return array + */ + private static function getCollectionItemTypes($itemType) { + $collectionTypes = array($itemType); + foreach (self::$backendTypes as $type => $backend) { + if (in_array($backend['collectionOf'], $collectionTypes)) { + $collectionTypes[] = $type; + } + } + // TODO Add option for collections to be collection of themselves, only 'folder' does it now... + if (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder') { + unset($collectionTypes[0]); + } + // Return array if collections were found or the item type is a + // collection itself - collections can be inside collections + if (count($collectionTypes) > 0) { + return $collectionTypes; + } + return false; + } + + /** + * Get shared items from the database + * @param string Item type + * @param string Item source or target (optional) + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique + * @param string User or group the item is being shared with + * @param string User that is the owner of shared items (optional) + * @param int Format to convert items to with formatItems() + * @param mixed Parameters to pass to formatItems() + * @param int Number of items to return, -1 to return all matches (optional) + * @param bool Include collection item types (optional) + * @param bool TODO (optional) + * @prams bool check expire date + * @return mixed + * + * See public functions getItem(s)... for parameter usage + * + */ + private static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, + $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, + $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) { + if (!self::isEnabled()) { + if ($limit == 1 || (isset($uidOwner) && isset($item))) { + return false; + } else { + return array(); + } + } + $backend = self::getBackend($itemType); + $collectionTypes = false; + // Get filesystem root to add it to the file target and remove from the + // file source, match file_source with the file cache + if ($itemType == 'file' || $itemType == 'folder') { + if(!is_null($uidOwner)) { + $root = \OC\Files\Filesystem::getRoot(); + } else { + $root = ''; + } + $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid`'; + if (!isset($item)) { + $where .= ' WHERE `file_target` IS NOT NULL'; + } + $fileDependent = true; + $queryArgs = array(); + } else { + $fileDependent = false; + $root = ''; + if ($includeCollections && !isset($item) && ($collectionTypes = self::getCollectionItemTypes($itemType))) { + // If includeCollections is true, find collections of this item type, e.g. a music album contains songs + if (!in_array($itemType, $collectionTypes)) { + $itemTypes = array_merge(array($itemType), $collectionTypes); + } else { + $itemTypes = $collectionTypes; + } + $placeholders = join(',', array_fill(0, count($itemTypes), '?')); + $where = ' WHERE `item_type` IN ('.$placeholders.'))'; + $queryArgs = $itemTypes; + } else { + $where = ' WHERE `item_type` = ?'; + $queryArgs = array($itemType); + } + } + if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') { + $where .= ' AND `share_type` != ?'; + $queryArgs[] = self::SHARE_TYPE_LINK; + } + if (isset($shareType)) { + // Include all user and group items + if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) { + $where .= ' AND `share_type` IN (?,?,?)'; + $queryArgs[] = self::SHARE_TYPE_USER; + $queryArgs[] = self::SHARE_TYPE_GROUP; + $queryArgs[] = self::$shareTypeGroupUserUnique; + $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith)); + $placeholders = join(',', array_fill(0, count($userAndGroups), '?')); + $where .= ' AND `share_with` IN ('.$placeholders.')'; + $queryArgs = array_merge($queryArgs, $userAndGroups); + // Don't include own group shares + $where .= ' AND `uid_owner` != ?'; + $queryArgs[] = $shareWith; + } else { + $where .= ' AND `share_type` = ?'; + $queryArgs[] = $shareType; + if (isset($shareWith)) { + $where .= ' AND `share_with` = ?'; + $queryArgs[] = $shareWith; + } + } + } + if (isset($uidOwner)) { + $where .= ' AND `uid_owner` = ?'; + $queryArgs[] = $uidOwner; + if (!isset($shareType)) { + // Prevent unique user targets for group shares from being selected + $where .= ' AND `share_type` != ?'; + $queryArgs[] = self::$shareTypeGroupUserUnique; + } + if ($itemType == 'file' || $itemType == 'folder') { + $column = 'file_source'; + } else { + $column = 'item_source'; + } + } else { + if ($itemType == 'file' || $itemType == 'folder') { + $column = 'file_target'; + } else { + $column = 'item_target'; + } + } + if (isset($item)) { + if ($includeCollections && $collectionTypes = self::getCollectionItemTypes($itemType)) { + $where .= ' AND ('; + } else { + $where .= ' AND'; + } + // If looking for own shared items, check item_source else check item_target + if (isset($uidOwner) || $itemShareWithBySource) { + // If item type is a file, file source needs to be checked in case the item was converted + if ($itemType == 'file' || $itemType == 'folder') { + $where .= ' `file_source` = ?'; + $column = 'file_source'; + } else { + $where .= ' `item_source` = ?'; + $column = 'item_source'; + } + } else { + if ($itemType == 'file' || $itemType == 'folder') { + $where .= ' `file_target` = ?'; + $item = \OC\Files\Filesystem::normalizePath($item); + } else { + $where .= ' `item_target` = ?'; + } + } + $queryArgs[] = $item; + if ($includeCollections && $collectionTypes) { + $placeholders = join(',', array_fill(0, count($collectionTypes), '?')); + $where .= ' OR `item_type` IN ('.$placeholders.'))'; + $queryArgs = array_merge($queryArgs, $collectionTypes); + } + } + if ($limit != -1 && !$includeCollections) { + if ($shareType == self::$shareTypeUserAndGroups) { + // Make sure the unique user target is returned if it exists, + // unique targets should follow the group share in the database + // If the limit is not 1, the filtering can be done later + $where .= ' ORDER BY `*PREFIX*share`.`id` DESC'; + } + // The limit must be at least 3, because filtering needs to be done + if ($limit < 3) { + $queryLimit = 3; + } else { + $queryLimit = $limit; + } + } else { + $queryLimit = null; + } + // TODO Optimize selects + if ($format == self::FORMAT_STATUSES) { + if ($itemType == 'file' || $itemType == 'folder') { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' + .' `share_type`, `file_source`, `path`, `expiration`, `storage`, `share_with`, `mail_send`, `uid_owner`'; + } else { + $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `expiration`, `mail_send`, `uid_owner`'; + } + } else { + if (isset($uidOwner)) { + if ($itemType == 'file' || $itemType == 'folder') { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' + .' `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`,' + .' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`'; + } else { + $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`,' + .' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; + } + } else { + if ($fileDependent) { + if (($itemType == 'file' || $itemType == 'folder') + && $format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS + || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT + ) { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' + .'`share_type`, `share_with`, `file_source`, `path`, `file_target`, ' + .'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' + .'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; + } else { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, + `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, + `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`'; + } + } else { + $select = '*'; + } + } + } + $root = strlen($root); + $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit); + $result = $query->execute($queryArgs); + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', + \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, + \OC_Log::ERROR); + } + $items = array(); + $targets = array(); + $switchedItems = array(); + $mounts = array(); + while ($row = $result->fetchRow()) { + if (isset($row['id'])) { + $row['id']=(int)$row['id']; + } + if (isset($row['share_type'])) { + $row['share_type']=(int)$row['share_type']; + } + if (isset($row['parent'])) { + $row['parent']=(int)$row['parent']; + } + if (isset($row['file_parent'])) { + $row['file_parent']=(int)$row['file_parent']; + } + if (isset($row['file_source'])) { + $row['file_source']=(int)$row['file_source']; + } + if (isset($row['permissions'])) { + $row['permissions']=(int)$row['permissions']; + } + if (isset($row['storage'])) { + $row['storage']=(int)$row['storage']; + } + if (isset($row['stime'])) { + $row['stime']=(int)$row['stime']; + } + // Filter out duplicate group shares for users with unique targets + if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) { + $row['share_type'] = self::SHARE_TYPE_GROUP; + $row['share_with'] = $items[$row['parent']]['share_with']; + // Remove the parent group share + unset($items[$row['parent']]); + if ($row['permissions'] == 0) { + continue; + } + } else if (!isset($uidOwner)) { + // Check if the same target already exists + if (isset($targets[$row[$column]])) { + // Check if the same owner shared with the user twice + // through a group and user share - this is allowed + $id = $targets[$row[$column]]; + if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) { + // Switch to group share type to ensure resharing conditions aren't bypassed + if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) { + $items[$id]['share_type'] = self::SHARE_TYPE_GROUP; + $items[$id]['share_with'] = $row['share_with']; + } + // Switch ids if sharing permission is granted on only + // one share to ensure correct parent is used if resharing + if (~(int)$items[$id]['permissions'] & \OCP\PERMISSION_SHARE + && (int)$row['permissions'] & \OCP\PERMISSION_SHARE) { + $items[$row['id']] = $items[$id]; + $switchedItems[$id] = $row['id']; + unset($items[$id]); + $id = $row['id']; + } + // Combine the permissions for the item + $items[$id]['permissions'] |= (int)$row['permissions']; + continue; + } + } else { + $targets[$row[$column]] = $row['id']; + } + } + // Remove root from file source paths if retrieving own shared items + if (isset($uidOwner) && isset($row['path'])) { + if (isset($row['parent'])) { + $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?'); + $parentResult = $query->execute(array($row['parent'])); + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', 'Can\'t select parent: ' . + \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, + \OC_Log::ERROR); + } else { + $parentRow = $parentResult->fetchRow(); + $splitPath = explode('/', $row['path']); + $tmpPath = '/Shared' . $parentRow['file_target']; + foreach (array_slice($splitPath, 2) as $pathPart) { + $tmpPath = $tmpPath . '/' . $pathPart; + } + $row['path'] = $tmpPath; + } + } else { + if (!isset($mounts[$row['storage']])) { + $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']); + if (is_array($mountPoints)) { + $mounts[$row['storage']] = current($mountPoints); + } + } + if ($mounts[$row['storage']]) { + $path = $mounts[$row['storage']]->getMountPoint().$row['path']; + $row['path'] = substr($path, $root); + } + } + } + if($checkExpireDate) { + if (self::expireItem($row)) { + continue; + } + } + // Check if resharing is allowed, if not remove share permission + if (isset($row['permissions']) && !self::isResharingAllowed()) { + $row['permissions'] &= ~\OCP\PERMISSION_SHARE; + } + // Add display names to result + if ( isset($row['share_with']) && $row['share_with'] != '') { + $row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']); + } + if ( isset($row['uid_owner']) && $row['uid_owner'] != '') { + $row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']); + } + + $items[$row['id']] = $row; + } + if (!empty($items)) { + $collectionItems = array(); + foreach ($items as &$row) { + // Return only the item instead of a 2-dimensional array + if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) { + if ($format == self::FORMAT_NONE) { + return $row; + } else { + break; + } + } + // Check if this is a collection of the requested item type + if ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) { + if (($collectionBackend = self::getBackend($row['item_type'])) + && $collectionBackend instanceof \OCP\Share_Backend_Collection) { + // Collections can be inside collections, check if the item is a collection + if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) { + $collectionItems[] = $row; + } else { + $collection = array(); + $collection['item_type'] = $row['item_type']; + if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { + $collection['path'] = basename($row['path']); + } + $row['collection'] = $collection; + // Fetch all of the children sources + $children = $collectionBackend->getChildren($row[$column]); + foreach ($children as $child) { + $childItem = $row; + $childItem['item_type'] = $itemType; + if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') { + $childItem['item_source'] = $child['source']; + $childItem['item_target'] = $child['target']; + } + if ($backend instanceof \OCP\Share_Backend_File_Dependent) { + if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { + $childItem['file_source'] = $child['source']; + } else { + $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']); + $childItem['file_source'] = $meta['fileid']; + } + $childItem['file_target'] = + \OC\Files\Filesystem::normalizePath($child['file_path']); + } + if (isset($item)) { + if ($childItem[$column] == $item) { + // Return only the item instead of a 2-dimensional array + if ($limit == 1) { + if ($format == self::FORMAT_NONE) { + return $childItem; + } else { + // Unset the items array and break out of both loops + $items = array(); + $items[] = $childItem; + break 2; + } + } else { + $collectionItems[] = $childItem; + } + } + } else { + $collectionItems[] = $childItem; + } + } + } + } + // Remove collection item + $toRemove = $row['id']; + if (array_key_exists($toRemove, $switchedItems)) { + $toRemove = $switchedItems[$toRemove]; + } + unset($items[$toRemove]); + } + } + if (!empty($collectionItems)) { + $items = array_merge($items, $collectionItems); + } + if (empty($items) && $limit == 1) { + return false; + } + if ($format == self::FORMAT_NONE) { + return $items; + } else if ($format == self::FORMAT_STATUSES) { + $statuses = array(); + foreach ($items as $item) { + if ($item['share_type'] == self::SHARE_TYPE_LINK) { + $statuses[$item[$column]]['link'] = true; + } else if (!isset($statuses[$item[$column]])) { + $statuses[$item[$column]]['link'] = false; + } + if ($itemType == 'file' || $itemType == 'folder') { + $statuses[$item[$column]]['path'] = $item['path']; + } + } + return $statuses; + } else { + return $backend->formatItems($items, $format, $parameters); + } + } else if ($limit == 1 || (isset($uidOwner) && isset($item))) { + return false; + } + return array(); + } + + /** + * Put shared item into the database + * @param string Item type + * @param string Item source + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string User or group the item is being shared with + * @param string User that is the owner of shared item + * @param int CRUDS permissions + * @param bool|array Parent folder target (optional) + * @param string token (optional) + * @param string name of the source item (optional) + * @return bool Returns true on success or false on failure + */ + private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, + $permissions, $parentFolder = null, $token = null, $itemSourceName = null) { + $backend = self::getBackend($itemType); + + // Check if this is a reshare + if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) { + + // Check if attempting to share back to owner + if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) { + $message = 'Sharing '.$itemSourceName.' failed, because the user '.$shareWith.' is the original sharer'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + // Check if share permissions is granted + if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\PERMISSION_SHARE) { + if (~(int)$checkReshare['permissions'] & $permissions) { + $message = 'Sharing '.$itemSourceName + .' failed, because the permissions exceed permissions granted to '.$uidOwner; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } else { + // TODO Don't check if inside folder + $parent = $checkReshare['id']; + $itemSource = $checkReshare['item_source']; + $fileSource = $checkReshare['file_source']; + $suggestedItemTarget = $checkReshare['item_target']; + $suggestedFileTarget = $checkReshare['file_target']; + $filePath = $checkReshare['file_target']; + } + } else { + $message = 'Sharing '.$itemSourceName.' failed, because resharing is not allowed'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } else { + $parent = null; + $suggestedItemTarget = null; + $suggestedFileTarget = null; + if (!$backend->isValidSource($itemSource, $uidOwner)) { + $message = 'Sharing '.$itemSource.' failed, because the sharing backend for ' + .$itemType.' could not find its source'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + $parent = null; + if ($backend instanceof \OCP\Share_Backend_File_Dependent) { + $filePath = $backend->getFilePath($itemSource, $uidOwner); + if ($itemType == 'file' || $itemType == 'folder') { + $fileSource = $itemSource; + } else { + $meta = \OC\Files\Filesystem::getFileInfo($filePath); + $fileSource = $meta['fileid']; + } + if ($fileSource == -1) { + $message = 'Sharing '.$itemSource.' failed, because the file could not be found in the file cache'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + } else { + $filePath = null; + $fileSource = null; + } + } + $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`, `token`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)'); + // Share with a group + 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, + 'itemTarget' => $groupItemTarget, + 'shareType' => $shareType, + 'shareWith' => $shareWith['group'], + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'token' => $token, + 'run' => &$run, + 'error' => &$error + )); + + if ($run === false) { + throw new \Exception($error); + } + + if (isset($fileSource)) { + if ($parentFolder) { + if ($parentFolder === true) { + $groupFileTarget = self::generateTarget('file', $filePath, $shareType, + $shareWith['group'], $uidOwner, $suggestedFileTarget); + // Set group default file target for future use + $parentFolders[0]['folder'] = $groupFileTarget; + } else { + // Get group default file target + $groupFileTarget = $parentFolder[0]['folder'].$itemSource; + $parent = $parentFolder[0]['id']; + } + } else { + $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], + $uidOwner, $suggestedFileTarget); + } + } else { + $groupFileTarget = null; + } + $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, + $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token)); + // Save this id, any extra rows for this group share will need to reference it + $parent = \OC_DB::insertid('*PREFIX*share'); + // Loop through all users of this group in case we need to add an extra row + foreach ($shareWith['users'] as $uid) { + $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, + $uidOwner, $suggestedItemTarget, $parent); + if (isset($fileSource)) { + if ($parentFolder) { + if ($parentFolder === true) { + $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, + $uidOwner, $suggestedFileTarget, $parent); + if ($fileTarget != $groupFileTarget) { + $parentFolders[$uid]['folder'] = $fileTarget; + } + } else if (isset($parentFolder[$uid])) { + $fileTarget = $parentFolder[$uid]['folder'].$itemSource; + $parent = $parentFolder[$uid]['id']; + } + } else { + $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, + $uid, $uidOwner, $suggestedFileTarget, $parent); + } + } else { + $fileTarget = null; + } + // Insert an extra row for the group share if the item or file target is unique for this user + if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, + self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), + $fileSource, $fileTarget, $token)); + $id = \OC_DB::insertid('*PREFIX*share'); + } + } + \OC_Hook::emit('OCP\Share', 'post_shared', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $groupItemTarget, + 'parent' => $parent, + 'shareType' => $shareType, + 'shareWith' => $shareWith['group'], + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'fileTarget' => $groupFileTarget, + 'id' => $parent, + 'token' => $token + )); + + if ($parentFolder === true) { + // Return parent folders to preserve file target paths for potential children + return $parentFolders; + } + } 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, + 'itemTarget' => $itemTarget, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'token' => $token, + 'run' => &$run, + 'error' => &$error + )); + + if ($run === false) { + throw new \Exception($error); + } + + if (isset($fileSource)) { + if ($parentFolder) { + if ($parentFolder === true) { + $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, + $uidOwner, $suggestedFileTarget); + $parentFolders['folder'] = $fileTarget; + } else { + $fileTarget = $parentFolder['folder'].$itemSource; + $parent = $parentFolder['id']; + } + } else { + $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, + $suggestedFileTarget); + } + } else { + $fileTarget = null; + } + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, + $permissions, time(), $fileSource, $fileTarget, $token)); + $id = \OC_DB::insertid('*PREFIX*share'); + \OC_Hook::emit('OCP\Share', 'post_shared', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $itemTarget, + 'parent' => $parent, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'fileTarget' => $fileTarget, + 'id' => $id, + 'token' => $token + )); + if ($parentFolder === true) { + $parentFolders['id'] = $id; + // Return parent folder to preserve file target paths for potential children + return $parentFolders; + } + } + return true; + } + + /** + * Generate a unique target for the item + * @param string Item type + * @param string Item source + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string User or group the item is being shared with + * @param string User that is the owner of shared item + * @param string The suggested target originating from a reshare (optional) + * @param int The id of the parent group share (optional) + * @return string Item target + */ + private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, + $suggestedTarget = null, $groupParent = null) { + $backend = self::getBackend($itemType); + if ($shareType == self::SHARE_TYPE_LINK) { + if (isset($suggestedTarget)) { + return $suggestedTarget; + } + return $backend->generateTarget($itemSource, false); + } else { + if ($itemType == 'file' || $itemType == 'folder') { + $column = 'file_target'; + $columnSource = 'file_source'; + } else { + $column = 'item_target'; + $columnSource = 'item_source'; + } + if ($shareType == self::SHARE_TYPE_USER) { + // Share with is a user, so set share type to user and groups + $shareType = self::$shareTypeUserAndGroups; + $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith)); + } else { + $userAndGroups = false; + } + $exclude = null; + // Backend has 3 opportunities to generate a unique target + for ($i = 0; $i < 2; $i++) { + // Check if suggested target exists first + if ($i == 0 && isset($suggestedTarget)) { + $target = $suggestedTarget; + } else { + if ($shareType == self::SHARE_TYPE_GROUP) { + $target = $backend->generateTarget($itemSource, false, $exclude); + } else { + $target = $backend->generateTarget($itemSource, $shareWith, $exclude); + } + if (is_array($exclude) && in_array($target, $exclude)) { + break; + } + } + // Check if target already exists + $checkTarget = self::getItems($itemType, $target, $shareType, $shareWith); + if (!empty($checkTarget)) { + foreach ($checkTarget as $item) { + // Skip item if it is the group parent row + if (isset($groupParent) && $item['id'] == $groupParent) { + if (count($checkTarget) == 1) { + return $target; + } else { + continue; + } + } + if ($item['uid_owner'] == $uidOwner) { + if ($itemType == 'file' || $itemType == 'folder') { + $meta = \OC\Files\Filesystem::getFileInfo($itemSource); + if ($item['file_source'] == $meta['fileid']) { + return $target; + } + } else if ($item['item_source'] == $itemSource) { + return $target; + } + } + } + if (!isset($exclude)) { + $exclude = array(); + } + // Find similar targets to improve backend's chances to generate a unqiue target + if ($userAndGroups) { + if ($column == 'file_target') { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` IN (\'file\', \'folder\')' + .' AND `share_type` IN (?,?,?)' + .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, + self::$shareTypeGroupUserUnique)); + } else { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` = ? AND `share_type` IN (?,?,?)' + .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, + self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); + } + } else { + if ($column == 'file_target') { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` IN (\'file\', \'folder\')' + .' AND `share_type` = ? AND `share_with` = ?'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith)); + } else { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith)); + } + } + while ($row = $result->fetchRow()) { + $exclude[] = $row[$column]; + } + } else { + return $target; + } + } + } + $message = 'Sharing backend registered for '.$itemType.' did not generate a unique target for '.$itemSource; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + + /** + * Delete all reshares of an item + * @param int Id of item to delete + * @param bool If true, exclude the parent from the delete (optional) + * @param string The user that the parent was shared with (optinal) + */ + private static function delete($parent, $excludeParent = false, $uidOwner = null) { + $ids = array($parent); + $parents = array($parent); + while (!empty($parents)) { + $parents = "'".implode("','", $parents)."'"; + // Check the owner on the first search of reshares, useful for + // finding and deleting the reshares by a single user of a group share + if (count($ids) == 1 && isset($uidOwner)) { + $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent`' + .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); + $result = $query->execute(array($uidOwner)); + } else { + $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner`' + .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); + $result = $query->execute(); + } + // Reset parents array, only go through loop again if items are found + $parents = array(); + while ($item = $result->fetchRow()) { + // Search for a duplicate parent share, this occurs when an + // item is shared to the same user through a group and user or the + // same item is shared by different users + $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner'])); + $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`' + .' WHERE `item_type` = ?' + .' AND `item_target` = ?' + .' AND `share_type` IN (?,?,?)' + .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')' + .' AND `uid_owner` != ? AND `id` != ?'); + $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], + self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, + $item['uid_owner'], $item['parent']))->fetchRow(); + if ($duplicateParent) { + // Change the parent to the other item id if share permission is granted + if ($duplicateParent['permissions'] & \OCP\PERMISSION_SHARE) { + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?'); + $query->execute(array($duplicateParent['id'], $item['id'])); + continue; + } + } + $ids[] = $item['id']; + $parents[] = $item['id']; + } + } + if ($excludeParent) { + unset($ids[0]); + } + if (!empty($ids)) { + $ids = "'".implode("','", $ids)."'"; + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$ids.')'); + $query->execute(); + } + } + + /** + * Delete all shares with type SHARE_TYPE_LINK + */ + public static function removeAllLinkShares() { + // Delete any link shares + $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?'); + $result = $query->execute(array(self::SHARE_TYPE_LINK)); + while ($item = $result->fetchRow()) { + self::delete($item['id']); + } + } + + /** + * Hook Listeners + */ + + /** + * Function that is called after a user is deleted. Cleans up the shares of that user. + * @param array arguments + */ + public static function post_deleteUser($arguments) { + // 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']); + } + } + + /** + * Function that is called after a user is added to a group. + * TODO what does it do? + * @param array arguments + */ + 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'); + } + } + } + + /** + * Function that is called after a user is removed from a group. Shares are cleaned up. + * @param array arguments + */ + public static function post_removeFromGroup($arguments) { + // TODO Don't call if user deleted? + $sql = 'SELECT `id`, `share_type` FROM `*PREFIX*share`' + .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'; + $result = \OC_DB::executeAudited($sql, 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']); + } + } + } + + /** + * Function that is called after a group is removed. Cleans up the shares to that group. + * @param array arguments + */ + public static function post_deleteGroup($arguments) { + $sql = 'SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'; + $result = \OC_DB::executeAudited($sql, array(self::SHARE_TYPE_GROUP, $arguments['gid'])); + while ($item = $result->fetchRow()) { + self::delete($item['id']); + } + } + + /** + * In case a password protected link is not yet authenticated this function will return false + * + * @param array $linkItem + * @return bool + */ + public static function checkPasswordProtectedShare(array $linkItem) { + if (!isset($linkItem['share_with'])) { + return true; + } + if (!isset($linkItem['share_type'])) { + return true; + } + if (!isset($linkItem['id'])) { + return true; + } + + if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) { + return true; + } + + if ( \OC::$session->exists('public_link_authenticated') + && \OC::$session->get('public_link_authenticated') === $linkItem['id'] ) { + return true; + } + + return false; + } +} diff --git a/lib/public/share.php b/lib/public/share.php index 5066d40354d..adc02dfe8c4 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -2,8 +2,9 @@ /** * ownCloud * - * @author Michael Gapczynski - * @copyright 2012 Michael Gapczynski mtgap@owncloud.com + * @author Bjoern Schiessle, Michael Gapczynski + * @copyright 2012 Michael Gapczynski + * 2014 Bjoern Schiessle * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -38,6 +39,10 @@ namespace OCP; */ class Share { + const FORMAT_NONE = -1; + const FORMAT_STATUSES = -2; + const FORMAT_SOURCES = -3; + const SHARE_TYPE_USER = 0; const SHARE_TYPE_GROUP = 1; const SHARE_TYPE_LINK = 3; @@ -45,77 +50,26 @@ class Share { const SHARE_TYPE_CONTACT = 5; const SHARE_TYPE_REMOTE = 6; - /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask - * Construct permissions for share() and setPermissions with Or (|) e.g. - * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE - * - * Check if permission is granted with And (&) e.g. Check if delete is - * granted: if ($permissions & PERMISSION_DELETE) - * - * Remove permissions with And (&) and Not (~) e.g. Remove the update - * permission: $permissions &= ~PERMISSION_UPDATE - * - * Apps are required to handle permissions on their own, this class only - * stores and manages the permissions of shares - * @see lib/public/constants.php - */ - - const FORMAT_NONE = -1; - const FORMAT_STATUSES = -2; - const FORMAT_SOURCES = -3; - - const TOKEN_LENGTH = 32; // see db_structure.xml - - private static $shareTypeUserAndGroups = -1; - private static $shareTypeGroupUserUnique = 2; - private static $backends = array(); - private static $backendTypes = array(); - private static $isResharingAllowed; - /** * Register a sharing backend class that implements OCP\Share_Backend for an item type * @param string Item type * @param string Backend class * @param string (optional) Depends on item type * @param array (optional) List of supported file extensions if this item type depends on files - * @param string $itemType - * @param string $class - * @param string $collectionOf - * @return boolean true if backend is registered or false if error + * @return Returns true if backend is registered or false if error */ public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) { - if (self::isEnabled()) { - if (!isset(self::$backendTypes[$itemType])) { - self::$backendTypes[$itemType] = array( - 'class' => $class, - 'collectionOf' => $collectionOf, - 'supportedFileExtensions' => $supportedFileExtensions - ); - if(count(self::$backendTypes) === 1) { - \OC_Util::addScript('core', 'share'); - \OC_Util::addStyle('core', 'share'); - } - return true; - } - \OC_Log::write('OCP\Share', - 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class'] - .' is already registered for '.$itemType, - \OC_Log::WARN); - } - return false; + return \OC\Share\Share::registerBackend($itemType, $class, $collectionOf, $supportedFileExtensions); } /** * Check if the Share API is enabled - * @return boolean true if enabled or false + * @return Returns true if enabled or false * * The Share API is enabled by default if not configured */ public static function isEnabled() { - if (\OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes') == 'yes') { - return true; - } - return false; + return \OC\Share\Share::isEnabled(); } /** @@ -123,22 +77,13 @@ class Share { * @param string $path path * @return string Prepared path */ - public static function prepFileTarget( $path ) { - - // Paths in DB are stored with leading slashes, so add one if necessary - if ( substr( $path, 0, 1 ) !== '/' ) { - - $path = '/' . $path; - - } - - return $path; - + public static function prepFileTarget($path) { + return \OC\Share\Share::prepFileTarget($path); } /** * Find which users can access a shared item - * @param string $path to the file + * @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 @@ -146,101 +91,7 @@ class Share { * not '/admin/data/file.txt' */ public static function getUsersSharingFile($path, $user, $includeOwner = false) { - - $shares = array(); - $publicShare = false; - $source = -1; - $cache = false; - - $view = new \OC\Files\View('/' . $user . '/files'); - if ($view->file_exists($path)) { - $meta = $view->getFileInfo($path); - } else { - // if the file doesn't exists yet we start with the parent folder - $meta = $view->getFileInfo(dirname($path)); - } - - if($meta !== false) { - $source = $meta['fileid']; - $cache = new \OC\Files\Cache\Cache($meta['storage']); - } - - while ($source !== -1) { - - // Fetch all shares with another user - $query = \OC_DB::prepare( - 'SELECT `share_with` - FROM - `*PREFIX*share` - WHERE - `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')' - ); - - $result = $query->execute(array($source, self::SHARE_TYPE_USER)); - - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); - } else { - while ($row = $result->fetchRow()) { - $shares[] = $row['share_with']; - } - } - // We also need to take group shares into account - - $query = \OC_DB::prepare( - 'SELECT `share_with` - FROM - `*PREFIX*share` - WHERE - `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')' - ); - - $result = $query->execute(array($source, self::SHARE_TYPE_GROUP)); - - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); - } else { - while ($row = $result->fetchRow()) { - $usersInGroup = \OC_Group::usersInGroup($row['share_with']); - $shares = array_merge($shares, $usersInGroup); - } - } - - //check for public link shares - if (!$publicShare) { - $query = \OC_DB::prepare( - 'SELECT `share_with` - FROM - `*PREFIX*share` - WHERE - `item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')' - ); - - $result = $query->execute(array($source, self::SHARE_TYPE_LINK)); - - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); - } else { - if ($result->fetchRow()) { - $publicShare = true; - } - } - } - - // let's get the parent for the next round - $meta = $cache->get((int)$source); - if($meta !== false) { - $source = (int)$meta['parent']; - } else { - $source = -1; - } - } - // Include owner in list of users, if requested - if ($includeOwner) { - $shares[] = $user; - } - - return array("users" => array_unique($shares), "public" => $publicShare); + return \OC\Share\Share::getUsersSharingFile($path, $user, $includeOwner); } /** @@ -250,13 +101,12 @@ class Share { * @param mixed Parameters (optional) * @param int Number of items to return (optional) Returns all by default * @param bool include collections (optional) - * @param string $itemType * @return Return depends on format */ public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) { - return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, - $parameters, $limit, $includeCollections); + + return \OC\Share\Share::getItemsSharedWith($itemType, $format, $parameters, $limit, $includeCollections); } /** @@ -266,12 +116,12 @@ class Share { * @param int $format (optional) Format type must be defined by the backend * @param mixed Parameters (optional) * @param bool include collections (optional) - * @return string depends on format + * @return Return depends on format */ public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { - return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, - $parameters, 1, $includeCollections); + + return \OC\Share\Share::getItemSharedWith($itemType, $itemTarget, $format, $parameters, $includeCollections); } /** @@ -282,45 +132,7 @@ class Share { * @return array Return list of items with file_target, permissions and expiration */ public static function getItemSharedWithUser($itemType, $itemSource, $user) { - - $shares = array(); - - // first check if there is a db entry for the specific user - $query = \OC_DB::prepare( - 'SELECT `file_target`, `permissions`, `expiration` - FROM - `*PREFIX*share` - WHERE - `item_source` = ? AND `item_type` = ? AND `share_with` = ?' - ); - - $result = \OC_DB::executeAudited($query, array($itemSource, $itemType, $user)); - - while ($row = $result->fetchRow()) { - $shares[] = $row; - } - - //if didn't found a result than let's look for a group share. - if(empty($shares)) { - $groups = \OC_Group::getUserGroups($user); - - $query = \OC_DB::prepare( - 'SELECT `file_target`, `permissions`, `expiration` - FROM - `*PREFIX*share` - WHERE - `item_source` = ? AND `item_type` = ? AND `share_with` in (?)' - ); - - $result = \OC_DB::executeAudited($query, array($itemSource, $itemType, implode(',', $groups))); - - while ($row = $result->fetchRow()) { - $shares[] = $row; - } - } - - return $shares; - + return \OC\Share\Share::getItemSharedWithUser($itemType, $itemSource, $user); } /** @@ -334,8 +146,7 @@ class Share { */ public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { - return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, - $parameters, 1, $includeCollections, true); + return \OC\Share\Share::getItemSharedWithBySource($itemType, $itemSource, $format, $parameters, $includeCollections); } /** @@ -346,8 +157,7 @@ class Share { * @return Item */ public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) { - return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, - null, 1); + return \OC\Share\Share::getItemSharedWithByLink($itemType, $itemSource, $uidOwner); } /** @@ -356,25 +166,7 @@ class Share { * @return array | bool false will be returned in case the token is unknown or unauthorized */ public static function getShareByToken($token, $checkPasswordProtection = true) { - $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1); - $result = $query->execute(array($token)); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', token=' . $token, \OC_Log::ERROR); - } - $row = $result->fetchRow(); - if ($row === false) { - return false; - } - if (is_array($row) and self::expireItem($row)) { - return false; - } - - // password protected shares need to be authenticated - if ($checkPasswordProtection && !\OCP\Share::checkPasswordProtectedShare($row)) { - return false; - } - - return $row; + return \OC\Share\Share::getShareByToken($token, $checkPasswordProtection); } /** @@ -382,21 +174,8 @@ class Share { * @param $linkItem * @return $fileOwner */ - public static function resolveReShare($linkItem) - { - if (isset($linkItem['parent'])) { - $parent = $linkItem['parent']; - while (isset($parent)) { - $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1); - $item = $query->execute(array($parent))->fetchRow(); - if (isset($item['parent'])) { - $parent = $item['parent']; - } else { - return $item; - } - } - } - return $linkItem; + public static function resolveReShare($linkItem) { + return \OC\Share\Share::resolveReShare($linkItem); } @@ -407,13 +186,12 @@ class Share { * @param mixed Parameters * @param int Number of items to return (optional) Returns all by default * @param bool include collections - * @param string $itemType * @return Return depends on format */ public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) { - return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format, - $parameters, $limit, $includeCollections); + + return \OC\Share\Share::getItemsShared($itemType, $format, $parameters, $limit, $includeCollections); } /** @@ -427,8 +205,8 @@ class Share { */ public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { - return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format, - $parameters, -1, $includeCollections); + + return \OC\Share\Share::getItemShared($itemType, $itemSource, $format, $parameters, $includeCollections); } /** @@ -441,19 +219,7 @@ class Share { * @return Return array of users */ public static function getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections = false, $checkExpireDate = true) { - - $users = array(); - $items = self::getItems($itemType, $itemSource, null, null, $uidOwner, self::FORMAT_NONE, null, -1, $includeCollections, false, $checkExpireDate); - if ($items) { - foreach ($items as $item) { - if ((int)$item['share_type'] === self::SHARE_TYPE_USER) { - $users[] = $item['share_with']; - } else if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) { - $users = array_merge($users, \OC_Group::usersInGroup($item['share_with'])); - } - } - } - return $users; + return \OC\Share\Share::getUsersItemShared($itemType, $itemSource, $uidOwner, $includeCollections, $checkExpireDate); } /** @@ -473,176 +239,7 @@ class Share { * @return bool|string Returns true on success or false on failure, Returns token on success for links */ public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null) { - $uidOwner = \OC_User::getUser(); - $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); - - if (is_null($itemSourceName)) { - $itemSourceName = $itemSource; - } - - // Verify share type and sharing conditions are met - if ($shareType === self::SHARE_TYPE_USER) { - if ($shareWith == $uidOwner) { - $message = 'Sharing '.$itemSourceName.' failed, because the user '.$shareWith.' is the item owner'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - if (!\OC_User::userExists($shareWith)) { - $message = 'Sharing '.$itemSourceName.' failed, because the user '.$shareWith.' does not exist'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - if ($sharingPolicy == 'groups_only') { - $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith)); - if (empty($inGroup)) { - $message = 'Sharing '.$itemSourceName.' failed, because the user ' - .$shareWith.' is not a member of any groups that '.$uidOwner.' is a member of'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } - // Check if the item source is already shared with the user, either from the same owner or a different user - if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, - $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { - // Only allow the same share to occur again if it is the same - // owner and is not a user share, this use case is for increasing - // permissions for a specific user - if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { - $message = 'Sharing '.$itemSourceName.' failed, because this item is already shared with '.$shareWith; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } - } else if ($shareType === self::SHARE_TYPE_GROUP) { - if (!\OC_Group::groupExists($shareWith)) { - $message = 'Sharing '.$itemSourceName.' failed, because the group '.$shareWith.' does not exist'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - if ($sharingPolicy == 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) { - $message = 'Sharing '.$itemSourceName.' failed, because ' - .$uidOwner.' is not a member of the group '.$shareWith; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - // Check if the item source is already shared with the group, either from the same owner or a different user - // The check for each user in the group is done inside the put() function - if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, - null, self::FORMAT_NONE, null, 1, true, true)) { - // Only allow the same share to occur again if it is the same - // owner and is not a group share, this use case is for increasing - // permissions for a specific user - if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { - $message = 'Sharing '.$itemSourceName.' failed, because this item is already shared with '.$shareWith; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } - // Convert share with into an array with the keys group and users - $group = $shareWith; - $shareWith = array(); - $shareWith['group'] = $group; - $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner)); - } else if ($shareType === self::SHARE_TYPE_LINK) { - if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') { - // when updating a link share - if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, - $uidOwner, self::FORMAT_NONE, null, 1)) { - // remember old token - $oldToken = $checkExists['token']; - $oldPermissions = $checkExists['permissions']; - //delete the old share - self::delete($checkExists['id']); - } - - // Generate hash of password - same method as user passwords - if (isset($shareWith)) { - $forcePortable = (CRYPT_BLOWFISH != 1); - $hasher = new \PasswordHash(8, $forcePortable); - $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', '')); - } else { - // reuse the already set password, but only if we change permissions - // otherwise the user disabled the password protection - if ($checkExists && (int)$permissions !== (int)$oldPermissions) { - $shareWith = $checkExists['share_with']; - } - } - - // Generate token - if (isset($oldToken)) { - $token = $oldToken; - } else { - $token = \OC_Util::generateRandomBytes(self::TOKEN_LENGTH); - } - $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, - null, $token, $itemSourceName); - if ($result) { - return $token; - } else { - return false; - } - } - $message = 'Sharing '.$itemSourceName.' failed, because sharing with links is not allowed'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - return false; -// } else if ($shareType === self::SHARE_TYPE_CONTACT) { -// if (!\OC_App::isEnabled('contacts')) { -// $message = 'Sharing '.$itemSource.' failed, because the contacts app is not enabled'; -// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); -// return false; -// } -// $vcard = \OC_Contacts_App::getContactVCard($shareWith); -// if (!isset($vcard)) { -// $message = 'Sharing '.$itemSource.' failed, because the contact does not exist'; -// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); -// throw new \Exception($message); -// } -// $details = \OC_Contacts_VCard::structureContact($vcard); -// // TODO Add ownCloud user to contacts vcard -// if (!isset($details['EMAIL'])) { -// $message = 'Sharing '.$itemSource.' failed, because no email address is associated with the contact'; -// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); -// throw new \Exception($message); -// } -// return self::shareItem($itemType, $itemSource, self::SHARE_TYPE_EMAIL, $details['EMAIL'], $permissions); - } else { - // Future share types need to include their own conditions - $message = 'Share type '.$shareType.' is not valid for '.$itemSource; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - // If the item is a folder, scan through the folder looking for equivalent item types -// if ($itemType == 'folder') { -// $parentFolder = self::put('folder', $itemSource, $shareType, $shareWith, $uidOwner, $permissions, true); -// if ($parentFolder && $files = \OC\Files\Filesystem::getDirectoryContent($itemSource)) { -// for ($i = 0; $i < count($files); $i++) { -// $name = substr($files[$i]['name'], strpos($files[$i]['name'], $itemSource) - strlen($itemSource)); -// if ($files[$i]['mimetype'] == 'httpd/unix-directory' -// && $children = \OC\Files\Filesystem::getDirectoryContent($name, '/') -// ) { -// // Continue scanning into child folders -// array_push($files, $children); -// } else { -// // Check file extension for an equivalent item type to convert to -// $extension = strtolower(substr($itemSource, strrpos($itemSource, '.') + 1)); -// foreach (self::$backends as $type => $backend) { -// if (isset($backend->dependsOn) && $backend->dependsOn == 'file' && isset($backend->supportedFileExtensions) && in_array($extension, $backend->supportedFileExtensions)) { -// $itemType = $type; -// break; -// } -// } -// // Pass on to put() to check if this item should be converted, the item won't be inserted into the database unless it can be converted -// self::put($itemType, $name, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder); -// } -// } -// return true; -// } -// return false; -// } else { - // Put the item into the database - return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName); -// } + return \OC\Share\Share::shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName); } /** @@ -651,88 +248,32 @@ class Share { * @param string Item source * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK * @param string User or group the item is being shared with - * @return boolean true on success or false on failure + * @return Returns true on success or false on failure */ public static function unshare($itemType, $itemSource, $shareType, $shareWith) { - if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), - self::FORMAT_NONE, null, 1)) { - self::unshareItem($item); - return true; - } - return false; + return \OC\Share\Share::unshare($itemType, $itemSource, $shareType, $shareWith); } /** * Unshare an item from all users, groups, and remove all links * @param string Item type * @param string Item source - * @param string $itemType - * @param string $itemSource - * @return boolean true on success or false on failure + * @return Returns true on success or false on failure */ public static function unshareAll($itemType, $itemSource) { - // Get all of the owners of shares of this item. - $query = \OC_DB::prepare( 'SELECT `uid_owner` from `*PREFIX*share` WHERE `item_type`=? AND `item_source`=?' ); - $result = $query->execute(array($itemType, $itemSource)); - $shares = array(); - // Add each owner's shares to the array of all shares for this item. - while ($row = $result->fetchRow()) { - $shares = array_merge($shares, self::getItems($itemType, $itemSource, null, null, $row['uid_owner'])); - } - if (!empty($shares)) { - // Pass all the vars we have for now, they may be useful - $hookParams = array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'shares' => $shares, - ); - \OC_Hook::emit('OCP\Share', 'pre_unshareAll', $hookParams); - foreach ($shares as $share) { - self::unshareItem($share); - } - \OC_Hook::emit('OCP\Share', 'post_unshareAll', $hookParams); - return true; - } - return false; + return \OC\Share\Share::unshareAll($itemType, $itemSource); } /** * Unshare an item shared with the current user * @param string Item type * @param string Item target - * @param string $itemType - * @param string $itemTarget - * @return boolean true on success or false on failure + * @return Returns true on success or false on failure * * Unsharing from self is not allowed for items inside collections */ public static function unshareFromSelf($itemType, $itemTarget) { - if ($item = self::getItemSharedWith($itemType, $itemTarget)) { - if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) { - // Insert an extra row for the group share and set permission - // to 0 to prevent it from showing up for the user - $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 (?,?,?,?,?,?,?,?,?,?,?)'); - $query->execute(array($item['item_type'], $item['item_source'], $item['item_target'], - $item['id'], self::$shareTypeGroupUserUnique, - \OC_User::getUser(), $item['uid_owner'], 0, $item['stime'], $item['file_source'], - $item['file_target'])); - \OC_DB::insertid('*PREFIX*share'); - // Delete all reshares by this user of the group share - self::delete($item['id'], true, \OC_User::getUser()); - } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) { - // Set permission to 0 to prevent it from showing up for the user - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?'); - $query->execute(array(0, $item['id'])); - self::delete($item['id'], true); - } else { - self::delete($item['id']); - } - return true; - } - return false; + return \OC\Share\Share::unshareFromSelf($itemType, $itemTarget); } /** * sent status if users got informed by mail about share @@ -742,102 +283,20 @@ class Share { * @param bool $status */ public static function setSendMailStatus($itemType, $itemSource, $shareType, $status) { - $status = $status ? 1 : 0; - - $query = \OC_DB::prepare( - 'UPDATE `*PREFIX*share` - SET `mail_send` = ? - WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ?'); - - $result = $query->execute(array($status, $itemType, $itemSource, $shareType)); - - if($result === false) { - \OC_Log::write('OCP\Share', 'Couldn\'t set send mail status', \OC_Log::ERROR); - } + return \OC\Share\Share::setSendMailStatus($itemType, $itemSource, $shareType, $status); } /** * Set the permissions of an item for a specific user or group - * @param string $itemType Item type - * @param string $itemSource Item source - * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK - * @param string $shareWith User or group the item is being shared with - * @param integer|null $permissions CRUDS - * @return boolean true on success or false on failure + * @param string Item type + * @param string Item source + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string User or group the item is being shared with + * @param int CRUDS permissions + * @return Returns true on success or false on failure */ public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) { - if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, - \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) { - // Check if this item is a reshare and verify that the permissions - // granted don't exceed the parent shared item - if (isset($item['parent'])) { - $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $result = $query->execute(array($item['parent']))->fetchRow(); - if (~(int)$result['permissions'] & $permissions) { - $message = 'Setting permissions for '.$itemSource.' failed,' - .' because the permissions exceed permissions granted to '.\OC_User::getUser(); - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?'); - $query->execute(array($permissions, $item['id'])); - if ($itemType === 'file' || $itemType === 'folder') { - \OC_Hook::emit('OCP\Share', 'post_update_permissions', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'shareType' => $shareType, - 'shareWith' => $shareWith, - 'uidOwner' => \OC_User::getUser(), - 'permissions' => $permissions, - 'path' => $item['path'], - )); - } - // Check if permissions were removed - if ($item['permissions'] & ~$permissions) { - // If share permission is removed all reshares must be deleted - if (($item['permissions'] & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE)) { - self::delete($item['id'], true); - } else { - $ids = array(); - $parents = array($item['id']); - while (!empty($parents)) { - $parents = "'".implode("','", $parents)."'"; - $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`' - .' WHERE `parent` IN ('.$parents.')'); - $result = $query->execute(); - // Reset parents array, only go through loop again if - // items are found that need permissions removed - $parents = array(); - while ($item = $result->fetchRow()) { - // Check if permissions need to be removed - if ($item['permissions'] & ~$permissions) { - // Add to list of items that need permissions removed - $ids[] = $item['id']; - $parents[] = $item['id']; - } - } - } - // Remove the permissions for all reshares of this item - if (!empty($ids)) { - $ids = "'".implode("','", $ids)."'"; - // TODO this should be done with Doctrine platform objects - if (\OC_Config::getValue( "dbtype") === 'oci') { - $andOp = 'BITAND(`permissions`, ?)'; - } else { - $andOp = '`permissions` & ?'; - } - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = '.$andOp - .' WHERE `id` IN ('.$ids.')'); - $query->execute(array($permissions)); - } - } - } - return true; - } - $message = 'Setting permissions for '.$itemSource.' failed, because the item was not found'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); + return \OC\Share\Share::setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions); } /** @@ -845,67 +304,10 @@ class Share { * @param string $itemType * @param string $itemSource * @param string $date expiration date - * @return boolean + * @return Share_Backend */ public static function setExpirationDate($itemType, $itemSource, $date) { - if ($items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), - self::FORMAT_NONE, null, -1, false)) { - if (!empty($items)) { - if ($date == '') { - $date = null; - } else { - $date = new \DateTime($date); - } - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `id` = ?'); - $query->bindValue(1, $date, 'datetime'); - foreach ($items as $item) { - $query->bindValue(2, (int) $item['id']); - $query->execute(); - } - return true; - } - } - return false; - } - - /** - * Checks whether a share has expired, calls unshareItem() if yes. - * @param array $item Share data (usually database row) - * @return bool True if item was expired, false otherwise. - */ - protected static function expireItem(array $item) { - if (!empty($item['expiration'])) { - $now = new \DateTime(); - $expires = new \DateTime($item['expiration']); - if ($now > $expires) { - self::unshareItem($item); - return true; - } - } - return false; - } - - /** - * Unshares a share given a share data array - * @param array $item Share data (usually database row) - * @return null - */ - protected static function unshareItem(array $item) { - // Pass all the vars we have for now, they may be useful - $hookParams = array( - 'itemType' => $item['item_type'], - 'itemSource' => $item['item_source'], - 'shareType' => $item['share_type'], - 'shareWith' => $item['share_with'], - 'itemParent' => $item['parent'], - 'uidOwner' => $item['uid_owner'], - ); - - \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams + array( - 'fileSource' => $item['file_source'], - )); - self::delete($item['id']); - \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams); + return \OC\Share\Share::setExpirationDate($itemType, $itemSource, $date); } /** @@ -914,930 +316,14 @@ class Share { * @return Share_Backend */ public static function getBackend($itemType) { - if (isset(self::$backends[$itemType])) { - return self::$backends[$itemType]; - } else if (isset(self::$backendTypes[$itemType]['class'])) { - $class = self::$backendTypes[$itemType]['class']; - if (class_exists($class)) { - self::$backends[$itemType] = new $class; - if (!(self::$backends[$itemType] instanceof Share_Backend)) { - $message = 'Sharing backend '.$class.' must implement the interface OCP\Share_Backend'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - return self::$backends[$itemType]; - } else { - $message = 'Sharing backend '.$class.' not found'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } - $message = 'Sharing backend for '.$itemType.' not found'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - - /** - * Check if resharing is allowed - * @return boolean true if allowed or false - * - * Resharing is allowed by default if not configured - */ - private static function isResharingAllowed() { - if (!isset(self::$isResharingAllowed)) { - if (\OC_Appconfig::getValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') { - self::$isResharingAllowed = true; - } else { - self::$isResharingAllowed = false; - } - } - return self::$isResharingAllowed; - } - - /** - * Get a list of collection item types for the specified item type - * @param string Item type - * @return array - */ - private static function getCollectionItemTypes($itemType) { - $collectionTypes = array($itemType); - foreach (self::$backendTypes as $type => $backend) { - if (in_array($backend['collectionOf'], $collectionTypes)) { - $collectionTypes[] = $type; - } - } - // TODO Add option for collections to be collection of themselves, only 'folder' does it now... - if (!self::getBackend($itemType) instanceof Share_Backend_Collection || $itemType != 'folder') { - unset($collectionTypes[0]); - } - // Return array if collections were found or the item type is a - // collection itself - collections can be inside collections - if (count($collectionTypes) > 0) { - return $collectionTypes; - } - return false; - } - - /** - * Get shared items from the database - * @param string Item type - * @param string Item source or target (optional) - * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique - * @param string User or group the item is being shared with - * @param string User that is the owner of shared items (optional) - * @param int Format to convert items to with formatItems() - * @param mixed Parameters to pass to formatItems() - * @param int Number of items to return, -1 to return all matches (optional) - * @param bool Include collection item types (optional) - * @param bool TODO (optional) - * @prams bool check expire date - * @return mixed - * - * See public functions getItem(s)... for parameter usage - * - */ - private static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, - $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, - $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) { - if (!self::isEnabled()) { - if ($limit == 1 || (isset($uidOwner) && isset($item))) { - return false; - } else { - return array(); - } - } - $backend = self::getBackend($itemType); - $collectionTypes = false; - // Get filesystem root to add it to the file target and remove from the - // file source, match file_source with the file cache - if ($itemType == 'file' || $itemType == 'folder') { - if(!is_null($uidOwner)) { - $root = \OC\Files\Filesystem::getRoot(); - } else { - $root = ''; - } - $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid`'; - if (!isset($item)) { - $where .= ' WHERE `file_target` IS NOT NULL'; - } - $fileDependent = true; - $queryArgs = array(); - } else { - $fileDependent = false; - $root = ''; - if ($includeCollections && !isset($item) && ($collectionTypes = self::getCollectionItemTypes($itemType))) { - // If includeCollections is true, find collections of this item type, e.g. a music album contains songs - if (!in_array($itemType, $collectionTypes)) { - $itemTypes = array_merge(array($itemType), $collectionTypes); - } else { - $itemTypes = $collectionTypes; - } - $placeholders = join(',', array_fill(0, count($itemTypes), '?')); - $where = ' WHERE `item_type` IN ('.$placeholders.'))'; - $queryArgs = $itemTypes; - } else { - $where = ' WHERE `item_type` = ?'; - $queryArgs = array($itemType); - } - } - if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') { - $where .= ' AND `share_type` != ?'; - $queryArgs[] = self::SHARE_TYPE_LINK; - } - if (isset($shareType)) { - // Include all user and group items - if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) { - $where .= ' AND `share_type` IN (?,?,?)'; - $queryArgs[] = self::SHARE_TYPE_USER; - $queryArgs[] = self::SHARE_TYPE_GROUP; - $queryArgs[] = self::$shareTypeGroupUserUnique; - $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith)); - $placeholders = join(',', array_fill(0, count($userAndGroups), '?')); - $where .= ' AND `share_with` IN ('.$placeholders.')'; - $queryArgs = array_merge($queryArgs, $userAndGroups); - // Don't include own group shares - $where .= ' AND `uid_owner` != ?'; - $queryArgs[] = $shareWith; - } else { - $where .= ' AND `share_type` = ?'; - $queryArgs[] = $shareType; - if (isset($shareWith)) { - $where .= ' AND `share_with` = ?'; - $queryArgs[] = $shareWith; - } - } - } - if (isset($uidOwner)) { - $where .= ' AND `uid_owner` = ?'; - $queryArgs[] = $uidOwner; - if (!isset($shareType)) { - // Prevent unique user targets for group shares from being selected - $where .= ' AND `share_type` != ?'; - $queryArgs[] = self::$shareTypeGroupUserUnique; - } - if ($itemType == 'file' || $itemType == 'folder') { - $column = 'file_source'; - } else { - $column = 'item_source'; - } - } else { - if ($itemType == 'file' || $itemType == 'folder') { - $column = 'file_target'; - } else { - $column = 'item_target'; - } - } - if (isset($item)) { - if ($includeCollections && $collectionTypes = self::getCollectionItemTypes($itemType)) { - $where .= ' AND ('; - } else { - $where .= ' AND'; - } - // If looking for own shared items, check item_source else check item_target - if (isset($uidOwner) || $itemShareWithBySource) { - // If item type is a file, file source needs to be checked in case the item was converted - if ($itemType == 'file' || $itemType == 'folder') { - $where .= ' `file_source` = ?'; - $column = 'file_source'; - } else { - $where .= ' `item_source` = ?'; - $column = 'item_source'; - } - } else { - if ($itemType == 'file' || $itemType == 'folder') { - $where .= ' `file_target` = ?'; - $item = \OC\Files\Filesystem::normalizePath($item); - } else { - $where .= ' `item_target` = ?'; - } - } - $queryArgs[] = $item; - if ($includeCollections && $collectionTypes) { - $placeholders = join(',', array_fill(0, count($collectionTypes), '?')); - $where .= ' OR `item_type` IN ('.$placeholders.'))'; - $queryArgs = array_merge($queryArgs, $collectionTypes); - } - } - if ($limit != -1 && !$includeCollections) { - if ($shareType == self::$shareTypeUserAndGroups) { - // Make sure the unique user target is returned if it exists, - // unique targets should follow the group share in the database - // If the limit is not 1, the filtering can be done later - $where .= ' ORDER BY `*PREFIX*share`.`id` DESC'; - } - // The limit must be at least 3, because filtering needs to be done - if ($limit < 3) { - $queryLimit = 3; - } else { - $queryLimit = $limit; - } - } else { - $queryLimit = null; - } - // TODO Optimize selects - if ($format == self::FORMAT_STATUSES) { - if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' - .' `share_type`, `file_source`, `path`, `expiration`, `storage`, `share_with`, `mail_send`, `uid_owner`'; - } else { - $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `expiration`, `mail_send`, `uid_owner`'; - } - } else { - if (isset($uidOwner)) { - if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' - .' `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`,' - .' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`'; - } else { - $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`,' - .' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; - } - } else { - if ($fileDependent) { - if (($itemType == 'file' || $itemType == 'folder') - && $format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS - || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT - ) { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' - .'`share_type`, `share_with`, `file_source`, `path`, `file_target`, ' - .'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' - .'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; - } else { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, - `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, - `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`'; - } - } else { - $select = '*'; - } - } - } - $root = strlen($root); - $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit); - $result = $query->execute($queryArgs); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', - \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, - \OC_Log::ERROR); - } - $items = array(); - $targets = array(); - $switchedItems = array(); - $mounts = array(); - while ($row = $result->fetchRow()) { - if (isset($row['id'])) { - $row['id']=(int)$row['id']; - } - if (isset($row['share_type'])) { - $row['share_type']=(int)$row['share_type']; - } - if (isset($row['parent'])) { - $row['parent']=(int)$row['parent']; - } - if (isset($row['file_parent'])) { - $row['file_parent']=(int)$row['file_parent']; - } - if (isset($row['file_source'])) { - $row['file_source']=(int)$row['file_source']; - } - if (isset($row['permissions'])) { - $row['permissions']=(int)$row['permissions']; - } - if (isset($row['storage'])) { - $row['storage']=(int)$row['storage']; - } - if (isset($row['stime'])) { - $row['stime']=(int)$row['stime']; - } - // Filter out duplicate group shares for users with unique targets - if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) { - $row['share_type'] = self::SHARE_TYPE_GROUP; - $row['share_with'] = $items[$row['parent']]['share_with']; - // Remove the parent group share - unset($items[$row['parent']]); - if ($row['permissions'] == 0) { - continue; - } - } else if (!isset($uidOwner)) { - // Check if the same target already exists - if (isset($targets[$row[$column]])) { - // Check if the same owner shared with the user twice - // through a group and user share - this is allowed - $id = $targets[$row[$column]]; - if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) { - // Switch to group share type to ensure resharing conditions aren't bypassed - if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) { - $items[$id]['share_type'] = self::SHARE_TYPE_GROUP; - $items[$id]['share_with'] = $row['share_with']; - } - // Switch ids if sharing permission is granted on only - // one share to ensure correct parent is used if resharing - if (~(int)$items[$id]['permissions'] & PERMISSION_SHARE - && (int)$row['permissions'] & PERMISSION_SHARE) { - $items[$row['id']] = $items[$id]; - $switchedItems[$id] = $row['id']; - unset($items[$id]); - $id = $row['id']; - } - // Combine the permissions for the item - $items[$id]['permissions'] |= (int)$row['permissions']; - continue; - } - } else { - $targets[$row[$column]] = $row['id']; - } - } - // Remove root from file source paths if retrieving own shared items - if (isset($uidOwner) && isset($row['path'])) { - if (isset($row['parent'])) { - // FIXME: Doesn't always construct the correct path, example: - // Folder '/a/b', share '/a' and '/a/b' to user2 - // user2 reshares /Shared/b and ask for share status of /Shared/a/b - // expected result: path=/Shared/a/b; actual result /Shared/b because of the parent - $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?'); - $parentResult = $query->execute(array($row['parent'])); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', 'Can\'t select parent: ' . - \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, - \OC_Log::ERROR); - } else { - $parentRow = $parentResult->fetchRow(); - $tmpPath = '/Shared' . $parentRow['file_target']; - // find the right position where the row path continues from the target path - $pos = strrpos($row['path'], $parentRow['file_target']); - $subPath = substr($row['path'], $pos); - $splitPath = explode('/', $subPath); - foreach (array_slice($splitPath, 2) as $pathPart) { - $tmpPath = $tmpPath . '/' . $pathPart; - } - $row['path'] = $tmpPath; - } - } else { - if (!isset($mounts[$row['storage']])) { - $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']); - if (is_array($mountPoints)) { - $mounts[$row['storage']] = current($mountPoints); - } - } - if ($mounts[$row['storage']]) { - $path = $mounts[$row['storage']]->getMountPoint().$row['path']; - $row['path'] = substr($path, $root); - } - } - } - if($checkExpireDate) { - if (self::expireItem($row)) { - continue; - } - } - // Check if resharing is allowed, if not remove share permission - if (isset($row['permissions']) && !self::isResharingAllowed()) { - $row['permissions'] &= ~PERMISSION_SHARE; - } - // Add display names to result - if ( isset($row['share_with']) && $row['share_with'] != '') { - $row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']); - } - if ( isset($row['uid_owner']) && $row['uid_owner'] != '') { - $row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']); - } - - $items[$row['id']] = $row; - } - if (!empty($items)) { - $collectionItems = array(); - foreach ($items as &$row) { - // Return only the item instead of a 2-dimensional array - if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) { - if ($format == self::FORMAT_NONE) { - return $row; - } else { - break; - } - } - // Check if this is a collection of the requested item type - if ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) { - if (($collectionBackend = self::getBackend($row['item_type'])) - && $collectionBackend instanceof Share_Backend_Collection) { - // Collections can be inside collections, check if the item is a collection - if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) { - $collectionItems[] = $row; - } else { - $collection = array(); - $collection['item_type'] = $row['item_type']; - if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { - $collection['path'] = basename($row['path']); - } - $row['collection'] = $collection; - // Fetch all of the children sources - $children = $collectionBackend->getChildren($row[$column]); - foreach ($children as $child) { - $childItem = $row; - $childItem['item_type'] = $itemType; - if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') { - $childItem['item_source'] = $child['source']; - $childItem['item_target'] = $child['target']; - } - if ($backend instanceof Share_Backend_File_Dependent) { - if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { - $childItem['file_source'] = $child['source']; - } else { - $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']); - $childItem['file_source'] = $meta['fileid']; - } - $childItem['file_target'] = - \OC\Files\Filesystem::normalizePath($child['file_path']); - } - if (isset($item)) { - if ($childItem[$column] == $item) { - // Return only the item instead of a 2-dimensional array - if ($limit == 1) { - if ($format == self::FORMAT_NONE) { - return $childItem; - } else { - // Unset the items array and break out of both loops - $items = array(); - $items[] = $childItem; - break 2; - } - } else { - $collectionItems[] = $childItem; - } - } - } else { - $collectionItems[] = $childItem; - } - } - } - } - // Remove collection item - $toRemove = $row['id']; - if (array_key_exists($toRemove, $switchedItems)) { - $toRemove = $switchedItems[$toRemove]; - } - unset($items[$toRemove]); - } - } - if (!empty($collectionItems)) { - $items = array_merge($items, $collectionItems); - } - if (empty($items) && $limit == 1) { - return false; - } - if ($format == self::FORMAT_NONE) { - return $items; - } else if ($format == self::FORMAT_STATUSES) { - $statuses = array(); - foreach ($items as $item) { - if ($item['share_type'] == self::SHARE_TYPE_LINK) { - $statuses[$item[$column]]['link'] = true; - } else if (!isset($statuses[$item[$column]])) { - $statuses[$item[$column]]['link'] = false; - } - if ($itemType == 'file' || $itemType == 'folder') { - $statuses[$item[$column]]['path'] = $item['path']; - } - } - return $statuses; - } else { - return $backend->formatItems($items, $format, $parameters); - } - } else if ($limit == 1 || (isset($uidOwner) && isset($item))) { - return false; - } - return array(); - } - - /** - * Put shared item into the database - * @param string $itemType Item type - * @param string $itemSource Item source - * @param integer $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK - * @param string $shareWith User or group the item is being shared with - * @param string $uidOwner User that is the owner of shared item - * @param int $permissions CRUDS permissions - * @param bool|array, $parentFolder Parent folder target (optional) - * @param string $token (optional) - * @param string $itemSourceName name of the source item (optional) - * @return bool Returns true on success or false on failure - */ - private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, - $permissions, $parentFolder = null, $token = null, $itemSourceName = null) { - $backend = self::getBackend($itemType); - - // Check if this is a reshare - if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) { - - // Check if attempting to share back to owner - if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) { - $message = 'Sharing '.$itemSourceName.' failed, because the user '.$shareWith.' is the original sharer'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - // Check if share permissions is granted - if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & PERMISSION_SHARE) { - if (~(int)$checkReshare['permissions'] & $permissions) { - $message = 'Sharing '.$itemSourceName - .' failed, because the permissions exceed permissions granted to '.$uidOwner; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } else { - // TODO Don't check if inside folder - $parent = $checkReshare['id']; - $itemSource = $checkReshare['item_source']; - $fileSource = $checkReshare['file_source']; - $suggestedItemTarget = $checkReshare['item_target']; - $suggestedFileTarget = $checkReshare['file_target']; - $filePath = $checkReshare['file_target']; - } - } else { - $message = 'Sharing '.$itemSourceName.' failed, because resharing is not allowed'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } else { - $parent = null; - $suggestedItemTarget = null; - $suggestedFileTarget = null; - if (!$backend->isValidSource($itemSource, $uidOwner)) { - $message = 'Sharing '.$itemSource.' failed, because the sharing backend for ' - .$itemType.' could not find its source'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - $parent = null; - if ($backend instanceof Share_Backend_File_Dependent) { - $filePath = $backend->getFilePath($itemSource, $uidOwner); - if ($itemType == 'file' || $itemType == 'folder') { - $fileSource = $itemSource; - } else { - $meta = \OC\Files\Filesystem::getFileInfo($filePath); - $fileSource = $meta['fileid']; - } - if ($fileSource == -1) { - $message = 'Sharing '.$itemSource.' failed, because the file could not be found in the file cache'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - } else { - $filePath = null; - $fileSource = null; - } - } - $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`, `token`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)'); - // Share with a group - 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, - 'itemTarget' => $groupItemTarget, - 'shareType' => $shareType, - 'shareWith' => $shareWith['group'], - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'token' => $token, - 'run' => &$run, - 'error' => &$error - )); - - if ($run === false) { - throw new \Exception($error); - } - - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $groupFileTarget = self::generateTarget('file', $filePath, $shareType, - $shareWith['group'], $uidOwner, $suggestedFileTarget); - // Set group default file target for future use - $parentFolders[0]['folder'] = $groupFileTarget; - } else { - // Get group default file target - $groupFileTarget = $parentFolder[0]['folder'].$itemSource; - $parent = $parentFolder[0]['id']; - } - } else { - $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], - $uidOwner, $suggestedFileTarget); - } - } else { - $groupFileTarget = null; - } - $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, - $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token)); - // Save this id, any extra rows for this group share will need to reference it - $parent = \OC_DB::insertid('*PREFIX*share'); - // Loop through all users of this group in case we need to add an extra row - foreach ($shareWith['users'] as $uid) { - $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, - $uidOwner, $suggestedItemTarget, $parent); - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, - $uidOwner, $suggestedFileTarget, $parent); - if ($fileTarget != $groupFileTarget) { - $parentFolders[$uid]['folder'] = $fileTarget; - } - } else if (isset($parentFolder[$uid])) { - $fileTarget = $parentFolder[$uid]['folder'].$itemSource; - $parent = $parentFolder[$uid]['id']; - } - } else { - $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, - $uid, $uidOwner, $suggestedFileTarget, $parent); - } - } else { - $fileTarget = null; - } - // Insert an extra row for the group share if the item or file target is unique for this user - if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { - $query->execute(array($itemType, $itemSource, $itemTarget, $parent, - self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), - $fileSource, $fileTarget, $token)); - $id = \OC_DB::insertid('*PREFIX*share'); - } - } - \OC_Hook::emit('OCP\Share', 'post_shared', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $groupItemTarget, - 'parent' => $parent, - 'shareType' => $shareType, - 'shareWith' => $shareWith['group'], - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'fileTarget' => $groupFileTarget, - 'id' => $parent, - 'token' => $token - )); - - if ($parentFolder === true) { - // Return parent folders to preserve file target paths for potential children - return $parentFolders; - } - } 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, - 'itemTarget' => $itemTarget, - 'shareType' => $shareType, - 'shareWith' => $shareWith, - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'token' => $token, - 'run' => &$run, - 'error' => &$error - )); - - if ($run === false) { - throw new \Exception($error); - } - - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, - $uidOwner, $suggestedFileTarget); - $parentFolders['folder'] = $fileTarget; - } else { - $fileTarget = $parentFolder['folder'].$itemSource; - $parent = $parentFolder['id']; - } - } else { - $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, - $suggestedFileTarget); - } - } else { - $fileTarget = null; - } - $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, - $permissions, time(), $fileSource, $fileTarget, $token)); - $id = \OC_DB::insertid('*PREFIX*share'); - \OC_Hook::emit('OCP\Share', 'post_shared', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $itemTarget, - 'parent' => $parent, - 'shareType' => $shareType, - 'shareWith' => $shareWith, - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'fileTarget' => $fileTarget, - 'id' => $id, - 'token' => $token - )); - if ($parentFolder === true) { - $parentFolders['id'] = $id; - // Return parent folder to preserve file target paths for potential children - return $parentFolders; - } - } - return true; - } - - /** - * Generate a unique target for the item - * @param string Item type - * @param string Item source - * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK - * @param string User or group the item is being shared with - * @param string User that is the owner of shared item - * @param string The suggested target originating from a reshare (optional) - * @param int The id of the parent group share (optional) - * @param integer $shareType - * @return string Item target - */ - private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, - $suggestedTarget = null, $groupParent = null) { - $backend = self::getBackend($itemType); - if ($shareType == self::SHARE_TYPE_LINK) { - if (isset($suggestedTarget)) { - return $suggestedTarget; - } - return $backend->generateTarget($itemSource, false); - } else { - if ($itemType == 'file' || $itemType == 'folder') { - $column = 'file_target'; - $columnSource = 'file_source'; - } else { - $column = 'item_target'; - $columnSource = 'item_source'; - } - if ($shareType == self::SHARE_TYPE_USER) { - // Share with is a user, so set share type to user and groups - $shareType = self::$shareTypeUserAndGroups; - $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith)); - } else { - $userAndGroups = false; - } - $exclude = null; - // Backend has 3 opportunities to generate a unique target - for ($i = 0; $i < 2; $i++) { - // Check if suggested target exists first - if ($i == 0 && isset($suggestedTarget)) { - $target = $suggestedTarget; - } else { - if ($shareType == self::SHARE_TYPE_GROUP) { - $target = $backend->generateTarget($itemSource, false, $exclude); - } else { - $target = $backend->generateTarget($itemSource, $shareWith, $exclude); - } - if (is_array($exclude) && in_array($target, $exclude)) { - break; - } - } - // Check if target already exists - $checkTarget = self::getItems($itemType, $target, $shareType, $shareWith); - if (!empty($checkTarget)) { - foreach ($checkTarget as $item) { - // Skip item if it is the group parent row - if (isset($groupParent) && $item['id'] == $groupParent) { - if (count($checkTarget) == 1) { - return $target; - } else { - continue; - } - } - if ($item['uid_owner'] == $uidOwner) { - if ($itemType == 'file' || $itemType == 'folder') { - $meta = \OC\Files\Filesystem::getFileInfo($itemSource); - if ($item['file_source'] == $meta['fileid']) { - return $target; - } - } else if ($item['item_source'] == $itemSource) { - return $target; - } - } - } - if (!isset($exclude)) { - $exclude = array(); - } - // Find similar targets to improve backend's chances to generate a unqiue target - if ($userAndGroups) { - if ($column == 'file_target') { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` IN (\'file\', \'folder\')' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); - $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, - self::$shareTypeGroupUserUnique)); - } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` = ? AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); - $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, - self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); - } - } else { - if ($column == 'file_target') { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` IN (\'file\', \'folder\')' - .' AND `share_type` = ? AND `share_with` = ?'); - $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith)); - } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?'); - $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith)); - } - } - while ($row = $result->fetchRow()) { - $exclude[] = $row[$column]; - } - } else { - return $target; - } - } - } - $message = 'Sharing backend registered for '.$itemType.' did not generate a unique target for '.$itemSource; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - - /** - * Delete all reshares of an item - * @param int Id of item to delete - * @param bool If true, exclude the parent from the delete (optional) - * @param string The user that the parent was shared with (optinal) - */ - private static function delete($parent, $excludeParent = false, $uidOwner = null) { - $ids = array($parent); - $parents = array($parent); - while (!empty($parents)) { - $parents = "'".implode("','", $parents)."'"; - // Check the owner on the first search of reshares, useful for - // finding and deleting the reshares by a single user of a group share - if (count($ids) == 1 && isset($uidOwner)) { - $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent`' - .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); - $result = $query->execute(array($uidOwner)); - } else { - $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner`' - .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); - $result = $query->execute(); - } - // Reset parents array, only go through loop again if items are found - $parents = array(); - while ($item = $result->fetchRow()) { - // Search for a duplicate parent share, this occurs when an - // item is shared to the same user through a group and user or the - // same item is shared by different users - $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner'])); - $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`' - .' WHERE `item_type` = ?' - .' AND `item_target` = ?' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')' - .' AND `uid_owner` != ? AND `id` != ?'); - $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], - self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, - $item['uid_owner'], $item['parent']))->fetchRow(); - if ($duplicateParent) { - // Change the parent to the other item id if share permission is granted - if ($duplicateParent['permissions'] & PERMISSION_SHARE) { - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?'); - $query->execute(array($duplicateParent['id'], $item['id'])); - continue; - } - } - $ids[] = $item['id']; - $parents[] = $item['id']; - } - } - if ($excludeParent) { - unset($ids[0]); - } - if (!empty($ids)) { - $ids = "'".implode("','", $ids)."'"; - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$ids.')'); - $query->execute(); - } + return \OC\Share\Share::getBackend($itemType); } /** * Delete all shares with type SHARE_TYPE_LINK */ public static function removeAllLinkShares() { - // Delete any link shares - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?'); - $result = $query->execute(array(self::SHARE_TYPE_LINK)); - while ($item = $result->fetchRow()) { - self::delete($item['id']); - } + return \OC\Share\Share::removeAllLinkShares(); } /** @@ -1849,16 +335,7 @@ class Share { * @param array arguments */ public static function post_deleteUser($arguments) { - // 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']); - } + return \OC\Share\Share::post_deleteUser($arguments); } /** @@ -1867,33 +344,7 @@ class Share { * @param array arguments */ 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'); - } - } + return \OC\Share\Share::post_addToGroup($arguments); } /** @@ -1901,19 +352,7 @@ class Share { * @param array arguments */ public static function post_removeFromGroup($arguments) { - // TODO Don't call if user deleted? - $sql = 'SELECT `id`, `share_type` FROM `*PREFIX*share`' - .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'; - $result = \OC_DB::executeAudited($sql, 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']); - } - } + return \OC\Share\Share::post_removeFromGroup($arguments); } /** @@ -1921,11 +360,7 @@ class Share { * @param array arguments */ public static function post_deleteGroup($arguments) { - $sql = 'SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'; - $result = \OC_DB::executeAudited($sql, array(self::SHARE_TYPE_GROUP, $arguments['gid'])); - while ($item = $result->fetchRow()) { - self::delete($item['id']); - } + return \OC\Share\Share::post_deleteGroup($arguments); } /** @@ -1935,26 +370,7 @@ class Share { * @return bool */ public static function checkPasswordProtectedShare(array $linkItem) { - if (!isset($linkItem['share_with'])) { - return true; - } - if (!isset($linkItem['share_type'])) { - return true; - } - if (!isset($linkItem['id'])) { - return true; - } - - if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) { - return true; - } - - if ( \OC::$session->exists('public_link_authenticated') - && \OC::$session->get('public_link_authenticated') === $linkItem['id'] ) { - return true; - } - - return false; + return \OC\Share\Share::checkPasswordProtectedShare($linkItem); } } @@ -1967,9 +383,7 @@ interface Share_Backend { * Get the source of the item to be stored in the database * @param string Item source * @param string Owner of the item - * @param string $itemSource - * @param string $uidOwner - * @return boolean Source + * @return mixed|array|false Source * * Return an array if the item is file dependent, the array needs two keys: 'item' and 'file' * Return false if the item does not exist for the user @@ -1992,8 +406,8 @@ interface Share_Backend { /** * Converts the shared item sources back into the item in the specified format - * @param array $items Shared items - * @param integer $format + * @param array Shared items + * @param int Format * @return TODO * * The items array is a 3-dimensional array with the item_source as the @@ -2025,9 +439,6 @@ interface Share_Backend_File_Dependent extends Share_Backend { * Get the file path of the item * @param string Item source * @param string User that is the owner of shared item - * @param string $itemSource - * @param string $uidOwner - * @return boolean */ public function getFilePath($itemSource, $uidOwner); -- cgit v1.2.3 From b6026625781b2fda8ee1b23c3984be4a064adccc Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 18 Feb 2014 15:07:03 +0100 Subject: add a "helper" and a "hooks" class. Move constants needed by multiple classes to a "constants" class --- lib/base.php | 8 +- lib/private/share/constants.php | 44 ++++++ lib/private/share/helper.php | 202 +++++++++++++++++++++++++ lib/private/share/hooks.php | 108 ++++++++++++++ lib/private/share/share.php | 320 +++------------------------------------- lib/public/share.php | 50 +------ 6 files changed, 377 insertions(+), 355 deletions(-) create mode 100644 lib/private/share/constants.php create mode 100644 lib/private/share/helper.php create mode 100644 lib/private/share/hooks.php (limited to 'lib/private') diff --git a/lib/base.php b/lib/base.php index 2515b9657cb..b3f6776e6df 100644 --- a/lib/base.php +++ b/lib/base.php @@ -659,10 +659,10 @@ class OC { */ public static function registerShareHooks() { if (\OC_Config::getValue('installed')) { - OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser'); - OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup'); - OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup'); - OC_Hook::connect('OC_User', 'post_deleteGroup', 'OCP\Share', 'post_deleteGroup'); + OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Share\Hooks', 'post_deleteUser'); + OC_Hook::connect('OC_User', 'post_addToGroup', 'OC\Share\Hooks', 'post_addToGroup'); + OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OC\Share\Hooks', 'post_removeFromGroup'); + OC_Hook::connect('OC_User', 'post_deleteGroup', 'OC\Share\Hooks', 'post_deleteGroup'); } } diff --git a/lib/private/share/constants.php b/lib/private/share/constants.php new file mode 100644 index 00000000000..7e4223d10fa --- /dev/null +++ b/lib/private/share/constants.php @@ -0,0 +1,44 @@ + + * + * 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; + +class Constants { + + const SHARE_TYPE_USER = 0; + const SHARE_TYPE_GROUP = 1; + const SHARE_TYPE_LINK = 3; + const SHARE_TYPE_EMAIL = 4; + const SHARE_TYPE_CONTACT = 5; + const SHARE_TYPE_REMOTE = 6; + + const FORMAT_NONE = -1; + const FORMAT_STATUSES = -2; + const FORMAT_SOURCES = -3; + + const TOKEN_LENGTH = 32; // see db_structure.xml + + protected static $shareTypeUserAndGroups = -1; + protected static $shareTypeGroupUserUnique = 2; + protected static $backends = array(); + protected static $backendTypes = array(); + protected static $isResharingAllowed; +} diff --git a/lib/private/share/helper.php b/lib/private/share/helper.php new file mode 100644 index 00000000000..fde55667281 --- /dev/null +++ b/lib/private/share/helper.php @@ -0,0 +1,202 @@ + + * + * 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; + +class Helper extends \OC\Share\Constants { + + /** + * Generate a unique target for the item + * @param string Item type + * @param string Item source + * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK + * @param string User or group the item is being shared with + * @param string User that is the owner of shared item + * @param string The suggested target originating from a reshare (optional) + * @param int The id of the parent group share (optional) + * @return string Item target + */ + public static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, + $suggestedTarget = null, $groupParent = null) { + $backend = \OC\Share\Share::getBackend($itemType); + if ($shareType == self::SHARE_TYPE_LINK) { + if (isset($suggestedTarget)) { + return $suggestedTarget; + } + return $backend->generateTarget($itemSource, false); + } else { + if ($itemType == 'file' || $itemType == 'folder') { + $column = 'file_target'; + $columnSource = 'file_source'; + } else { + $column = 'item_target'; + $columnSource = 'item_source'; + } + if ($shareType == self::SHARE_TYPE_USER) { + // Share with is a user, so set share type to user and groups + $shareType = self::$shareTypeUserAndGroups; + $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith)); + } else { + $userAndGroups = false; + } + $exclude = null; + // Backend has 3 opportunities to generate a unique target + for ($i = 0; $i < 2; $i++) { + // Check if suggested target exists first + if ($i == 0 && isset($suggestedTarget)) { + $target = $suggestedTarget; + } else { + if ($shareType == self::SHARE_TYPE_GROUP) { + $target = $backend->generateTarget($itemSource, false, $exclude); + } else { + $target = $backend->generateTarget($itemSource, $shareWith, $exclude); + } + if (is_array($exclude) && in_array($target, $exclude)) { + break; + } + } + // Check if target already exists + $checkTarget = \OC\Share\Share::getItems($itemType, $target, $shareType, $shareWith); + if (!empty($checkTarget)) { + foreach ($checkTarget as $item) { + // Skip item if it is the group parent row + if (isset($groupParent) && $item['id'] == $groupParent) { + if (count($checkTarget) == 1) { + return $target; + } else { + continue; + } + } + if ($item['uid_owner'] == $uidOwner) { + if ($itemType == 'file' || $itemType == 'folder') { + $meta = \OC\Files\Filesystem::getFileInfo($itemSource); + if ($item['file_source'] == $meta['fileid']) { + return $target; + } + } else if ($item['item_source'] == $itemSource) { + return $target; + } + } + } + if (!isset($exclude)) { + $exclude = array(); + } + // Find similar targets to improve backend's chances to generate a unqiue target + if ($userAndGroups) { + if ($column == 'file_target') { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` IN (\'file\', \'folder\')' + .' AND `share_type` IN (?,?,?)' + .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, + self::$shareTypeGroupUserUnique)); + } else { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` = ? AND `share_type` IN (?,?,?)' + .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, + self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); + } + } else { + if ($column == 'file_target') { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` IN (\'file\', \'folder\')' + .' AND `share_type` = ? AND `share_with` = ?'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith)); + } else { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' + .' WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith)); + } + } + while ($row = $result->fetchRow()) { + $exclude[] = $row[$column]; + } + } else { + return $target; + } + } + } + $message = 'Sharing backend registered for '.$itemType.' did not generate a unique target for '.$itemSource; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + throw new \Exception($message); + } + + /** + * Delete all reshares of an item + * @param int Id of item to delete + * @param bool If true, exclude the parent from the delete (optional) + * @param string The user that the parent was shared with (optinal) + */ + public static function delete($parent, $excludeParent = false, $uidOwner = null) { + $ids = array($parent); + $parents = array($parent); + while (!empty($parents)) { + $parents = "'".implode("','", $parents)."'"; + // Check the owner on the first search of reshares, useful for + // finding and deleting the reshares by a single user of a group share + if (count($ids) == 1 && isset($uidOwner)) { + $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent`' + .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); + $result = $query->execute(array($uidOwner)); + } else { + $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner`' + .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); + $result = $query->execute(); + } + // Reset parents array, only go through loop again if items are found + $parents = array(); + while ($item = $result->fetchRow()) { + // Search for a duplicate parent share, this occurs when an + // item is shared to the same user through a group and user or the + // same item is shared by different users + $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner'])); + $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`' + .' WHERE `item_type` = ?' + .' AND `item_target` = ?' + .' AND `share_type` IN (?,?,?)' + .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')' + .' AND `uid_owner` != ? AND `id` != ?'); + $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], + self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, + $item['uid_owner'], $item['parent']))->fetchRow(); + if ($duplicateParent) { + // Change the parent to the other item id if share permission is granted + if ($duplicateParent['permissions'] & \OCP\PERMISSION_SHARE) { + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?'); + $query->execute(array($duplicateParent['id'], $item['id'])); + continue; + } + } + $ids[] = $item['id']; + $parents[] = $item['id']; + } + } + if ($excludeParent) { + unset($ids[0]); + } + if (!empty($ids)) { + $ids = "'".implode("','", $ids)."'"; + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$ids.')'); + $query->execute(); + } + } +} diff --git a/lib/private/share/hooks.php b/lib/private/share/hooks.php new file mode 100644 index 00000000000..a33c71eedd2 --- /dev/null +++ b/lib/private/share/hooks.php @@ -0,0 +1,108 @@ + + * + * 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; + +class Hooks extends \OC\Share\Constants { + /** + * Function that is called after a user is deleted. Cleans up the shares of that user. + * @param array arguments + */ + public static function post_deleteUser($arguments) { + // 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()) { + Helper::delete($item['id']); + } + } + + /** + * Function that is called after a user is added to a group. + * TODO what does it do? + * @param array arguments + */ + 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 = Helper::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 = Helper::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'); + } + } + } + + /** + * Function that is called after a user is removed from a group. Shares are cleaned up. + * @param array arguments + */ + public static function post_removeFromGroup($arguments) { + $sql = 'SELECT `id`, `share_type` FROM `*PREFIX*share`' + .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'; + $result = \OC_DB::executeAudited($sql, 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 + Helper::delete($item['id'], true, $arguments['uid']); + } else { + Helper::delete($item['id']); + } + } + } + + /** + * Function that is called after a group is removed. Cleans up the shares to that group. + * @param array arguments + */ + public static function post_deleteGroup($arguments) { + $sql = 'SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'; + $result = \OC_DB::executeAudited($sql, array(self::SHARE_TYPE_GROUP, $arguments['gid'])); + while ($item = $result->fetchRow()) { + Helper::delete($item['id']); + } + } + +} diff --git a/lib/private/share/share.php b/lib/private/share/share.php index b44d362672b..ef0ed257c5d 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -29,14 +29,7 @@ namespace OC\Share; * It provides the following hooks: * - post_shared */ -class Share { - - const SHARE_TYPE_USER = 0; - const SHARE_TYPE_GROUP = 1; - const SHARE_TYPE_LINK = 3; - const SHARE_TYPE_EMAIL = 4; - const SHARE_TYPE_CONTACT = 5; - const SHARE_TYPE_REMOTE = 6; +class Share extends \OC\Share\Constants { /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask * Construct permissions for share() and setPermissions with Or (|) e.g. @@ -53,18 +46,6 @@ class Share { * @see lib/public/constants.php */ - const FORMAT_NONE = -1; - const FORMAT_STATUSES = -2; - const FORMAT_SOURCES = -3; - - const TOKEN_LENGTH = 32; // see db_structure.xml - - private static $shareTypeUserAndGroups = -1; - private static $shareTypeGroupUserUnique = 2; - private static $backends = array(); - private static $backendTypes = array(); - private static $isResharingAllowed; - /** * Register a sharing backend class that implements OCP\Share_Backend for an item type * @param string Item type @@ -540,7 +521,7 @@ class Share { $oldToken = $checkExists['token']; $oldPermissions = $checkExists['permissions']; //delete the old share - self::delete($checkExists['id']); + Helper::delete($checkExists['id']); } // Generate hash of password - same method as user passwords @@ -656,14 +637,14 @@ class Share { $item['file_target'])); \OC_DB::insertid('*PREFIX*share'); // Delete all reshares by this user of the group share - self::delete($item['id'], true, \OC_User::getUser()); + Helper::delete($item['id'], true, \OC_User::getUser()); } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) { // Set permission to 0 to prevent it from showing up for the user $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?'); $query->execute(array(0, $item['id'])); - self::delete($item['id'], true); + Helper::delete($item['id'], true); } else { - self::delete($item['id']); + Helper::delete($item['id']); } return true; } @@ -732,7 +713,7 @@ class Share { if ($item['permissions'] & ~$permissions) { // If share permission is removed all reshares must be deleted if (($item['permissions'] & \OCP\PERMISSION_SHARE) && (~$permissions & \OCP\PERMISSION_SHARE)) { - self::delete($item['id'], true); + Helper::delete($item['id'], true); } else { $ids = array(); $parents = array($item['id']); @@ -839,7 +820,7 @@ class Share { \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams + array( 'fileSource' => $item['file_source'], )); - self::delete($item['id']); + Helper::delete($item['id']); \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams); } @@ -931,7 +912,7 @@ class Share { * See public functions getItem(s)... for parameter usage * */ - private static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, + public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) { if (!self::isEnabled()) { @@ -1417,7 +1398,7 @@ class Share { .' `file_target`, `token`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)'); // Share with a group if ($shareType == self::SHARE_TYPE_GROUP) { - $groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], + $groupItemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget); $run = true; $error = ''; @@ -1442,7 +1423,7 @@ class Share { if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { - $groupFileTarget = self::generateTarget('file', $filePath, $shareType, + $groupFileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget); // Set group default file target for future use $parentFolders[0]['folder'] = $groupFileTarget; @@ -1452,7 +1433,7 @@ class Share { $parent = $parentFolder[0]['id']; } } else { - $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], + $groupFileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget); } } else { @@ -1464,12 +1445,12 @@ class Share { $parent = \OC_DB::insertid('*PREFIX*share'); // Loop through all users of this group in case we need to add an extra row foreach ($shareWith['users'] as $uid) { - $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, + $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedItemTarget, $parent); if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, + $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent); if ($fileTarget != $groupFileTarget) { $parentFolders[$uid]['folder'] = $fileTarget; @@ -1479,7 +1460,7 @@ class Share { $parent = $parentFolder[$uid]['id']; } } else { - $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, + $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent); } } else { @@ -1513,7 +1494,7 @@ class Share { return $parentFolders; } } else { - $itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, + $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedItemTarget); $run = true; $error = ''; @@ -1538,7 +1519,7 @@ class Share { if (isset($fileSource)) { if ($parentFolder) { if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, + $fileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget); $parentFolders['folder'] = $fileTarget; } else { @@ -1546,7 +1527,7 @@ class Share { $parent = $parentFolder['id']; } } else { - $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, + $fileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget); } } else { @@ -1578,183 +1559,6 @@ class Share { return true; } - /** - * Generate a unique target for the item - * @param string Item type - * @param string Item source - * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK - * @param string User or group the item is being shared with - * @param string User that is the owner of shared item - * @param string The suggested target originating from a reshare (optional) - * @param int The id of the parent group share (optional) - * @return string Item target - */ - private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, - $suggestedTarget = null, $groupParent = null) { - $backend = self::getBackend($itemType); - if ($shareType == self::SHARE_TYPE_LINK) { - if (isset($suggestedTarget)) { - return $suggestedTarget; - } - return $backend->generateTarget($itemSource, false); - } else { - if ($itemType == 'file' || $itemType == 'folder') { - $column = 'file_target'; - $columnSource = 'file_source'; - } else { - $column = 'item_target'; - $columnSource = 'item_source'; - } - if ($shareType == self::SHARE_TYPE_USER) { - // Share with is a user, so set share type to user and groups - $shareType = self::$shareTypeUserAndGroups; - $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith)); - } else { - $userAndGroups = false; - } - $exclude = null; - // Backend has 3 opportunities to generate a unique target - for ($i = 0; $i < 2; $i++) { - // Check if suggested target exists first - if ($i == 0 && isset($suggestedTarget)) { - $target = $suggestedTarget; - } else { - if ($shareType == self::SHARE_TYPE_GROUP) { - $target = $backend->generateTarget($itemSource, false, $exclude); - } else { - $target = $backend->generateTarget($itemSource, $shareWith, $exclude); - } - if (is_array($exclude) && in_array($target, $exclude)) { - break; - } - } - // Check if target already exists - $checkTarget = self::getItems($itemType, $target, $shareType, $shareWith); - if (!empty($checkTarget)) { - foreach ($checkTarget as $item) { - // Skip item if it is the group parent row - if (isset($groupParent) && $item['id'] == $groupParent) { - if (count($checkTarget) == 1) { - return $target; - } else { - continue; - } - } - if ($item['uid_owner'] == $uidOwner) { - if ($itemType == 'file' || $itemType == 'folder') { - $meta = \OC\Files\Filesystem::getFileInfo($itemSource); - if ($item['file_source'] == $meta['fileid']) { - return $target; - } - } else if ($item['item_source'] == $itemSource) { - return $target; - } - } - } - if (!isset($exclude)) { - $exclude = array(); - } - // Find similar targets to improve backend's chances to generate a unqiue target - if ($userAndGroups) { - if ($column == 'file_target') { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` IN (\'file\', \'folder\')' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); - $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, - self::$shareTypeGroupUserUnique)); - } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` = ? AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); - $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, - self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); - } - } else { - if ($column == 'file_target') { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` IN (\'file\', \'folder\')' - .' AND `share_type` = ? AND `share_with` = ?'); - $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith)); - } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share`' - .' WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?'); - $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith)); - } - } - while ($row = $result->fetchRow()) { - $exclude[] = $row[$column]; - } - } else { - return $target; - } - } - } - $message = 'Sharing backend registered for '.$itemType.' did not generate a unique target for '.$itemSource; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } - - /** - * Delete all reshares of an item - * @param int Id of item to delete - * @param bool If true, exclude the parent from the delete (optional) - * @param string The user that the parent was shared with (optinal) - */ - private static function delete($parent, $excludeParent = false, $uidOwner = null) { - $ids = array($parent); - $parents = array($parent); - while (!empty($parents)) { - $parents = "'".implode("','", $parents)."'"; - // Check the owner on the first search of reshares, useful for - // finding and deleting the reshares by a single user of a group share - if (count($ids) == 1 && isset($uidOwner)) { - $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent`' - .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); - $result = $query->execute(array($uidOwner)); - } else { - $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner`' - .' FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); - $result = $query->execute(); - } - // Reset parents array, only go through loop again if items are found - $parents = array(); - while ($item = $result->fetchRow()) { - // Search for a duplicate parent share, this occurs when an - // item is shared to the same user through a group and user or the - // same item is shared by different users - $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner'])); - $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share`' - .' WHERE `item_type` = ?' - .' AND `item_target` = ?' - .' AND `share_type` IN (?,?,?)' - .' AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')' - .' AND `uid_owner` != ? AND `id` != ?'); - $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], - self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, - $item['uid_owner'], $item['parent']))->fetchRow(); - if ($duplicateParent) { - // Change the parent to the other item id if share permission is granted - if ($duplicateParent['permissions'] & \OCP\PERMISSION_SHARE) { - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?'); - $query->execute(array($duplicateParent['id'], $item['id'])); - continue; - } - } - $ids[] = $item['id']; - $parents[] = $item['id']; - } - } - if ($excludeParent) { - unset($ids[0]); - } - if (!empty($ids)) { - $ids = "'".implode("','", $ids)."'"; - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$ids.')'); - $query->execute(); - } - } - /** * Delete all shares with type SHARE_TYPE_LINK */ @@ -1763,95 +1567,7 @@ class Share { $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ?'); $result = $query->execute(array(self::SHARE_TYPE_LINK)); while ($item = $result->fetchRow()) { - self::delete($item['id']); - } - } - - /** - * Hook Listeners - */ - - /** - * Function that is called after a user is deleted. Cleans up the shares of that user. - * @param array arguments - */ - public static function post_deleteUser($arguments) { - // 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']); - } - } - - /** - * Function that is called after a user is added to a group. - * TODO what does it do? - * @param array arguments - */ - 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'); - } - } - } - - /** - * Function that is called after a user is removed from a group. Shares are cleaned up. - * @param array arguments - */ - public static function post_removeFromGroup($arguments) { - // TODO Don't call if user deleted? - $sql = 'SELECT `id`, `share_type` FROM `*PREFIX*share`' - .' WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)'; - $result = \OC_DB::executeAudited($sql, 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']); - } - } - } - - /** - * Function that is called after a group is removed. Cleans up the shares to that group. - * @param array arguments - */ - public static function post_deleteGroup($arguments) { - $sql = 'SELECT `id` FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?'; - $result = \OC_DB::executeAudited($sql, array(self::SHARE_TYPE_GROUP, $arguments['gid'])); - while ($item = $result->fetchRow()) { - self::delete($item['id']); + Helper::delete($item['id']); } } diff --git a/lib/public/share.php b/lib/public/share.php index adc02dfe8c4..fcc61b2f4fd 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -37,18 +37,7 @@ namespace OCP; * It provides the following hooks: * - post_shared */ -class Share { - - const FORMAT_NONE = -1; - const FORMAT_STATUSES = -2; - const FORMAT_SOURCES = -3; - - const SHARE_TYPE_USER = 0; - const SHARE_TYPE_GROUP = 1; - const SHARE_TYPE_LINK = 3; - const SHARE_TYPE_EMAIL = 4; - const SHARE_TYPE_CONTACT = 5; - const SHARE_TYPE_REMOTE = 6; +class Share extends \OC\Share\Constants { /** * Register a sharing backend class that implements OCP\Share_Backend for an item type @@ -326,43 +315,6 @@ class Share { return \OC\Share\Share::removeAllLinkShares(); } - /** - * Hook Listeners - */ - - /** - * Function that is called after a user is deleted. Cleans up the shares of that user. - * @param array arguments - */ - public static function post_deleteUser($arguments) { - return \OC\Share\Share::post_deleteUser($arguments); - } - - /** - * Function that is called after a user is added to a group. - * TODO what does it do? - * @param array arguments - */ - public static function post_addToGroup($arguments) { - return \OC\Share\Share::post_addToGroup($arguments); - } - - /** - * Function that is called after a user is removed from a group. Shares are cleaned up. - * @param array arguments - */ - public static function post_removeFromGroup($arguments) { - return \OC\Share\Share::post_removeFromGroup($arguments); - } - - /** - * Function that is called after a group is removed. Cleans up the shares to that group. - * @param array arguments - */ - public static function post_deleteGroup($arguments) { - return \OC\Share\Share::post_deleteGroup($arguments); - } - /** * In case a password protected link is not yet authenticated this function will return false * -- cgit v1.2.3 From 6afd496d9bf64cdc911bab6393d24240db3df04d Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 18 Feb 2014 16:32:49 +0100 Subject: remove prepFileTarget() seems that it is no longer in use --- lib/private/share/share.php | 18 ------------------ lib/public/share.php | 9 --------- 2 files changed, 27 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index ef0ed257c5d..c819f6bf54c 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -89,24 +89,6 @@ class Share extends \OC\Share\Constants { return false; } - /** - * Prepare a path to be passed to DB as file_target - * @param string $path path - * @return string Prepared path - */ - public static function prepFileTarget( $path ) { - - // Paths in DB are stored with leading slashes, so add one if necessary - if ( substr( $path, 0, 1 ) !== '/' ) { - - $path = '/' . $path; - - } - - return $path; - - } - /** * Find which users can access a shared item * @param $path to the file diff --git a/lib/public/share.php b/lib/public/share.php index fcc61b2f4fd..a08134b3837 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -61,15 +61,6 @@ class Share extends \OC\Share\Constants { return \OC\Share\Share::isEnabled(); } - /** - * Prepare a path to be passed to DB as file_target - * @param string $path path - * @return string Prepared path - */ - public static function prepFileTarget($path) { - return \OC\Share\Share::prepFileTarget($path); - } - /** * Find which users can access a shared item * @param $path to the file -- cgit v1.2.3 From 6607f7cb5e170568129ddd3ea0a7839a7f6229b5 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 3 Mar 2014 17:06:45 +0100 Subject: seperate creation of select statement --- lib/private/share/share.php | 82 ++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 38 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index c819f6bf54c..d743cfccb71 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -1032,44 +1032,7 @@ class Share extends \OC\Share\Constants { } else { $queryLimit = null; } - // TODO Optimize selects - if ($format == self::FORMAT_STATUSES) { - if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' - .' `share_type`, `file_source`, `path`, `expiration`, `storage`, `share_with`, `mail_send`, `uid_owner`'; - } else { - $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `expiration`, `mail_send`, `uid_owner`'; - } - } else { - if (isset($uidOwner)) { - if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' - .' `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`,' - .' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`'; - } else { - $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`,' - .' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; - } - } else { - if ($fileDependent) { - if (($itemType == 'file' || $itemType == 'folder') - && $format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS - || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT - ) { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' - .'`share_type`, `share_with`, `file_source`, `path`, `file_target`, ' - .'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' - .'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; - } else { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, - `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, - `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`'; - } - } else { - $select = '*'; - } - } - } + $select = self::createSelectStatement($format, $fileDependent, $uidOwner); $root = strlen($root); $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit); $result = $query->execute($queryArgs); @@ -1581,4 +1544,47 @@ class Share extends \OC\Share\Constants { return false; } + + /** + * @breif construct select statement + * @param int $format + * @param bool $fileDependent ist it a file/folder share or a generla share + * @param string $uidOwner + * @return string select statement + */ + private static function createSelectStatement($format, $fileDependent, $uidOwner = null) { + $select = '*'; + if ($format == self::FORMAT_STATUSES) { + if ($fileDependent) { + $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `share_with`, `uid_owner`'; + } else { + $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`'; + } + } else { + if (isset($uidOwner)) { + if ($fileDependent) { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' + . ' `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`,' + . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`'; + } else { + $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`,' + . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; + } + } else { + if ($fileDependent) { + if ($format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' + . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, ' + . '`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' + . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; + } else { + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, + `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, + `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`'; + } + } + } + } + return $select; + } } -- cgit v1.2.3 From 3a459db3585f02d02c492dc3ce836e2fea1c8cb2 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 3 Mar 2014 17:20:09 +0100 Subject: seperate transformDBResults --- lib/private/share/share.php | 57 ++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index d743cfccb71..45ed4c70458 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -1046,30 +1046,7 @@ class Share extends \OC\Share\Constants { $switchedItems = array(); $mounts = array(); while ($row = $result->fetchRow()) { - if (isset($row['id'])) { - $row['id']=(int)$row['id']; - } - if (isset($row['share_type'])) { - $row['share_type']=(int)$row['share_type']; - } - if (isset($row['parent'])) { - $row['parent']=(int)$row['parent']; - } - if (isset($row['file_parent'])) { - $row['file_parent']=(int)$row['file_parent']; - } - if (isset($row['file_source'])) { - $row['file_source']=(int)$row['file_source']; - } - if (isset($row['permissions'])) { - $row['permissions']=(int)$row['permissions']; - } - if (isset($row['storage'])) { - $row['storage']=(int)$row['storage']; - } - if (isset($row['stime'])) { - $row['stime']=(int)$row['stime']; - } + self::transformDBResults($row); // Filter out duplicate group shares for users with unique targets if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) { $row['share_type'] = self::SHARE_TYPE_GROUP; @@ -1587,4 +1564,36 @@ class Share extends \OC\Share\Constants { } return $select; } + + + /** + * @brief transform db results + * @param array $row result + */ + private static function transformDBResults(&$row) { + if (isset($row['id'])) { + $row['id'] = (int) $row['id']; + } + if (isset($row['share_type'])) { + $row['share_type'] = (int) $row['share_type']; + } + if (isset($row['parent'])) { + $row['parent'] = (int) $row['parent']; + } + if (isset($row['file_parent'])) { + $row['file_parent'] = (int) $row['file_parent']; + } + if (isset($row['file_source'])) { + $row['file_source'] = (int) $row['file_source']; + } + if (isset($row['permissions'])) { + $row['permissions'] = (int) $row['permissions']; + } + if (isset($row['storage'])) { + $row['storage'] = (int) $row['storage']; + } + if (isset($row['stime'])) { + $row['stime'] = (int) $row['stime']; + } + } } -- cgit v1.2.3 From 078fafdc5ace1981a9e5582ac66cc087a1277aed Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 3 Mar 2014 17:24:31 +0100 Subject: use variable --- lib/private/share/share.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 45ed4c70458..48dd3cd68ea 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -973,13 +973,13 @@ class Share extends \OC\Share\Constants { $where .= ' AND `share_type` != ?'; $queryArgs[] = self::$shareTypeGroupUserUnique; } - if ($itemType == 'file' || $itemType == 'folder') { + if ($fileDependent) { $column = 'file_source'; } else { $column = 'item_source'; } } else { - if ($itemType == 'file' || $itemType == 'folder') { + if ($fileDependent) { $column = 'file_target'; } else { $column = 'item_target'; @@ -994,7 +994,7 @@ class Share extends \OC\Share\Constants { // If looking for own shared items, check item_source else check item_target if (isset($uidOwner) || $itemShareWithBySource) { // If item type is a file, file source needs to be checked in case the item was converted - if ($itemType == 'file' || $itemType == 'folder') { + if ($fileDependent) { $where .= ' `file_source` = ?'; $column = 'file_source'; } else { @@ -1002,7 +1002,7 @@ class Share extends \OC\Share\Constants { $column = 'item_source'; } } else { - if ($itemType == 'file' || $itemType == 'folder') { + if ($fileDependent) { $where .= ' `file_target` = ?'; $item = \OC\Files\Filesystem::normalizePath($item); } else { @@ -1225,7 +1225,7 @@ class Share extends \OC\Share\Constants { } else if (!isset($statuses[$item[$column]])) { $statuses[$item[$column]]['link'] = false; } - if ($itemType == 'file' || $itemType == 'folder') { + if ($fileDependent) { $statuses[$item[$column]]['path'] = $item['path']; } } @@ -1296,7 +1296,6 @@ class Share extends \OC\Share\Constants { \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } - $parent = null; if ($backend instanceof \OCP\Share_Backend_File_Dependent) { $filePath = $backend->getFilePath($itemSource, $uidOwner); if ($itemType == 'file' || $itemType == 'folder') { -- cgit v1.2.3 From ecde48fce8b0cc580161da539b44899c406cd10d Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 3 Mar 2014 17:27:26 +0100 Subject: don't assign variables in if conditions --- lib/private/share/share.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 48dd3cd68ea..69d93797ba0 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -923,7 +923,8 @@ class Share extends \OC\Share\Constants { } else { $fileDependent = false; $root = ''; - if ($includeCollections && !isset($item) && ($collectionTypes = self::getCollectionItemTypes($itemType))) { + $collectionTypes = self::getCollectionItemTypes($itemType); + if ($includeCollections && !isset($item) && $collectionTypes) { // If includeCollections is true, find collections of this item type, e.g. a music album contains songs if (!in_array($itemType, $collectionTypes)) { $itemTypes = array_merge(array($itemType), $collectionTypes); @@ -986,7 +987,8 @@ class Share extends \OC\Share\Constants { } } if (isset($item)) { - if ($includeCollections && $collectionTypes = self::getCollectionItemTypes($itemType)) { + $collectionTypes = self::getCollectionItemTypes($itemType); + if ($includeCollections && $collectionTypes) { $where .= ' AND ('; } else { $where .= ' AND'; -- cgit v1.2.3 From 154277ab1139c0705be2947c4c9995794c7d092b Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 3 Mar 2014 17:30:16 +0100 Subject: seperate formatResults() --- lib/private/share/share.php | 49 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 69d93797ba0..f6f2ac8ccf8 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -1217,24 +1217,7 @@ class Share extends \OC\Share\Constants { if (empty($items) && $limit == 1) { return false; } - if ($format == self::FORMAT_NONE) { - return $items; - } else if ($format == self::FORMAT_STATUSES) { - $statuses = array(); - foreach ($items as $item) { - if ($item['share_type'] == self::SHARE_TYPE_LINK) { - $statuses[$item[$column]]['link'] = true; - } else if (!isset($statuses[$item[$column]])) { - $statuses[$item[$column]]['link'] = false; - } - if ($fileDependent) { - $statuses[$item[$column]]['path'] = $item['path']; - } - } - return $statuses; - } else { - return $backend->formatItems($items, $format, $parameters); - } + return self::formatResult($items, $column, $backend, $format, $parameters); } else if ($limit == 1 || (isset($uidOwner) && isset($item))) { return false; } @@ -1597,4 +1580,34 @@ class Share extends \OC\Share\Constants { $row['stime'] = (int) $row['stime']; } } + + /** + * @brief format result + * @param array $items result + * @prams string $column is it a file share or a general share ('file_target' or 'item_target') + * @params \OCP\Share_Backend $backend sharing backend + * @param int $format + * @param array additional format parameters + * @return array formate result + */ + private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) { + if ($format === self::FORMAT_NONE) { + return $items; + } else if ($format === self::FORMAT_STATUSES) { + $statuses = array(); + foreach ($items as $item) { + if ($item['share_type'] === self::SHARE_TYPE_LINK) { + $statuses[$item[$column]]['link'] = true; + } else if (!isset($statuses[$item[$column]])) { + $statuses[$item[$column]]['link'] = false; + } + if ('file_target') { + $statuses[$item[$column]]['path'] = $item['path']; + } + } + return $statuses; + } else { + return $backend->formatItems($items, $format, $parameters); + } + } } -- cgit v1.2.3 From bc0292c16d5fa8e99727306ef703da1e018defa2 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 6 Mar 2014 14:00:12 +0100 Subject: always return an array --- lib/private/share/share.php | 15 ++++----------- tests/lib/share/share.php | 12 ++++++------ 2 files changed, 10 insertions(+), 17 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index f6f2ac8ccf8..b69f620646f 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -889,7 +889,7 @@ class Share extends \OC\Share\Constants { * @param bool Include collection item types (optional) * @param bool TODO (optional) * @prams bool check expire date - * @return mixed + * @return array * * See public functions getItem(s)... for parameter usage * @@ -898,11 +898,7 @@ class Share extends \OC\Share\Constants { $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) { if (!self::isEnabled()) { - if ($limit == 1 || (isset($uidOwner) && isset($item))) { - return false; - } else { - return array(); - } + return array(); } $backend = self::getBackend($itemType); $collectionTypes = false; @@ -1214,13 +1210,10 @@ class Share extends \OC\Share\Constants { if (!empty($collectionItems)) { $items = array_merge($items, $collectionItems); } - if (empty($items) && $limit == 1) { - return false; - } + return self::formatResult($items, $column, $backend, $format, $parameters); - } else if ($limit == 1 || (isset($uidOwner) && isset($item))) { - return false; } + return array(); } diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php index b5cba9430aa..aae91fa1087 100644 --- a/tests/lib/share/share.php +++ b/tests/lib/share/share.php @@ -282,7 +282,7 @@ class Test_Share extends PHPUnit_Framework_TestCase { 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')); + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt')); // Reshare again, and then have owner unshare OC_User::setUserId($this->user1); @@ -292,9 +292,9 @@ class Test_Share extends PHPUnit_Framework_TestCase { 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')); + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt')); OC_User::setUserId($this->user3); - $this->assertFalse(OCP\Share::getItemSharedWith('test', 'test.txt')); + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt')); // Attempt target conflict OC_User::setUserId($this->user1); @@ -325,7 +325,7 @@ class Test_Share extends PHPUnit_Framework_TestCase { ); OC_User::setUserId($this->user2); - $this->assertFalse( + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE), 'Failed asserting that user 2 no longer has access to test.txt after expiration.' ); @@ -526,13 +526,13 @@ class Test_Share extends PHPUnit_Framework_TestCase { ); OC_User::setUserId($this->user2); - $this->assertFalse( + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE), 'Failed asserting that user 2 no longer has access to test.txt after expiration.' ); OC_User::setUserId($this->user3); - $this->assertFalse( + $this->assertSame(array(), OCP\Share::getItemSharedWith('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE), 'Failed asserting that user 3 no longer has access to test.txt after expiration.' ); -- cgit v1.2.3 From 5db3b049fd459e3a8e6e36a3a9e12f53e97c4b0b Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 6 Mar 2014 15:30:01 +0100 Subject: add todo --- lib/private/share/share.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index b69f620646f..3471514c487 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -1170,7 +1170,7 @@ class Share extends \OC\Share\Constants { if ($backend instanceof \OCP\Share_Backend_File_Dependent) { if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { $childItem['file_source'] = $child['source']; - } else { + } else { // TODO is this really needed if we already know that we use the file backend? $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']); $childItem['file_source'] = $meta['fileid']; } -- cgit v1.2.3 From 2d8607fae92e083a431d476f670acdbc1cfdc947 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 7 Mar 2014 15:38:14 +0100 Subject: don't assign variables in if condition --- lib/private/share/share.php | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 3471514c487..ae7b6f5fbc7 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -556,8 +556,8 @@ class Share extends \OC\Share\Constants { * @return Returns true on success or false on failure */ public static function unshare($itemType, $itemSource, $shareType, $shareWith) { - if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), - self::FORMAT_NONE, null, 1)) { + $item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(),self::FORMAT_NONE, null, 1); + if (!empty($item)) { self::unshareItem($item); return true; } @@ -605,7 +605,8 @@ class Share extends \OC\Share\Constants { * Unsharing from self is not allowed for items inside collections */ public static function unshareFromSelf($itemType, $itemTarget) { - if ($item = self::getItemSharedWith($itemType, $itemTarget)) { + $item = self::getItemSharedWith($itemType, $itemTarget); + if (!empty($item)) { if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) { // Insert an extra row for the group share and set permission // to 0 to prevent it from showing up for the user @@ -746,22 +747,20 @@ class Share extends \OC\Share\Constants { * @return \OCP\Share_Backend */ public static function setExpirationDate($itemType, $itemSource, $date) { - if ($items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), - self::FORMAT_NONE, null, -1, false)) { - if (!empty($items)) { - if ($date == '') { - $date = null; - } else { - $date = new \DateTime($date); - } - $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `id` = ?'); - $query->bindValue(1, $date, 'datetime'); - foreach ($items as $item) { - $query->bindValue(2, (int) $item['id']); - $query->execute(); - } - return true; + $items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE, null, -1, false); + if (!empty($items)) { + if ($date == '') { + $date = null; + } else { + $date = new \DateTime($date); + } + $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `id` = ?'); + $query->bindValue(1, $date, 'datetime'); + foreach ($items as $item) { + $query->bindValue(2, (int) $item['id']); + $query->execute(); } + return true; } return false; } -- cgit v1.2.3 From 3653a51af2f21065f7afad40624e053f0dfaadb3 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 11 Mar 2014 12:58:46 +0100 Subject: fix path creation for re-shares, issue #7662 --- apps/files_sharing/tests/api.php | 83 ---------------------------------------- lib/private/share/share.php | 9 ++++- 2 files changed, 7 insertions(+), 85 deletions(-) (limited to 'lib/private') diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php index e2bbb548182..4ada0118d37 100644 --- a/apps/files_sharing/tests/api.php +++ b/apps/files_sharing/tests/api.php @@ -477,89 +477,6 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base { } - /** - * @brief test multiple shared folder if the path gets constructed correctly - * @medium - */ - function testGetShareMultipleSharedFolder() { - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - - $fileInfo1 = $this->view->getFileInfo($this->folder); - $fileInfo2 = $this->view->getFileInfo($this->folder . $this->subfolder); - - - // share sub-folder to user2 - $result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - - // share was successful? - $this->assertTrue($result); - - // share folder to user2 - $result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); - - // share was successful? - $this->assertTrue($result); - - - // login as user2 - self::loginHelper(self::TEST_FILES_SHARING_API_USER2); - - $result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1); - // share was successful? - $this->assertTrue(is_string($result)); - - - // ask for shared/subfolder - $expectedPath1 = '/Shared' . $this->subfolder; - $_GET['path'] = $expectedPath1; - - $result1 = Share\Api::getAllShares(array()); - - $this->assertTrue($result1->succeeded()); - - // test should return one share within $this->folder - $data1 = $result1->getData(); - $share1 = reset($data1); - - // ask for shared/folder/subfolder - $expectedPath2 = '/Shared' . $this->folder . $this->subfolder; - $_GET['path'] = $expectedPath2; - - $result2 = Share\Api::getAllShares(array()); - - $this->assertTrue($result2->succeeded()); - - // test should return one share within $this->folder - $data2 = $result2->getData(); - $share2 = reset($data2); - - - // validate results - // we should get exactly one result each time - $this->assertEquals(1, count($data1)); - $this->assertEquals(1, count($data2)); - - $this->assertEquals($expectedPath1, $share1['path']); - $this->assertEquals($expectedPath2, $share2['path']); - - - // cleanup - $result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); - $this->assertTrue($result); - - self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $result = \OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - $result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, - \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); - $this->assertTrue($result); - - } - /** * @brief test re-re-share of folder if the path gets constructed correctly * @medium diff --git a/lib/private/share/share.php b/lib/private/share/share.php index ae7b6f5fbc7..e4886abd2b5 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -1087,18 +1087,23 @@ class Share extends \OC\Share\Constants { if (isset($row['parent'])) { $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?'); $parentResult = $query->execute(array($row['parent'])); + //$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?'); + //$parentResult = $query->execute(array($row['id'])); if (\OC_DB::isError($result)) { \OC_Log::write('OCP\Share', 'Can\'t select parent: ' . \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, \OC_Log::ERROR); } else { $parentRow = $parentResult->fetchRow(); - $splitPath = explode('/', $row['path']); $tmpPath = '/Shared' . $parentRow['file_target']; + // find the right position where the row path continues from the target path + $pos = strrpos($row['path'], $parentRow['file_target']); + $subPath = substr($row['path'], $pos); + $splitPath = explode('/', $subPath); foreach (array_slice($splitPath, 2) as $pathPart) { $tmpPath = $tmpPath . '/' . $pathPart; } - $row['path'] = $tmpPath; + $row['path'] = $tmpPath; } } else { if (!isset($mounts[$row['storage']])) { -- cgit v1.2.3 From 31681a3a27d1f36a980a044479a5948b4310ebe5 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 12 Mar 2014 11:00:30 +0100 Subject: finally fix the paths for the OCS Share API --- apps/files_sharing/tests/api.php | 85 +++++++++++++++++++++++++++++++++++++++- lib/private/share/share.php | 6 ++- 2 files changed, 88 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php index 4ada0118d37..e3c5b6e4315 100644 --- a/apps/files_sharing/tests/api.php +++ b/apps/files_sharing/tests/api.php @@ -477,6 +477,89 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base { } + /** + * @brief test multiple shared folder if the path gets constructed correctly + * @medium + */ + function testGetShareMultipleSharedFolder() { + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $fileInfo1 = $this->view->getFileInfo($this->folder); + $fileInfo2 = $this->view->getFileInfo($this->folder . $this->subfolder); + + + // share sub-folder to user2 + $result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + // share was successful? + $this->assertTrue($result); + + // share folder to user2 + $result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31); + + // share was successful? + $this->assertTrue($result); + + + // login as user2 + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + $result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1); + // share was successful? + $this->assertTrue(is_string($result)); + + + // ask for shared/subfolder + $expectedPath1 = '/Shared' . $this->subfolder; + $_GET['path'] = $expectedPath1; + + $result1 = Share\Api::getAllShares(array()); + + $this->assertTrue($result1->succeeded()); + + // test should return one share within $this->folder + $data1 = $result1->getData(); + $share1 = reset($data1); + + // ask for shared/folder/subfolder + $expectedPath2 = '/Shared' . $this->folder . $this->subfolder; + $_GET['path'] = $expectedPath2; + + $result2 = Share\Api::getAllShares(array()); + + $this->assertTrue($result2->succeeded()); + + // test should return one share within $this->folder + $data2 = $result2->getData(); + $share2 = reset($data2); + + + // validate results + // we should get exactly one result each time + $this->assertEquals(1, count($data1)); + $this->assertEquals(1, count($data2)); + + $this->assertEquals($expectedPath1, $share1['path']); + $this->assertEquals($expectedPath2, $share2['path']); + + + // cleanup + $result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + $this->assertTrue($result); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + $result = \OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + $this->assertTrue($result); + $result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER, + \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2); + $this->assertTrue($result); + + } + /** * @brief test re-re-share of folder if the path gets constructed correctly * @medium @@ -803,5 +886,5 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base { class TestShareApi extends \OCA\Files\Share\Api { public function correctPathTest($path, $folder) { return self::correctPath($path, $folder); -} + } } diff --git a/lib/private/share/share.php b/lib/private/share/share.php index e4886abd2b5..a385328edc1 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -1085,10 +1085,12 @@ class Share extends \OC\Share\Constants { // Remove root from file source paths if retrieving own shared items if (isset($uidOwner) && isset($row['path'])) { if (isset($row['parent'])) { + // FIXME: Doesn't always construct the correct path, example: + // Folder '/a/b', share '/a' and '/a/b' to user2 + // user2 reshares /Shared/b and ask for share status of /Shared/a/b + // expected result: path=/Shared/a/b; actual result /Shared/b because of the parent $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?'); $parentResult = $query->execute(array($row['parent'])); - //$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?'); - //$parentResult = $query->execute(array($row['id'])); if (\OC_DB::isError($result)) { \OC_Log::write('OCP\Share', 'Can\'t select parent: ' . \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, -- cgit v1.2.3 From 6bfeb342db32feff686f4fc6d7bd0d42de9d297b Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 25 Mar 2014 23:17:00 +0100 Subject: fixing code style --- lib/private/util.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/util.php b/lib/private/util.php index d039d9f6a96..7168ed00244 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -514,8 +514,7 @@ class OC_Util { ); } } - } - catch (\Doctrine\DBAL\DBALException $e){ + } catch (\Doctrine\DBAL\DBALException $e) { \OCP\Util::logException('core', $e); $errors[] = array( 'error' => 'Error occurred while checking PostgreSQL version', -- cgit v1.2.3 From e76be308eb8e969b1a4b74d97c2ccb320a986937 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 26 Mar 2014 09:39:09 +0100 Subject: Remove unused setUserVars utility method That method was moved to the external storage recently so isn't needed here any more. --- lib/private/files/filesystem.php | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'lib/private') diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 56bafc7e974..7e27650c557 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -350,17 +350,6 @@ class Filesystem { } } - /** - * fill in the correct values for $user - * - * @param string $user - * @param string $input - * @return string - */ - private static function setUserVars($user, $input) { - return str_replace('$user', $user, $input); - } - /** * get the default filesystem view * -- cgit v1.2.3 From 9b2bb7c6abba9cdbcd982c7460e43d024b11198b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 26 Mar 2014 13:02:11 +0100 Subject: fix undefined index warning in router --- lib/private/route/router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/route/router.php b/lib/private/route/router.php index bad74c925fa..1f0a23ee124 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -114,7 +114,7 @@ class Router implements IRouter { } } foreach ($routingFiles as $app => $file) { - if (!$this->loadedApps[$app]) { + if (!isset($this->loadedApps[$app])) { $this->loadedApps[$app] = true; $this->useCollection($app); require_once $file; -- cgit v1.2.3 From 93b984ecf8da4148fa10a72a35ce5cba371c7a87 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 26 Mar 2014 15:36:55 +0100 Subject: css files are not to be routed through index.php anymore --- lib/private/urlgenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php index 44b46ef6700..b7ae8dd0f60 100644 --- a/lib/private/urlgenerator.php +++ b/lib/private/urlgenerator.php @@ -60,7 +60,7 @@ class URLGenerator implements IURLGenerator { $app_path = \OC_App::getAppPath($app); // Check if the app is in the app folder if ($app_path && file_exists($app_path . '/' . $file)) { - if (substr($file, -3) == 'php' || substr($file, -3) == 'css') { + if (substr($file, -3) == 'php') { $urlLinkTo = \OC::$WEBROOT . '/index.php/apps/' . $app; if ($frontControllerActive) { -- cgit v1.2.3 From b48510c978810a485f3ab72b28ec1c32350a6332 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 26 Mar 2014 18:14:35 +0100 Subject: Use the correct resolve method to resolve file storage When detecting whether the file to be downloaded is on external storage, the correct path needs to be used. It turns out that \OC\Files\View is needed to resolve the path correctly relative to the user's home. --- lib/private/files.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/files.php b/lib/private/files.php index 7e7a27f48dc..bfe6d3c02da 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -148,8 +148,9 @@ class OC_Files { set_time_limit($executionTime); } else { if ($xsendfile) { + $view = \OC\Files\Filesystem::getView(); /** @var $storage \OC\Files\Storage\Storage */ - list($storage) = \OC\Files\Filesystem::resolvePath($filename); + list($storage) = $view->resolvePath($filename); if ($storage->isLocal()) { self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename)); } else { -- cgit v1.2.3 From 2d592ddc8f26e72211d1c01cec8979cd371b8215 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 28 Mar 2014 12:07:44 +0100 Subject: Fix CURLOPT_FOLLOWLOCATION bug with open_basedir or safe_mode restriction enabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commit of the following: commit eaf4f43f687db59137a0b00bc0e12ed4eb0d0943 Merge: 1e9c5be 1e7d7bd Author: Thomas Müller Date: Fri Mar 28 11:49:04 2014 +0100 Merge branch 'master' of https://github.com/kev300/core into kev300-master commit 1e7d7bdd8b5c7f301501cb822cdf2ef0ad3f2872 Author: kev300 Date: Tue Dec 17 14:11:42 2013 +0100 Update util.php commit 3f0723f054a27a506be7f26932ccb54fff6f2be9 Author: kev300 Date: Tue Dec 17 14:09:15 2013 +0100 Update util.php commit 512176abdcfbe5b2b060b91033abc9608912d1f8 Author: kev300 Date: Tue Dec 17 14:02:04 2013 +0100 Update util.php commit 6cbefd080188d287024e0b047b88dd4525d6c2c1 Author: kev300 Date: Mon Dec 16 16:44:46 2013 +0100 Update util.php Fix CURLOPT_FOLLOWLOCATION bug with open_basedir or safe_mode restriction enabled. --- lib/private/util.php | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/private/util.php b/lib/private/util.php index cd152234cc9..c48a5505d41 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -1072,13 +1072,13 @@ class OC_Util { public static function getUrlContent($url) { if (function_exists('curl_init')) { $curl = curl_init(); + $max_redirects = 10; curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($curl, CURLOPT_URL, $url); - curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($curl, CURLOPT_MAXREDIRS, 10); + curl_setopt($curl, CURLOPT_USERAGENT, "ownCloud Server Crawler"); if(OC_Config::getValue('proxy', '') != '') { @@ -1087,9 +1087,50 @@ class OC_Util { if(OC_Config::getValue('proxyuserpwd', '') != '') { curl_setopt($curl, CURLOPT_PROXYUSERPWD, OC_Config::getValue('proxyuserpwd')); } - $data = curl_exec($curl); + + if (ini_get('open_basedir') === '' && ini_get('safe_mode' === 'Off')) { + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_MAXREDIRS, $max_redirects); + $data = curl_exec($curl); + } else { + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false); + $mr = $max_redirects; + if ($mr > 0) { + $newurl = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); + + $rcurl = curl_copy_handle($curl); + curl_setopt($rcurl, CURLOPT_HEADER, true); + curl_setopt($rcurl, CURLOPT_NOBODY, true); + curl_setopt($rcurl, CURLOPT_FORBID_REUSE, false); + curl_setopt($rcurl, CURLOPT_RETURNTRANSFER, true); + do { + curl_setopt($rcurl, CURLOPT_URL, $newurl); + $header = curl_exec($rcurl); + if (curl_errno($rcurl)) { + $code = 0; + } else { + $code = curl_getinfo($rcurl, CURLINFO_HTTP_CODE); + if ($code == 301 || $code == 302) { + preg_match('/Location:(.*?)\n/', $header, $matches); + $newurl = trim(array_pop($matches)); + } else { + $code = 0; + } + } + } while ($code && --$mr); + curl_close($rcurl); + if ($mr > 0) { + curl_setopt($curl, CURLOPT_URL, $newurl); + } + } + + if($mr == 0 && $max_redirects > 0) { + $data = false; + } else { + $data = curl_exec($curl); + } + } curl_close($curl); - } else { $contextArray = null; -- cgit v1.2.3 From f1b085df0189dee6c92a4a6145d22206d7cba778 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 28 Mar 2014 12:57:27 +0100 Subject: adding @method annotation to declare methods which can be called on the wrapped statement object --- lib/private/db/statementwrapper.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'lib/private') diff --git a/lib/private/db/statementwrapper.php b/lib/private/db/statementwrapper.php index eaf215c7231..492209b883b 100644 --- a/lib/private/db/statementwrapper.php +++ b/lib/private/db/statementwrapper.php @@ -8,6 +8,11 @@ /** * small wrapper around \Doctrine\DBAL\Driver\Statement to make it behave, more like an MDB2 Statement + * + * @method boolean bindValue(mixed $param, mixed $value, integer $type = null); + * @method string errorCode(); + * @method array errorInfo(); + * @method integer rowCount(); */ class OC_DB_StatementWrapper { /** @@ -161,6 +166,8 @@ class OC_DB_StatementWrapper { /** * provide an alias for fetch + * + * @return mixed */ public function fetchRow() { return $this->statement->fetch(); @@ -168,12 +175,13 @@ class OC_DB_StatementWrapper { /** * Provide a simple fetchOne. + * * fetch single column from the next row - * @param int $colnum the column number to fetch + * @param int $column the column number to fetch * @return string */ - public function fetchOne($colnum = 0) { - return $this->statement->fetchColumn($colnum); + public function fetchOne($column = 0) { + return $this->statement->fetchColumn($column); } /** -- cgit v1.2.3 From e4069e155386fbb8391b76ba7684512dc57897aa Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 28 Mar 2014 15:00:13 +0100 Subject: Emit event after setting a new expiration for a share all credits to @frisco82 https://github.com/owncloud/core/pull/5335 --- lib/private/share/share.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/share/share.php b/lib/private/share/share.php index a385328edc1..8238797600e 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -747,7 +747,8 @@ class Share extends \OC\Share\Constants { * @return \OCP\Share_Backend */ public static function setExpirationDate($itemType, $itemSource, $date) { - $items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE, null, -1, false); + $user = \OC_User::getUser(); + $items = self::getItems($itemType, $itemSource, null, null, $user, self::FORMAT_NONE, null, -1, false); if (!empty($items)) { if ($date == '') { $date = null; @@ -759,6 +760,12 @@ class Share extends \OC\Share\Constants { foreach ($items as $item) { $query->bindValue(2, (int) $item['id']); $query->execute(); + \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'date' => $date, + 'uidOwner' => $user + )); } return true; } -- cgit v1.2.3 From c14107550d8c7588bb78e7ffc34c7190e475c23e Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 28 Mar 2014 18:05:48 +0100 Subject: Use UrlGenerator in OC\Util::redirectToDefaultPage(). Fix #7936 --- lib/private/util.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib/private') diff --git a/lib/private/util.php b/lib/private/util.php index c48a5505d41..c1adbaf2544 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -701,17 +701,18 @@ class OC_Util { * @return void */ public static function redirectToDefaultPage() { + $urlGenerator = \OC::$server->getURLGenerator(); if(isset($_REQUEST['redirect_url'])) { - $location = OC_Helper::makeURLAbsolute(urldecode($_REQUEST['redirect_url'])); + $location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url'])); } else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) { - $location = OC_Helper::linkToAbsolute( OC::$REQUESTEDAPP, 'index.php' ); + $location = $urlGenerator->getAbsoluteURL('/index.php/apps/'.OC::$REQUESTEDAPP.'/index.php'); } else { $defaultPage = OC_Appconfig::getValue('core', 'defaultpage'); if ($defaultPage) { - $location = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/'.$defaultPage); + $location = $urlGenerator->getAbsoluteURL($defaultPage); } else { - $location = OC_Helper::linkToAbsolute( 'files', 'index.php' ); + $location = $urlGenerator->getAbsoluteURL('/index.php/files/index.php'); } } OC_Log::write('core', 'redirectToDefaultPage: '.$location, OC_Log::DEBUG); -- cgit v1.2.3 From 3a7829f784a3f98642ac19b633c003e74aa87e9d Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 29 Mar 2014 20:39:55 +0100 Subject: Sub-dir was prepended twice --- lib/private/helper.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/private') diff --git a/lib/private/helper.php b/lib/private/helper.php index 98a86388d20..d7ac0b5f4fa 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -78,8 +78,7 @@ class OC_Helper { * Returns a absolute url to the given app and file. */ public static function linkToAbsolute($app, $file, $args = array()) { - $urlLinkTo = self::linkTo($app, $file, $args); - return self::makeURLAbsolute($urlLinkTo); + return self::linkTo($app, $file, $args); } /** -- cgit v1.2.3 From 7278f2f5673ca3ebc62938f854cb1028bb5bcfef Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 29 Mar 2014 20:40:49 +0100 Subject: Sub-dir was prepended twice --- lib/private/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/private') diff --git a/lib/private/util.php b/lib/private/util.php index c1adbaf2544..731b7c97503 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -703,7 +703,7 @@ class OC_Util { public static function redirectToDefaultPage() { $urlGenerator = \OC::$server->getURLGenerator(); if(isset($_REQUEST['redirect_url'])) { - $location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url'])); + $location = urldecode($_REQUEST['redirect_url']); } else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) { $location = $urlGenerator->getAbsoluteURL('/index.php/apps/'.OC::$REQUESTEDAPP.'/index.php'); -- cgit v1.2.3
  +  <?php p($theme->getName()); ?>