diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml
index e86a5e459d1a..f6d583d0a5ad 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.2
+ 0.5.0
diff --git a/apps/files_external/appinfo/update.php b/apps/files_external/appinfo/update.php
new file mode 100644
index 000000000000..2eedfe9b88fb
--- /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 3a04512e8a80..ab0a66a3c51c 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;
@@ -45,17 +46,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;
}
/**
@@ -109,6 +115,8 @@ private function constructStorage(StorageConfig $storageConfig) {
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
+ $this->migrator->migrateUser();
+
$mounts = [];
$this->userStoragesService->setUser($user);
@@ -125,7 +133,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) {
$mount = new MountPoint(
$impl,
- '/'.$user->getUID().'/files' . $storage->getMountPoint(),
+ '/' . $user->getUID() . '/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
@@ -146,7 +154,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) {
$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 000000000000..931b0210779e
--- /dev/null
+++ b/apps/files_external/migration/storagemigrator.php
@@ -0,0 +1,108 @@
+
+ *
+ * @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\IUserSession;
+
+class StorageMigrator {
+ /**
+ * @var BackendService
+ */
+ private $backendService;
+
+ /**
+ * @var DBConfigService
+ */
+ private $dbConfig;
+
+ /**
+ * @var IUserSession
+ */
+ private $userSession;
+
+ /**
+ * @var IConfig
+ */
+ private $config;
+
+ /**
+ * StorageMigrator constructor.
+ *
+ * @param BackendService $backendService
+ * @param DBConfigService $dbConfig
+ * @param IUserSession $userSession
+ * @param IConfig $config
+ */
+ public function __construct(
+ BackendService $backendService,
+ DBConfigService $dbConfig,
+ IUserSession $userSession,
+ IConfig $config
+ ) {
+ $this->backendService = $backendService;
+ $this->dbConfig = $dbConfig;
+ $this->userSession = $userSession;
+ $this->config = $config;
+ }
+
+ private function migrate(LegacyStoragesService $legacyService, StoragesService $storageService) {
+ $existingStorage = $legacyService->getAllStorages();
+
+ foreach ($existingStorage as $storage) {
+ $storageService->addStorage($storage);
+ }
+ }
+
+ /**
+ * 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/globallegacystoragesservice.php b/apps/files_external/service/globallegacystoragesservice.php
new file mode 100644
index 000000000000..eb41806dffcb
--- /dev/null
+++ b/apps/files_external/service/globallegacystoragesservice.php
@@ -0,0 +1,41 @@
+
+ *
+ * @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;
+
+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/legacystoragesservice.php b/apps/files_external/service/legacystoragesservice.php
new file mode 100644
index 000000000000..c9ffa83f98c2
--- /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;
+
+/**
+ * Service class to manage external storages
+ */
+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/userlegacystoragesservice.php b/apps/files_external/service/userlegacystoragesservice.php
new file mode 100644
index 000000000000..441fc58806d6
--- /dev/null
+++ b/apps/files_external/service/userlegacystoragesservice.php
@@ -0,0 +1,51 @@
+
+ *
+ * @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;
+
+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);
+ }
+}