aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_external/lib/Command
diff options
context:
space:
mode:
authorJoas Schilling <nickvergessen@owncloud.com>2016-05-13 11:22:28 +0200
committerJoas Schilling <nickvergessen@owncloud.com>2016-05-24 08:41:20 +0200
commit328b3c47d7fdf61b6de3c2d9129d392d3a9f5a87 (patch)
tree4d7f5eedc7861b40271bcfe1e95cc01d5ed0296d /apps/files_external/lib/Command
parentadcf942901fd567d97dbe105e8f3dfb7cea738e3 (diff)
downloadnextcloud-server-328b3c47d7fdf61b6de3c2d9129d392d3a9f5a87.tar.gz
nextcloud-server-328b3c47d7fdf61b6de3c2d9129d392d3a9f5a87.zip
Move stuff from outside lib/ to PSR-4
Diffstat (limited to 'apps/files_external/lib/Command')
-rw-r--r--apps/files_external/lib/Command/Applicable.php154
-rw-r--r--apps/files_external/lib/Command/Backends.php112
-rw-r--r--apps/files_external/lib/Command/Config.php120
-rw-r--r--apps/files_external/lib/Command/Create.php221
-rw-r--r--apps/files_external/lib/Command/Delete.php110
-rw-r--r--apps/files_external/lib/Command/Export.php56
-rw-r--r--apps/files_external/lib/Command/Import.php223
-rw-r--r--apps/files_external/lib/Command/ListCommand.php247
-rw-r--r--apps/files_external/lib/Command/Option.php75
-rw-r--r--apps/files_external/lib/Command/Verify.php142
10 files changed, 1460 insertions, 0 deletions
diff --git a/apps/files_external/lib/Command/Applicable.php b/apps/files_external/lib/Command/Applicable.php
new file mode 100644
index 00000000000..902e76cb4cb
--- /dev/null
+++ b/apps/files_external/lib/Command/Applicable.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_External\Service\GlobalStoragesService;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+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 Applicable extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /**
+ * @var IGroupManager
+ */
+ private $groupManager;
+
+ function __construct(
+ GlobalStoragesService $globalService,
+ IUserManager $userManager,
+ IGroupManager $groupManager
+ ) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:applicable')
+ ->setDescription('Manage applicable users and groups for a mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addOption(
+ 'add-user',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'user to add as applicable'
+ )->addOption(
+ 'remove-user',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'user to remove as applicable'
+ )->addOption(
+ 'add-group',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'group to add as applicable'
+ )->addOption(
+ 'remove-group',
+ null,
+ InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
+ 'group to remove as applicable'
+ )->addOption(
+ 'remove-all',
+ null,
+ InputOption::VALUE_NONE,
+ 'Set the mount to be globally applicable'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $mountId = $input->getArgument('mount_id');
+ try {
+ $mount = $this->globalService->getStorage($mountId);
+ } catch (NotFoundException $e) {
+ $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts</error>');
+ return 404;
+ }
+
+ if ($mount->getType() === StorageConfig::MOUNT_TYPE_PERSONAl) {
+ $output->writeln('<error>Can\'t change applicables on personal mounts</error>');
+ return 1;
+ }
+
+ $addUsers = $input->getOption('add-user');
+ $removeUsers = $input->getOption('remove-user');
+ $addGroups = $input->getOption('add-group');
+ $removeGroups = $input->getOption('remove-group');
+
+ $applicableUsers = $mount->getApplicableUsers();
+ $applicableGroups = $mount->getApplicableGroups();
+
+ if ((count($addUsers) + count($removeUsers) + count($addGroups) + count($removeGroups) > 0) || $input->getOption('remove-all')) {
+ foreach ($addUsers as $addUser) {
+ if (!$this->userManager->userExists($addUser)) {
+ $output->writeln('<error>User "' . $addUser . '" not found</error>');
+ return 404;
+ }
+ }
+ foreach ($addGroups as $addGroup) {
+ if (!$this->groupManager->groupExists($addGroup)) {
+ $output->writeln('<error>Group "' . $addGroup . '" not found</error>');
+ return 404;
+ }
+ }
+
+ if ($input->getOption('remove-all')) {
+ $applicableUsers = [];
+ $applicableGroups = [];
+ } else {
+ $applicableUsers = array_unique(array_merge($applicableUsers, $addUsers));
+ $applicableUsers = array_values(array_diff($applicableUsers, $removeUsers));
+ $applicableGroups = array_unique(array_merge($applicableGroups, $addGroups));
+ $applicableGroups = array_values(array_diff($applicableGroups, $removeGroups));
+ }
+ $mount->setApplicableUsers($applicableUsers);
+ $mount->setApplicableGroups($applicableGroups);
+ $this->globalService->updateStorage($mount);
+ }
+
+ $this->writeArrayInOutputFormat($input, $output, [
+ 'users' => $applicableUsers,
+ 'groups' => $applicableGroups
+ ]);
+ }
+}
diff --git a/apps/files_external/lib/Command/Backends.php b/apps/files_external/lib/Command/Backends.php
new file mode 100644
index 00000000000..260ea210397
--- /dev/null
+++ b/apps/files_external/lib/Command/Backends.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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\DefinitionParameter;
+use OCA\Files_External\Service\BackendService;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\Input;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Backends extends Base {
+ /** @var BackendService */
+ private $backendService;
+
+ function __construct(BackendService $backendService
+ ) {
+ parent::__construct();
+
+ $this->backendService = $backendService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:backends')
+ ->setDescription('Show available authentication and storage backends')
+ ->addArgument(
+ 'type',
+ InputArgument::OPTIONAL,
+ 'only show backends of a certain type. Possible values are "authentication" or "storage"'
+ )->addArgument(
+ 'backend',
+ InputArgument::OPTIONAL,
+ 'only show information of a specific backend'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $authBackends = $this->backendService->getAuthMechanisms();
+ $storageBackends = $this->backendService->getBackends();
+
+ $data = [
+ 'authentication' => array_map([$this, 'serializeAuthBackend'], $authBackends),
+ 'storage' => array_map([$this, 'serializeAuthBackend'], $storageBackends)
+ ];
+
+ $type = $input->getArgument('type');
+ $backend = $input->getArgument('backend');
+ if ($type) {
+ if (!isset($data[$type])) {
+ $output->writeln('<error>Invalid type "' . $type . '". Possible values are "authentication" or "storage"</error>');
+ return 1;
+ }
+ $data = $data[$type];
+
+ if ($backend) {
+ if (!isset($data[$backend])) {
+ $output->writeln('<error>Unknown backend "' . $backend . '" of type "' . $type . '"</error>');
+ return 1;
+ }
+ $data = $data[$backend];
+ }
+ }
+
+ $this->writeArrayInOutputFormat($input, $output, $data);
+ }
+
+ private function serializeAuthBackend(\JsonSerializable $backend) {
+ $data = $backend->jsonSerialize();
+ $result = [
+ 'name' => $data['name'],
+ 'identifier' => $data['identifier'],
+ 'configuration' => array_map(function (DefinitionParameter $parameter) {
+ return $parameter->getTypeName();
+ }, $data['configuration'])
+ ];
+ if ($backend instanceof Backend) {
+ $result['storage_class'] = $backend->getStorageClass();
+ $authBackends = $this->backendService->getAuthMechanismsByScheme(array_keys($backend->getAuthSchemes()));
+ $result['supported_authentication_backends'] = array_keys($authBackends);
+ }
+ return $result;
+ }
+}
diff --git a/apps/files_external/lib/Command/Config.php b/apps/files_external/lib/Command/Config.php
new file mode 100644
index 00000000000..873fece86d7
--- /dev/null
+++ b/apps/files_external/lib/Command/Config.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_External\Service\GlobalStoragesService;
+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 Config extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ function __construct(GlobalStoragesService $globalService) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:config')
+ ->setDescription('Manage backend configuration for a mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addArgument(
+ 'key',
+ InputArgument::REQUIRED,
+ 'key of the config option to set/get'
+ )->addArgument(
+ 'value',
+ InputArgument::OPTIONAL,
+ 'value to set the config option to, when no value is provided the existing value will be printed'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $mountId = $input->getArgument('mount_id');
+ $key = $input->getArgument('key');
+ try {
+ $mount = $this->globalService->getStorage($mountId);
+ } catch (NotFoundException $e) {
+ $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
+ return 404;
+ }
+
+ $value = $input->getArgument('value');
+ if ($value) {
+ $this->setOption($mount, $key, $value, $output);
+ } else {
+ $this->getOption($mount, $key, $output);
+ }
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param OutputInterface $output
+ */
+ protected function getOption(StorageConfig $mount, $key, OutputInterface $output) {
+ if ($key === 'mountpoint' || $key === 'mount_point') {
+ $value = $mount->getMountPoint();
+ } else {
+ $value = $mount->getBackendOption($key);
+ }
+ if (!is_string($value)) { // show bools and objects correctly
+ $value = json_encode($value);
+ }
+ $output->writeln($value);
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param string $value
+ * @param OutputInterface $output
+ */
+ protected function setOption(StorageConfig $mount, $key, $value, OutputInterface $output) {
+ $decoded = json_decode($value, true);
+ if (!is_null($decoded)) {
+ $value = $decoded;
+ }
+ if ($key === 'mountpoint' || $key === 'mount_point') {
+ $mount->setMountPoint($value);
+ } else {
+ $mount->setBackendOption($key, $value);
+ }
+ $this->globalService->updateStorage($mount);
+ }
+}
diff --git a/apps/files_external/lib/Command/Create.php b/apps/files_external/lib/Command/Create.php
new file mode 100644
index 00000000000..17ad7ef1a16
--- /dev/null
+++ b/apps/files_external/lib/Command/Create.php
@@ -0,0 +1,221 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OC\Files\Filesystem;
+use OC\User\NoUserException;
+use OCA\Files_External\Lib\Auth\AuthMechanism;
+use OCA\Files_External\Lib\Backend\Backend;
+use OCA\Files_External\Lib\DefinitionParameter;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_External\Service\BackendService;
+use OCA\Files_External\Service\GlobalStoragesService;
+use OCA\Files_External\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Input\ArrayInput;
+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 Create extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ private $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ private $userService;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /** @var BackendService */
+ private $backendService;
+
+ /** @var IUserSession */
+ private $userSession;
+
+ function __construct(GlobalStoragesService $globalService,
+ UserStoragesService $userService,
+ IUserManager $userManager,
+ IUserSession $userSession,
+ BackendService $backendService
+ ) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userManager = $userManager;
+ $this->userSession = $userSession;
+ $this->backendService = $backendService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:create')
+ ->setDescription('Create a new mount configuration')
+ ->addOption(
+ 'user',
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'user to add the mount configuration for, if not set the mount will be added as system mount'
+ )
+ ->addArgument(
+ 'mount_point',
+ InputArgument::REQUIRED,
+ 'mount point for the new mount'
+ )
+ ->addArgument(
+ 'storage_backend',
+ InputArgument::REQUIRED,
+ 'storage backend identifier for the new mount, see `occ files_external:backends` for possible values'
+ )
+ ->addArgument(
+ 'authentication_backend',
+ InputArgument::REQUIRED,
+ 'authentication backend identifier for the new mount, see `occ files_external:backends` for possible values'
+ )
+ ->addOption(
+ 'config',
+ 'c',
+ InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
+ 'Mount configuration option in key=value format'
+ )
+ ->addOption(
+ 'dry',
+ null,
+ InputOption::VALUE_NONE,
+ 'Don\'t save the created mount, only list the new mount'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $user = $input->getOption('user');
+ $mountPoint = $input->getArgument('mount_point');
+ $storageIdentifier = $input->getArgument('storage_backend');
+ $authIdentifier = $input->getArgument('authentication_backend');
+ $configInput = $input->getOption('config');
+
+ $storageBackend = $this->backendService->getBackend($storageIdentifier);
+ $authBackend = $this->backendService->getAuthMechanism($authIdentifier);
+
+ if (!Filesystem::isValidPath($mountPoint)) {
+ $output->writeln('<error>Invalid mountpoint "' . $mountPoint . '"</error>');
+ return 1;
+ }
+ if (is_null($storageBackend)) {
+ $output->writeln('<error>Storage backend with identifier "' . $storageIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
+ return 404;
+ }
+ if (is_null($authBackend)) {
+ $output->writeln('<error>Authentication backend with identifier "' . $authIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
+ return 404;
+ }
+ $supportedSchemes = array_keys($storageBackend->getAuthSchemes());
+ if (!in_array($authBackend->getScheme(), $supportedSchemes)) {
+ $output->writeln('<error>Authentication backend "' . $authIdentifier . '" not valid for storage backend "' . $storageIdentifier . '" (see `occ files_external:backends storage ' . $storageIdentifier . '` for possible values)</error>');
+ return 1;
+ }
+
+ $config = [];
+ foreach ($configInput as $configOption) {
+ if (!strpos($configOption, '=')) {
+ $output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
+ return 1;
+ }
+ list($key, $value) = explode('=', $configOption, 2);
+ if (!$this->validateParam($key, $value, $storageBackend, $authBackend)) {
+ $output->writeln('<error>Unknown configuration for backends "' . $key . '"</error>');
+ return 1;
+ }
+ $config[$key] = $value;
+ }
+
+ $mount = new StorageConfig();
+ $mount->setMountPoint($mountPoint);
+ $mount->setBackend($storageBackend);
+ $mount->setAuthMechanism($authBackend);
+ $mount->setBackendOptions($config);
+
+ if ($user) {
+ if (!$this->userManager->userExists($user)) {
+ $output->writeln('<error>User "' . $user . '" not found</error>');
+ return 1;
+ }
+ $mount->setApplicableUsers([$user]);
+ }
+
+ if ($input->getOption('dry')) {
+ $this->showMount($user, $mount, $input, $output);
+ } else {
+ $this->getStorageService($user)->addStorage($mount);
+ if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) {
+ $output->writeln('<info>Storage created with id ' . $mount->getId() . '</info>');
+ } else {
+ $output->writeln($mount->getId());
+ }
+ }
+ return 0;
+ }
+
+ private function validateParam($key, &$value, Backend $storageBackend, AuthMechanism $authBackend) {
+ $params = array_merge($storageBackend->getParameters(), $authBackend->getParameters());
+ foreach ($params as $param) {
+ /** @var DefinitionParameter $param */
+ if ($param->getName() === $key) {
+ if ($param->getType() === DefinitionParameter::VALUE_BOOLEAN) {
+ $value = ($value === 'true');
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function showMount($user, StorageConfig $mount, InputInterface $input, OutputInterface $output) {
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setOption('output', $input->getOption('output'));
+ $listInput->setOption('show-password', true);
+ $listCommand->listMounts($user, [$mount], $listInput, $output);
+ }
+
+ protected function getStorageService($userId) {
+ if (!empty($userId)) {
+ $user = $this->userManager->get($userId);
+ if (is_null($user)) {
+ throw new NoUserException("user $userId not found");
+ }
+ $this->userSession->setUser($user);
+ return $this->userService;
+ } else {
+ return $this->globalService;
+ }
+ }
+}
diff --git a/apps/files_external/lib/Command/Delete.php b/apps/files_external/lib/Command/Delete.php
new file mode 100644
index 00000000000..a3aef7f3303
--- /dev/null
+++ b/apps/files_external/lib/Command/Delete.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OCA\Files_external\NotFoundException;
+use OCA\Files_External\Service\GlobalStoragesService;
+use OCA\Files_External\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+class Delete extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ protected $userService;
+
+ /**
+ * @var IUserSession
+ */
+ protected $userSession;
+
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
+
+ function __construct(GlobalStoragesService $globalService, UserStoragesService $userService, IUserSession $userSession, IUserManager $userManager) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:delete')
+ ->setDescription('Delete an external mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addOption(
+ 'yes',
+ 'y',
+ InputOption::VALUE_NONE,
+ 'Skip confirmation'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $mountId = $input->getArgument('mount_id');
+ try {
+ $mount = $this->globalService->getStorage($mountId);
+ } catch (NotFoundException $e) {
+ $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
+ return 404;
+ }
+
+ $noConfirm = $input->getOption('yes');
+
+ if (!$noConfirm) {
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setOption('output', $input->getOption('output'));
+ $listCommand->listMounts(null, [$mount], $listInput, $output);
+
+ $questionHelper = $this->getHelper('question');
+ $question = new ConfirmationQuestion('Delete this mount? [y/N] ', false);
+
+ if (!$questionHelper->ask($input, $output, $question)) {
+ return;
+ }
+ }
+
+ $this->globalService->removeStorage($mountId);
+ }
+}
diff --git a/apps/files_external/lib/Command/Export.php b/apps/files_external/lib/Command/Export.php
new file mode 100644
index 00000000000..09c5ea8a9df
--- /dev/null
+++ b/apps/files_external/lib/Command/Export.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableHelper;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\Input;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Export extends ListCommand {
+
+ protected function configure() {
+ $this
+ ->setName('files_external:export')
+ ->setDescription('Export mount configurations')
+ ->addArgument(
+ 'user_id',
+ InputArgument::OPTIONAL,
+ 'user id to export the personal mounts for, if no user is provided admin mounts will be exported'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setArgument('user_id', $input->getArgument('user_id'));
+ $listInput->setOption('output', 'json_pretty');
+ $listInput->setOption('show-password', true);
+ $listInput->setOption('full', true);
+ $listCommand->execute($listInput, $output);
+ }
+}
diff --git a/apps/files_external/lib/Command/Import.php b/apps/files_external/lib/Command/Import.php
new file mode 100644
index 00000000000..55528b66472
--- /dev/null
+++ b/apps/files_external/lib/Command/Import.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OC\User\NoUserException;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_External\Service\BackendService;
+use OCA\Files_External\Service\GlobalStoragesService;
+use OCA\Files_External\Service\ImportLegacyStoragesService;
+use OCA\Files_External\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Input\ArrayInput;
+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 Import extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ private $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ private $userService;
+
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
+
+ /** @var ImportLegacyStoragesService */
+ private $importLegacyStorageService;
+
+ /** @var BackendService */
+ private $backendService;
+
+ function __construct(GlobalStoragesService $globalService,
+ UserStoragesService $userService,
+ IUserSession $userSession,
+ IUserManager $userManager,
+ ImportLegacyStoragesService $importLegacyStorageService,
+ BackendService $backendService
+ ) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ $this->importLegacyStorageService = $importLegacyStorageService;
+ $this->backendService = $backendService;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:import')
+ ->setDescription('Import mount configurations')
+ ->addOption(
+ 'user',
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'user to add the mount configurations for, if not set the mount will be added as system mount'
+ )
+ ->addArgument(
+ 'path',
+ InputArgument::REQUIRED,
+ 'path to a json file containing the mounts to import, use "-" to read from stdin'
+ )
+ ->addOption(
+ 'dry',
+ null,
+ InputOption::VALUE_NONE,
+ 'Don\'t save the imported mounts, only list the new mounts'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $user = $input->getOption('user');
+ $path = $input->getArgument('path');
+ if ($path === '-') {
+ $json = file_get_contents('php://stdin');
+ } else {
+ if (!file_exists($path)) {
+ $output->writeln('<error>File not found: ' . $path . '</error>');
+ return 1;
+ }
+ $json = file_get_contents($path);
+ }
+ if (!is_string($json) || strlen($json) < 2) {
+ $output->writeln('<error>Error while reading json</error>');
+ return 1;
+ }
+ $data = json_decode($json, true);
+ if (!is_array($data)) {
+ $output->writeln('<error>Error while parsing json</error>');
+ return 1;
+ }
+
+ $isLegacy = isset($data['user']) || isset($data['group']);
+ if ($isLegacy) {
+ $this->importLegacyStorageService->setData($data);
+ $mounts = $this->importLegacyStorageService->getAllStorages();
+ foreach ($mounts as $mount) {
+ if ($mount->getBackendOption('password') === false) {
+ $output->writeln('<error>Failed to decrypt password</error>');
+ return 1;
+ }
+ }
+ } else {
+ if (!isset($data[0])) { //normalize to an array of mounts
+ $data = [$data];
+ }
+ $mounts = array_map([$this, 'parseData'], $data);
+ }
+
+ if ($user) {
+ // ensure applicables are correct for personal mounts
+ foreach ($mounts as $mount) {
+ $mount->setApplicableGroups([]);
+ $mount->setApplicableUsers([$user]);
+ }
+ }
+
+ $storageService = $this->getStorageService($user);
+
+ $existingMounts = $storageService->getAllStorages();
+
+ foreach ($mounts as $mount) {
+ foreach ($existingMounts as $existingMount) {
+ if (
+ $existingMount->getMountPoint() === $mount->getMountPoint() &&
+ $existingMount->getApplicableGroups() === $mount->getApplicableGroups() &&
+ $existingMount->getApplicableUsers() == $mount->getApplicableUsers() &&
+ $existingMount->getBackendOptions() == $mount->getBackendOptions()
+ ) {
+ $output->writeln("<error>Duplicate mount (" . $mount->getMountPoint() . ")</error>");
+ return 1;
+ }
+ }
+ }
+
+ if ($input->getOption('dry')) {
+ if (count($mounts) === 0) {
+ $output->writeln('<error>No mounts to be imported</error>');
+ return 1;
+ }
+ $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
+ $listInput = new ArrayInput([], $listCommand->getDefinition());
+ $listInput->setOption('output', $input->getOption('output'));
+ $listInput->setOption('show-password', true);
+ $listCommand->listMounts($user, $mounts, $listInput, $output);
+ } else {
+ foreach ($mounts as $mount) {
+ $storageService->addStorage($mount);
+ }
+ }
+ return 0;
+ }
+
+ private function parseData(array $data) {
+ $mount = new StorageConfig($data['mount_id']);
+ $mount->setMountPoint($data['mount_point']);
+ $mount->setBackend($this->getBackendByClass($data['storage']));
+ $authBackend = $this->backendService->getAuthMechanism($data['authentication_type']);
+ $mount->setAuthMechanism($authBackend);
+ $mount->setBackendOptions($data['configuration']);
+ $mount->setMountOptions($data['options']);
+ $mount->setApplicableUsers(isset($data['applicable_users']) ? $data['applicable_users'] : []);
+ $mount->setApplicableGroups(isset($data['applicable_groups']) ? $data['applicable_groups'] : []);
+ return $mount;
+ }
+
+ private function getBackendByClass($className) {
+ $backends = $this->backendService->getBackends();
+ foreach ($backends as $backend) {
+ if ($backend->getStorageClass() === $className) {
+ return $backend;
+ }
+ }
+ }
+
+ protected function getStorageService($userId) {
+ if (!empty($userId)) {
+ $user = $this->userManager->get($userId);
+ if (is_null($user)) {
+ throw new NoUserException("user $userId not found");
+ }
+ $this->userSession->setUser($user);
+ return $this->userService;
+ } else {
+ return $this->globalService;
+ }
+ }
+}
diff --git a/apps/files_external/lib/Command/ListCommand.php b/apps/files_external/lib/Command/ListCommand.php
new file mode 100644
index 00000000000..cbe1913ccfc
--- /dev/null
+++ b/apps/files_external/lib/Command/ListCommand.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OC\Core\Command\Base;
+use OC\User\NoUserException;
+use OCA\Files_external\Lib\StorageConfig;
+use OCA\Files_External\Service\GlobalStoragesService;
+use OCA\Files_External\Service\UserStoragesService;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Helper\Table;
+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 ListCommand extends Base {
+ /**
+ * @var GlobalStoragesService
+ */
+ protected $globalService;
+
+ /**
+ * @var UserStoragesService
+ */
+ protected $userService;
+
+ /**
+ * @var IUserSession
+ */
+ protected $userSession;
+
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
+
+ function __construct(GlobalStoragesService $globalService, UserStoragesService $userService, IUserSession $userSession, IUserManager $userManager) {
+ parent::__construct();
+ $this->globalService = $globalService;
+ $this->userService = $userService;
+ $this->userSession = $userSession;
+ $this->userManager = $userManager;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('files_external:list')
+ ->setDescription('List configured mounts')
+ ->addArgument(
+ 'user_id',
+ InputArgument::OPTIONAL,
+ 'user id to list the personal mounts for, if no user is provided admin mounts will be listed'
+ )->addOption(
+ 'show-password',
+ null,
+ InputOption::VALUE_NONE,
+ 'show passwords and secrets'
+ )->addOption(
+ 'full',
+ null,
+ InputOption::VALUE_NONE,
+ 'don\'t truncate long values in table output'
+ );
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $userId = $input->getArgument('user_id');
+ $storageService = $this->getStorageService($userId);
+
+ /** @var $mounts StorageConfig[] */
+ $mounts = $storageService->getAllStorages();
+
+ $this->listMounts($userId, $mounts, $input, $output);
+ }
+
+ /**
+ * @param $userId $userId
+ * @param StorageConfig[] $mounts
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ */
+ public function listMounts($userId, array $mounts, InputInterface $input, OutputInterface $output){
+ $outputType = $input->getOption('output');
+ if (count($mounts) === 0) {
+ if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
+ $output->writeln('[]');
+ } else {
+ if ($userId) {
+ $output->writeln("<info>No mounts configured by $userId</info>");
+ } else {
+ $output->writeln("<info>No admin mounts configured</info>");
+ }
+ }
+ return;
+ }
+
+ $headers = ['Mount ID', 'Mount Point', 'Storage', 'Authentication Type', 'Configuration', 'Options'];
+
+ if (!$userId) {
+ $headers[] = 'Applicable Users';
+ $headers[] = 'Applicable Groups';
+ }
+
+ if (!$input->getOption('show-password')) {
+ $hideKeys = ['password', 'refresh_token', 'token', 'client_secret', 'public_key', 'private_key'];
+ foreach ($mounts as $mount) {
+ $config = $mount->getBackendOptions();
+ foreach ($config as $key => $value) {
+ if (in_array($key, $hideKeys)) {
+ $mount->setBackendOption($key, '***');
+ }
+ }
+ }
+ }
+
+ if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
+ $keys = array_map(function ($header) {
+ return strtolower(str_replace(' ', '_', $header));
+ }, $headers);
+
+ $pairs = array_map(function (StorageConfig $config) use ($keys, $userId) {
+ $values = [
+ $config->getId(),
+ $config->getMountPoint(),
+ $config->getBackend()->getStorageClass(),
+ $config->getAuthMechanism()->getIdentifier(),
+ $config->getBackendOptions(),
+ $config->getMountOptions()
+ ];
+ if (!$userId) {
+ $values[] = $config->getApplicableUsers();
+ $values[] = $config->getApplicableGroups();
+ }
+
+ return array_combine($keys, $values);
+ }, $mounts);
+ if ($outputType === self::OUTPUT_FORMAT_JSON) {
+ $output->writeln(json_encode(array_values($pairs)));
+ } else {
+ $output->writeln(json_encode(array_values($pairs), JSON_PRETTY_PRINT));
+ }
+ } else {
+ $full = $input->getOption('full');
+ $defaultMountOptions = [
+ 'encrypt' => true,
+ 'previews' => true,
+ 'filesystem_check_changes' => 1
+ ];
+ $rows = array_map(function (StorageConfig $config) use ($userId, $defaultMountOptions, $full) {
+ $storageConfig = $config->getBackendOptions();
+ $keys = array_keys($storageConfig);
+ $values = array_values($storageConfig);
+
+ if (!$full) {
+ $values = array_map(function ($value) {
+ if (is_string($value) && strlen($value) > 32) {
+ return substr($value, 0, 6) . '...' . substr($value, -6, 6);
+ } else {
+ return $value;
+ }
+ }, $values);
+ }
+
+ $configStrings = array_map(function ($key, $value) {
+ return $key . ': ' . json_encode($value);
+ }, $keys, $values);
+ $configString = implode(', ', $configStrings);
+
+ $mountOptions = $config->getMountOptions();
+ // hide defaults
+ foreach ($mountOptions as $key => $value) {
+ if ($value === $defaultMountOptions[$key]) {
+ unset($mountOptions[$key]);
+ }
+ }
+ $keys = array_keys($mountOptions);
+ $values = array_values($mountOptions);
+
+ $optionsStrings = array_map(function ($key, $value) {
+ return $key . ': ' . json_encode($value);
+ }, $keys, $values);
+ $optionsString = implode(', ', $optionsStrings);
+
+ $values = [
+ $config->getId(),
+ $config->getMountPoint(),
+ $config->getBackend()->getText(),
+ $config->getAuthMechanism()->getText(),
+ $configString,
+ $optionsString
+ ];
+
+ if (!$userId) {
+ $applicableUsers = implode(', ', $config->getApplicableUsers());
+ $applicableGroups = implode(', ', $config->getApplicableGroups());
+ if ($applicableUsers === '' && $applicableGroups === '') {
+ $applicableUsers = 'All';
+ }
+ $values[] = $applicableUsers;
+ $values[] = $applicableGroups;
+ }
+
+ return $values;
+ }, $mounts);
+
+ $table = new Table($output);
+ $table->setHeaders($headers);
+ $table->setRows($rows);
+ $table->render();
+ }
+ }
+
+ protected function getStorageService($userId) {
+ if (!empty($userId)) {
+ $user = $this->userManager->get($userId);
+ if (is_null($user)) {
+ throw new NoUserException("user $userId not found");
+ }
+ $this->userSession->setUser($user);
+ return $this->userService;
+ } else {
+ return $this->globalService;
+ }
+ }
+}
diff --git a/apps/files_external/lib/Command/Option.php b/apps/files_external/lib/Command/Option.php
new file mode 100644
index 00000000000..109ca26c31f
--- /dev/null
+++ b/apps/files_external/lib/Command/Option.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Command;
+
+use OCA\Files_external\Lib\StorageConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Option extends Config {
+ protected function configure() {
+ $this
+ ->setName('files_external:option')
+ ->setDescription('Manage mount options for a mount')
+ ->addArgument(
+ 'mount_id',
+ InputArgument::REQUIRED,
+ 'The id of the mount to edit'
+ )->addArgument(
+ 'key',
+ InputArgument::REQUIRED,
+ 'key of the mount option to set/get'
+ )->addArgument(
+ 'value',
+ InputArgument::OPTIONAL,
+ 'value to set the mount option to, when no value is provided the existing value will be printed'
+ );
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param OutputInterface $output
+ */
+ protected function getOption(StorageConfig $mount, $key, OutputInterface $output) {
+ $value = $mount->getMountOption($key);
+ if (!is_string($value)) { // show bools and objects correctly
+ $value = json_encode($value);
+ }
+ $output->writeln($value);
+ }
+
+ /**
+ * @param StorageConfig $mount
+ * @param string $key
+ * @param string $value
+ * @param OutputInterface $output
+ */
+ protected function setOption(StorageConfig $mount, $key, $value, OutputInterface $output) {
+ $decoded = json_decode($value, true);
+ if (!is_null($decoded)) {
+ $value = $decoded;
+ }
+ $mount->setMountOption($key, $value);
+ $this->globalService->updateStorage($mount);
+ }
+}
diff --git a/apps/files_external/lib/Command/Verify.php b/apps/files_external/lib/Command/Verify.php
new file mode 100644
index 00000000000..6ff871a6094
--- /dev/null
+++ b/apps/files_external/lib/Command/Verify.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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\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('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
+ 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('<error>Invalid mount configuration option "' . $configOption . '"</error>');
+ 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()
+ );
+ }
+ }
+}