From 80c8666d3abae0a4004e48ad9f580397e98c6ac0 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 30 Oct 2013 22:34:37 +0100 Subject: [PATCH 01/16] Deleting all files in trash now only sends a single flag To prevent having to send the list of all files for deletion, only set a flag "allfiles". This should make it a bit smoother when deleting 5000+ files. Also fixes some "empty trash" message issues. --- apps/files/js/filelist.js | 5 +-- apps/files_trashbin/ajax/delete.php | 39 ++++++++++++++------ apps/files_trashbin/js/filelist.js | 7 ++++ apps/files_trashbin/js/trash.js | 48 +++++++++++++++++++------ apps/files_trashbin/templates/index.php | 4 +-- 5 files changed, 77 insertions(+), 26 deletions(-) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 0a94657c2d..eaa60f9aaa 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -681,8 +681,9 @@ var FileList={ var $fileList = $('#fileList'); var permissions = $('#permissions').val(); var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; - $('#emptycontent').toggleClass('hidden', !isCreatable || $fileList.find('tr').exists()); - $('#filestable th').toggleClass('hidden', $fileList.find('tr').exists() === false); + var exists = $fileList.find('tr:first').exists(); + $('#emptycontent').toggleClass('hidden', !isCreatable || exists); + $('#filestable th').toggleClass('hidden', !exists); }, showMask: function() { // in case one was shown before diff --git a/apps/files_trashbin/ajax/delete.php b/apps/files_trashbin/ajax/delete.php index 92361b65f6..5498250dbf 100644 --- a/apps/files_trashbin/ajax/delete.php +++ b/apps/files_trashbin/ajax/delete.php @@ -3,10 +3,19 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); -$files = $_POST['files']; -$dirlisting = $_POST['dirlisting']; -$list = json_decode($files); - +// "empty trash" command +$deleteAll = false; +if (isset($_POST['allfiles']) and $_POST['allfiles'] === 'true'){ + $user = \OCP\User::getUser(); + $list = OCA\Files_Trashbin\Helper::getTrashFiles('/'); + $deleteAll = true; + $dirlisting = '0'; +} +else { + $files = $_POST['files']; + $dirlisting = $_POST['dirlisting']; + $list = json_decode($files); +} $error = array(); $success = array(); @@ -14,22 +23,30 @@ $success = array(); $i = 0; foreach ($list as $file) { if ( $dirlisting === '0') { - $delimiter = strrpos($file, '.d'); - $filename = substr($file, 0, $delimiter); - $timestamp = substr($file, $delimiter+2); + if ($deleteAll) { + $filename = $file['name']; + $timestamp = $file['timestamp']; + } + else { + $delimiter = strrpos($file, '.d'); + $filename = substr($file, 0, $delimiter); + $timestamp = substr($file, $delimiter+2); + } } else { $filename = $file; $timestamp = null; } OCA\Files_Trashbin\Trashbin::delete($filename, $timestamp); - if (!OCA\Files_Trashbin\Trashbin::file_exists($filename, $timestamp)) { + if (OCA\Files_Trashbin\Trashbin::file_exists($filename, $timestamp)) { + $error[] = $filename; + OC_Log::write('trashbin','can\'t delete ' . $filename . ' permanently.', OC_Log::ERROR); + } + // only list deleted files if not deleting everything + else if (!$deleteAll) { $success[$i]['filename'] = $file; $success[$i]['timestamp'] = $timestamp; $i++; - } else { - $error[] = $filename; - OC_Log::write('trashbin','can\'t delete ' . $filename . ' permanently.', OC_Log::ERROR); } } diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js index cd5a67ddfe..f42abb6d02 100644 --- a/apps/files_trashbin/js/filelist.js +++ b/apps/files_trashbin/js/filelist.js @@ -22,3 +22,10 @@ FileList.reload = function(){ FileList.linkTo = function(dir){ return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); } + +FileList.updateEmptyContent = function(){ + var $fileList = $('#fileList'); + var exists = $fileList.find('tr:first').exists(); + $('#emptycontent').toggleClass('hidden', exists); + $('#filestable th').toggleClass('hidden', !exists); +} diff --git a/apps/files_trashbin/js/trash.js b/apps/files_trashbin/js/trash.js index 4e6a1e93fa..84c23d6699 100644 --- a/apps/files_trashbin/js/trash.js +++ b/apps/files_trashbin/js/trash.js @@ -19,6 +19,7 @@ $(document).ready(function() { } enableActions(); FileList.updateFileSummary(); + FileList.updateEmptyContent(); } ); @@ -45,6 +46,7 @@ $(document).ready(function() { } enableActions(); FileList.updateFileSummary(); + FileList.updateEmptyContent(); } ); @@ -122,34 +124,60 @@ $(document).ready(function() { } enableActions(); FileList.updateFileSummary(); + FileList.updateEmptyContent(); } ); }); $('.delete').click('click', function(event) { event.preventDefault(); - var files = getSelectedFiles('file'); - var fileslist = JSON.stringify(files); - var dirlisting = getSelectedFiles('dirlisting')[0]; + var allFiles = $('#select_all').is(':checked'); + var files = []; + var params = {}; + if (allFiles) { + params = { + allfiles: true + }; + } + else { + files = getSelectedFiles('file'); + params = { + files: JSON.stringify(files), + dirlisting: getSelectedFiles('dirlisting')[0] + }; + }; disableActions(); - for (var i = 0; i < files.length; i++) { - var deleteAction = $('tr').filterAttr('data-file', files[i]).children("td.date").children(".action.delete"); - deleteAction.removeClass('delete-icon').addClass('progress-icon'); + if (allFiles) { + FileList.showMask(); + } + else { + for (var i = 0; i < files.length; i++) { + var deleteAction = $('tr').filterAttr('data-file', files[i]).children("td.date").children(".action.delete"); + deleteAction.removeClass('delete-icon').addClass('progress-icon'); + } } $.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'), - {files: fileslist, dirlisting: dirlisting}, + params, function(result) { - for (var i = 0; i < result.data.success.length; i++) { - var row = document.getElementById(result.data.success[i].filename); - row.parentNode.removeChild(row); + if (allFiles) { + FileList.hideMask(); + // simply remove all files + $('#fileList').empty(); + } + else { + for (var i = 0; i < result.data.success.length; i++) { + var row = document.getElementById(result.data.success[i].filename); + row.parentNode.removeChild(row); + } } if (result.status !== 'success') { OC.dialogs.alert(result.data.message, t('core', 'Error')); } enableActions(); FileList.updateFileSummary(); + FileList.updateEmptyContent(); } ); diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index 15ba074e45..f9264d4352 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -4,9 +4,7 @@
- -
t('Nothing in here. Your trash bin is empty!'))?>
- +
class="hidden">t('Nothing in here. Your trash bin is empty!'))?>
From d88025bf6b1d8b146605da6c518c4af9624394a4 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 25 Nov 2013 12:44:27 +0100 Subject: [PATCH 02/16] Fixed ext storage touch function to return true on success Some ext storage impl didn't return true on success. Fixes #5943 (Dropbox) Fixes #6010 (WebDAV) --- apps/files_external/lib/dropbox.php | 6 +++++- apps/files_external/lib/swift.php | 4 ++-- apps/files_external/lib/webdav.php | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index 6e464f4e28..5f603b7fe4 100755 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -269,7 +269,11 @@ class Dropbox extends \OC\Files\Storage\Common { } public function touch($path, $mtime = null) { - return false; + if ($this->file_exists($path)) { + return false; + } else { + $this->file_put_contents($path, ''); + } } } diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index 86938ef3bb..b615d24ce7 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -364,7 +364,7 @@ class Swift extends \OC\Files\Storage\Common { 'X-Object-Meta-Timestamp' => $mtime ) ); - $object->Update($settings); + return $object->Update($settings); } else { $object = $this->container->DataObject(); if (is_null($mtime)) { @@ -377,7 +377,7 @@ class Swift extends \OC\Files\Storage\Common { 'X-Object-Meta-Timestamp' => $mtime ) ); - $object->Create($settings); + return $object->Create($settings); } } diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 0837222e51..02f6cb5fc4 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -234,6 +234,7 @@ class DAV extends \OC\Files\Storage\Common{ } else { $this->file_put_contents($path, ''); } + return true; } public function getFile($path, $target) { From 317d421874158cefba5fae80398513a453c38f77 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 25 Nov 2013 13:04:23 +0100 Subject: [PATCH 03/16] provide more cli friendly error messages --- lib/base.php | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/base.php b/lib/base.php index 865d174d21..187cedf942 100644 --- a/lib/base.php +++ b/lib/base.php @@ -178,11 +178,19 @@ class OC { if (file_exists(OC::$SERVERROOT . "/config/config.php") and !is_writable(OC::$SERVERROOT . "/config/config.php")) { $defaults = new OC_Defaults(); - OC_Template::printErrorPage( - "Can't write into config directory!", - 'This can usually be fixed by ' - .'giving the webserver write access to the config directory.' - ); + if (self::$CLI) { + echo "Can't write into config directory!\n"; + echo "This can usually be fixed by giving the webserver write access to the config directory\n"; + echo "\n"; + echo "See " . \OC_Helper::linkToDocs('admin-dir_permissions') . "\n"; + exit; + } else { + OC_Template::printErrorPage( + "Can't write into config directory!", + 'This can usually be fixed by ' + .'giving the webserver write access to the config directory.' + ); + } } } @@ -480,7 +488,14 @@ class OC { $errors = OC_Util::checkServer(); if (count($errors) > 0) { - OC_Template::printGuestPage('', 'error', array('errors' => $errors)); + if (self::$CLI) { + foreach ($errors as $error) { + echo $error['error']."\n"; + echo $error['hint'] . "\n\n"; + } + } else { + OC_Template::printGuestPage('', 'error', array('errors' => $errors)); + } exit; } From d3bfb433d1d9419095e2e3d8d9bfad1977bb8d22 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 25 Nov 2013 13:20:16 +0100 Subject: [PATCH 04/16] add occ commands for enabling and disabling apps --- core/command/app/disable.php | 37 ++++++++++++++++++++++++++++++++++ core/command/app/enable.php | 39 ++++++++++++++++++++++++++++++++++++ core/register_command.php | 2 ++ 3 files changed, 78 insertions(+) create mode 100644 core/command/app/disable.php create mode 100644 core/command/app/enable.php diff --git a/core/command/app/disable.php b/core/command/app/disable.php new file mode 100644 index 0000000000..fc95739d99 --- /dev/null +++ b/core/command/app/disable.php @@ -0,0 +1,37 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Core\Command\App; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Disable extends Command { + protected function configure() { + $this + ->setName('app:disable') + ->setDescription('disable an app') + ->addArgument( + 'app_id', + InputArgument::REQUIRED, + 'disable the specified app' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $appId = $input->getArgument('app_id'); + if (\OC_App::isEnabled($appId)) { + \OC_App::disable($appId); + $output->writeln($appId . ' disabled'); + } else { + $output->writeln('No such app enabled: ' . $appId); + } + } +} diff --git a/core/command/app/enable.php b/core/command/app/enable.php new file mode 100644 index 0000000000..20cb55c4aa --- /dev/null +++ b/core/command/app/enable.php @@ -0,0 +1,39 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Core\Command\App; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Enable extends Command { + protected function configure() { + $this + ->setName('app:enable') + ->setDescription('enable an app') + ->addArgument( + 'app_id', + InputArgument::REQUIRED, + 'enable the specified app' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $appId = $input->getArgument('app_id'); + if (\OC_App::isEnabled($appId)) { + $output->writeln($appId . ' is already enabled'); + } else if (!\OC_App::getAppPath($appId)) { + $output->writeln($appId . ' not found'); + } else { + \OC_App::enable($appId); + $output->writeln($appId . ' enabled'); + } + } +} diff --git a/core/register_command.php b/core/register_command.php index cfea1a6b88..9ca2a8660b 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -10,3 +10,5 @@ $application->add(new OC\Core\Command\Status); $application->add(new OC\Core\Command\Db\GenerateChangeScript()); $application->add(new OC\Core\Command\Upgrade()); +$application->add(new OC\Core\Command\App\Disable()); +$application->add(new OC\Core\Command\App\Enable()); From b7ddc78626930dea0ade30a26edf62e204d2fc37 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 14:06:25 +0100 Subject: [PATCH 05/16] fix db.php doc --- lib/public/db.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/public/db.php b/lib/public/db.php index b9424b5386..c9997c79c3 100644 --- a/lib/public/db.php +++ b/lib/public/db.php @@ -37,6 +37,8 @@ class DB { /** * Prepare a SQL query * @param string $query Query string + * @param int $limit Limit of the SQL statement + * @param int $offset Offset of the SQL statement * @return \MDB2_Statement_Common prepared SQL query * * SQL query via MDB2 prepare(), needs to be execute()'d! From 7f47cc062c3bddd788bfc6dbbe720ec55cc2f3bf Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 14:12:07 +0100 Subject: [PATCH 06/16] fix defaults.php doc --- lib/private/defaults.php | 50 +++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/private/defaults.php b/lib/private/defaults.php index 4951c6f50a..cec9a65c7f 100644 --- a/lib/private/defaults.php +++ b/lib/private/defaults.php @@ -1,15 +1,13 @@ themeExist('getBaseUrl')) { return $this->theme->getBaseUrl(); @@ -56,6 +58,10 @@ class OC_Defaults { } } + /** + * Returns the URL where the sync clients are listed + * @return string URL + */ public function getSyncClientUrl() { if ($this->themeExist('getSyncClientUrl')) { return $this->theme->getSyncClientUrl(); @@ -64,6 +70,10 @@ class OC_Defaults { } } + /** + * Returns the documentation URL + * @return string URL + */ public function getDocBaseUrl() { if ($this->themeExist('getDocBaseUrl')) { return $this->theme->getDocBaseUrl(); @@ -72,6 +82,10 @@ class OC_Defaults { } } + /** + * Returns the title + * @return string title + */ public function getTitle() { if ($this->themeExist('getTitle')) { return $this->theme->getTitle(); @@ -80,6 +94,10 @@ class OC_Defaults { } } + /** + * Returns the short name of the software + * @return string title + */ public function getName() { if ($this->themeExist('getName')) { return $this->theme->getName(); @@ -88,6 +106,10 @@ class OC_Defaults { } } + /** + * Returns entity (e.g. company name) - used for footer, copyright + * @return string entity name + */ public function getEntity() { if ($this->themeExist('getEntity')) { return $this->theme->getEntity(); @@ -96,6 +118,10 @@ class OC_Defaults { } } + /** + * Returns slogan + * @return string slogan + */ public function getSlogan() { if ($this->themeExist('getSlogan')) { return $this->theme->getSlogan(); @@ -104,6 +130,10 @@ class OC_Defaults { } } + /** + * Returns logo claim + * @return string logo claim + */ public function getLogoClaim() { if ($this->themeExist('getLogoClaim')) { return $this->theme->getLogoClaim(); @@ -112,6 +142,10 @@ class OC_Defaults { } } + /** + * Returns short version of the footer + * @return string short footer + */ public function getShortFooter() { if ($this->themeExist('getShortFooter')) { $footer = $this->theme->getShortFooter(); @@ -123,6 +157,10 @@ class OC_Defaults { return $footer; } + /** + * Returns long version of the footer + * @return string long footer + */ public function getLongFooter() { if ($this->themeExist('getLongFooter')) { $footer = $this->theme->getLongFooter(); From a0a665ea459fe96a0006766cc0d0b25e5cd258df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 25 Nov 2013 14:21:51 +0100 Subject: [PATCH 07/16] handle duplicate slashes in case of reverse proxy configuration --- lib/private/request.php | 5 ++++- tests/lib/request.php | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/private/request.php b/lib/private/request.php index d11e5b16cf..9cf09ac734 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -136,7 +136,10 @@ class OC_Request { * @returns string Path info or false when not found */ public static function getRawPathInfo() { - $path_info = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME'])); + $requestUri = $_SERVER['REQUEST_URI']; + // remove too many leading slashes - can be caused by reverse proxy configuration + $requestUri = '/' . ltrim($requestUri, '/'); + $path_info = substr($requestUri, strlen($_SERVER['SCRIPT_NAME'])); // Remove the query string from REQUEST_URI if ($pos = strpos($path_info, '?')) { $path_info = substr($path_info, 0, $pos); diff --git a/tests/lib/request.php b/tests/lib/request.php index 2b2094a612..d7ccb2146d 100644 --- a/tests/lib/request.php +++ b/tests/lib/request.php @@ -23,4 +23,24 @@ class Test_Request extends PHPUnit_Framework_TestCase { $scriptName = OC_Request::scriptName(); $this->assertEquals('/domain.tld/ownCloud/tests/lib/request.php', $scriptName); } + + /** + * @dataProvider rawPathInfoProvider + * @param $expected + * @param $requestUri + * @param $scriptName + */ + public function testRawPathInfo($expected, $requestUri, $scriptName) { + $_SERVER['REQUEST_URI'] = $requestUri; + $_SERVER['SCRIPT_NAME'] = $scriptName; + $rawPathInfo = OC_Request::getRawPathInfo(); + $this->assertEquals($expected, $rawPathInfo); + } + + function rawPathInfoProvider() { + return array( + array('/core/ajax/translations.php', '/index.php/core/ajax/translations.php', '/index.php'), + array('/core/ajax/translations.php', '//index.php/core/ajax/translations.php', '/index.php'), + ); + } } From 248eed16a6bf917292d4a99191d123a7e7cc9002 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 14:26:26 +0100 Subject: [PATCH 08/16] fix defaults.php doc --- lib/public/defaults.php | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/public/defaults.php b/lib/public/defaults.php index 8f7853a86a..34b68903ee 100644 --- a/lib/public/defaults.php +++ b/lib/public/defaults.php @@ -30,19 +30,27 @@ // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP; -/* +/** * public api to access default strings and urls for your templates */ class Defaults { + /** + * \OC_Defaults instance to retrieve the defaults + * @return string + */ private $defaults; + /** + * creates a \OC_Defaults instance which is used in all methods to retrieve the + * actual defaults + */ function __construct() { $this->defaults = new \OC_Defaults(); } /** - * @breif get base URL for the organisation behind your ownCloud instance + * get base URL for the organisation behind your ownCloud instance * @return string */ public function getBaseUrl() { @@ -50,7 +58,7 @@ class Defaults { } /** - * @breif link to the desktop sync client + * link to the desktop sync client * @return string */ public function getSyncClientUrl() { @@ -58,7 +66,7 @@ class Defaults { } /** - * @breif base URL to the documentation of your ownCloud instance + * base URL to the documentation of your ownCloud instance * @return string */ public function getDocBaseUrl() { @@ -66,7 +74,7 @@ class Defaults { } /** - * @breif name of your ownCloud instance + * name of your ownCloud instance * @return string */ public function getName() { @@ -74,7 +82,7 @@ class Defaults { } /** - * @breif Entity behind your onwCloud instance + * Entity behind your onwCloud instance * @return string */ public function getEntity() { @@ -82,7 +90,7 @@ class Defaults { } /** - * @breif ownCloud slogan + * ownCloud slogan * @return string */ public function getSlogan() { @@ -90,7 +98,7 @@ class Defaults { } /** - * @breif logo claim + * logo claim * @return string */ public function getLogoClaim() { @@ -98,7 +106,7 @@ class Defaults { } /** - * @breif footer, short version + * footer, short version * @return string */ public function getShortFooter() { @@ -106,7 +114,7 @@ class Defaults { } /** - * @breif footer, long version + * footer, long version * @return string */ public function getLongFooter() { From b9fed935b455d06ef943c562093c87171b71e4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 25 Nov 2013 14:42:34 +0100 Subject: [PATCH 09/16] in case uri and script name don't match we better throw an exception --- lib/private/request.php | 12 ++++++++++-- tests/lib/request.php | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/private/request.php b/lib/private/request.php index 9cf09ac734..7a75bf2520 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -138,8 +138,16 @@ class OC_Request { public static function getRawPathInfo() { $requestUri = $_SERVER['REQUEST_URI']; // remove too many leading slashes - can be caused by reverse proxy configuration - $requestUri = '/' . ltrim($requestUri, '/'); - $path_info = substr($requestUri, strlen($_SERVER['SCRIPT_NAME'])); + if (strpos($requestUri, '/') === 0) { + $requestUri = '/' . ltrim($requestUri, '/'); + } + + $scriptName = $_SERVER['SCRIPT_NAME']; + // in case uri and script name don't match we better throw an exception + if (strpos($requestUri, $scriptName) !== 0) { + throw new Exception("REQUEST_URI($requestUri) does not start with the SCRIPT_NAME($scriptName)"); + } + $path_info = substr($requestUri, strlen($scriptName)); // Remove the query string from REQUEST_URI if ($pos = strpos($path_info, '?')) { $path_info = substr($path_info, 0, $pos); diff --git a/tests/lib/request.php b/tests/lib/request.php index d7ccb2146d..a740751f06 100644 --- a/tests/lib/request.php +++ b/tests/lib/request.php @@ -39,8 +39,30 @@ class Test_Request extends PHPUnit_Framework_TestCase { function rawPathInfoProvider() { return array( + array('/core/ajax/translations.php', 'index.php/core/ajax/translations.php', 'index.php'), array('/core/ajax/translations.php', '/index.php/core/ajax/translations.php', '/index.php'), array('/core/ajax/translations.php', '//index.php/core/ajax/translations.php', '/index.php'), ); } + + /** + * @dataProvider rawPathInfoThrowsExceptionProvider + * @expectedException Exception + * + * @param $requestUri + * @param $scriptName + */ + public function testRawPathInfoThrowsException($requestUri, $scriptName) { + $_SERVER['REQUEST_URI'] = $requestUri; + $_SERVER['SCRIPT_NAME'] = $scriptName; + OC_Request::getRawPathInfo(); + } + + function rawPathInfoThrowsExceptionProvider() { + return array( + array('core/ajax/translations.php', '/index.php'), + array('/core/ajax/translations.php', '/index.php'), + array('//core/ajax/translations.php', '/index.php'), + ); + } } From 27cc333dfef71a4331ad66fa7ce0b1de53e73099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 25 Nov 2013 15:35:26 +0100 Subject: [PATCH 10/16] adding chunked upload handling --- lib/private/connector/sabre/filesplugin.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/private/connector/sabre/filesplugin.php b/lib/private/connector/sabre/filesplugin.php index 1c80ebe804..65231040fb 100644 --- a/lib/private/connector/sabre/filesplugin.php +++ b/lib/private/connector/sabre/filesplugin.php @@ -78,7 +78,19 @@ class OC_Connector_Sabre_FilesPlugin extends Sabre_DAV_ServerPlugin * @throws Sabre_DAV_Exception_BadRequest */ public function sendFileIdHeader($filePath, Sabre_DAV_INode $node = null) { + // chunked upload handling + if (isset($_SERVER['HTTP_OC_CHUNKED'])) { + list($path, $name) = \Sabre_DAV_URLUtil::splitPath($filePath); + $info = OC_FileChunking::decodeName($name); + if (!empty($info)) { + $filePath = $path . '/' . $info['name']; + } + } + // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder + if (!$this->server->tree->nodeExists($filePath)) { + return; + } $node = $this->server->tree->getNodeForPath($filePath); if ($node instanceof OC_Connector_Sabre_Node) { $fileId = $node->getFileId(); From bc8cc9142e08611104cdc4df9d518775ef576066 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 16:28:24 +0100 Subject: [PATCH 11/16] AppFramework(Controller|HTTP|HTTP-Responses|Middleware), IContainer API fixes --- lib/public/appframework/controller.php | 7 +++++ lib/public/appframework/http.php | 8 +++++- lib/public/appframework/http/jsonresponse.php | 11 +++++++- lib/public/appframework/http/response.php | 4 +++ .../appframework/http/templateresponse.php | 26 ++++++++++++++++++- lib/public/appframework/middleware.php | 4 +++ lib/public/icontainer.php | 2 +- 7 files changed, 58 insertions(+), 4 deletions(-) diff --git a/lib/public/appframework/controller.php b/lib/public/appframework/controller.php index 320e0cfebb..dc8da96787 100644 --- a/lib/public/appframework/controller.php +++ b/lib/public/appframework/controller.php @@ -20,6 +20,10 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework\Controller class + */ namespace OCP\AppFramework; @@ -34,16 +38,19 @@ use OCP\IRequest; abstract class Controller { /** + * app container for dependency injection * @var \OCP\AppFramework\IAppContainer */ protected $app; /** + * current request * @var \OCP\IRequest */ protected $request; /** + * constructor of the controller * @param IAppContainer $app interface to the app * @param IRequest $request an instance of the request */ diff --git a/lib/public/appframework/http.php b/lib/public/appframework/http.php index c584d4ec67..60f314202c 100644 --- a/lib/public/appframework/http.php +++ b/lib/public/appframework/http.php @@ -20,10 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP class + */ namespace OCP\AppFramework; - +/** + * Base class which contains constants for HTTP status codes + */ class Http { const STATUS_CONTINUE = 100; diff --git a/lib/public/appframework/http/jsonresponse.php b/lib/public/appframework/http/jsonresponse.php index 7c2b609bc2..b54b23a34e 100644 --- a/lib/public/appframework/http/jsonresponse.php +++ b/lib/public/appframework/http/jsonresponse.php @@ -20,6 +20,10 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\JSONResponse class + */ namespace OCP\AppFramework\Http; @@ -30,10 +34,15 @@ use OCP\AppFramework\Http; */ class JSONResponse extends Response { + /** + * response data + * @var array|object + */ protected $data; /** + * constructor of JSONResponse * @param array|object $data the object or array that should be transformed * @param int $statusCode the Http status code, defaults to 200 */ @@ -55,7 +64,7 @@ class JSONResponse extends Response { /** * Sets values in the data json array - * @param array|object $params an array or object which will be transformed + * @param array|object $data an array or object which will be transformed * to JSON */ public function setData($data){ diff --git a/lib/public/appframework/http/response.php b/lib/public/appframework/http/response.php index f776878a81..0f5a18ca4f 100644 --- a/lib/public/appframework/http/response.php +++ b/lib/public/appframework/http/response.php @@ -20,6 +20,10 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\Response class + */ namespace OCP\AppFramework\Http; diff --git a/lib/public/appframework/http/templateresponse.php b/lib/public/appframework/http/templateresponse.php index 6156f8062f..2200a38bec 100644 --- a/lib/public/appframework/http/templateresponse.php +++ b/lib/public/appframework/http/templateresponse.php @@ -20,6 +20,10 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\TemplateResponse class + */ namespace OCP\AppFramework\Http; @@ -29,14 +33,34 @@ namespace OCP\AppFramework\Http; */ class TemplateResponse extends Response { + /** + * name of the template + * @var string + */ protected $templateName; + + /** + * parameters + * @var array + */ protected $params; + + /** + * rendering type (admin, user, blank) + * @var string + */ protected $renderAs; + + /** + * app name + * @var string + */ protected $appName; /** - * @param string $templateName the name of the template + * constructor of TemplateResponse * @param string $appName the name of the app to load the template from + * @param string $templateName the name of the template */ public function __construct($appName, $templateName) { $this->templateName = $templateName; diff --git a/lib/public/appframework/middleware.php b/lib/public/appframework/middleware.php index c4ee1c0dba..24f3193993 100644 --- a/lib/public/appframework/middleware.php +++ b/lib/public/appframework/middleware.php @@ -20,6 +20,10 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework\Middleware class + */ namespace OCP\AppFramework; diff --git a/lib/public/icontainer.php b/lib/public/icontainer.php index 6b7052cc4f..eaffa5d5a0 100644 --- a/lib/public/icontainer.php +++ b/lib/public/icontainer.php @@ -64,7 +64,7 @@ interface IContainer { * In case the parameter is false the service will be recreated on every call. * * @param string $name - * @param callable $closure + * @param \Closure $closure * @param bool $shared * @return void */ From 4e0fa85307105a40395987b3d6e50cb5a1652a18 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 16:39:01 +0100 Subject: [PATCH 12/16] page level doc blocks and class descriptions --- lib/public/activity/iconsumer.php | 5 +++++ lib/public/activity/imanager.php | 5 +++++ lib/public/appframework/app.php | 5 +++++ lib/public/appframework/iapi.php | 4 ++++ lib/public/authentication/iapachebackend.php | 5 +++++ lib/public/files/alreadyexistsexception.php | 8 ++++++++ lib/public/files/entitytoolargeexception.php | 8 ++++++++ lib/public/files/file.php | 5 +++++ lib/public/files/invalidcontentexception.php | 8 ++++++++ lib/public/files/invalidpathexception.php | 8 ++++++++ lib/public/files/notenoughspaceexception.php | 8 ++++++++ lib/public/files/notfoundexception.php | 8 ++++++++ lib/public/files/notpermittedexception.php | 8 ++++++++ lib/public/files/storage.php | 5 +++++ lib/public/iaddressbook.php | 5 +++++ 15 files changed, 95 insertions(+) diff --git a/lib/public/activity/iconsumer.php b/lib/public/activity/iconsumer.php index a0134a379d..9afacf4e74 100644 --- a/lib/public/activity/iconsumer.php +++ b/lib/public/activity/iconsumer.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Activity/IConsumer interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Activity; diff --git a/lib/public/activity/imanager.php b/lib/public/activity/imanager.php index 90215d637c..a389bd6a70 100644 --- a/lib/public/activity/imanager.php +++ b/lib/public/activity/imanager.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Activity/IManager interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Activity; diff --git a/lib/public/appframework/app.php b/lib/public/appframework/app.php index 6ac48bf102..0ff6648c5d 100644 --- a/lib/public/appframework/app.php +++ b/lib/public/appframework/app.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework/App class + */ + namespace OCP\AppFramework; diff --git a/lib/public/appframework/iapi.php b/lib/public/appframework/iapi.php index a22b056635..963e870f79 100644 --- a/lib/public/appframework/iapi.php +++ b/lib/public/appframework/iapi.php @@ -20,6 +20,10 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * AppFramework/IApi interface + */ namespace OCP\AppFramework; diff --git a/lib/public/authentication/iapachebackend.php b/lib/public/authentication/iapachebackend.php index 2d2f8c4e48..3979a14302 100644 --- a/lib/public/authentication/iapachebackend.php +++ b/lib/public/authentication/iapachebackend.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Authentication/IApacheBackend interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Authentication; diff --git a/lib/public/files/alreadyexistsexception.php b/lib/public/files/alreadyexistsexception.php index 3132e3b0c3..7bea947aef 100644 --- a/lib/public/files/alreadyexistsexception.php +++ b/lib/public/files/alreadyexistsexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for already existing files/folders + */ class AlreadyExistsException extends \Exception {} diff --git a/lib/public/files/entitytoolargeexception.php b/lib/public/files/entitytoolargeexception.php index e0d93ccbcd..eaa68a548b 100644 --- a/lib/public/files/entitytoolargeexception.php +++ b/lib/public/files/entitytoolargeexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/EntityTooLargeException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for too large entity + */ class EntityTooLargeException extends \Exception {} diff --git a/lib/public/files/file.php b/lib/public/files/file.php index 730213039d..c6cda59f9b 100644 --- a/lib/public/files/file.php +++ b/lib/public/files/file.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/File interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; diff --git a/lib/public/files/invalidcontentexception.php b/lib/public/files/invalidcontentexception.php index 2e1356e2ba..3dfe7378c4 100644 --- a/lib/public/files/invalidcontentexception.php +++ b/lib/public/files/invalidcontentexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/InvalidContentException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for invalid content + */ class InvalidContentException extends \Exception {} diff --git a/lib/public/files/invalidpathexception.php b/lib/public/files/invalidpathexception.php index 893eb1e43f..8ecfa7d89a 100644 --- a/lib/public/files/invalidpathexception.php +++ b/lib/public/files/invalidpathexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/InvalidPathException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for invalid path + */ class InvalidPathException extends \Exception {} diff --git a/lib/public/files/notenoughspaceexception.php b/lib/public/files/notenoughspaceexception.php index 1597a4518b..17f91b31bf 100644 --- a/lib/public/files/notenoughspaceexception.php +++ b/lib/public/files/notenoughspaceexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/NotEnoughSpaceException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for not enough space + */ class NotEnoughSpaceException extends \Exception {} diff --git a/lib/public/files/notfoundexception.php b/lib/public/files/notfoundexception.php index 489e43fc5f..cb35199220 100644 --- a/lib/public/files/notfoundexception.php +++ b/lib/public/files/notfoundexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/NotFoundException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for not found entity + */ class NotFoundException extends \Exception {} diff --git a/lib/public/files/notpermittedexception.php b/lib/public/files/notpermittedexception.php index a5be43dbf5..e37bd6fad3 100644 --- a/lib/public/files/notpermittedexception.php +++ b/lib/public/files/notpermittedexception.php @@ -20,8 +20,16 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/NotPermittedException class + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +/** + * Exception for not permitted action + */ class NotPermittedException extends \Exception {} diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 7a7d5ec1ef..194b42a648 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/Storage interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; diff --git a/lib/public/iaddressbook.php b/lib/public/iaddressbook.php index 77e8750d9d..dcfe08012e 100644 --- a/lib/public/iaddressbook.php +++ b/lib/public/iaddressbook.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * IAddressBook interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP { From b3e7e54c8d05b256ef523d7bdbbbb86a7aab8df7 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 16:42:28 +0100 Subject: [PATCH 13/16] fix some capital letters --- lib/public/activity/imanager.php | 1 - lib/public/files/folder.php | 5 +++++ lib/public/files/node.php | 5 +++++ lib/public/idbconnection.php | 2 +- lib/public/share.php | 6 +++--- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/public/activity/imanager.php b/lib/public/activity/imanager.php index a389bd6a70..086e430d67 100644 --- a/lib/public/activity/imanager.php +++ b/lib/public/activity/imanager.php @@ -52,7 +52,6 @@ interface IManager { * * $callable has to return an instance of OCA\Activity\IConsumer * - * @param string $key * @param \Closure $callable */ function registerConsumer(\Closure $callable); diff --git a/lib/public/files/folder.php b/lib/public/files/folder.php index 5c9785db57..7fec1c529a 100644 --- a/lib/public/files/folder.php +++ b/lib/public/files/folder.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/Folder interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; diff --git a/lib/public/files/node.php b/lib/public/files/node.php index e38bfa3b2e..972b1cfa49 100644 --- a/lib/public/files/node.php +++ b/lib/public/files/node.php @@ -20,6 +20,11 @@ * */ +/** + * Public interface of ownCloud for apps to use. + * Files/Node interface + */ + // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; diff --git a/lib/public/idbconnection.php b/lib/public/idbconnection.php index 17e3de0ffe..656b5e7e5b 100644 --- a/lib/public/idbconnection.php +++ b/lib/public/idbconnection.php @@ -45,7 +45,7 @@ interface IDBConnection { /** * Used to get the id of the just inserted element - * @param string $tableName the name of the table where we inserted the item + * @param string $table the name of the table where we inserted the item * @return int the id of the inserted element */ public function lastInsertId($table = null); diff --git a/lib/public/share.php b/lib/public/share.php index 01bf61a60a..003a91a93b 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -256,7 +256,7 @@ class Share { /** * Get the item of item type shared with the current user * @param string $itemType - * @param string $ItemTarget + * @param string $itemTarget * @param int $format (optional) Format type must be defined by the backend * @return Return depends on format */ @@ -268,8 +268,8 @@ class Share { /** * Get the item of item type shared with a given user by source - * @param string $ItemType - * @param string $ItemSource + * @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 */ From 4dc35909b5ae83d1dd8af9b930658e1e1662e024 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 25 Nov 2013 17:04:19 +0100 Subject: [PATCH 14/16] Fix navbar issue fixes #6024 --- core/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/css/styles.css b/core/css/styles.css index 938b522a90..5c0aa1fedc 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -561,7 +561,7 @@ label.infield { cursor:text !important; top:1.05em; left:.85em; } /* NAVIGATION ------------------------------------------------------------- */ #navigation { - position: absolute; + position: fixed; top: 0; bottom: 0; left: 0; From fc1d897ea5d0b6f702f3c649637f5a83693d1ac3 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 25 Nov 2013 17:28:01 +0100 Subject: [PATCH 15/16] rename app_id to app-id --- core/command/app/disable.php | 4 ++-- core/command/app/enable.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/command/app/disable.php b/core/command/app/disable.php index fc95739d99..dcdee92349 100644 --- a/core/command/app/disable.php +++ b/core/command/app/disable.php @@ -19,14 +19,14 @@ class Disable extends Command { ->setName('app:disable') ->setDescription('disable an app') ->addArgument( - 'app_id', + 'app-id', InputArgument::REQUIRED, 'disable the specified app' ); } protected function execute(InputInterface $input, OutputInterface $output) { - $appId = $input->getArgument('app_id'); + $appId = $input->getArgument('app-id'); if (\OC_App::isEnabled($appId)) { \OC_App::disable($appId); $output->writeln($appId . ' disabled'); diff --git a/core/command/app/enable.php b/core/command/app/enable.php index 20cb55c4aa..f08546602e 100644 --- a/core/command/app/enable.php +++ b/core/command/app/enable.php @@ -19,14 +19,14 @@ class Enable extends Command { ->setName('app:enable') ->setDescription('enable an app') ->addArgument( - 'app_id', + 'app-id', InputArgument::REQUIRED, 'enable the specified app' ); } protected function execute(InputInterface $input, OutputInterface $output) { - $appId = $input->getArgument('app_id'); + $appId = $input->getArgument('app-id'); if (\OC_App::isEnabled($appId)) { $output->writeln($appId . ' is already enabled'); } else if (!\OC_App::getAppPath($appId)) { From abe63bd329e1180173e249f6edbe440a289d809f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 25 Nov 2013 17:34:16 +0100 Subject: [PATCH 16/16] Add occ command to list all apps --- core/command/app/listapps.php | 47 +++++++++++++++++++++++++++++++++++ core/register_command.php | 1 + 2 files changed, 48 insertions(+) create mode 100644 core/command/app/listapps.php diff --git a/core/command/app/listapps.php b/core/command/app/listapps.php new file mode 100644 index 0000000000..dc471c5453 --- /dev/null +++ b/core/command/app/listapps.php @@ -0,0 +1,47 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Core\Command\App; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class ListApps extends Command { + protected function configure() { + $this + ->setName('app:list') + ->setDescription('List all available apps'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $apps = \OC_App::getAllApps(); + $enabledApps = array(); + $disabledApps = array(); + + //sort enabled apps above disabled apps + foreach ($apps as $app) { + if (\OC_App::isEnabled($app)) { + $enabledApps[] = $app; + } else { + $disabledApps[] = $app; + } + } + + sort($enabledApps); + sort($disabledApps); + $output->writeln('Enabled:'); + foreach ($enabledApps as $app) { + $output->writeln(' - ' . $app); + } + $output->writeln('Disabled:'); + foreach ($disabledApps as $app) { + $output->writeln(' - ' . $app); + } + } +} diff --git a/core/register_command.php b/core/register_command.php index 9ca2a8660b..144dcd3dc5 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -12,3 +12,4 @@ $application->add(new OC\Core\Command\Db\GenerateChangeScript()); $application->add(new OC\Core\Command\Upgrade()); $application->add(new OC\Core\Command\App\Disable()); $application->add(new OC\Core\Command\App\Enable()); +$application->add(new OC\Core\Command\App\ListApps());