Move files_external mount config to the databasetags/v9.0beta1
@@ -0,0 +1,222 @@ | |||
<database> | |||
<name>*dbname*</name> | |||
<create>true</create> | |||
<overwrite>false</overwrite> | |||
<charset>utf8</charset> | |||
<table> | |||
<name>*dbprefix*external_mounts</name> | |||
<declaration> | |||
<field> | |||
<name>mount_id</name> | |||
<type>integer</type> | |||
<default>0</default> | |||
<notnull>true</notnull> | |||
<autoincrement>1</autoincrement> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<name>mount_point</name> | |||
<type>text</type> | |||
<length>128</length> | |||
<notnull>true</notnull> | |||
</field> | |||
<field> | |||
<name>storage_backend</name> | |||
<type>text</type> | |||
<length>64</length> | |||
<notnull>true</notnull> | |||
</field> | |||
<field> | |||
<name>auth_backend</name> | |||
<type>text</type> | |||
<length>64</length> | |||
<notnull>true</notnull> | |||
</field> | |||
<field> | |||
<name>priority</name> | |||
<type>integer</type> | |||
<default>100</default> | |||
<length>4</length> | |||
<notnull>true</notnull> | |||
</field> | |||
<!-- admin = 1, personal = 2--> | |||
<field> | |||
<name>type</name> | |||
<type>integer</type> | |||
<length>4</length> | |||
<notnull>true</notnull> | |||
</field> | |||
</declaration> | |||
</table> | |||
<table> | |||
<name>*dbprefix*external_applicable</name> | |||
<declaration> | |||
<field> | |||
<name>applicable_id</name> | |||
<type>integer</type> | |||
<default>0</default> | |||
<notnull>true</notnull> | |||
<autoincrement>1</autoincrement> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<!--foreign key: external_mounts.mount_id--> | |||
<name>mount_id</name> | |||
<type>integer</type> | |||
<notnull>true</notnull> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<!-- possible mount types: global = 1, group = 2, user = 3 --> | |||
<name>type</name> | |||
<type>integer</type> | |||
<length>4</length> | |||
<notnull>true</notnull> | |||
</field> | |||
<field> | |||
<!-- user_id, group_id or null for global mounts --> | |||
<name>value</name> | |||
<type>text</type> | |||
<length>64</length> | |||
</field> | |||
<index> | |||
<name>mount_id_app_index</name> | |||
<field> | |||
<name>mount_id</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
<index> | |||
<name>applicable_value_index</name> | |||
<field> | |||
<name>type</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
<field> | |||
<name>value</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
<index> | |||
<name>applicable_value_mount_index</name> | |||
<unique>true</unique> | |||
<field> | |||
<name>type</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
<field> | |||
<name>value</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
<field> | |||
<name>mount_id</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
</declaration> | |||
</table> | |||
<table> | |||
<name>*dbprefix*external_config</name> | |||
<declaration> | |||
<field> | |||
<name>config_id</name> | |||
<type>integer</type> | |||
<default>0</default> | |||
<notnull>true</notnull> | |||
<autoincrement>1</autoincrement> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<!--foreign key: external_mounts.mount_id--> | |||
<name>mount_id</name> | |||
<type>integer</type> | |||
<notnull>true</notnull> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<name>key</name> | |||
<type>text</type> | |||
<notnull>true</notnull> | |||
<length>64</length> | |||
</field> | |||
<field> | |||
<name>value</name> | |||
<type>text</type> | |||
<notnull>true</notnull> | |||
<length>4096</length> | |||
</field> | |||
<index> | |||
<name>config_mount_id</name> | |||
<field> | |||
<name>mount_id</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
<index> | |||
<name>config_mount_key</name> | |||
<unique>true</unique> | |||
<field> | |||
<name>mount_id</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
<field> | |||
<name>key</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
</declaration> | |||
</table> | |||
<table> | |||
<name>*dbprefix*external_options</name> | |||
<declaration> | |||
<field> | |||
<name>option_id</name> | |||
<type>integer</type> | |||
<default>0</default> | |||
<notnull>true</notnull> | |||
<autoincrement>1</autoincrement> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<!--foreign key: external_mounts.mount_id--> | |||
<name>mount_id</name> | |||
<type>integer</type> | |||
<notnull>true</notnull> | |||
<length>6</length> | |||
</field> | |||
<field> | |||
<name>key</name> | |||
<type>text</type> | |||
<notnull>true</notnull> | |||
<length>64</length> | |||
</field> | |||
<field> | |||
<name>value</name> | |||
<type>text</type> | |||
<notnull>true</notnull> | |||
<length>256</length> | |||
</field> | |||
<index> | |||
<name>option_mount_id</name> | |||
<field> | |||
<name>mount_id</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
<index> | |||
<name>option_mount_key</name> | |||
<unique>true</unique> | |||
<field> | |||
<name>mount_id</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
<field> | |||
<name>key</name> | |||
<sorting>ascending</sorting> | |||
</field> | |||
</index> | |||
</declaration> | |||
</table> | |||
</database> |
@@ -14,7 +14,7 @@ | |||
<admin>admin-external-storage</admin> | |||
</documentation> | |||
<rememberlogin>false</rememberlogin> | |||
<version>0.4.0</version> | |||
<version>0.5.0</version> | |||
<types> | |||
<filesystem/> | |||
</types> |
@@ -0,0 +1,30 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
$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(); | |||
} |
@@ -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() |
@@ -0,0 +1,136 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,376 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
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); | |||
} | |||
} |
@@ -0,0 +1,44 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
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(); | |||
} | |||
} |
@@ -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 |
@@ -0,0 +1,209 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
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; | |||
} | |||
} |
@@ -42,88 +42,60 @@ abstract class StoragesService { | |||
protected $backendService; | |||
/** | |||
* @param BackendService $backendService | |||
* @var DBConfigService | |||
*/ | |||
public function __construct(BackendService $backendService) { | |||
$this->backendService = $backendService; | |||
} | |||
protected $dbConfig; | |||
/** | |||
* Read legacy config data | |||
* | |||
* @return array list of mount configs | |||
* @param BackendService $backendService | |||
* @param DBConfigService $dbConfigService | |||
*/ | |||
protected function readLegacyConfig() { | |||
// read global config | |||
return \OC_Mount_Config::readData(); | |||
public function __construct(BackendService $backendService, DBConfigService $dbConfigService) { | |||
$this->backendService = $backendService; | |||
$this->dbConfig = $dbConfigService; | |||
} | |||
/** | |||
* Write legacy config data | |||
* | |||
* @param array $mountPoints | |||
*/ | |||
protected function writeLegacyConfig(array $mountPoints) { | |||
// write global config | |||
\OC_Mount_Config::writeData(null, $mountPoints); | |||
protected function readDBConfig() { | |||
return $this->dbConfig->getAdminMounts(); | |||
} | |||
/** | |||
* 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']); | |||
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); | |||
$applicableGroups = array_filter($mount['applicable'], function ($applicable) { | |||
return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_GROUP; | |||
}); | |||
$applicableGroups = array_map(function ($applicable) { | |||
return $applicable['value']; | |||
}, $applicableGroups); | |||
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); | |||
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; | |||
} | |||
return $storageConfig; | |||
} | |||
/** | |||
@@ -132,198 +104,19 @@ abstract class StoragesService { | |||
* @return array map of storage id to storage config | |||
*/ | |||
protected function readConfig() { | |||
$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 | |||
$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); | |||
} | |||
$mounts = $this->readDBConfig(); | |||
$configs = array_map([$this, 'getStorageConfigFromDBMount'], $mounts); | |||
$configs = array_filter($configs, function ($config) { | |||
return $config instanceof StorageConfig; | |||
}); | |||
// convert parameter values | |||
foreach ($storages as $storage) { | |||
$storage->getBackend()->validateStorageDefinition($storage); | |||
$storage->getAuthMechanism()->validateStorageDefinition($storage); | |||
} | |||
$keys = array_map(function (StorageConfig $config) { | |||
return $config->getId(); | |||
}, $configs); | |||
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'); | |||
$existingMount = $this->dbConfig->getMountById($id); | |||
if (!is_array($existingMount)) { | |||
throw new NotFoundException('Storage with id "' . $id . '" not found while updating storage'); | |||
} | |||
$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); | |||
} | |||
$oldStorage = $allStorages[$id]; | |||
// ensure objectstore is persistent | |||
if ($objectstore = $oldStorage->getBackendOption('objectstore')) { | |||
$updatedStorage->setBackendOption('objectstore', $objectstore); | |||
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); | |||
} | |||
$allStorages[$id] = $updatedStorage; | |||
$this->writeConfig($allStorages); | |||
$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. | |||
* |
@@ -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 = []; | |||
} | |||
return array_merge($userMounts, $groupMounts, $globalMounts); | |||
} | |||
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; | |||
} | |||
public function addStorage(StorageConfig $newStorage) { | |||
throw new \DomainException('UserGlobalStoragesService writing disallowed'); | |||
} | |||
return $data; | |||
public function updateStorage(StorageConfig $updatedStorage) { | |||
throw new \DomainException('UserGlobalStoragesService writing disallowed'); | |||
} | |||
/** | |||
* Write legacy config data | |||
* | |||
* @param array $mountPoints | |||
*/ | |||
protected function writeLegacyConfig(array $mountPoints) { | |||
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); |
@@ -0,0 +1,54 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
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); | |||
} | |||
} |
@@ -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); | |||
} | |||
/** | |||
* 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; | |||
parent::__construct($backendService, $dbConfig); | |||
} | |||
/** | |||
* 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 | |||
* |
@@ -0,0 +1,233 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @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 <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
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']); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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()); |
@@ -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() { |
@@ -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()); | |||
} | |||
} |