When reading in old mount.json files, they do not contain config ids.
Since these are needed to be able to use the UI and the new service
classes, these will be generated automatically.
The config grouping is based on a config hash.
use \OCP\IConfig;
use \OCP\IUserSession;
use \OCP\IRequest;
+use \OCP\IL10N;
use \OCP\AppFramework\Http\DataResponse;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http;
class GlobalStoragesController extends StoragesController {
/**
- * @param string $appName
- * @param IRequest $request
- * @param IConfig $config
- * @param GlobalStoragesService $globalStoragesService
+ * Creates a new global storages controller.
+ *
+ * @param string $AppName application name
+ * @param IRequest $request request object
+ * @param IL10N $l10n l10n service
+ * @param GlobalStoragesService $globalStoragesService storage service
*/
public function __construct(
$AppName,
IRequest $request,
- \OCP\IL10N $l10n,
+ IL10N $l10n,
GlobalStoragesService $globalStoragesService
){
parent::__construct(
use \OCP\IConfig;
use \OCP\IUserSession;
use \OCP\IRequest;
+use \OCP\IL10N;
use \OCP\AppFramework\Http\DataResponse;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http;
class UserStoragesController extends StoragesController {
/**
- * @param string $appName
- * @param IRequest $request
- * @param IConfig $config
- * @param UserStoragesService $userStoragesService
+ * Creates a new user storages controller.
+ *
+ * @param string $AppName application name
+ * @param IRequest $request request object
+ * @param IL10N $l10n l10n service
+ * @param UserStoragesService $userStoragesService storage service
*/
public function __construct(
$AppName,
IRequest $request,
- \OCP\IL10N $l10n,
+ IL10N $l10n,
UserStoragesService $userStoragesService
){
parent::__construct(
* This is mostly used to find out whether configurations
* are the same.
*/
- private static function makeConfigHash($config) {
+ public static function makeConfigHash($config) {
$data = json_encode(
array(
'c' => $config['class'],
'm' => $config['mountpoint'],
- 'o' => $config['options']
+ 'o' => $config['options'],
+ 'p' => isset($config['priority']) ? $config['priority'] : -1,
+ 'mo' => isset($config['mountOptions']) ? $config['mountOptions'] : [],
)
);
return hash('md5', $data);
OCP\Util::addStyle('files_external', 'settings');
$backends = OC_Mount_Config::getPersonalBackends();
+$mounts = OC_Mount_Config::getPersonalMountPoints();
+$hasId = true;
+foreach ($mounts as $mount) {
+ if (!isset($mount['id'])) {
+ // some mount points are missing ids
+ $hasId = false;
+ break;
+ }
+}
+
+if (!$hasId) {
+ $service = new \OCA\Files_external\Service\UserStoragesService(\OC::$server->getUserSession());
+ // this will trigger the new storage code which will automatically
+ // generate storage config ids
+ $service->getAllStorages();
+ // re-read updated config
+ $mounts = OC_Mount_Config::getPersonalMountPoints();
+ // TODO: use the new storage config format in the template
+}
+
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('isAdminPage', false);
-$tmpl->assign('mounts', OC_Mount_Config::getPersonalMountPoints());
+$tmpl->assign('mounts', $mounts);
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
$tmpl->assign('backends', $backends);
return $tmpl->fetchPage();
return \OC_Mount_Config::readData();
}
+ /**
+ * 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) {
+ $storageConfig->setBackendClass($storageOptions['class']);
+ $storageConfig->setBackendOptions($storageOptions['options']);
+ if (isset($storageOptions['mountOptions'])) {
+ $storageConfig->setMountOptions($storageOptions['mountOptions']);
+ }
+ if (isset($storageOptions['priority'])) {
+ $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
*
// 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('/', trim($rootMountPath, '/'), 3);
$relativeMountPath = $parts[2];
- $configId = (int)$storageOptions['id'];
- if (isset($storages[$configId])) {
- $currentStorage = $storages[$configId];
+ // 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['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);
}
- $currentStorage->setBackendClass($storageOptions['class']);
- $currentStorage->setBackendOptions($storageOptions['options']);
- if (isset($storageOptions['mountOptions'])) {
- $currentStorage->setMountOptions($storageOptions['mountOptions']);
- }
- if (isset($storageOptions['priority'])) {
- $currentStorage->setPriority($storageOptions['priority']);
- }
+ $this->populateStorageConfigWithLegacyOptions(
+ $currentStorage,
+ $mountType,
+ $applicable,
+ $storageOptions
+ );
- if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) {
- $applicableUsers = $currentStorage->getApplicableUsers();
- if ($applicable !== 'all') {
- $applicableUsers[] = $applicable;
- $currentStorage->setApplicableUsers($applicableUsers);
- }
- } else if ($mountType === \OC_Mount_Config::MOUNT_TYPE_GROUP) {
- $applicableGroups = $currentStorage->getApplicableGroups();
- $applicableGroups[] = $applicable;
- $currentStorage->setApplicableGroups($applicableGroups);
+ if ($hasId) {
+ $storages[$configId] = $currentStorage;
+ } else {
+ $storagesWithConfigHash[$configId] = $currentStorage;
}
- $storages[$configId] = $currentStorage;
}
}
}
- // decrypt passwords
- foreach ($storages as &$storage) {
- $storage->setBackendOptions(
- \OC_Mount_Config::decryptPasswords(
- $storage->getBackendOptions()
- )
- );
+ // process storages with config hash, they must get a real id
+ if (!empty($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);
}
return $storages;
return $allStorages[$id];
}
+ /**
+ * Gets all storages
+ *
+ * @return array array of storage configs
+ */
+ public function getAllStorages() {
+ return $this->readConfig();
+ }
+
/**
* Add new storage to the configuration
*
}
}
+$mounts = OC_Mount_Config::getSystemMountPoints();
+$hasId = true;
+foreach ($mounts as $mount) {
+ if (!isset($mount['id'])) {
+ // some mount points are missing ids
+ $hasId = false;
+ break;
+ }
+}
+
+if (!$hasId) {
+ $service = new \OCA\Files_external\Service\GlobalStoragesService();
+ // this will trigger the new storage code which will automatically
+ // generate storage config ids
+ $service->getAllStorages();
+ // re-read updated config
+ $mounts = OC_Mount_Config::getSystemMountPoints();
+ // TODO: use the new storage config format in the template
+}
+
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('isAdminPage', true);
-$tmpl->assign('mounts', OC_Mount_Config::getSystemMountPoints());
+$tmpl->assign('mounts', $mounts);
$tmpl->assign('backends', $backends);
$tmpl->assign('personal_backends', $personal_backends);
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
}
}
+ /**
+ * 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 = [
+ 'class' => '\OC\Files\Storage\SMB',
+ 'options' => $legacyBackendOptions,
+ 'mountOptions' => ['preview' => false],
+ ];
+ // different mount options
+ $legacyConfig2 = [
+ 'class' => '\OC\Files\Storage\SMB',
+ 'options' => $legacyBackendOptions,
+ 'mountOptions' => ['preview' => true],
+ ];
+
+ $legacyBackendOptions2 = $legacyBackendOptions;
+ $legacyBackendOptions2 = ['user' => 'someuser2', 'password' => 'somepassword2'];
+ $legacyBackendOptions2 = \OC_Mount_Config::encryptPasswords($legacyBackendOptions2);
+
+ // different config
+ $legacyConfig3 = [
+ 'class' => '\OC\Files\Storage\SMB',
+ '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));
+
+ $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());
+ }
}
$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 = [
+ 'class' => '\OC\Files\Storage\SMB',
+ 'options' => $legacyBackendOptions,
+ 'mountOptions' => ['preview' => false],
+ ];
+ // different mount options
+ $legacyConfig2 = [
+ 'class' => '\OC\Files\Storage\SMB',
+ '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());
+ }
}