From a1898dc2bf9a89def29c1437903e560609f0cf40 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 2 Nov 2015 13:13:06 +0100 Subject: [PATCH] db config backend for files_external --- apps/files_external/appinfo/database.xml | 222 +++++++++ apps/files_external/appinfo/info.xml | 2 +- apps/files_external/appinfo/update.php | 30 ++ .../lib/config/configadapter.php | 14 +- .../migration/storagemigrator.php | 136 ++++++ .../service/dbconfigservice.php | 376 +++++++++++++++ .../service/globallegacystoragesservice.php | 44 ++ .../service/globalstoragesservice.php | 62 --- .../service/legacystoragesservice.php | 209 ++++++++ .../service/storagesservice.php | 446 ++++++------------ .../service/userglobalstoragesservice.php | 61 +-- .../service/userlegacystoragesservice.php | 54 +++ .../service/userstoragesservice.php | 108 +---- .../tests/service/dbconfigservicetest.php | 233 +++++++++ .../service/globalstoragesservicetest.php | 345 +------------- .../tests/service/storagesservicetest.php | 53 ++- .../service/userglobalstoragesservicetest.php | 52 +- .../tests/service/userstoragesservicetest.php | 124 +---- 18 files changed, 1617 insertions(+), 954 deletions(-) create mode 100644 apps/files_external/appinfo/database.xml create mode 100644 apps/files_external/appinfo/update.php create mode 100644 apps/files_external/migration/storagemigrator.php create mode 100644 apps/files_external/service/dbconfigservice.php create mode 100644 apps/files_external/service/globallegacystoragesservice.php create mode 100644 apps/files_external/service/legacystoragesservice.php create mode 100644 apps/files_external/service/userlegacystoragesservice.php create mode 100644 apps/files_external/tests/service/dbconfigservicetest.php diff --git a/apps/files_external/appinfo/database.xml b/apps/files_external/appinfo/database.xml new file mode 100644 index 0000000000..27918bf981 --- /dev/null +++ b/apps/files_external/appinfo/database.xml @@ -0,0 +1,222 @@ + + *dbname* + true + false + utf8 + + *dbprefix*external_mounts + + + mount_id + integer + 0 + true + 1 + 6 + + + mount_point + text + 128 + true + + + storage_backend + text + 64 + true + + + auth_backend + text + 64 + true + + + priority + integer + 100 + 4 + true + + + + type + integer + 4 + true + + +
+ + *dbprefix*external_applicable + + + applicable_id + integer + 0 + true + 1 + 6 + + + + mount_id + integer + true + 6 + + + + type + integer + 4 + true + + + + value + text + 64 + + + mount_id_app_index + + mount_id + ascending + + + + applicable_value_index + + type + ascending + + + value + ascending + + + + applicable_value_mount_index + true + + type + ascending + + + value + ascending + + + mount_id + ascending + + + +
+ + *dbprefix*external_config + + + config_id + integer + 0 + true + 1 + 6 + + + + mount_id + integer + true + 6 + + + key + text + true + 64 + + + value + text + true + 4096 + + + + config_mount_id + + mount_id + ascending + + + + config_mount_key + true + + mount_id + ascending + + + key + ascending + + + +
+ + *dbprefix*external_options + + + option_id + integer + 0 + true + 1 + 6 + + + + mount_id + integer + true + 6 + + + key + text + true + 64 + + + value + text + true + 256 + + + + option_mount_id + + mount_id + ascending + + + + option_mount_key + true + + mount_id + ascending + + + key + ascending + + + +
+
diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index bb494a2eab..f6d583d0a5 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -14,7 +14,7 @@ admin-external-storage false - 0.4.0 + 0.5.0 diff --git a/apps/files_external/appinfo/update.php b/apps/files_external/appinfo/update.php new file mode 100644 index 0000000000..2eedfe9b88 --- /dev/null +++ b/apps/files_external/appinfo/update.php @@ -0,0 +1,30 @@ + + * + * @copyright Copyright (c) 2015, 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 + * + */ + +$installedVersion = \OC::$server->getConfig()->getAppValue('files_external', 'installed_version'); + +$app = new \OCA\Files_external\Appinfo\Application(); + +// Migration to db config +if (version_compare($installedVersion, '0.5.0', '<')) { + $migrator = $app->getContainer()->query('OCA\Files_external\Migration\StorageMigrator'); + $migrator->migrateGlobal(); +} diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php index f9640d5337..4e37e6a400 100644 --- a/apps/files_external/lib/config/configadapter.php +++ b/apps/files_external/lib/config/configadapter.php @@ -23,6 +23,7 @@ namespace OCA\Files_External\Config; +use OCA\Files_external\Migration\StorageMigrator; use OCP\Files\Storage; use OC\Files\Mount\MountPoint; use OCP\Files\Storage\IStorageFactory; @@ -44,17 +45,22 @@ class ConfigAdapter implements IMountProvider { /** @var UserGlobalStoragesService */ private $userGlobalStoragesService; + /** @var StorageMigrator */ + private $migrator; /** * @param UserStoragesService $userStoragesService * @param UserGlobalStoragesService $userGlobalStoragesService + * @param StorageMigrator $migrator */ public function __construct( UserStoragesService $userStoragesService, - UserGlobalStoragesService $userGlobalStoragesService + UserGlobalStoragesService $userGlobalStoragesService, + StorageMigrator $migrator ) { $this->userStoragesService = $userStoragesService; $this->userGlobalStoragesService = $userGlobalStoragesService; + $this->migrator = $migrator; } /** @@ -108,6 +114,8 @@ class ConfigAdapter implements IMountProvider { * @return \OCP\Files\Mount\IMountPoint[] */ public function getMountsForUser(IUser $user, IStorageFactory $loader) { + $this->migrator->migrateUser(); + $mounts = []; $this->userStoragesService->setUser($user); @@ -124,7 +132,7 @@ class ConfigAdapter implements IMountProvider { $mount = new MountPoint( $impl, - '/'.$user->getUID().'/files' . $storage->getMountPoint(), + '/' . $user->getUID() . '/files' . $storage->getMountPoint(), null, $loader, $storage->getMountOptions() @@ -145,7 +153,7 @@ class ConfigAdapter implements IMountProvider { $this->userStoragesService, $storage->getId(), $impl, - '/'.$user->getUID().'/files' . $storage->getMountPoint(), + '/' . $user->getUID() . '/files' . $storage->getMountPoint(), null, $loader, $storage->getMountOptions() diff --git a/apps/files_external/migration/storagemigrator.php b/apps/files_external/migration/storagemigrator.php new file mode 100644 index 0000000000..c8e323121e --- /dev/null +++ b/apps/files_external/migration/storagemigrator.php @@ -0,0 +1,136 @@ + + * + * @copyright Copyright (c) 2015, 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\Migration; + +use OCA\Files_External\Service\BackendService; +use OCA\Files_External\Service\DBConfigService; +use OCA\Files_external\Service\GlobalLegacyStoragesService; +use OCA\Files_external\Service\GlobalStoragesService; +use OCA\Files_external\Service\LegacyStoragesService; +use OCA\Files_external\Service\StoragesService; +use OCA\Files_external\Service\UserLegacyStoragesService; +use OCA\Files_external\Service\UserStoragesService; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\ILogger; +use OCP\IUserSession; + +/** + * Migrate mount config from mount.json to the database + */ +class StorageMigrator { + /** + * @var BackendService + */ + private $backendService; + + /** + * @var DBConfigService + */ + private $dbConfig; + + /** + * @var IUserSession + */ + private $userSession; + + /** + * @var IConfig + */ + private $config; + + /** + * @var IDBConnection + */ + private $connection; + + /** + * @var ILogger + */ + private $logger; + + /** + * StorageMigrator constructor. + * + * @param BackendService $backendService + * @param DBConfigService $dbConfig + * @param IUserSession $userSession + * @param IConfig $config + * @param IDBConnection $connection + * @param ILogger $logger + */ + public function __construct( + BackendService $backendService, + DBConfigService $dbConfig, + IUserSession $userSession, + IConfig $config, + IDBConnection $connection, + ILogger $logger + ) { + $this->backendService = $backendService; + $this->dbConfig = $dbConfig; + $this->userSession = $userSession; + $this->config = $config; + $this->connection = $connection; + $this->logger = $logger; + } + + private function migrate(LegacyStoragesService $legacyService, StoragesService $storageService) { + $existingStorage = $legacyService->getAllStorages(); + + $this->connection->beginTransaction(); + try { + foreach ($existingStorage as $storage) { + $storageService->addStorage($storage); + } + $this->connection->commit(); + } catch (\Exception $e) { + $this->logger->logException($e); + $this->connection->rollBack(); + } + } + + /** + * Migrate admin configured storages + */ + public function migrateGlobal() { + $legacyService = new GlobalLegacyStoragesService($this->backendService); + $storageService = new GlobalStoragesService($this->backendService, $this->dbConfig); + + $this->migrate($legacyService, $storageService); + } + + /** + * Migrate personal storages configured by the current user + */ + public function migrateUser() { + $userId = $this->userSession->getUser()->getUID(); + $userVersion = $this->config->getUserValue($userId, 'files_external', 'config_version', '0.0.0'); + if (version_compare($userVersion, '0.5.0', '<')) { + $this->config->setUserValue($userId, 'files_external', 'config_version', '0.5.0'); + $legacyService = new UserLegacyStoragesService($this->backendService, $this->userSession); + $storageService = new UserStoragesService($this->backendService, $this->dbConfig, $this->userSession); + + $this->migrate($legacyService, $storageService); + } + } +} diff --git a/apps/files_external/service/dbconfigservice.php b/apps/files_external/service/dbconfigservice.php new file mode 100644 index 0000000000..76f7052c4e --- /dev/null +++ b/apps/files_external/service/dbconfigservice.php @@ -0,0 +1,376 @@ + + * + * @copyright Copyright (c) 2015, 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\Service; + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +/** + * Stores the mount config in the database + */ +class DBConfigService { + const MOUNT_TYPE_ADMIN = 1; + const MOUNT_TYPE_PERSONAl = 2; + + const APPLICABLE_TYPE_GLOBAL = 1; + const APPLICABLE_TYPE_GROUP = 2; + const APPLICABLE_TYPE_USER = 3; + + /** + * @var IDBConnection + */ + private $connection; + + /** + * DBConfigService constructor. + * + * @param IDBConnection $connection + */ + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + } + + /** + * @param int $mountId + * @return array + */ + public function getMountById($mountId) { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type']) + ->from('external_mounts', 'm') + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))); + $mounts = $this->getMountsFromQuery($query); + if (count($mounts) > 0) { + return $mounts[0]; + } else { + return null; + } + } + + /** + * Get admin defined mounts + * + * @return array + */ + public function getAdminMounts() { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type']) + ->from('external_mounts') + ->where($builder->expr()->eq('type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT))); + return $this->getMountsFromQuery($query); + } + + protected function getForQuery(IQueryBuilder $builder, $type, $value) { + $query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type']) + ->from('external_mounts', 'm') + ->innerJoin('m', 'external_applicable', 'a', 'm.mount_id = a.mount_id') + ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, \PDO::PARAM_INT))); + + if (is_null($value)) { + $query = $query->andWhere($builder->expr()->isNull('a.value')); + } else { + $query = $query->andWhere($builder->expr()->eq('a.value', $builder->createNamedParameter($value))); + } + + return $query; + } + + /** + * Get mounts by applicable + * + * @param int $type any of the self::APPLICABLE_TYPE_ constants + * @param string|null $value user_id, group_id or null for global mounts + * @return array + */ + public function getMountsFor($type, $value) { + $builder = $this->connection->getQueryBuilder(); + $query = $this->getForQuery($builder, $type, $value); + + return $this->getMountsFromQuery($query); + } + + /** + * Get admin defined mounts by applicable + * + * @param int $type any of the self::APPLICABLE_TYPE_ constants + * @param string|null $value user_id, group_id or null for global mounts + * @return array + */ + public function getAdminMountsFor($type, $value) { + $builder = $this->connection->getQueryBuilder(); + $query = $this->getForQuery($builder, $type, $value); + $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT))); + + return $this->getMountsFromQuery($query); + } + + /** + * Get admin defined mounts for multiple applicable + * + * @param int $type any of the self::APPLICABLE_TYPE_ constants + * @param string[] $values user_ids or group_ids + * @return array + */ + public function getAdminMountsForMultiple($type, array $values) { + $builder = $this->connection->getQueryBuilder(); + $params = array_map(function ($value) use ($builder) { + return $builder->createNamedParameter($value, \PDO::PARAM_STR); + }, $values); + + $query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type']) + ->from('external_mounts', 'm') + ->innerJoin('m', 'external_applicable', 'a', 'm.mount_id = a.mount_id') + ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, \PDO::PARAM_INT))) + ->andWhere($builder->expr()->in('a.value', $params)); + $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, \PDO::PARAM_INT))); + + return $this->getMountsFromQuery($query); + } + + /** + * Get user defined mounts by applicable + * + * @param int $type any of the self::APPLICABLE_TYPE_ constants + * @param string|null $value user_id, group_id or null for global mounts + * @return array + */ + public function getUserMountsFor($type, $value) { + $builder = $this->connection->getQueryBuilder(); + $query = $this->getForQuery($builder, $type, $value); + $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_PERSONAl, \PDO::PARAM_INT))); + + return $this->getMountsFromQuery($query); + } + + /** + * Add a mount to the database + * + * @param string $mountPoint + * @param string $storageBackend + * @param string $authBackend + * @param int $priority + * @param int $type self::MOUNT_TYPE_ADMIN or self::MOUNT_TYPE_PERSONAL + * @return int the id of the new mount + */ + public function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) { + if (!$priority) { + $priority = 100; + } + $builder = $this->connection->getQueryBuilder(); + $query = $builder->insert('external_mounts') + ->values([ + 'mount_point' => $builder->createNamedParameter($mountPoint, \PDO::PARAM_STR), + 'storage_backend' => $builder->createNamedParameter($storageBackend, \PDO::PARAM_STR), + 'auth_backend' => $builder->createNamedParameter($authBackend, \PDO::PARAM_STR), + 'priority' => $builder->createNamedParameter($priority, \PDO::PARAM_INT), + 'type' => $builder->createNamedParameter($type, \PDO::PARAM_INT) + ]); + $query->execute(); + return (int)$this->connection->lastInsertId('external_mounts'); + } + + /** + * Remove a mount from the database + * + * @param int $mountId + */ + public function removeMount($mountId) { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->delete('external_mounts') + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))); + $query->execute(); + + $query = $builder->delete('external_applicable') + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))); + $query->execute(); + + $query = $builder->delete('external_config') + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))); + $query->execute(); + + $query = $builder->delete('external_options') + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))); + $query->execute(); + } + + /** + * @param int $mountId + * @param string $key + * @param string $value + */ + public function setConfig($mountId, $key, $value) { + $count = $this->connection->insertIfNotExist('*PREFIX*external_config', [ + 'mount_id' => $mountId, + 'key' => $key, + 'value' => $value + ], ['mount_id', 'key']); + if ($count === 0) { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->update('external_config') + ->set('value', $builder->createNamedParameter($value, \PDO::PARAM_STR)) + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))) + ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, \PDO::PARAM_STR))); + $query->execute(); + } + } + + /** + * @param int $mountId + * @param string $key + * @param string $value + */ + public function setOption($mountId, $key, $value) { + $count = $this->connection->insertIfNotExist('*PREFIX*external_options', [ + 'mount_id' => $mountId, + 'key' => $key, + 'value' => json_encode($value) + ], ['mount_id', 'key']); + if ($count === 0) { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->update('external_options') + ->set('value', $builder->createNamedParameter(json_encode($value), \PDO::PARAM_STR)) + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))) + ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, \PDO::PARAM_STR))); + $query->execute(); + } + } + + public function addApplicable($mountId, $type, $value) { + $this->connection->insertIfNotExist('*PREFIX*external_applicable', [ + 'mount_id' => $mountId, + 'type' => $type, + 'value' => $value + ], ['mount_id', 'type', 'value']); + } + + public function removeApplicable($mountId, $type, $value) { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->delete('external_applicable') + ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, \PDO::PARAM_INT))) + ->andWhere($builder->expr()->eq('type', $builder->createNamedParameter($type, \PDO::PARAM_INT))) + ->andWhere($builder->expr()->eq('value', $builder->createNamedParameter($value, \PDO::PARAM_STR))); + $query->execute(); + } + + private function getMountsFromQuery(IQueryBuilder $query) { + $result = $query->execute(); + $mounts = $result->fetchAll(); + + $mountIds = array_map(function ($mount) { + return $mount['mount_id']; + }, $mounts); + + $applicable = $this->getApplicableForMounts($mountIds); + $config = $this->getConfigForMounts($mountIds); + $options = $this->getOptionsForMounts($mountIds); + + return array_map(function ($mount, $applicable, $config, $options) { + $mount['type'] = (int)$mount['type']; + $mount['priority'] = (int)$mount['priority']; + $mount['applicable'] = $applicable; + $mount['config'] = $config; + $mount['options'] = $options; + return $mount; + }, $mounts, $applicable, $config, $options); + } + + /** + * Get mount options from a table grouped by mount id + * + * @param string $table + * @param string[] $fields + * @param int[] $mountIds + * @return array [$mountId => [['field1' => $value1, ...], ...], ...] + */ + private function selectForMounts($table, array $fields, array $mountIds) { + if (count($mountIds) === 0) { + return []; + } + $builder = $this->connection->getQueryBuilder(); + $fields[] = 'mount_id'; + $placeHolders = array_map(function ($id) use ($builder) { + return $builder->createPositionalParameter($id, \PDO::PARAM_INT); + }, $mountIds); + $query = $builder->select($fields) + ->from($table) + ->where($builder->expr()->in('mount_id', $placeHolders)); + $rows = $query->execute()->fetchAll(); + + $result = []; + foreach ($mountIds as $mountId) { + $result[$mountId] = []; + } + foreach ($rows as $row) { + if (isset($row['type'])) { + $row['type'] = (int)$row['type']; + } + $result[$row['mount_id']][] = $row; + } + return $result; + } + + /** + * @param int[] $mountIds + * @return array [$id => [['type' => $type, 'value' => $value], ...], ...] + */ + public function getApplicableForMounts($mountIds) { + return $this->selectForMounts('external_applicable', ['type', 'value'], $mountIds); + } + + /** + * @param int[] $mountIds + * @return array [$id => ['key1' => $value1, ...], ...] + */ + public function getConfigForMounts($mountIds) { + $mountConfigs = $this->selectForMounts('external_config', ['key', 'value'], $mountIds); + return array_map([$this, 'createKeyValueMap'], $mountConfigs); + } + + /** + * @param int[] $mountIds + * @return array [$id => ['key1' => $value1, ...], ...] + */ + public function getOptionsForMounts($mountIds) { + $mountOptions = $this->selectForMounts('external_options', ['key', 'value'], $mountIds); + $optionsMap = array_map([$this, 'createKeyValueMap'], $mountOptions); + return array_map(function (array $options) { + return array_map(function ($option) { + return json_decode($option); + }, $options); + }, $optionsMap); + } + + /** + * @param array $keyValuePairs [['key'=>$key, 'value=>$value], ...] + * @return array ['key1' => $value1, ...] + */ + private function createKeyValueMap(array $keyValuePairs) { + $keys = array_map(function ($pair) { + return $pair['key']; + }, $keyValuePairs); + $values = array_map(function ($pair) { + return $pair['value']; + }, $keyValuePairs); + + return array_combine($keys, $values); + } +} diff --git a/apps/files_external/service/globallegacystoragesservice.php b/apps/files_external/service/globallegacystoragesservice.php new file mode 100644 index 0000000000..cc6a8862cd --- /dev/null +++ b/apps/files_external/service/globallegacystoragesservice.php @@ -0,0 +1,44 @@ + + * + * @copyright Copyright (c) 2015, 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\Service; + +/** + * Read admin defined mounts from the legacy mount.json + */ +class GlobalLegacyStoragesService extends LegacyStoragesService { + /** + * @param BackendService $backendService + */ + public function __construct(BackendService $backendService) { + $this->backendService = $backendService; + } + + /** + * Read legacy config data + * + * @return array list of mount configs + */ + protected function readLegacyConfig() { + // read global config + return \OC_Mount_Config::readData(); + } +} diff --git a/apps/files_external/service/globalstoragesservice.php b/apps/files_external/service/globalstoragesservice.php index ec9b8e782f..2d25288e7b 100644 --- a/apps/files_external/service/globalstoragesservice.php +++ b/apps/files_external/service/globalstoragesservice.php @@ -33,68 +33,6 @@ use \OCA\Files_external\NotFoundException; * Service class to manage global external storages */ class GlobalStoragesService extends StoragesService { - - /** - * Write the storages to the configuration. - * - * @param array $storages map of storage id to storage config - */ - public function writeConfig($storages) { - // let the horror begin - $mountPoints = []; - foreach ($storages as $storageConfig) { - $mountPoint = $storageConfig->getMountPoint(); - $oldBackendOptions = $storageConfig->getBackendOptions(); - $storageConfig->setBackendOptions( - \OC_Mount_Config::encryptPasswords( - $oldBackendOptions - ) - ); - - // system mount - $rootMountPoint = '/$user/files/' . ltrim($mountPoint, '/'); - - $applicableUsers = $storageConfig->getApplicableUsers(); - $applicableGroups = $storageConfig->getApplicableGroups(); - foreach ($applicableUsers as $applicable) { - $this->addMountPoint( - $mountPoints, - \OC_Mount_Config::MOUNT_TYPE_USER, - $applicable, - $rootMountPoint, - $storageConfig - ); - } - - foreach ($applicableGroups as $applicable) { - $this->addMountPoint( - $mountPoints, - \OC_Mount_Config::MOUNT_TYPE_GROUP, - $applicable, - $rootMountPoint, - $storageConfig - ); - } - - // if neither "applicableGroups" or "applicableUsers" were set, use "all" user - if (empty($applicableUsers) && empty($applicableGroups)) { - $this->addMountPoint( - $mountPoints, - \OC_Mount_Config::MOUNT_TYPE_USER, - 'all', - $rootMountPoint, - $storageConfig - ); - } - - // restore old backend options where the password was not encrypted, - // because we don't want to change the state of the original object - $storageConfig->setBackendOptions($oldBackendOptions); - } - - $this->writeLegacyConfig($mountPoints); - } - /** * Triggers $signal for all applicable users of the given * storage diff --git a/apps/files_external/service/legacystoragesservice.php b/apps/files_external/service/legacystoragesservice.php new file mode 100644 index 0000000000..19cec733c1 --- /dev/null +++ b/apps/files_external/service/legacystoragesservice.php @@ -0,0 +1,209 @@ + + * + * @copyright Copyright (c) 2015, 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\Service; + +use \OCA\Files_external\Lib\StorageConfig; + +/** + * Read mount config from legacy mount.json + */ +abstract class LegacyStoragesService { + /** @var BackendService */ + protected $backendService; + + /** + * Read legacy config data + * + * @return array list of mount configs + */ + abstract protected function readLegacyConfig(); + + /** + * Copy legacy storage options into the given storage config object. + * + * @param StorageConfig $storageConfig storage config to populate + * @param string $mountType mount type + * @param string $applicable applicable user or group + * @param array $storageOptions legacy storage options + * + * @return StorageConfig populated storage config + */ + protected function populateStorageConfigWithLegacyOptions( + &$storageConfig, + $mountType, + $applicable, + $storageOptions + ) { + $backend = $this->backendService->getBackend($storageOptions['backend']); + if (!$backend) { + throw new \UnexpectedValueException('Invalid backend ' . $storageOptions['backend']); + } + $storageConfig->setBackend($backend); + if (isset($storageOptions['authMechanism']) && $storageOptions['authMechanism'] !== 'builtin::builtin') { + $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']); + } else { + $authMechanism = $backend->getLegacyAuthMechanism($storageOptions); + $storageOptions['authMechanism'] = 'null'; // to make error handling easier + } + if (!$authMechanism) { + throw new \UnexpectedValueException('Invalid authentication mechanism ' . $storageOptions['authMechanism']); + } + $storageConfig->setAuthMechanism($authMechanism); + $storageConfig->setBackendOptions($storageOptions['options']); + if (isset($storageOptions['mountOptions'])) { + $storageConfig->setMountOptions($storageOptions['mountOptions']); + } + if (!isset($storageOptions['priority'])) { + $storageOptions['priority'] = $backend->getPriority(); + } + $storageConfig->setPriority($storageOptions['priority']); + if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) { + $applicableUsers = $storageConfig->getApplicableUsers(); + if ($applicable !== 'all') { + $applicableUsers[] = $applicable; + $storageConfig->setApplicableUsers($applicableUsers); + } + } else if ($mountType === \OC_Mount_Config::MOUNT_TYPE_GROUP) { + $applicableGroups = $storageConfig->getApplicableGroups(); + $applicableGroups[] = $applicable; + $storageConfig->setApplicableGroups($applicableGroups); + } + return $storageConfig; + } + + /** + * Read the external storages config + * + * @return StorageConfig[] map of storage id to storage config + */ + public function getAllStorages() { + $mountPoints = $this->readLegacyConfig(); + /** + * Here is the how the horribly messy mount point array looks like + * from the mount.json file: + * + * $storageOptions = $mountPoints[$mountType][$applicable][$mountPath] + * + * - $mountType is either "user" or "group" + * - $applicable is the name of a user or group (or the current user for personal mounts) + * - $mountPath is the mount point path (where the storage must be mounted) + * - $storageOptions is a map of storage options: + * - "priority": storage priority + * - "backend": backend identifier + * - "class": LEGACY backend class name + * - "options": backend-specific options + * - "authMechanism": authentication mechanism identifier + * - "mountOptions": mount-specific options (ex: disable previews, scanner, etc) + */ + // group by storage id + /** @var StorageConfig[] $storages */ + $storages = []; + // for storages without id (legacy), group by config hash for + // later processing + $storagesWithConfigHash = []; + foreach ($mountPoints as $mountType => $applicables) { + foreach ($applicables as $applicable => $mountPaths) { + foreach ($mountPaths as $rootMountPath => $storageOptions) { + $currentStorage = null; + /** + * Flag whether the config that was read already has an id. + * If not, it will use a config hash instead and generate + * a proper id later + * + * @var boolean + */ + $hasId = false; + // the root mount point is in the format "/$user/files/the/mount/point" + // we remove the "/$user/files" prefix + $parts = explode('/', ltrim($rootMountPath, '/'), 3); + if (count($parts) < 3) { + // something went wrong, skip + \OCP\Util::writeLog( + 'files_external', + 'Could not parse mount point "' . $rootMountPath . '"', + \OCP\Util::ERROR + ); + continue; + } + $relativeMountPath = rtrim($parts[2], '/'); + // note: we cannot do this after the loop because the decrypted config + // options might be needed for the config hash + $storageOptions['options'] = \OC_Mount_Config::decryptPasswords($storageOptions['options']); + if (!isset($storageOptions['backend'])) { + $storageOptions['backend'] = $storageOptions['class']; // legacy compat + } + if (!isset($storageOptions['authMechanism'])) { + $storageOptions['authMechanism'] = null; // ensure config hash works + } + if (isset($storageOptions['id'])) { + $configId = (int)$storageOptions['id']; + if (isset($storages[$configId])) { + $currentStorage = $storages[$configId]; + } + $hasId = true; + } else { + // missing id in legacy config, need to generate + // but at this point we don't know the max-id, so use + // first group it by config hash + $storageOptions['mountpoint'] = $rootMountPath; + $configId = \OC_Mount_Config::makeConfigHash($storageOptions); + if (isset($storagesWithConfigHash[$configId])) { + $currentStorage = $storagesWithConfigHash[$configId]; + } + } + if (is_null($currentStorage)) { + // create new + $currentStorage = new StorageConfig($configId); + $currentStorage->setMountPoint($relativeMountPath); + } + try { + $this->populateStorageConfigWithLegacyOptions( + $currentStorage, + $mountType, + $applicable, + $storageOptions + ); + if ($hasId) { + $storages[$configId] = $currentStorage; + } else { + $storagesWithConfigHash[$configId] = $currentStorage; + } + } catch (\UnexpectedValueException $e) { + // dont die if a storage backend doesn't exist + \OCP\Util::writeLog( + 'files_external', + 'Could not load storage: "' . $e->getMessage() . '"', + \OCP\Util::ERROR + ); + } + } + } + } + + // convert parameter values + foreach ($storages as $storage) { + $storage->getBackend()->validateStorageDefinition($storage); + $storage->getAuthMechanism()->validateStorageDefinition($storage); + } + return $storages; + } +} diff --git a/apps/files_external/service/storagesservice.php b/apps/files_external/service/storagesservice.php index c847930ba2..9be6498435 100644 --- a/apps/files_external/service/storagesservice.php +++ b/apps/files_external/service/storagesservice.php @@ -41,89 +41,61 @@ abstract class StoragesService { /** @var BackendService */ protected $backendService; + /** + * @var DBConfigService + */ + protected $dbConfig; + /** * @param BackendService $backendService + * @param DBConfigService $dbConfigService */ - public function __construct(BackendService $backendService) { + public function __construct(BackendService $backendService, DBConfigService $dbConfigService) { $this->backendService = $backendService; + $this->dbConfig = $dbConfigService; } - /** - * Read legacy config data - * - * @return array list of mount configs - */ - protected function readLegacyConfig() { - // read global config - return \OC_Mount_Config::readData(); + protected function readDBConfig() { + return $this->dbConfig->getAdminMounts(); } - /** - * Write legacy config data - * - * @param array $mountPoints - */ - protected function writeLegacyConfig(array $mountPoints) { - // write global config - \OC_Mount_Config::writeData(null, $mountPoints); - } + protected function getStorageConfigFromDBMount(array $mount) { + $applicableUsers = array_filter($mount['applicable'], function ($applicable) { + return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_USER; + }); + $applicableUsers = array_map(function ($applicable) { + return $applicable['value']; + }, $applicableUsers); - /** - * Copy legacy storage options into the given storage config object. - * - * @param StorageConfig $storageConfig storage config to populate - * @param string $mountType mount type - * @param string $applicable applicable user or group - * @param array $storageOptions legacy storage options - * - * @return StorageConfig populated storage config - */ - protected function populateStorageConfigWithLegacyOptions( - &$storageConfig, - $mountType, - $applicable, - $storageOptions - ) { - $backend = $this->backendService->getBackend($storageOptions['backend']); - if (!$backend) { - throw new \UnexpectedValueException('Invalid backend '.$storageOptions['backend']); - } - $storageConfig->setBackend($backend); + $applicableGroups = array_filter($mount['applicable'], function ($applicable) { + return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_GROUP; + }); + $applicableGroups = array_map(function ($applicable) { + return $applicable['value']; + }, $applicableGroups); - if (isset($storageOptions['authMechanism']) && $storageOptions['authMechanism'] !== 'builtin::builtin') { - $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']); - } else { - $authMechanism = $backend->getLegacyAuthMechanism($storageOptions); - $storageOptions['authMechanism'] = 'null'; // to make error handling easier + try { + $config = $this->createStorage( + $mount['mount_point'], + $mount['storage_backend'], + $mount['auth_backend'], + $mount['config'], + $mount['options'], + array_values($applicableUsers), + array_values($applicableGroups), + $mount['priority'] + ); + $config->setId((int)$mount['mount_id']); + return $config; + } catch (\UnexpectedValueException $e) { + // dont die if a storage backend doesn't exist + \OCP\Util::writeLog( + 'files_external', + 'Could not load storage: "' . $e->getMessage() . '"', + \OCP\Util::ERROR + ); + return null; } - if (!$authMechanism) { - throw new \UnexpectedValueException('Invalid authentication mechanism '.$storageOptions['authMechanism']); - } - $storageConfig->setAuthMechanism($authMechanism); - - $storageConfig->setBackendOptions($storageOptions['options']); - if (isset($storageOptions['mountOptions'])) { - $storageConfig->setMountOptions($storageOptions['mountOptions']); - } - if (!isset($storageOptions['priority'])) { - $storageOptions['priority'] = $backend->getPriority(); - } - $storageConfig->setPriority($storageOptions['priority']); - - if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) { - $applicableUsers = $storageConfig->getApplicableUsers(); - if ($applicable !== 'all') { - $applicableUsers[] = $applicable; - $storageConfig->setApplicableUsers($applicableUsers); - } - } else if ($mountType === \OC_Mount_Config::MOUNT_TYPE_GROUP) { - $applicableGroups = $storageConfig->getApplicableGroups(); - $applicableGroups[] = $applicable; - $storageConfig->setApplicableGroups($applicableGroups); - } - - - return $storageConfig; } /** @@ -132,198 +104,19 @@ abstract class StoragesService { * @return array map of storage id to storage config */ protected function readConfig() { - $mountPoints = $this->readLegacyConfig(); + $mounts = $this->readDBConfig(); + $configs = array_map([$this, 'getStorageConfigFromDBMount'], $mounts); + $configs = array_filter($configs, function ($config) { + return $config instanceof StorageConfig; + }); - /** - * Here is the how the horribly messy mount point array looks like - * from the mount.json file: - * - * $storageOptions = $mountPoints[$mountType][$applicable][$mountPath] - * - * - $mountType is either "user" or "group" - * - $applicable is the name of a user or group (or the current user for personal mounts) - * - $mountPath is the mount point path (where the storage must be mounted) - * - $storageOptions is a map of storage options: - * - "priority": storage priority - * - "backend": backend identifier - * - "class": LEGACY backend class name - * - "options": backend-specific options - * - "authMechanism": authentication mechanism identifier - * - "mountOptions": mount-specific options (ex: disable previews, scanner, etc) - */ + $keys = array_map(function (StorageConfig $config) { + return $config->getId(); + }, $configs); - // group by storage id - $storages = []; - - // for storages without id (legacy), group by config hash for - // later processing - $storagesWithConfigHash = []; - - foreach ($mountPoints as $mountType => $applicables) { - foreach ($applicables as $applicable => $mountPaths) { - foreach ($mountPaths as $rootMountPath => $storageOptions) { - $currentStorage = null; - - /** - * Flag whether the config that was read already has an id. - * If not, it will use a config hash instead and generate - * a proper id later - * - * @var boolean - */ - $hasId = false; - - // the root mount point is in the format "/$user/files/the/mount/point" - // we remove the "/$user/files" prefix - $parts = explode('/', ltrim($rootMountPath, '/'), 3); - if (count($parts) < 3) { - // something went wrong, skip - \OCP\Util::writeLog( - 'files_external', - 'Could not parse mount point "' . $rootMountPath . '"', - \OCP\Util::ERROR - ); - continue; - } - - $relativeMountPath = rtrim($parts[2], '/'); - - // note: we cannot do this after the loop because the decrypted config - // options might be needed for the config hash - $storageOptions['options'] = \OC_Mount_Config::decryptPasswords($storageOptions['options']); - - if (!isset($storageOptions['backend'])) { - $storageOptions['backend'] = $storageOptions['class']; // legacy compat - } - if (!isset($storageOptions['authMechanism'])) { - $storageOptions['authMechanism'] = null; // ensure config hash works - } - - if (isset($storageOptions['id'])) { - $configId = (int)$storageOptions['id']; - if (isset($storages[$configId])) { - $currentStorage = $storages[$configId]; - } - $hasId = true; - } else { - // missing id in legacy config, need to generate - // but at this point we don't know the max-id, so use - // first group it by config hash - $storageOptions['mountpoint'] = $rootMountPath; - $configId = \OC_Mount_Config::makeConfigHash($storageOptions); - if (isset($storagesWithConfigHash[$configId])) { - $currentStorage = $storagesWithConfigHash[$configId]; - } - } - - if (is_null($currentStorage)) { - // create new - $currentStorage = new StorageConfig($configId); - $currentStorage->setMountPoint($relativeMountPath); - } - - try { - $this->populateStorageConfigWithLegacyOptions( - $currentStorage, - $mountType, - $applicable, - $storageOptions - ); - - if ($hasId) { - $storages[$configId] = $currentStorage; - } else { - $storagesWithConfigHash[$configId] = $currentStorage; - } - } catch (\UnexpectedValueException $e) { - // dont die if a storage backend doesn't exist - \OCP\Util::writeLog( - 'files_external', - 'Could not load storage: "' . $e->getMessage() . '"', - \OCP\Util::ERROR - ); - } - } - } - } - - // process storages with config hash, they must get a real id - if (!empty($storagesWithConfigHash)) { - $this->setRealStorageIds($storages, $storagesWithConfigHash); - } - - // convert parameter values - foreach ($storages as $storage) { - $storage->getBackend()->validateStorageDefinition($storage); - $storage->getAuthMechanism()->validateStorageDefinition($storage); - } - - return $storages; + return array_combine($keys, $configs); } - /** - * Replace config hash ID with real IDs, for migrating legacy storages - * - * @param StorageConfig[] $storages Storages with real IDs - * @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs - */ - protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) { - $nextId = $this->generateNextId($storages); - foreach ($storagesWithConfigHash as $storage) { - $storage->setId($nextId); - $storages[$nextId] = $storage; - $nextId++; - } - - // re-save the config with the generated ids - $this->writeConfig($storages); - } - - /** - * Add mount point into the messy mount point structure - * - * @param array $mountPoints messy array of mount points - * @param string $mountType mount type - * @param string $applicable single applicable user or group - * @param string $rootMountPoint root mount point to use - * @param array $storageConfig storage config to set to the mount point - */ - protected function addMountPoint(&$mountPoints, $mountType, $applicable, $rootMountPoint, $storageConfig) { - if (!isset($mountPoints[$mountType])) { - $mountPoints[$mountType] = []; - } - - if (!isset($mountPoints[$mountType][$applicable])) { - $mountPoints[$mountType][$applicable] = []; - } - - $options = [ - 'id' => $storageConfig->getId(), - 'backend' => $storageConfig->getBackend()->getIdentifier(), - //'class' => $storageConfig->getBackend()->getClass(), - 'authMechanism' => $storageConfig->getAuthMechanism()->getIdentifier(), - 'options' => $storageConfig->getBackendOptions(), - ]; - - if (!is_null($storageConfig->getPriority())) { - $options['priority'] = $storageConfig->getPriority(); - } - - $mountOptions = $storageConfig->getMountOptions(); - if (!empty($mountOptions)) { - $options['mountOptions'] = $mountOptions; - } - - $mountPoints[$mountType][$applicable][$rootMountPoint] = $options; - } - - /** - * Write the storages to the configuration. - * - * @param array $storages map of storage id to storage config - */ - abstract protected function writeConfig($storages); - /** * Get a storage with status * @@ -333,19 +126,19 @@ abstract class StoragesService { * @throws NotFoundException if the storage with the given id was not found */ public function getStorage($id) { - $allStorages = $this->readConfig(); + $mount = $this->dbConfig->getMountById($id); - if (!isset($allStorages[$id])) { + if (!is_array($mount)) { throw new NotFoundException('Storage with id "' . $id . '" not found'); } - return $allStorages[$id]; + return $this->getStorageConfigFromDBMount($mount); } /** * Gets all storages, valid or not * - * @return array array of storage configs + * @return StorageConfig[] array of storage configs */ public function getAllStorages() { return $this->readConfig(); @@ -354,7 +147,7 @@ abstract class StoragesService { /** * Gets all valid storages * - * @return array + * @return StorageConfig[] */ public function getStorages() { return array_filter($this->getAllStorages(), [$this, 'validateStorage']); @@ -392,24 +185,50 @@ abstract class StoragesService { */ abstract public function getVisibilityType(); + protected function getType() { + return DBConfigService::MOUNT_TYPE_ADMIN; + } + /** * Add new storage to the configuration * - * @param array $newStorage storage attributes + * @param StorageConfig $newStorage storage attributes * * @return StorageConfig storage config, with added id */ public function addStorage(StorageConfig $newStorage) { $allStorages = $this->readConfig(); - $configId = $this->generateNextId($allStorages); + $configId = $this->dbConfig->addMount( + $newStorage->getMountPoint(), + $newStorage->getBackend()->getIdentifier(), + $newStorage->getAuthMechanism()->getIdentifier(), + $newStorage->getPriority(), + $this->getType() + ); + $newStorage->setId($configId); + foreach ($newStorage->getApplicableUsers() as $user) { + $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_USER, $user); + } + foreach ($newStorage->getApplicableGroups() as $group) { + $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_GROUP, $group); + } + foreach ($newStorage->getBackendOptions() as $key => $value) { + $this->dbConfig->setConfig($configId, $key, $value); + } + foreach ($newStorage->getMountOptions() as $key => $value) { + $this->dbConfig->setOption($configId, $key, $value); + } + + if (count($newStorage->getApplicableUsers()) === 0 && count($newStorage->getApplicableGroups()) === 0) { + $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + } + // add new storage $allStorages[$configId] = $newStorage; - $this->writeConfig($allStorages); - $this->triggerHooks($newStorage, Filesystem::signal_create_mount); $newStorage->setStatus(StorageNotAvailableException::STATUS_SUCCESS); @@ -442,11 +261,11 @@ abstract class StoragesService { ) { $backend = $this->backendService->getBackend($backendIdentifier); if (!$backend) { - throw new \InvalidArgumentException('Unable to get backend for '.$backendIdentifier); + throw new \InvalidArgumentException('Unable to get backend for ' . $backendIdentifier); } $authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier); if (!$authMechanism) { - throw new \InvalidArgumentException('Unable to get authentication mechanism for '.$authMechanismIdentifier); + throw new \InvalidArgumentException('Unable to get authentication mechanism for ' . $authMechanismIdentifier); } $newStorage = new StorageConfig(); $newStorage->setMountPoint($mountPoint); @@ -519,21 +338,56 @@ abstract class StoragesService { * @throws NotFoundException if the given storage does not exist in the config */ public function updateStorage(StorageConfig $updatedStorage) { - $allStorages = $this->readConfig(); - $id = $updatedStorage->getId(); - if (!isset($allStorages[$id])) { - throw new NotFoundException('Storage with id "' . $id . '" not found'); - } - $oldStorage = $allStorages[$id]; - // ensure objectstore is persistent - if ($objectstore = $oldStorage->getBackendOption('objectstore')) { - $updatedStorage->setBackendOption('objectstore', $objectstore); + $existingMount = $this->dbConfig->getMountById($id); + + if (!is_array($existingMount)) { + throw new NotFoundException('Storage with id "' . $id . '" not found while updating storage'); } - $allStorages[$id] = $updatedStorage; - $this->writeConfig($allStorages); + $oldStorage = $this->getStorageConfigFromDBMount($existingMount); + + $removedUsers = array_diff($oldStorage->getApplicableUsers(), $updatedStorage->getApplicableUsers()); + $removedGroups = array_diff($oldStorage->getApplicableGroups(), $updatedStorage->getApplicableGroups()); + $addedUsers = array_diff($updatedStorage->getApplicableUsers(), $oldStorage->getApplicableUsers()); + $addedGroups = array_diff($updatedStorage->getApplicableGroups(), $oldStorage->getApplicableGroups()); + + $oldUserCount = count($oldStorage->getApplicableUsers()); + $oldGroupCount = count($oldStorage->getApplicableGroups()); + $newUserCount = count($oldStorage->getApplicableUsers()); + $newGroupCount = count($oldStorage->getApplicableGroups()); + $wasGlobal = ($oldUserCount + $oldGroupCount) === 0; + $isGlobal = ($newUserCount + $newGroupCount) === 0; + + foreach ($removedUsers as $user) { + $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, $user); + } + foreach ($removedGroups as $group) { + $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_GROUP, $group); + } + foreach ($addedUsers as $user) { + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, $user); + } + foreach ($addedGroups as $group) { + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GROUP, $group); + } + + if ($wasGlobal && !$isGlobal) { + $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + } else if (!$wasGlobal && $isGlobal) { + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + } + + $changedConfig = array_diff_assoc($updatedStorage->getBackendOptions(), $oldStorage->getBackendOptions()); + $changedOptions = array_diff_assoc($updatedStorage->getMountOptions(), $oldStorage->getMountOptions()); + + foreach ($changedConfig as $key => $value) { + $this->dbConfig->setConfig($id, $key, $value); + } + foreach ($changedOptions as $key => $value) { + $this->dbConfig->setOption($id, $key, $value); + } $this->triggerChangeHooks($oldStorage, $updatedStorage); @@ -548,17 +402,15 @@ abstract class StoragesService { * @throws NotFoundException if no storage was found with the given id */ public function removeStorage($id) { - $allStorages = $this->readConfig(); + $existingMount = $this->dbConfig->getMountById($id); - if (!isset($allStorages[$id])) { + if (!is_array($existingMount)) { throw new NotFoundException('Storage with id "' . $id . '" not found'); } - $deletedStorage = $allStorages[$id]; - unset($allStorages[$id]); - - $this->writeConfig($allStorages); + $this->dbConfig->removeMount($id); + $deletedStorage = $this->getStorageConfigFromDBMount($existingMount); $this->triggerHooks($deletedStorage, Filesystem::signal_delete_mount); // delete oc_storages entries and oc_filecache @@ -577,24 +429,6 @@ abstract class StoragesService { } } - /** - * Generates a configuration id to use for a new configuration entry. - * - * @param array $allStorages array of all storage configs - * - * @return int id - */ - protected function generateNextId($allStorages) { - if (empty($allStorages)) { - return 1; - } - // note: this will mess up with with concurrency, - // but so did the mount.json. This horribly hack - // will disappear once we move to DB tables to - // store the config - return (max(array_keys($allStorages)) + 1); - } - /** * Returns the rusty storage id from oc_storages from the given storage config. * diff --git a/apps/files_external/service/userglobalstoragesservice.php b/apps/files_external/service/userglobalstoragesservice.php index afe77e1e05..cb49f0f672 100644 --- a/apps/files_external/service/userglobalstoragesservice.php +++ b/apps/files_external/service/userglobalstoragesservice.php @@ -41,15 +41,17 @@ class UserGlobalStoragesService extends GlobalStoragesService { /** * @param BackendService $backendService + * @param DBConfigService $dbConfig * @param IUserSession $userSession * @param IGroupManager $groupManager */ public function __construct( BackendService $backendService, + DBConfigService $dbConfig, IUserSession $userSession, IGroupManager $groupManager ) { - parent::__construct($backendService); + parent::__construct($backendService, $dbConfig); $this->userSession = $userSession; $this->groupManager = $groupManager; } @@ -67,46 +69,27 @@ class UserGlobalStoragesService extends GlobalStoragesService { } } - /** - * Read legacy config data - * - * @return array list of mount configs - */ - protected function readLegacyConfig() { - // read global config - $data = parent::readLegacyConfig(); - $userId = $this->getUser()->getUID(); - - // don't use array_filter() with ARRAY_FILTER_USE_KEY, it's PHP 5.6+ - if (isset($data[\OC_Mount_Config::MOUNT_TYPE_USER])) { - $newData = []; - foreach ($data[\OC_Mount_Config::MOUNT_TYPE_USER] as $key => $value) { - if (strtolower($key) === strtolower($userId) || $key === 'all') { - $newData[$key] = $value; - } - } - $data[\OC_Mount_Config::MOUNT_TYPE_USER] = $newData; + protected function readDBConfig() { + $userMounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_USER, $this->getUser()->getUID()); + $globalMounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + $groups = $this->groupManager->getUserGroupIds($this->getUser()); + if (is_array($groups) && count($groups) !== 0) { + $groupMounts = $this->dbConfig->getAdminMountsForMultiple(DBConfigService::APPLICABLE_TYPE_GROUP, $groups); + } else { + $groupMounts = []; } - - if (isset($data[\OC_Mount_Config::MOUNT_TYPE_GROUP])) { - $newData = []; - foreach ($data[\OC_Mount_Config::MOUNT_TYPE_GROUP] as $key => $value) { - if ($this->groupManager->isInGroup($userId, $key)) { - $newData[$key] = $value; - } - } - $data[\OC_Mount_Config::MOUNT_TYPE_GROUP] = $newData; - } - - return $data; + return array_merge($userMounts, $groupMounts, $globalMounts); } - /** - * Write legacy config data - * - * @param array $mountPoints - */ - protected function writeLegacyConfig(array $mountPoints) { + public function addStorage(StorageConfig $newStorage) { + throw new \DomainException('UserGlobalStoragesService writing disallowed'); + } + + public function updateStorage(StorageConfig $updatedStorage) { + throw new \DomainException('UserGlobalStoragesService writing disallowed'); + } + + public function removeStorage($id) { throw new \DomainException('UserGlobalStoragesService writing disallowed'); } @@ -126,7 +109,7 @@ class UserGlobalStoragesService extends GlobalStoragesService { $result = []; foreach ($storagesByMountpoint as $storageList) { - $storage = array_reduce($storageList, function($carry, $item) { + $storage = array_reduce($storageList, function ($carry, $item) { if (isset($carry)) { $carryPriorityType = $this->getPriorityType($carry); $itemPriorityType = $this->getPriorityType($item); diff --git a/apps/files_external/service/userlegacystoragesservice.php b/apps/files_external/service/userlegacystoragesservice.php new file mode 100644 index 0000000000..13f34225d6 --- /dev/null +++ b/apps/files_external/service/userlegacystoragesservice.php @@ -0,0 +1,54 @@ + + * + * @copyright Copyright (c) 2015, 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\Service; + +use OCP\IUserSession; + +/** + * Read user defined mounts from the legacy mount.json + */ +class UserLegacyStoragesService extends LegacyStoragesService { + /** + * @var IUserSession + */ + private $userSession; + + /** + * @param BackendService $backendService + * @param IUserSession $userSession + */ + public function __construct(BackendService $backendService, IUserSession $userSession) { + $this->backendService = $backendService; + $this->userSession = $userSession; + } + + /** + * Read legacy config data + * + * @return array list of storage configs + */ + protected function readLegacyConfig() { + // read user config + $user = $this->userSession->getUser()->getUID(); + return \OC_Mount_Config::readData($user); + } +} diff --git a/apps/files_external/service/userstoragesservice.php b/apps/files_external/service/userstoragesservice.php index a8cdf60ad9..5cf04578ca 100644 --- a/apps/files_external/service/userstoragesservice.php +++ b/apps/files_external/service/userstoragesservice.php @@ -35,107 +35,26 @@ use \OCA\Files_External\Service\UserTrait; * (aka personal storages) */ class UserStoragesService extends StoragesService { - use UserTrait; /** * Create a user storages service * * @param BackendService $backendService + * @param DBConfigService $dbConfig * @param IUserSession $userSession user session */ public function __construct( BackendService $backendService, + DBConfigService $dbConfig, IUserSession $userSession ) { $this->userSession = $userSession; - parent::__construct($backendService); + parent::__construct($backendService, $dbConfig); } - /** - * Read legacy config data - * - * @return array list of storage configs - */ - protected function readLegacyConfig() { - // read user config - $user = $this->getUser()->getUID(); - return \OC_Mount_Config::readData($user); - } - - /** - * Write legacy config data - * - * @param array $mountPoints - */ - protected function writeLegacyConfig(array $mountPoints) { - // write user config - $user = $this->getUser()->getUID(); - \OC_Mount_Config::writeData($user, $mountPoints); - } - - /** - * Read the external storages config - * - * @return array map of storage id to storage config - */ - protected function readConfig() { - $user = $this->getUser()->getUID(); - // TODO: in the future don't rely on the global config reading code - $storages = parent::readConfig(); - - $filteredStorages = []; - foreach ($storages as $configId => $storage) { - // filter out all bogus storages that aren't for the current user - if (!in_array($user, $storage->getApplicableUsers())) { - continue; - } - - // clear applicable users, should not be used - $storage->setApplicableUsers([]); - - // strip out unneeded applicableUser fields - $filteredStorages[$configId] = $storage; - } - - return $filteredStorages; - } - - /** - * Write the storages to the user's configuration. - * - * @param array $storages map of storage id to storage config - */ - public function writeConfig($storages) { - $user = $this->getUser()->getUID(); - - // let the horror begin - $mountPoints = []; - foreach ($storages as $storageConfig) { - $mountPoint = $storageConfig->getMountPoint(); - $oldBackendOptions = $storageConfig->getBackendOptions(); - $storageConfig->setBackendOptions( - \OC_Mount_Config::encryptPasswords( - $oldBackendOptions - ) - ); - - $rootMountPoint = '/' . $user . '/files/' . ltrim($mountPoint, '/'); - - $this->addMountPoint( - $mountPoints, - \OC_Mount_Config::MOUNT_TYPE_USER, - $user, - $rootMountPoint, - $storageConfig - ); - - // restore old backend options where the password was not encrypted, - // because we don't want to change the state of the original object - $storageConfig->setBackendOptions($oldBackendOptions); - } - - $this->writeLegacyConfig($mountPoints); + protected function readDBConfig() { + return $this->dbConfig->getUserMountsFor(DBConfigService::APPLICABLE_TYPE_USER, $this->getUser()->getUID()); } /** @@ -173,6 +92,23 @@ class UserStoragesService extends StoragesService { } } + protected function getType() { + return DBConfigService::MOUNT_TYPE_PERSONAl; + } + + /** + * Add new storage to the configuration + * + * @param StorageConfig $newStorage storage attributes + * + * @return StorageConfig storage config, with added id + */ + public function addStorage(StorageConfig $newStorage) { + $config = parent::addStorage($newStorage); + $this->dbConfig->addApplicable($config->getId(), DBConfigService::APPLICABLE_TYPE_USER, $this->getUser()->getUID()); + return $config; + } + /** * Get the visibility type for this controller, used in validation * diff --git a/apps/files_external/tests/service/dbconfigservicetest.php b/apps/files_external/tests/service/dbconfigservicetest.php new file mode 100644 index 0000000000..d5b4ff1585 --- /dev/null +++ b/apps/files_external/tests/service/dbconfigservicetest.php @@ -0,0 +1,233 @@ + + * + * @copyright Copyright (c) 2015, 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\Tests\Service; + + +use OCA\Files_External\Service\DBConfigService; +use OCP\IDBConnection; +use Test\TestCase; + +/** + * @group DB + */ +class DBConfigServiceTest extends TestCase { + /** + * @var DBConfigService + */ + private $dbConfig; + + /** + * @var IDBConnection + */ + private $connection; + + private $mounts = []; + + public function setUp() { + parent::setUp(); + $this->connection = \OC::$server->getDatabaseConnection(); + $this->dbConfig = new DBConfigService($this->connection); + } + + public function tearDown() { + foreach ($this->mounts as $mount) { + $this->dbConfig->removeMount($mount); + } + $this->mounts = []; + } + + private function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) { + $id = $this->dbConfig->addMount($mountPoint, $storageBackend, $authBackend, $priority, $type); + $this->mounts[] = $id; + return $id; + } + + public function testAddSimpleMount() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals('/test', $mount['mount_point']); + $this->assertEquals('foo', $mount['storage_backend']); + $this->assertEquals('bar', $mount['auth_backend']); + $this->assertEquals(100, $mount['priority']); + $this->assertEquals(DBConfigService::MOUNT_TYPE_ADMIN, $mount['type']); + $this->assertEquals([], $mount['applicable']); + $this->assertEquals([], $mount['config']); + $this->assertEquals([], $mount['options']); + } + + public function testAddApplicable() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals([ + ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id] + ], $mount['applicable']); + + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GROUP, 'bar'); + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals([ + ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id], + ['type' => DBConfigService::APPLICABLE_TYPE_GROUP, 'value' => 'bar', 'mount_id' => $id], + ['type' => DBConfigService::APPLICABLE_TYPE_GLOBAL, 'value' => null, 'mount_id' => $id] + ], $mount['applicable']); + } + + public function testAddApplicableDouble() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals([ + ['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id] + ], $mount['applicable']); + } + + public function testDeleteMount() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + + $this->dbConfig->removeMount($id); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(null, $mount); + } + + public function testRemoveApplicable() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->dbConfig->removeApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals([], $mount['applicable']); + } + + public function testSetConfig() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->setConfig($id, 'foo', 'bar'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(['foo' => 'bar'], $mount['config']); + + $this->dbConfig->setConfig($id, 'foo2', 'bar2'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(['foo' => 'bar', 'foo2' => 'bar2'], $mount['config']); + } + + public function testSetConfigOverwrite() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->setConfig($id, 'foo', 'bar'); + $this->dbConfig->setConfig($id, 'asd', '1'); + $this->dbConfig->setConfig($id, 'foo', 'qwerty'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(['foo' => 'qwerty', 'asd' => '1'], $mount['config']); + } + + public function testSetOption() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->setOption($id, 'foo', 'bar'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(['foo' => 'bar'], $mount['options']); + + $this->dbConfig->setOption($id, 'foo2', 'bar2'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(['foo' => 'bar', 'foo2' => 'bar2'], $mount['options']); + } + + public function testSetOptionOverwrite() { + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->setOption($id, 'foo', 'bar'); + $this->dbConfig->setOption($id, 'asd', '1'); + $this->dbConfig->setOption($id, 'foo', 'qwerty'); + + $mount = $this->dbConfig->getMountById($id); + $this->assertEquals(['foo' => 'qwerty', 'asd' => '1'], $mount['options']); + } + + public function testGetMountsFor() { + $mounts = $this->dbConfig->getMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->assertEquals([], $mounts); + + $id = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->dbConfig->addApplicable($id, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + + $mounts = $this->dbConfig->getMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->assertCount(1, $mounts); + $this->assertEquals($id, $mounts[0]['mount_id']); + $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id]], $mounts[0]['applicable']); + } + + public function testGetAdminMounts() { + $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->addMount('/test2', 'foo2', 'bar2', 100, DBConfigService::MOUNT_TYPE_PERSONAl); + + $mounts = $this->dbConfig->getAdminMounts(); + $this->assertCount(1, $mounts); + $this->assertEquals($id1, $mounts[0]['mount_id']); + } + + public function testGetAdminMountsFor() { + $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->addMount('/test2', 'foo2', 'bar2', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $id3 = $this->addMount('/test3', 'foo3', 'bar3', 100, DBConfigService::MOUNT_TYPE_PERSONAl); + + $this->dbConfig->addApplicable($id1, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->dbConfig->addApplicable($id3, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + + $mounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->assertCount(1, $mounts); + $this->assertEquals($id1, $mounts[0]['mount_id']); + $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id1]], $mounts[0]['applicable']); + } + + public function testGetUserMountsFor() { + $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + $this->addMount('/test2', 'foo2', 'bar2', 100, DBConfigService::MOUNT_TYPE_PERSONAl); + $id3 = $this->addMount('/test3', 'foo3', 'bar3', 100, DBConfigService::MOUNT_TYPE_PERSONAl); + + $this->dbConfig->addApplicable($id1, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->dbConfig->addApplicable($id3, DBConfigService::APPLICABLE_TYPE_USER, 'test'); + + $mounts = $this->dbConfig->getUserMountsFor(DBConfigService::APPLICABLE_TYPE_USER, 'test'); + $this->assertCount(1, $mounts); + $this->assertEquals($id3, $mounts[0]['mount_id']); + $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_USER, 'value' => 'test', 'mount_id' => $id3]], $mounts[0]['applicable']); + } + + public function testGetAdminMountsForGlobal() { + $id1 = $this->addMount('/test', 'foo', 'bar', 100, DBConfigService::MOUNT_TYPE_ADMIN); + + $this->dbConfig->addApplicable($id1, DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + + $mounts = $this->dbConfig->getAdminMountsFor(DBConfigService::APPLICABLE_TYPE_GLOBAL, null); + $this->assertCount(1, $mounts); + $this->assertEquals($id1, $mounts[0]['mount_id']); + $this->assertEquals([['type' => DBConfigService::APPLICABLE_TYPE_GLOBAL, 'value' => null, 'mount_id' => $id1]], $mounts[0]['applicable']); + } +} diff --git a/apps/files_external/tests/service/globalstoragesservicetest.php b/apps/files_external/tests/service/globalstoragesservicetest.php index c129365913..7c77616563 100644 --- a/apps/files_external/tests/service/globalstoragesservicetest.php +++ b/apps/files_external/tests/service/globalstoragesservicetest.php @@ -23,14 +23,18 @@ namespace OCA\Files_external\Tests\Service; use \OC\Files\Filesystem; +use OCA\Files_External\Service\DBConfigService; use \OCA\Files_external\Service\GlobalStoragesService; use \OCA\Files_external\NotFoundException; use \OCA\Files_external\Lib\StorageConfig; +/** + * @group DB + */ class GlobalStoragesServiceTest extends StoragesServiceTest { public function setUp() { parent::setUp(); - $this->service = new GlobalStoragesService($this->backendService); + $this->service = new GlobalStoragesService($this->backendService, $this->dbConfig); } public function tearDown() { @@ -39,7 +43,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { } protected function makeTestStorageData() { - return $this->makeStorageConfig([ + return $this->makeStorageConfig([ 'mountPoint' => 'mountpoint', 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB', 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism', @@ -133,10 +137,9 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { $storage = $this->makeStorageConfig($storageParams); $newStorage = $this->service->addStorage($storage); - $this->assertEquals(1, $newStorage->getId()); + $baseId = $newStorage->getId(); - - $newStorage = $this->service->getStorage(1); + $newStorage = $this->service->getStorage($baseId); $this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($storage->getBackend(), $newStorage->getBackend()); @@ -145,12 +148,10 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { $this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers()); $this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups()); $this->assertEquals($storage->getPriority(), $newStorage->getPriority()); - $this->assertEquals(1, $newStorage->getId()); $this->assertEquals(0, $newStorage->getStatus()); - // next one gets id 2 $nextStorage = $this->service->addStorage($storage); - $this->assertEquals(2, $nextStorage->getId()); + $this->assertEquals($baseId + 1, $nextStorage->getId()); } /** @@ -173,19 +174,18 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { ]); $newStorage = $this->service->addStorage($storage); - $this->assertEquals(1, $newStorage->getId()); + $id = $newStorage->getId(); - $updatedStorage->setId(1); + $updatedStorage->setId($id); $this->service->updateStorage($updatedStorage); - $newStorage = $this->service->getStorage(1); + $newStorage = $this->service->getStorage($id); $this->assertEquals($updatedStorage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($updatedStorage->getBackendOptions()['password'], $newStorage->getBackendOptions()['password']); $this->assertEquals($updatedStorage->getApplicableUsers(), $newStorage->getApplicableUsers()); $this->assertEquals($updatedStorage->getApplicableGroups(), $newStorage->getApplicableGroups()); $this->assertEquals($updatedStorage->getPriority(), $newStorage->getPriority()); - $this->assertEquals(1, $newStorage->getId()); $this->assertEquals(0, $newStorage->getStatus()); } @@ -442,7 +442,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { $sourceApplicableGroups, $updatedApplicableUsers, $updatedApplicableGroups, - $expectedCalls) { + $expectedCalls) { $storage = $this->makeTestStorageData(); $storage->setApplicableUsers($sourceApplicableUsers); @@ -601,7 +601,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { public function testHooksDeleteStorage( $sourceApplicableUsers, $sourceApplicableGroups, - $expectedCalls) { + $expectedCalls) { $storage = $this->makeTestStorageData(); $storage->setApplicableUsers($sourceApplicableUsers); @@ -626,321 +626,4 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { } } - /** - * Make sure it uses the correct format when reading/writing - * the legacy config - */ - public function testLegacyConfigConversionApplicableAll() { - $configFile = $this->dataDir . '/mount.json'; - - $storage = $this->makeTestStorageData(); - $storage = $this->service->addStorage($storage); - - $json = json_decode(file_get_contents($configFile), true); - - $this->assertCount(1, $json); - - $this->assertEquals([\OC_Mount_Config::MOUNT_TYPE_USER], array_keys($json)); - $this->assertEquals(['all'], array_keys($json[\OC_Mount_config::MOUNT_TYPE_USER])); - - $mountPointData = $json[\OC_Mount_config::MOUNT_TYPE_USER]['all']; - $this->assertEquals(['/$user/files/mountpoint'], array_keys($mountPointData)); - - $mountPointOptions = current($mountPointData); - $this->assertEquals(1, $mountPointOptions['id']); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']); - $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']); - $this->assertEquals(15, $mountPointOptions['priority']); - $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); - - $backendOptions = $mountPointOptions['options']; - $this->assertEquals('value1', $backendOptions['option1']); - $this->assertEquals('value2', $backendOptions['option2']); - $this->assertEquals('', $backendOptions['password']); - $this->assertNotEmpty($backendOptions['password_encrypted']); - } - - /** - * Make sure it uses the correct format when reading/writing - * the legacy config - */ - public function testLegacyConfigConversionApplicableUserAndGroup() { - $configFile = $this->dataDir . '/mount.json'; - - $storage = $this->makeTestStorageData(); - $storage->setApplicableUsers(['user1', 'user2']); - $storage->setApplicableGroups(['group1', 'group2']); - - $storage = $this->service->addStorage($storage); - - $json = json_decode(file_get_contents($configFile), true); - - $this->assertCount(2, $json); - - $this->assertTrue(isset($json[\OC_Mount_Config::MOUNT_TYPE_USER])); - $this->assertTrue(isset($json[\OC_Mount_Config::MOUNT_TYPE_GROUP])); - $this->assertEquals(['user1', 'user2'], array_keys($json[\OC_Mount_config::MOUNT_TYPE_USER])); - $this->assertEquals(['group1', 'group2'], array_keys($json[\OC_Mount_config::MOUNT_TYPE_GROUP])); - - // check that all options are the same for both users and both groups - foreach ($json[\OC_Mount_Config::MOUNT_TYPE_USER] as $mountPointData) { - $this->assertEquals(['/$user/files/mountpoint'], array_keys($mountPointData)); - - $mountPointOptions = current($mountPointData); - - $this->assertEquals(1, $mountPointOptions['id']); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']); - $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']); - $this->assertEquals(15, $mountPointOptions['priority']); - $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); - - $backendOptions = $mountPointOptions['options']; - $this->assertEquals('value1', $backendOptions['option1']); - $this->assertEquals('value2', $backendOptions['option2']); - $this->assertEquals('', $backendOptions['password']); - $this->assertNotEmpty($backendOptions['password_encrypted']); - } - - foreach ($json[\OC_Mount_Config::MOUNT_TYPE_GROUP] as $mountPointData) { - $this->assertEquals(['/$user/files/mountpoint'], array_keys($mountPointData)); - - $mountPointOptions = current($mountPointData); - - $this->assertEquals(1, $mountPointOptions['id']); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']); - $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']); - $this->assertEquals(15, $mountPointOptions['priority']); - $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); - - $backendOptions = $mountPointOptions['options']; - $this->assertEquals('value1', $backendOptions['option1']); - $this->assertEquals('value2', $backendOptions['option2']); - $this->assertEquals('', $backendOptions['password']); - $this->assertNotEmpty($backendOptions['password_encrypted']); - } - } - - /** - * Test reading in a legacy config and generating config ids. - */ - public function testReadLegacyConfigAndGenerateConfigId() { - $configFile = $this->dataDir . '/mount.json'; - - $legacyBackendOptions = [ - 'user' => 'someuser', - 'password' => 'somepassword', - ]; - $legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions); - - $legacyConfig = [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => $legacyBackendOptions, - 'mountOptions' => ['preview' => false], - ]; - // different mount options - $legacyConfig2 = [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => $legacyBackendOptions, - 'mountOptions' => ['preview' => true], - ]; - - $legacyBackendOptions2 = $legacyBackendOptions; - $legacyBackendOptions2 = ['user' => 'someuser2', 'password' => 'somepassword2']; - $legacyBackendOptions2 = \OC_Mount_Config::encryptPasswords($legacyBackendOptions2); - - // different config - $legacyConfig3 = [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => $legacyBackendOptions2, - 'mountOptions' => ['preview' => true], - ]; - - $json = [ - 'user' => [ - 'user1' => [ - '/$user/files/somemount' => $legacyConfig, - ], - // same config - 'user2' => [ - '/$user/files/somemount' => $legacyConfig, - ], - // different mountOptions - 'user3' => [ - '/$user/files/somemount' => $legacyConfig2, - ], - // different mount point - 'user4' => [ - '/$user/files/anothermount' => $legacyConfig, - ], - // different storage config - 'user5' => [ - '/$user/files/somemount' => $legacyConfig3, - ], - ], - 'group' => [ - 'group1' => [ - // will get grouped with user configs - '/$user/files/somemount' => $legacyConfig, - ], - ], - ]; - - file_put_contents($configFile, json_encode($json)); - - $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB') - ->expects($this->exactly(4)) - ->method('validateStorageDefinition'); - $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism') - ->expects($this->exactly(4)) - ->method('validateStorageDefinition'); - - $allStorages = $this->service->getAllStorages(); - - $this->assertCount(4, $allStorages); - - $storage1 = $allStorages[1]; - $storage2 = $allStorages[2]; - $storage3 = $allStorages[3]; - $storage4 = $allStorages[4]; - - $this->assertEquals('/somemount', $storage1->getMountPoint()); - $this->assertEquals('someuser', $storage1->getBackendOptions()['user']); - $this->assertEquals('somepassword', $storage1->getBackendOptions()['password']); - $this->assertEquals(['user1', 'user2'], $storage1->getApplicableUsers()); - $this->assertEquals(['group1'], $storage1->getApplicableGroups()); - $this->assertEquals(['preview' => false], $storage1->getMountOptions()); - - $this->assertEquals('/somemount', $storage2->getMountPoint()); - $this->assertEquals('someuser', $storage2->getBackendOptions()['user']); - $this->assertEquals('somepassword', $storage2->getBackendOptions()['password']); - $this->assertEquals(['user3'], $storage2->getApplicableUsers()); - $this->assertEquals([], $storage2->getApplicableGroups()); - $this->assertEquals(['preview' => true], $storage2->getMountOptions()); - - $this->assertEquals('/anothermount', $storage3->getMountPoint()); - $this->assertEquals('someuser', $storage3->getBackendOptions()['user']); - $this->assertEquals('somepassword', $storage3->getBackendOptions()['password']); - $this->assertEquals(['user4'], $storage3->getApplicableUsers()); - $this->assertEquals([], $storage3->getApplicableGroups()); - $this->assertEquals(['preview' => false], $storage3->getMountOptions()); - - $this->assertEquals('/somemount', $storage4->getMountPoint()); - $this->assertEquals('someuser2', $storage4->getBackendOptions()['user']); - $this->assertEquals('somepassword2', $storage4->getBackendOptions()['password']); - $this->assertEquals(['user5'], $storage4->getApplicableUsers()); - $this->assertEquals([], $storage4->getApplicableGroups()); - $this->assertEquals(['preview' => true], $storage4->getMountOptions()); - } - - public function testReadLegacyConfigNoAuthMechanism() { - $configFile = $this->dataDir . '/mount.json'; - - $json = [ - 'user' => [ - 'user1' => [ - '/$user/files/somemount' => [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => [], - 'mountOptions' => [], - ], - '/$user/files/othermount' => [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP', - // no authMechanism - 'options' => [], - 'mountOptions' => [], - ], - ] - ] - ]; - - file_put_contents($configFile, json_encode($json)); - - $allStorages = $this->service->getAllStorages(); - - $this->assertCount(2, $allStorages); - - $storage1 = $allStorages[1]; - $storage2 = $allStorages[2]; - - $this->assertEquals('/somemount', $storage1->getMountPoint()); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier()); - $this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier()); - - $this->assertEquals('/othermount', $storage2->getMountPoint()); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier()); - $this->assertEquals('identifier:\Other\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier()); - } - - public function testReadLegacyConfigClass() { - $configFile = $this->dataDir . '/mount.json'; - - $json = [ - 'user' => [ - 'user1' => [ - '/$user/files/somemount' => [ - 'class' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => [], - 'mountOptions' => [], - ], - '/$user/files/othermount' => [ - 'class' => 'identifier:sftp_alias', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => [], - 'mountOptions' => [], - ], - ] - ] - ]; - - file_put_contents($configFile, json_encode($json)); - - $allStorages = $this->service->getAllStorages(); - - $this->assertCount(2, $allStorages); - - $storage1 = $allStorages[1]; - $storage2 = $allStorages[2]; - - $this->assertEquals('/somemount', $storage1->getMountPoint()); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier()); - $this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier()); - - $this->assertEquals('/othermount', $storage2->getMountPoint()); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier()); - $this->assertEquals('identifier:\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier()); - } - - public function testReadEmptyMountPoint() { - $configFile = $this->dataDir . '/mount.json'; - - $json = [ - 'user' => [ - 'user1' => [ - '/$user/files/' => [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => [], - 'mountOptions' => [], - ], - ] - ] - ]; - - file_put_contents($configFile, json_encode($json)); - - $allStorages = $this->service->getAllStorages(); - - $this->assertCount(1, $allStorages); - - $storage1 = $allStorages[1]; - - $this->assertEquals('/', $storage1->getMountPoint()); - } - - } diff --git a/apps/files_external/tests/service/storagesservicetest.php b/apps/files_external/tests/service/storagesservicetest.php index 7487ba459a..7847bd45d4 100644 --- a/apps/files_external/tests/service/storagesservicetest.php +++ b/apps/files_external/tests/service/storagesservicetest.php @@ -25,8 +25,29 @@ use \OC\Files\Filesystem; use \OCA\Files_external\NotFoundException; use \OCA\Files_external\Lib\StorageConfig; -use \OCA\Files_External\Lib\BackendService; +use OCA\Files_External\Service\BackendService; +use OCA\Files_External\Service\DBConfigService; +use OCA\Files_external\Service\StoragesService; +class CleaningDBConfig extends DBConfigService { + private $mountIds = []; + + public function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) { + $id = parent::addMount($mountPoint, $storageBackend, $authBackend, $priority, $type); // TODO: Change the autogenerated stub + $this->mountIds[] = $id; + return $id; + } + + public function clean() { + foreach ($this->mountIds as $id) { + $this->removeMount($id); + } + } +} + +/** + * @group DB + */ abstract class StoragesServiceTest extends \Test\TestCase { /** @@ -44,6 +65,9 @@ abstract class StoragesServiceTest extends \Test\TestCase { */ protected $dataDir; + /** @var CleaningDBConfig */ + protected $dbConfig; + /** * Hook calls * @@ -52,6 +76,8 @@ abstract class StoragesServiceTest extends \Test\TestCase { protected static $hookCalls; public function setUp() { + parent::setUp(); + $this->dbConfig = new CleaningDBConfig(\OC::$server->getDatabaseConnection()); self::$hookCalls = array(); $config = \OC::$server->getConfig(); $this->dataDir = $config->getSystemValue( @@ -63,8 +89,8 @@ abstract class StoragesServiceTest extends \Test\TestCase { // prepare BackendService mock $this->backendService = $this->getMockBuilder('\OCA\Files_External\Service\BackendService') - ->disableOriginalConstructor() - ->getMock(); + ->disableOriginalConstructor() + ->getMock(); $authMechanisms = [ 'identifier:\Auth\Mechanism' => $this->getAuthMechMock('null', '\Auth\Mechanism'), @@ -72,14 +98,14 @@ abstract class StoragesServiceTest extends \Test\TestCase { 'identifier:\OCA\Files_External\Lib\Auth\NullMechanism' => $this->getAuthMechMock(), ]; $this->backendService->method('getAuthMechanism') - ->will($this->returnCallback(function($class) use ($authMechanisms) { + ->will($this->returnCallback(function ($class) use ($authMechanisms) { if (isset($authMechanisms[$class])) { return $authMechanisms[$class]; } return null; })); $this->backendService->method('getAuthMechanismsByScheme') - ->will($this->returnCallback(function($schemes) use ($authMechanisms) { + ->will($this->returnCallback(function ($schemes) use ($authMechanisms) { return array_filter($authMechanisms, function ($authMech) use ($schemes) { return in_array($authMech->getScheme(), $schemes, true); }); @@ -96,7 +122,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $backends['identifier:\OCA\Files_External\Lib\Backend\SFTP']->method('getLegacyAuthMechanism') ->willReturn($authMechanisms['identifier:\Other\Auth\Mechanism']); $this->backendService->method('getBackend') - ->will($this->returnCallback(function($backendClass) use ($backends) { + ->will($this->returnCallback(function ($backendClass) use ($backends) { if (isset($backends[$backendClass])) { return $backends[$backendClass]; } @@ -116,7 +142,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $containerMock = $this->getMock('\OCP\AppFramework\IAppContainer'); $containerMock->method('query') - ->will($this->returnCallback(function($name) { + ->will($this->returnCallback(function ($name) { if ($name === 'OCA\Files_External\Service\BackendService') { return $this->backendService; } @@ -132,6 +158,9 @@ abstract class StoragesServiceTest extends \Test\TestCase { public function tearDown() { \OC_Mount_Config::$skipTest = false; self::$hookCalls = array(); + if ($this->dbConfig) { + $this->dbConfig->clean(); + } } protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') { @@ -141,7 +170,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $backend->method('getStorageClass') ->willReturn($storageClass); $backend->method('getIdentifier') - ->willReturn('identifier:'.$class); + ->willReturn('identifier:' . $class); return $backend; } @@ -152,7 +181,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $authMech->method('getScheme') ->willReturn($scheme); $authMech->method('getIdentifier') - ->willReturn('identifier:'.$class); + ->willReturn('identifier:' . $class); return $authMech; } @@ -258,7 +287,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $storage->setBackendOptions($backendOptions); $newStorage = $this->service->addStorage($storage); - $this->assertEquals(1, $newStorage->getId()); + $id = $newStorage->getId(); // manually trigger storage entry because normally it happens on first // access, which isn't possible within this test @@ -267,7 +296,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { // get numeric id for later check $numericId = $storageCache->getNumericId(); - $newStorage = $this->service->removeStorage(1); + $this->service->removeStorage($id); $caught = false; try { @@ -317,7 +346,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $priority ); - $this->assertEquals('/'.$mountPoint, $storage->getMountPoint()); + $this->assertEquals('/' . $mountPoint, $storage->getMountPoint()); $this->assertEquals($backend, $storage->getBackend()); $this->assertEquals($authMechanism, $storage->getAuthMechanism()); $this->assertEquals($backendOptions, $storage->getBackendOptions()); diff --git a/apps/files_external/tests/service/userglobalstoragesservicetest.php b/apps/files_external/tests/service/userglobalstoragesservicetest.php index e88764d0f7..b8379288d4 100644 --- a/apps/files_external/tests/service/userglobalstoragesservicetest.php +++ b/apps/files_external/tests/service/userglobalstoragesservicetest.php @@ -21,17 +21,33 @@ */ namespace OCA\Files_External\Tests\Service; +use OCA\Files_external\Service\StoragesService; use \OCA\Files_External\Service\UserGlobalStoragesService; use \OCP\IGroupManager; use \OCA\Files_External\Lib\StorageConfig; +use OCP\IUser; +use Test\Traits\UserTrait; +/** + * @group DB + */ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { + use UserTrait; + /** @var \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject groupManager */ protected $groupManager; + /** + * @var StoragesService + */ protected $globalStoragesService; + /** + * @var UserGlobalStoragesService + */ + protected $service; + protected $user; const USER_ID = 'test_user'; @@ -44,6 +60,7 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { $this->globalStoragesService = $this->service; $this->user = new \OC\User\User(self::USER_ID, null); + /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject $userSession */ $userSession = $this->getMock('\OCP\IUserSession'); $userSession ->expects($this->any()) @@ -52,19 +69,28 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { $this->groupManager = $this->getMock('\OCP\IGroupManager'); $this->groupManager->method('isInGroup') - ->will($this->returnCallback(function($userId, $groupId) { + ->will($this->returnCallback(function ($userId, $groupId) { if ($userId === self::USER_ID) { switch ($groupId) { - case self::GROUP_ID: - case self::GROUP_ID2: - return true; + case self::GROUP_ID: + case self::GROUP_ID2: + return true; } } return false; })); + $this->groupManager->method('getUserGroupIds') + ->will($this->returnCallback(function (IUser $user) { + if ($user->getUID() === self::USER_ID) { + return [self::GROUP_ID, self::GROUP_ID2]; + } else { + return []; + } + })); $this->service = new UserGlobalStoragesService( $this->backendService, + $this->dbConfig, $userSession, $this->groupManager ); @@ -154,6 +180,13 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { $this->service->updateStorage($retrievedStorage); } + /** + * @expectedException \DomainException + */ + public function testNonExistingStorage() { + parent::testNonExistingStorage(); + } + /** * @expectedException \DomainException * @dataProvider deleteStorageDataProvider @@ -169,9 +202,16 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { $storage->setBackendOptions($backendOptions); $newStorage = $this->globalStoragesService->addStorage($storage); - $this->assertEquals(1, $newStorage->getId()); + $id = $newStorage->getId(); - $this->service->removeStorage(1); + $this->service->removeStorage($id); + } + + /** + * @expectedException \DomainException + */ + public function testDeleteUnexistingStorage() { + parent::testDeleteUnexistingStorage(); } public function getUniqueStoragesProvider() { diff --git a/apps/files_external/tests/service/userstoragesservicetest.php b/apps/files_external/tests/service/userstoragesservicetest.php index 78f9231c3d..5e984c52bf 100644 --- a/apps/files_external/tests/service/userstoragesservicetest.php +++ b/apps/files_external/tests/service/userstoragesservicetest.php @@ -26,36 +26,33 @@ use \OC\Files\Filesystem; use \OCA\Files_external\Service\UserStoragesService; use \OCA\Files_external\NotFoundException; use \OCA\Files_external\Lib\StorageConfig; +use Test\Traits\UserTrait; +/** + * @group DB + */ class UserStoragesServiceTest extends StoragesServiceTest { + use UserTrait; + + private $user; + + private $userId; public function setUp() { parent::setUp(); - $userManager = \OC::$server->getUserManager(); - $this->userId = $this->getUniqueID('user_'); - $this->user = $userManager->createUser( - $this->userId, - $this->userId - ); + $this->createUser($this->userId, $this->userId); + $this->user = \OC::$server->getUserManager()->get($this->userId); + /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject $userSession */ $userSession = $this->getMock('\OCP\IUserSession'); $userSession ->expects($this->any()) ->method('getUser') ->will($this->returnValue($this->user)); - $this->service = new UserStoragesService($this->backendService, $userSession); - - // create home folder - mkdir($this->dataDir . '/' . $this->userId . '/'); - } - - public function tearDown() { - @unlink($this->dataDir . '/' . $this->userId . '/mount.json'); - $this->user->delete(); - parent::tearDown(); + $this->service = new UserStoragesService($this->backendService, $this->dbConfig, $userSession); } private function makeTestStorageData() { @@ -79,15 +76,14 @@ class UserStoragesServiceTest extends StoragesServiceTest { $newStorage = $this->service->addStorage($storage); - $this->assertEquals(1, $newStorage->getId()); + $id = $newStorage->getId(); - $newStorage = $this->service->getStorage(1); + $newStorage = $this->service->getStorage($id); $this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($storage->getBackend(), $newStorage->getBackend()); $this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism()); $this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); - $this->assertEquals(1, $newStorage->getId()); $this->assertEquals(0, $newStorage->getStatus()); // hook called once for user @@ -99,9 +95,8 @@ class UserStoragesServiceTest extends StoragesServiceTest { $this->userId ); - // next one gets id 2 $nextStorage = $this->service->addStorage($storage); - $this->assertEquals(2, $nextStorage->getId()); + $this->assertEquals($id + 1, $nextStorage->getId()); } public function testUpdateStorage() { @@ -117,7 +112,6 @@ class UserStoragesServiceTest extends StoragesServiceTest { ]); $newStorage = $this->service->addStorage($storage); - $this->assertEquals(1, $newStorage->getId()); $backendOptions = $newStorage->getBackendOptions(); $backendOptions['password'] = 'anotherPassword'; @@ -131,7 +125,6 @@ class UserStoragesServiceTest extends StoragesServiceTest { // these attributes are unused for user storages $this->assertEmpty($newStorage->getApplicableUsers()); $this->assertEmpty($newStorage->getApplicableGroups()); - $this->assertEquals(1, $newStorage->getId()); $this->assertEquals(0, $newStorage->getStatus()); // no hook calls @@ -181,89 +174,4 @@ class UserStoragesServiceTest extends StoragesServiceTest { $this->userId ); } - - /** - * Make sure it uses the correct format when reading/writing - * the legacy config - */ - public function testLegacyConfigConversion() { - $configFile = $this->dataDir . '/' . $this->userId . '/mount.json'; - - $storage = $this->makeTestStorageData(); - $storage = $this->service->addStorage($storage); - - $json = json_decode(file_get_contents($configFile), true); - - $this->assertCount(1, $json); - - $this->assertEquals([\OC_Mount_Config::MOUNT_TYPE_USER], array_keys($json)); - $this->assertEquals([$this->userId], array_keys($json[\OC_Mount_config::MOUNT_TYPE_USER])); - - $mountPointData = $json[\OC_Mount_config::MOUNT_TYPE_USER][$this->userId]; - $this->assertEquals(['/' . $this->userId . '/files/mountpoint'], array_keys($mountPointData)); - - $mountPointOptions = current($mountPointData); - $this->assertEquals(1, $mountPointOptions['id']); - $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']); - $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']); - $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); - - $backendOptions = $mountPointOptions['options']; - $this->assertEquals('value1', $backendOptions['option1']); - $this->assertEquals('value2', $backendOptions['option2']); - $this->assertEquals('', $backendOptions['password']); - $this->assertNotEmpty($backendOptions['password_encrypted']); - } - - /** - * Test reading in a legacy config and generating config ids. - */ - public function testReadLegacyConfigAndGenerateConfigId() { - $configFile = $this->dataDir . '/' . $this->userId . '/mount.json'; - - $legacyBackendOptions = [ - 'user' => 'someuser', - 'password' => 'somepassword', - ]; - $legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions); - - $legacyConfig = [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => $legacyBackendOptions, - 'mountOptions' => ['preview' => false], - ]; - // different mount options - $legacyConfig2 = [ - 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB', - 'authMechanism' => 'identifier:\Auth\Mechanism', - 'options' => $legacyBackendOptions, - 'mountOptions' => ['preview' => true], - ]; - - $json = ['user' => []]; - $json['user'][$this->userId] = [ - '/$user/files/somemount' => $legacyConfig, - '/$user/files/anothermount' => $legacyConfig2, - ]; - - file_put_contents($configFile, json_encode($json)); - - $allStorages = $this->service->getAllStorages(); - - $this->assertCount(2, $allStorages); - - $storage1 = $allStorages[1]; - $storage2 = $allStorages[2]; - - $this->assertEquals('/somemount', $storage1->getMountPoint()); - $this->assertEquals('someuser', $storage1->getBackendOptions()['user']); - $this->assertEquals('somepassword', $storage1->getBackendOptions()['password']); - $this->assertEquals(['preview' => false], $storage1->getMountOptions()); - - $this->assertEquals('/anothermount', $storage2->getMountPoint()); - $this->assertEquals('someuser', $storage2->getBackendOptions()['user']); - $this->assertEquals('somepassword', $storage2->getBackendOptions()['password']); - $this->assertEquals(['preview' => true], $storage2->getMountOptions()); - } }