diff --git a/apps/files_external/appinfo/register_command.php b/apps/files_external/appinfo/register_command.php index 5f6f42bf8c..927ce9869f 100644 --- a/apps/files_external/appinfo/register_command.php +++ b/apps/files_external/appinfo/register_command.php @@ -29,6 +29,7 @@ use OCA\Files_External\Command\Export; use OCA\Files_External\Command\Delete; use OCA\Files_External\Command\Create; use OCA\Files_External\Command\Backends; +use OCA\Files_External\Command\Verify; $userManager = OC::$server->getUserManager(); $userSession = OC::$server->getUserSession(); @@ -51,3 +52,4 @@ $application->add(new Export($globalStorageService, $userStorageService, $userSe $application->add(new Delete($globalStorageService, $userStorageService, $userSession, $userManager)); $application->add(new Create($globalStorageService, $userStorageService, $userManager, $userSession, $backendService)); $application->add(new Backends($backendService)); +$application->add(new Verify($globalStorageService)); diff --git a/apps/files_external/command/verify.php b/apps/files_external/command/verify.php new file mode 100644 index 0000000000..f985cb401a --- /dev/null +++ b/apps/files_external/command/verify.php @@ -0,0 +1,145 @@ + + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_External\Command; + +use OC\Core\Command\Base; +use OCA\Files_External\Lib\Auth\AuthMechanism; +use OCA\Files_External\Lib\Backend\Backend; +use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; +use OCA\Files_external\Lib\StorageConfig; +use OCA\Files_external\NotFoundException; +use OCA\Files_external\Service\GlobalStoragesService; +use OCP\Files\StorageNotAvailableException; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableHelper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class Verify extends Base { + /** + * @var GlobalStoragesService + */ + protected $globalService; + + function __construct(GlobalStoragesService $globalService) { + parent::__construct(); + $this->globalService = $globalService; + } + + protected function configure() { + $this + ->setName('files_external:verify') + ->setDescription('Verify mount configuration') + ->addArgument( + 'mount_id', + InputArgument::REQUIRED, + 'The id of the mount to check' + )->addOption( + 'config', + 'c', + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Additional config option to set before checking in key=value pairs, required for certain auth backends such as login credentails' + ); + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $mountId = $input->getArgument('mount_id'); + $configInput = $input->getOption('config'); + + try { + $mount = $this->globalService->getStorage($mountId); + } catch (NotFoundException $e) { + $output->writeln('Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"'); + return 404; + } + + $this->updateStorageStatus($mount, $configInput, $output); + + $this->writeArrayInOutputFormat($input, $output, [ + 'status' => StorageNotAvailableException::getStateCodeName($mount->getStatus()), + 'code' => $mount->getStatus(), + 'message' => $mount->getStatusMessage() + ]); + } + + private function manipulateStorageConfig(StorageConfig $storage) { + /** @var AuthMechanism */ + $authMechanism = $storage->getAuthMechanism(); + $authMechanism->manipulateStorageConfig($storage); + /** @var Backend */ + $backend = $storage->getBackend(); + $backend->manipulateStorageConfig($storage); + } + + private function updateStorageStatus(StorageConfig &$storage, $configInput, OutputInterface $output) { + try { + try { + $this->manipulateStorageConfig($storage); + } catch (InsufficientDataForMeaningfulAnswerException $e) { + if (count($configInput) === 0) { // extra config options might solve the error + throw $e; + } + } + + foreach ($configInput as $configOption) { + if (!strpos($configOption, '=')) { + $output->writeln('Invalid mount configuration option "' . $configOption . '"'); + return; + } + list($key, $value) = explode('=', $configOption, 2); + $storage->setBackendOption($key, $value); + } + + /** @var Backend */ + $backend = $storage->getBackend(); + // update status (can be time-consuming) + $storage->setStatus( + \OC_Mount_Config::getBackendStatus( + $backend->getStorageClass(), + $storage->getBackendOptions(), + false + ) + ); + } catch (InsufficientDataForMeaningfulAnswerException $e) { + $status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE; + $storage->setStatus( + $status, + $e->getMessage() + ); + } catch (StorageNotAvailableException $e) { + $storage->setStatus( + $e->getCode(), + $e->getMessage() + ); + } catch (\Exception $e) { + // FIXME: convert storage exceptions to StorageNotAvailableException + $storage->setStatus( + StorageNotAvailableException::STATUS_ERROR, + get_class($e) . ': ' . $e->getMessage() + ); + } + } +} diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php index f9ac79d66e..dd3915a2f6 100644 --- a/lib/public/files/storagenotavailableexception.php +++ b/lib/public/files/storagenotavailableexception.php @@ -58,4 +58,30 @@ class StorageNotAvailableException extends HintException { $l = \OC::$server->getL10N('core'); parent::__construct($message, $l->t('Storage not available'), $code, $previous); } + + /** + * Get the name for a status code + * + * @param int $code + * @return string + * @since 9.0.0 + */ + public static function getStateCodeName($code) { + switch ($code) { + case self::STATUS_SUCCESS: + return 'ok'; + case self::STATUS_ERROR: + return 'error'; + case self::STATUS_INDETERMINATE: + return 'indeterminate'; + case self::STATUS_UNAUTHORIZED: + return 'unauthorized'; + case self::STATUS_TIMEOUT: + return 'timeout'; + case self::STATUS_NETWORK_ERROR: + return 'network error'; + default: + return 'unknown'; + } + } }