Backends are registered to the BackendService through new data structures: Backends are concrete classes, deriving from \OCA\Files_External\Lib\Backend\Backend. During construction, the various configuration parameters of the Backend can be set, in a design similar to Symfony Console. DefinitionParameter stores a parameter configuration for an external storage: name of parameter, human-readable name, type of parameter (text, password, hidden, checkbox), flags (optional or not). Storages in the StoragesController now get their parameters validated server-side (fixes a TODO).tags/v8.2beta1
@@ -30,9 +30,6 @@ | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
$app = new \OCA\Files_external\Appinfo\Application(); | |||
$l = \OC::$server->getL10N('files_external'); | |||
OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php'; | |||
OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php'; | |||
@@ -50,6 +47,11 @@ OC::$CLASSPATH['OCA\Files\External\Api'] = 'files_external/lib/api.php'; | |||
require_once __DIR__ . '/../3rdparty/autoload.php'; | |||
$app = new \OCA\Files_external\Appinfo\Application(); | |||
$appContainer = $app->getContainer(); | |||
$l = \OC::$server->getL10N('files_external'); | |||
OCP\App::registerAdmin('files_external', 'settings'); | |||
if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') { | |||
OCP\App::registerPersonal('files_external', 'personal'); | |||
@@ -63,6 +65,9 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == ' | |||
"name" => $l->t('External storage') | |||
]); | |||
// Teach OC_Mount_Config about the AppFramework | |||
\OC_Mount_Config::initApp($appContainer); | |||
// connecting hooks | |||
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); | |||
OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login'); | |||
@@ -237,5 +242,5 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\SFTP_Key', [ | |||
'custom' => 'sftp_key', | |||
] | |||
); | |||
$mountProvider = new \OCA\Files_External\Config\ConfigAdapter(); | |||
$mountProvider = $appContainer->query('OCA\Files_External\Config\ConfigAdapter'); | |||
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider); |
@@ -3,6 +3,7 @@ | |||
* @author Morris Jobke <hey@morrisjobke.de> | |||
* @author Ross Nicoll <jrn@jrn.me.uk> | |||
* @author Vincent Petry <pvince81@owncloud.com> | |||
* @author Robin McCorkell <rmccorkell@owncloud.com> | |||
* | |||
* @copyright Copyright (c) 2015, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
@@ -26,6 +27,9 @@ namespace OCA\Files_External\AppInfo; | |||
use \OCA\Files_External\Controller\AjaxController; | |||
use \OCP\AppFramework\App; | |||
use \OCP\IContainer; | |||
use \OCA\Files_External\Service\BackendService; | |||
use \OCA\Files_External\Lib\BackendConfig; | |||
use \OCA\Files_External\Lib\BackendParameter; | |||
/** | |||
* @package OCA\Files_External\Appinfo | |||
@@ -45,5 +49,16 @@ class Application extends App { | |||
$c->query('Request') | |||
); | |||
}); | |||
$this->loadBackends(); | |||
} | |||
/** | |||
* Load storage backends provided by this app | |||
*/ | |||
protected function loadBackends() { | |||
$container = $this->getContainer(); | |||
$service = $container->query('OCA\\Files_External\\Service\\BackendService'); | |||
} | |||
} |
@@ -81,14 +81,18 @@ class GlobalStoragesController extends StoragesController { | |||
$applicableGroups, | |||
$priority | |||
) { | |||
$newStorage = new StorageConfig(); | |||
$newStorage->setMountPoint($mountPoint); | |||
$newStorage->setBackendClass($backendClass); | |||
$newStorage->setBackendOptions($backendOptions); | |||
$newStorage->setMountOptions($mountOptions); | |||
$newStorage->setApplicableUsers($applicableUsers); | |||
$newStorage->setApplicableGroups($applicableGroups); | |||
$newStorage->setPriority($priority); | |||
$newStorage = $this->createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions, | |||
$applicableUsers, | |||
$applicableGroups, | |||
$priority | |||
); | |||
if ($newStorage instanceof DataResponse) { | |||
return $newStorage; | |||
} | |||
$response = $this->validate($newStorage); | |||
if (!empty($response)) { | |||
@@ -129,14 +133,19 @@ class GlobalStoragesController extends StoragesController { | |||
$applicableGroups, | |||
$priority | |||
) { | |||
$storage = new StorageConfig($id); | |||
$storage->setMountPoint($mountPoint); | |||
$storage->setBackendClass($backendClass); | |||
$storage->setBackendOptions($backendOptions); | |||
$storage->setMountOptions($mountOptions); | |||
$storage->setApplicableUsers($applicableUsers); | |||
$storage->setApplicableGroups($applicableGroups); | |||
$storage->setPriority($priority); | |||
$storage = $this->createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions, | |||
$applicableUsers, | |||
$applicableGroups, | |||
$priority | |||
); | |||
if ($storage instanceof DataResponse) { | |||
return $storage; | |||
} | |||
$storage->setId($id); | |||
$response = $this->validate($storage); | |||
if (!empty($response)) { |
@@ -32,6 +32,7 @@ use \OCP\AppFramework\Http; | |||
use \OCA\Files_external\Service\StoragesService; | |||
use \OCA\Files_external\NotFoundException; | |||
use \OCA\Files_external\Lib\StorageConfig; | |||
use \OCA\Files_External\Lib\Backend\Backend; | |||
/** | |||
* Base class for storages controllers | |||
@@ -71,6 +72,48 @@ abstract class StoragesController extends Controller { | |||
$this->service = $storagesService; | |||
} | |||
/** | |||
* Create a storage from its parameters | |||
* | |||
* @param string $mountPoint storage mount point | |||
* @param string $backendClass backend class name | |||
* @param array $backendOptions backend-specific options | |||
* @param array|null $mountOptions mount-specific options | |||
* @param array|null $applicableUsers users for which to mount the storage | |||
* @param array|null $applicableGroups groups for which to mount the storage | |||
* @param int|null $priority priority | |||
* | |||
* @return StorageConfig|DataResponse | |||
*/ | |||
protected function createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions = null, | |||
$applicableUsers = null, | |||
$applicableGroups = null, | |||
$priority = null | |||
) { | |||
try { | |||
return $this->service->createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions, | |||
$applicableUsers, | |||
$applicableGroups, | |||
$priority | |||
); | |||
} catch (\InvalidArgumentException $e) { | |||
return new DataResponse( | |||
[ | |||
'message' => (string)$this->l10n->t('Invalid backend class "%s"', [$backendClass]) | |||
], | |||
Http::STATUS_UNPROCESSABLE_ENTITY | |||
); | |||
} | |||
} | |||
/** | |||
* Validate storage config | |||
* | |||
@@ -89,14 +132,24 @@ abstract class StoragesController extends Controller { | |||
); | |||
} | |||
// TODO: validate that other attrs are set | |||
$backends = \OC_Mount_Config::getBackends(); | |||
if (!isset($backends[$storage->getBackendClass()])) { | |||
/** @var Backend */ | |||
$backend = $storage->getBackend(); | |||
if (!$backend || $backend->checkDependencies()) { | |||
// invalid backend | |||
return new DataResponse( | |||
array( | |||
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass())) | |||
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', [ | |||
$storage->getBackend()->getClass() | |||
]) | |||
), | |||
Http::STATUS_UNPROCESSABLE_ENTITY | |||
); | |||
} | |||
if (!$backend->validateStorage($storage)) { | |||
// unsatisfied parameters | |||
return new DataResponse( | |||
array( | |||
'message' => (string)$this->l10n->t('Unsatisfied backend parameters') | |||
), | |||
Http::STATUS_UNPROCESSABLE_ENTITY | |||
); | |||
@@ -114,10 +167,14 @@ abstract class StoragesController extends Controller { | |||
* @param StorageConfig $storage storage configuration | |||
*/ | |||
protected function updateStorageStatus(StorageConfig &$storage) { | |||
/** @var Backend */ | |||
$backend = $storage->getBackend(); | |||
$backend->manipulateStorageConfig($storage); | |||
// update status (can be time-consuming) | |||
$storage->setStatus( | |||
\OC_Mount_Config::getBackendStatus( | |||
$storage->getBackendClass(), | |||
$storage->getBackend()->getStorageClass(), | |||
$storage->getBackendOptions(), | |||
false | |||
) |
@@ -30,8 +30,10 @@ use \OCP\AppFramework\Http\DataResponse; | |||
use \OCP\AppFramework\Controller; | |||
use \OCP\AppFramework\Http; | |||
use \OCA\Files_external\Service\UserStoragesService; | |||
use \OCA\Files_External\Service\BackendService; | |||
use \OCA\Files_external\NotFoundException; | |||
use \OCA\Files_external\Lib\StorageConfig; | |||
use \OCA\Files_External\Lib\Backend\Backend; | |||
/** | |||
* User storages controller | |||
@@ -69,17 +71,20 @@ class UserStoragesController extends StoragesController { | |||
protected function validate(StorageConfig $storage) { | |||
$result = parent::validate($storage); | |||
if ($result != null) { | |||
if ($result !== null) { | |||
return $result; | |||
} | |||
// Verify that the mount point applies for the current user | |||
// Prevent non-admin users from mounting local storage and other disabled backends | |||
$allowedBackends = \OC_Mount_Config::getPersonalBackends(); | |||
if (!isset($allowedBackends[$storage->getBackendClass()])) { | |||
/** @var Backend */ | |||
$backend = $storage->getBackend(); | |||
if (!$backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) { | |||
return new DataResponse( | |||
array( | |||
'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass())) | |||
'message' => (string)$this->l10n->t('Admin-only storage backend "%s"', [ | |||
$storage->getBackend()->getClass() | |||
]) | |||
), | |||
Http::STATUS_UNPROCESSABLE_ENTITY | |||
); | |||
@@ -117,11 +122,15 @@ class UserStoragesController extends StoragesController { | |||
$backendOptions, | |||
$mountOptions | |||
) { | |||
$newStorage = new StorageConfig(); | |||
$newStorage->setMountPoint($mountPoint); | |||
$newStorage->setBackendClass($backendClass); | |||
$newStorage->setBackendOptions($backendOptions); | |||
$newStorage->setMountOptions($mountOptions); | |||
$newStorage = $this->createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions | |||
); | |||
if ($newStorage instanceOf DataResponse) { | |||
return $newStorage; | |||
} | |||
$response = $this->validate($newStorage); | |||
if (!empty($response)) { | |||
@@ -157,11 +166,16 @@ class UserStoragesController extends StoragesController { | |||
$backendOptions, | |||
$mountOptions | |||
) { | |||
$storage = new StorageConfig($id); | |||
$storage->setMountPoint($mountPoint); | |||
$storage->setBackendClass($backendClass); | |||
$storage->setBackendOptions($backendOptions); | |||
$storage->setMountOptions($mountOptions); | |||
$storage = $this->createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions | |||
); | |||
if ($storage instanceOf DataResponse) { | |||
return $storage; | |||
} | |||
$storage->setId($id); | |||
$response = $this->validate($storage); | |||
if (!empty($response)) { |
@@ -0,0 +1,94 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@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\Lib\Backend; | |||
use \OCA\Files_External\Lib\StorageConfig; | |||
use \OCA\Files_External\Lib\VisibilityTrait; | |||
use \OCA\Files_External\Lib\FrontendDefinitionTrait; | |||
use \OCA\Files_External\Lib\PriorityTrait; | |||
use \OCA\Files_External\Lib\DependencyTrait; | |||
use \OCA\Files_External\Lib\StorageModifierTrait; | |||
/** | |||
* Storage backend | |||
*/ | |||
class Backend implements \JsonSerializable { | |||
use VisibilityTrait; | |||
use FrontendDefinitionTrait; | |||
use PriorityTrait; | |||
use DependencyTrait; | |||
use StorageModifierTrait; | |||
/** @var string storage class */ | |||
private $storageClass; | |||
/** | |||
* @return string | |||
*/ | |||
public function getClass() { | |||
// return storage class for legacy compat | |||
return $this->getStorageClass(); | |||
} | |||
/** | |||
* @return string | |||
*/ | |||
public function getStorageClass() { | |||
return $this->storageClass; | |||
} | |||
/** | |||
* @param string $class | |||
* @return self | |||
*/ | |||
public function setStorageClass($class) { | |||
$this->storageClass = $class; | |||
return $this; | |||
} | |||
/** | |||
* Serialize into JSON for client-side JS | |||
* | |||
* @return array | |||
*/ | |||
public function jsonSerialize() { | |||
$data = $this->jsonSerializeDefinition(); | |||
$data['backend'] = $data['name']; // legacy compat | |||
$data['priority'] = $this->getPriority(); | |||
return $data; | |||
} | |||
/** | |||
* Check if parameters are satisfied in a StorageConfig | |||
* | |||
* @param StorageConfig $storage | |||
* @return bool | |||
*/ | |||
public function validateStorage(StorageConfig $storage) { | |||
return $this->validateStorageDefinition($storage); | |||
} | |||
} | |||
@@ -32,6 +32,9 @@ | |||
*/ | |||
use phpseclib\Crypt\AES; | |||
use \OCP\AppFramework\IAppContainer; | |||
use \OCA\Files_External\Lib\BackendConfig; | |||
use \OCA\Files_External\Service\BackendService; | |||
/** | |||
* Class to configure mount.json globally and for users | |||
@@ -51,71 +54,19 @@ class OC_Mount_Config { | |||
// whether to skip backend test (for unit tests, as this static class is not mockable) | |||
public static $skipTest = false; | |||
private static $backends = array(); | |||
/** @var IAppContainer */ | |||
private static $appContainer; | |||
/** | |||
* @param string $class | |||
* @param array $definition | |||
* @return bool | |||
*/ | |||
public static function registerBackend($class, $definition) { | |||
if (!isset($definition['backend'])) { | |||
return false; | |||
} | |||
OC_Mount_Config::$backends[$class] = $definition; | |||
return true; | |||
} | |||
/** | |||
* Setup backends | |||
* Teach OC_Mount_Config about the AppFramework | |||
* | |||
* @return array of previously registered backends | |||
* @param IAppContainer $appContainer | |||
*/ | |||
public static function setUp($backends = array()) { | |||
$backup = self::$backends; | |||
self::$backends = $backends; | |||
return $backup; | |||
} | |||
/** | |||
* Get details on each of the external storage backends, used for the mount config UI | |||
* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded | |||
* If the configuration parameter should be secret, add a '*' to the beginning of the value | |||
* If the configuration parameter is a boolean, add a '!' to the beginning of the value | |||
* If the configuration parameter is optional, add a '&' to the beginning of the value | |||
* If the configuration parameter is hidden, add a '#' to the beginning of the value | |||
* | |||
* @return array | |||
*/ | |||
public static function getBackends() { | |||
$sortFunc = function ($a, $b) { | |||
return strcasecmp($a['backend'], $b['backend']); | |||
}; | |||
$backEnds = array(); | |||
foreach (OC_Mount_Config::$backends as $class => $backend) { | |||
if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) { | |||
if (!method_exists($class, 'checkDependencies')) { | |||
\OCP\Util::writeLog('files_external', | |||
"Backend class $class has dependencies but doesn't provide method checkDependencies()", | |||
\OCP\Util::DEBUG); | |||
continue; | |||
} elseif ($class::checkDependencies() !== true) { | |||
continue; | |||
} | |||
} | |||
$backEnds[$class] = $backend; | |||
} | |||
uasort($backEnds, $sortFunc); | |||
return $backEnds; | |||
public static function initApp(IAppContainer $appContainer) { | |||
self::$appContainer = $appContainer; | |||
} | |||
/** | |||
/* | |||
* Hook that mounts the given user's visible mount points | |||
* | |||
* @param array $data | |||
@@ -151,14 +102,14 @@ class OC_Mount_Config { | |||
/** | |||
* Returns the mount points for the given user. | |||
* The mount point is relative to the data directory. | |||
* TODO: Move me into StoragesService | |||
* | |||
* @param string $user user | |||
* @return array of mount point string as key, mountpoint config as value | |||
*/ | |||
public static function getAbsoluteMountPoints($user) { | |||
$mountPoints = array(); | |||
$backends = self::getBackends(); | |||
$backendService = self::$appContainer->query('OCA\Files_External\Service\BackendService'); | |||
// Load system mount points | |||
$mountConfig = self::readData(); | |||
@@ -166,18 +117,20 @@ class OC_Mount_Config { | |||
// Global mount points (is this redundant?) | |||
if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) { | |||
foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) { | |||
$backend = $backendService->getBackend($options['class']); | |||
$options['personal'] = false; | |||
$options['options'] = self::decryptPasswords($options['options']); | |||
if (!isset($options['priority'])) { | |||
$options['priority'] = $backends[$options['class']]['priority']; | |||
$options['priority'] = $backend->getPriority(); | |||
} | |||
// Override if priority greater | |||
if ((!isset($mountPoints[$mountPoint])) | |||
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority']) | |||
) { | |||
$options['priority_type'] = self::MOUNT_TYPE_GLOBAL; | |||
$options['backend'] = $backends[$options['class']]['backend']; | |||
$options['backend'] = $backend->getText(); | |||
$mountPoints[$mountPoint] = $options; | |||
} | |||
} | |||
@@ -190,10 +143,11 @@ class OC_Mount_Config { | |||
foreach ($options as &$option) { | |||
$option = self::setUserVars($user, $option); | |||
} | |||
$backend = $backendService->getBackend($options['class']); | |||
$options['personal'] = false; | |||
$options['options'] = self::decryptPasswords($options['options']); | |||
if (!isset($options['priority'])) { | |||
$options['priority'] = $backends[$options['class']]['priority']; | |||
$options['priority'] = $backend->getPriority(); | |||
} | |||
// Override if priority greater | |||
@@ -201,7 +155,7 @@ class OC_Mount_Config { | |||
|| ($options['priority'] >= $mountPoints[$mountPoint]['priority']) | |||
) { | |||
$options['priority_type'] = self::MOUNT_TYPE_GLOBAL; | |||
$options['backend'] = $backends[$options['class']]['backend']; | |||
$options['backend'] = $backend->getText(); | |||
$mountPoints[$mountPoint] = $options; | |||
} | |||
} | |||
@@ -215,10 +169,11 @@ class OC_Mount_Config { | |||
foreach ($options as &$option) { | |||
$option = self::setUserVars($user, $option); | |||
} | |||
$backend = $backendService->getBackend($options['class']); | |||
$options['personal'] = false; | |||
$options['options'] = self::decryptPasswords($options['options']); | |||
if (!isset($options['priority'])) { | |||
$options['priority'] = $backends[$options['class']]['priority']; | |||
$options['priority'] = $backend->getPriority(); | |||
} | |||
// Override if priority greater or if priority type different | |||
@@ -227,7 +182,7 @@ class OC_Mount_Config { | |||
|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_GROUP) | |||
) { | |||
$options['priority_type'] = self::MOUNT_TYPE_GROUP; | |||
$options['backend'] = $backends[$options['class']]['backend']; | |||
$options['backend'] = $backend->getText(); | |||
$mountPoints[$mountPoint] = $options; | |||
} | |||
} | |||
@@ -243,10 +198,11 @@ class OC_Mount_Config { | |||
foreach ($options as &$option) { | |||
$option = self::setUserVars($user, $option); | |||
} | |||
$backend = $backendService->getBackend($options['class']); | |||
$options['personal'] = false; | |||
$options['options'] = self::decryptPasswords($options['options']); | |||
if (!isset($options['priority'])) { | |||
$options['priority'] = $backends[$options['class']]['priority']; | |||
$options['priority'] = $backend->getPriority(); | |||
} | |||
// Override if priority greater or if priority type different | |||
@@ -255,7 +211,7 @@ class OC_Mount_Config { | |||
|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_USER) | |||
) { | |||
$options['priority_type'] = self::MOUNT_TYPE_USER; | |||
$options['backend'] = $backends[$options['class']]['backend']; | |||
$options['backend'] = $backend->getText(); | |||
$mountPoints[$mountPoint] = $options; | |||
} | |||
} | |||
@@ -263,19 +219,18 @@ class OC_Mount_Config { | |||
} | |||
} | |||
$personalBackends = self::getPersonalBackends(); | |||
// Load personal mount points | |||
$mountConfig = self::readData($user); | |||
if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) { | |||
foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) { | |||
if (isset($personalBackends[$options['class']])) { | |||
$backend = $backendService->getBackend($options['class']); | |||
if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) { | |||
$options['personal'] = true; | |||
$options['options'] = self::decryptPasswords($options['options']); | |||
// Always override previous config | |||
$options['priority_type'] = self::MOUNT_TYPE_PERSONAL; | |||
$options['backend'] = $backends[$options['class']]['backend']; | |||
$options['backend'] = $backend->getText(); | |||
$mountPoints[$mountPoint] = $options; | |||
} | |||
} | |||
@@ -304,43 +259,6 @@ class OC_Mount_Config { | |||
return $input; | |||
} | |||
/** | |||
* Get details on each of the external storage backends, used for the mount config UI | |||
* Some backends are not available as a personal backend, f.e. Local and such that have | |||
* been disabled by the admin. | |||
* | |||
* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded | |||
* If the configuration parameter should be secret, add a '*' to the beginning of the value | |||
* If the configuration parameter is a boolean, add a '!' to the beginning of the value | |||
* If the configuration parameter is optional, add a '&' to the beginning of the value | |||
* If the configuration parameter is hidden, add a '#' to the beginning of the value | |||
* | |||
* @return array | |||
*/ | |||
public static function getPersonalBackends() { | |||
// Check whether the user has permissions to add personal storage backends | |||
// return an empty array if this is not the case | |||
if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') { | |||
return array(); | |||
} | |||
$backEnds = self::getBackends(); | |||
// Remove local storage and other disabled storages | |||
unset($backEnds['\OC\Files\Storage\Local']); | |||
$allowedBackEnds = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', '')); | |||
foreach ($backEnds as $backend => $null) { | |||
if (!in_array($backend, $allowedBackEnds)) { | |||
unset($backEnds[$backend]); | |||
} | |||
} | |||
return $backEnds; | |||
} | |||
/** | |||
* Get the system mount points | |||
* The returned array is not in the same format as getUserMountPoints() | |||
@@ -349,7 +267,7 @@ class OC_Mount_Config { | |||
*/ | |||
public static function getSystemMountPoints() { | |||
$mountPoints = self::readData(); | |||
$backends = self::getBackends(); | |||
$backendService = self::$appContainer->query('\OCA\Files_External\Service\BackendService'); | |||
$system = array(); | |||
if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) { | |||
foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) { | |||
@@ -358,9 +276,10 @@ class OC_Mount_Config { | |||
if (strpos($mount['class'], 'OC_Filestorage_') !== false) { | |||
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15); | |||
} | |||
$backend = $backendService->getBackend($mount['class']); | |||
$mount['options'] = self::decryptPasswords($mount['options']); | |||
if (!isset($mount['priority'])) { | |||
$mount['priority'] = $backends[$mount['class']]['priority']; | |||
$mount['priority'] = $backend->getPriority(); | |||
} | |||
// Remove '/$user/files/' from mount point | |||
$mountPoint = substr($mountPoint, 13); | |||
@@ -368,7 +287,7 @@ class OC_Mount_Config { | |||
$config = array( | |||
'class' => $mount['class'], | |||
'mountpoint' => $mountPoint, | |||
'backend' => $backends[$mount['class']]['backend'], | |||
'backend' => $backend->getText(), | |||
'priority' => $mount['priority'], | |||
'options' => $mount['options'], | |||
'applicable' => array('groups' => array($group), 'users' => array()) | |||
@@ -401,16 +320,17 @@ class OC_Mount_Config { | |||
if (strpos($mount['class'], 'OC_Filestorage_') !== false) { | |||
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15); | |||
} | |||
$backend = $backendService->getBackend($mount['class']); | |||
$mount['options'] = self::decryptPasswords($mount['options']); | |||
if (!isset($mount['priority'])) { | |||
$mount['priority'] = $backends[$mount['class']]['priority']; | |||
$mount['priority'] = $backend->getPriority(); | |||
} | |||
// Remove '/$user/files/' from mount point | |||
$mountPoint = substr($mountPoint, 13); | |||
$config = array( | |||
'class' => $mount['class'], | |||
'mountpoint' => $mountPoint, | |||
'backend' => $backends[$mount['class']]['backend'], | |||
'backend' => $backend->getText(), | |||
'priority' => $mount['priority'], | |||
'options' => $mount['options'], | |||
'applicable' => array('groups' => array(), 'users' => array($user)) | |||
@@ -447,7 +367,7 @@ class OC_Mount_Config { | |||
*/ | |||
public static function getPersonalMountPoints() { | |||
$mountPoints = self::readData(OCP\User::getUser()); | |||
$backEnds = self::getBackends(); | |||
$backendService = self::$appContainer->query('\OCA\Files_External\Service\BackendService'); | |||
$uid = OCP\User::getUser(); | |||
$personal = array(); | |||
if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) { | |||
@@ -456,12 +376,13 @@ class OC_Mount_Config { | |||
if (strpos($mount['class'], 'OC_Filestorage_') !== false) { | |||
$mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15); | |||
} | |||
$backend = $backendService->getBackend($mount['class']); | |||
$mount['options'] = self::decryptPasswords($mount['options']); | |||
$config = array( | |||
'class' => $mount['class'], | |||
// Remove '/uid/files/' from mount point | |||
'mountpoint' => substr($mountPoint, strlen($uid) + 8), | |||
'backend' => $backEnds[$mount['class']]['backend'], | |||
'backend' => $backend->getText(), | |||
'options' => $mount['options'] | |||
); | |||
if (isset($mount['id'])) { | |||
@@ -535,7 +456,7 @@ class OC_Mount_Config { | |||
$applicable, | |||
$isPersonal = false, | |||
$priority = null) { | |||
$backends = self::getBackends(); | |||
$backendService = self::$appContainer->query('\OCA\Files_External\Service\BackendService'); | |||
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint); | |||
$relMountPoint = $mountPoint; | |||
if ($mountPoint === '' || $mountPoint === '/') { | |||
@@ -543,15 +464,15 @@ class OC_Mount_Config { | |||
return false; | |||
} | |||
if (!isset($backends[$class])) { | |||
$backend = $backendService->getBackend($class); | |||
if (!isset($backend)) { | |||
// invalid backend | |||
return false; | |||
} | |||
if ($isPersonal) { | |||
// Verify that the mount point applies for the current user | |||
// Prevent non-admin users from mounting local storage and other disabled backends | |||
$allowed_backends = self::getPersonalBackends(); | |||
if ($applicable != OCP\User::getUser() || !isset($allowed_backends[$class])) { | |||
if ($applicable != OCP\User::getUser() || !$backend->isVisibleFor(BackendConfig::VISIBILITY_PERSONAL)) { | |||
return false; | |||
} | |||
$mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/'); | |||
@@ -578,13 +499,8 @@ class OC_Mount_Config { | |||
// Set default priority if none set | |||
if (!isset($mountPoints[$mountType][$applicable][$mountPoint]['priority'])) { | |||
if (isset($backends[$class]['priority'])) { | |||
$mountPoints[$mountType][$applicable][$mountPoint]['priority'] | |||
= $backends[$class]['priority']; | |||
} else { | |||
$mountPoints[$mountType][$applicable][$mountPoint]['priority'] | |||
= 100; | |||
} | |||
$mountPoints[$mountType][$applicable][$mountPoint]['priority'] | |||
= $backend->getPriority(); | |||
} | |||
self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints); | |||
@@ -721,74 +637,35 @@ class OC_Mount_Config { | |||
} | |||
/** | |||
* check dependencies | |||
* Get backend dependency message | |||
* TODO: move into AppFramework along with templates | |||
* | |||
* @param BackendConfig[] $backends | |||
* @return string | |||
*/ | |||
public static function checkDependencies() { | |||
$dependencies = array(); | |||
foreach (OC_Mount_Config::$backends as $class => $backend) { | |||
if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) { | |||
$result = $class::checkDependencies(); | |||
if ($result !== true) { | |||
if (!is_array($result)) { | |||
$result = array($result); | |||
} | |||
foreach ($result as $key => $value) { | |||
if (is_numeric($key)) { | |||
OC_Mount_Config::addDependency($dependencies, $value, $backend['backend']); | |||
} else { | |||
OC_Mount_Config::addDependency($dependencies, $key, $backend['backend'], $value); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
if (count($dependencies) > 0) { | |||
return OC_Mount_Config::generateDependencyMessage($dependencies); | |||
} | |||
return ''; | |||
} | |||
private static function addDependency(&$dependencies, $module, $backend, $message = null) { | |||
if (!isset($dependencies[$module])) { | |||
$dependencies[$module] = array(); | |||
} | |||
if ($message === null) { | |||
$dependencies[$module][] = $backend; | |||
} else { | |||
$dependencies[$module][] = array('backend' => $backend, 'message' => $message); | |||
} | |||
} | |||
private static function generateDependencyMessage($dependencies) { | |||
public static function dependencyMessage($backends) { | |||
$l = new \OC_L10N('files_external'); | |||
$dependencyMessage = ''; | |||
foreach ($dependencies as $module => $backends) { | |||
$dependencyGroup = array(); | |||
foreach ($backends as $backend) { | |||
if (is_array($backend)) { | |||
$dependencyMessage .= '<br />' . $l->t('<b>Note:</b> ') . $backend['message']; | |||
$message = ''; | |||
$dependencyGroups = []; | |||
foreach ($backends as $backend) { | |||
foreach ($backend->checkDependencies() as $dependency) { | |||
if ($message = $dependency->getMessage()) { | |||
$message .= '<br />' . $l->t('<b>Note:</b> ') . $message; | |||
} else { | |||
$dependencyGroup[] = $backend; | |||
$dependencyGroups[$dependency->getDependency()][] = $backend; | |||
} | |||
} | |||
} | |||
$dependencyGroupCount = count($dependencyGroup); | |||
if ($dependencyGroupCount > 0) { | |||
$backends = ''; | |||
for ($i = 0; $i < $dependencyGroupCount; $i++) { | |||
if ($i > 0 && $i === $dependencyGroupCount - 1) { | |||
$backends .= ' ' . $l->t('and') . ' '; | |||
} elseif ($i > 0) { | |||
$backends .= ', '; | |||
} | |||
$backends .= '<i>' . $dependencyGroup[$i] . '</i>'; | |||
} | |||
$dependencyMessage .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends); | |||
} | |||
foreach ($dependencyGroups as $module => $dependants) { | |||
$backends = implode(', ', array_map(function($backend) { | |||
return '<i>' . $backend->getText() . '</i>'; | |||
}, $dependants)); | |||
$message .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends); | |||
} | |||
return $dependencyMessage; | |||
return $message; | |||
} | |||
/** |
@@ -24,14 +24,23 @@ namespace OCA\Files_External\Config; | |||
use OC\Files\Mount\MountPoint; | |||
use OCP\Files\Storage\IStorageFactory; | |||
use OCA\Files_External\PersonalMount; | |||
use OCA\Files_External\Lib\PersonalMount; | |||
use OCP\Files\Config\IMountProvider; | |||
use OCP\IUser; | |||
use OCA\Files_external\Service\UserStoragesService; | |||
/** | |||
* Make the old files_external config work with the new public mount config api | |||
*/ | |||
class ConfigAdapter implements IMountProvider { | |||
/** | |||
* @param UserStoragesService $userStoragesService | |||
*/ | |||
public function __construct(UserStoragesService $userStoragesService) { | |||
$this->userStoragesService = $userStoragesService; | |||
} | |||
/** | |||
* Get all mountpoints applicable for the user | |||
* | |||
@@ -49,7 +58,8 @@ class ConfigAdapter implements IMountProvider { | |||
} | |||
$mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : []; | |||
if (isset($options['personal']) && $options['personal']) { | |||
$mounts[] = new PersonalMount($options['class'], $mountPoint, $options['options'], $loader, $mountOptions); | |||
$mount = new PersonalMount($this->userStoragesService, $options['id'], $options['class'], $mountPoint, $options['options'], $loader, $mountOptions); | |||
$mounts[] = $mount; | |||
} else { | |||
$mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions); | |||
} |
@@ -0,0 +1,179 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk> | |||
* | |||
* @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\Lib; | |||
/** | |||
* Parameter for an external storage definition | |||
*/ | |||
class DefinitionParameter implements \JsonSerializable { | |||
/** Value constants */ | |||
const VALUE_TEXT = 0; | |||
const VALUE_BOOLEAN = 1; | |||
const VALUE_PASSWORD = 2; | |||
const VALUE_HIDDEN = 3; | |||
/** Flag constants */ | |||
const FLAG_NONE = 0; | |||
const FLAG_OPTIONAL = 1; | |||
/** @var string name of parameter */ | |||
private $name; | |||
/** @var string human-readable parameter text */ | |||
private $text; | |||
/** @var int value type, see self::VALUE_* constants */ | |||
private $type = self::VALUE_TEXT; | |||
/** @var int flags, see self::FLAG_* constants */ | |||
private $flags = self::FLAG_NONE; | |||
/** | |||
* @param string $name | |||
* @param string $text | |||
*/ | |||
public function __construct($name, $text) { | |||
$this->name = $name; | |||
$this->text = $text; | |||
} | |||
/** | |||
* @return string | |||
*/ | |||
public function getName() { | |||
return $this->name; | |||
} | |||
/** | |||
* @return string | |||
*/ | |||
public function getText() { | |||
return $this->text; | |||
} | |||
/** | |||
* Get value type | |||
* | |||
* @return int | |||
*/ | |||
public function getType() { | |||
return $this->type; | |||
} | |||
/** | |||
* Set value type | |||
* | |||
* @param int $type | |||
* @return self | |||
*/ | |||
public function setType($type) { | |||
$this->type = $type; | |||
return $this; | |||
} | |||
/** | |||
* @return int | |||
*/ | |||
public function getFlags() { | |||
return $this->flags; | |||
} | |||
/** | |||
* @param int $flags | |||
* @return self | |||
*/ | |||
public function setFlags($flags) { | |||
$this->flags = $flags; | |||
return $this; | |||
} | |||
/** | |||
* @param int $flag | |||
* @return self | |||
*/ | |||
public function setFlag($flag) { | |||
$this->flags |= $flag; | |||
return $this; | |||
} | |||
/** | |||
* @param int $flag | |||
* @return bool | |||
*/ | |||
public function isFlagSet($flag) { | |||
return (bool) $this->flags & $flag; | |||
} | |||
/** | |||
* Serialize into JSON for client-side JS | |||
* | |||
* @return string | |||
*/ | |||
public function jsonSerialize() { | |||
$prefix = ''; | |||
switch ($this->getType()) { | |||
case self::VALUE_BOOLEAN: | |||
$prefix = '!'; | |||
break; | |||
case self::VALUE_PASSWORD: | |||
$prefix = '*'; | |||
break; | |||
case self::VALUE_HIDDEN: | |||
$prefix = '#'; | |||
break; | |||
} | |||
switch ($this->getFlags()) { | |||
case self::FLAG_OPTIONAL: | |||
$prefix = '&' . $prefix; | |||
break; | |||
} | |||
return $prefix . $this->getText(); | |||
} | |||
/** | |||
* Validate a parameter value against this | |||
* | |||
* @param mixed $value Value to check | |||
* @return bool success | |||
*/ | |||
public function validateValue($value) { | |||
if ($this->getFlags() & self::FLAG_OPTIONAL) { | |||
return true; | |||
} | |||
switch ($this->getType()) { | |||
case self::VALUE_BOOLEAN: | |||
if (!is_bool($value)) { | |||
return false; | |||
} | |||
break; | |||
default: | |||
if (empty($value)) { | |||
return false; | |||
} | |||
break; | |||
} | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,86 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@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\Lib; | |||
use \OCA\Files_External\Lib\MissingDependency; | |||
/** | |||
* Trait for objects that have dependencies for use | |||
*/ | |||
trait DependencyTrait { | |||
/** @var callable|null dependency check */ | |||
private $dependencyCheck = null; | |||
/** | |||
* @return bool | |||
*/ | |||
public function hasDependencies() { | |||
return !is_null($this->dependencyCheck); | |||
} | |||
/** | |||
* @param callable $dependencyCheck | |||
* @return self | |||
*/ | |||
public function setDependencyCheck(callable $dependencyCheck) { | |||
$this->dependencyCheck = $dependencyCheck; | |||
return $this; | |||
} | |||
/** | |||
* Check if object is valid for use | |||
* | |||
* @return MissingDependency[] Unsatisfied dependencies | |||
*/ | |||
public function checkDependencies() { | |||
$ret = []; | |||
if ($this->hasDependencies()) { | |||
$result = call_user_func($this->dependencyCheck); | |||
if ($result !== true) { | |||
if (!is_array($result)) { | |||
$result = [$result]; | |||
} | |||
foreach ($result as $key => $value) { | |||
if (!($value instanceof MissingDependency)) { | |||
$module = null; | |||
$message = null; | |||
if (is_numeric($key)) { | |||
$module = $value; | |||
} else { | |||
$module = $key; | |||
$message = $value; | |||
} | |||
$value = new MissingDependency($module, $this); | |||
$value->setMessage($message); | |||
} | |||
$ret[] = $value; | |||
} | |||
} | |||
} | |||
return $ret; | |||
} | |||
} | |||
@@ -0,0 +1,147 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@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\Lib; | |||
use \OCA\Files_External\Lib\DefinitionParameter; | |||
use \OCA\Files_External\Lib\StorageConfig; | |||
/** | |||
* Trait for objects that have a frontend representation | |||
*/ | |||
trait FrontendDefinitionTrait { | |||
/** @var string human-readable mechanism name */ | |||
private $text; | |||
/** @var DefinitionParameter[] parameters for mechanism */ | |||
private $parameters = []; | |||
/** @var string|null custom JS */ | |||
private $customJs = null; | |||
/** | |||
* @return string | |||
*/ | |||
public function getText() { | |||
return $this->text; | |||
} | |||
/** | |||
* @param string $text | |||
* @return self | |||
*/ | |||
public function setText($text) { | |||
$this->text = $text; | |||
return $this; | |||
} | |||
/** | |||
* @param FrontendDefinitionTrait $a | |||
* @param FrontendDefinitionTrait $b | |||
* @return int | |||
*/ | |||
public static function lexicalCompare(FrontendDefinitionTrait $a, FrontendDefinitionTrait $b) { | |||
return strcmp($a->getText(), $b->getText()); | |||
} | |||
/** | |||
* @return DefinitionParameter[] | |||
*/ | |||
public function getParameters() { | |||
return $this->parameters; | |||
} | |||
/** | |||
* @param DefinitionParameter[] $parameters | |||
* @return self | |||
*/ | |||
public function addParameters(array $parameters) { | |||
foreach ($parameters as $parameter) { | |||
$this->addParameter($parameter); | |||
} | |||
return $this; | |||
} | |||
/** | |||
* @param DefinitionParameter $parameter | |||
* @return self | |||
*/ | |||
public function addParameter(DefinitionParameter $parameter) { | |||
$this->parameters[$parameter->getName()] = $parameter; | |||
return $this; | |||
} | |||
/** | |||
* @return string|null | |||
*/ | |||
public function getCustomJs() { | |||
return $this->customJs; | |||
} | |||
/** | |||
* @param string $custom | |||
* @return self | |||
*/ | |||
public function setCustomJs($custom) { | |||
$this->customJs = $custom; | |||
return $this; | |||
} | |||
/** | |||
* Serialize into JSON for client-side JS | |||
* | |||
* @return array | |||
*/ | |||
public function jsonSerializeDefinition() { | |||
$configuration = []; | |||
foreach ($this->getParameters() as $parameter) { | |||
$configuration[$parameter->getName()] = $parameter; | |||
} | |||
$data = [ | |||
'name' => $this->getText(), | |||
'configuration' => $configuration, | |||
]; | |||
if (isset($this->customJs)) { | |||
$data['custom'] = $this->getCustomJs(); | |||
} | |||
return $data; | |||
} | |||
/** | |||
* Check if parameters are satisfied in a StorageConfig | |||
* | |||
* @param StorageConfig $storage | |||
* @return bool | |||
*/ | |||
public function validateStorageDefinition(StorageConfig $storage) { | |||
$options = $storage->getBackendOptions(); | |||
foreach ($this->getParameters() as $name => $parameter) { | |||
$value = isset($options[$name]) ? $options[$name] : null; | |||
if (!$parameter->validateValue($value)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk> | |||
* | |||
* @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\Lib; | |||
/** | |||
* External storage backend dependency | |||
*/ | |||
class MissingDependency { | |||
/** @var string */ | |||
private $dependency; | |||
/** @var string|null Custom message */ | |||
private $message = null; | |||
/** | |||
* @param string $dependency | |||
*/ | |||
public function __construct($dependency) { | |||
$this->dependency = $dependency; | |||
} | |||
/** | |||
* @return string | |||
*/ | |||
public function getDependency() { | |||
return $this->dependency; | |||
} | |||
/** | |||
* @return string|null | |||
*/ | |||
public function getMessage() { | |||
return $this->message; | |||
} | |||
/** | |||
* @param string $message | |||
* @return self | |||
*/ | |||
public function setMessage($message) { | |||
$this->message = $message; | |||
return $this; | |||
} | |||
} |
@@ -20,15 +20,45 @@ | |||
* | |||
*/ | |||
namespace OCA\Files_External; | |||
namespace OCA\Files_External\Lib; | |||
use OC\Files\Mount\MountPoint; | |||
use OC\Files\Mount\MoveableMount; | |||
use OCA\Files_External\Service\UserStoragesService; | |||
/** | |||
* Person mount points can be moved by the user | |||
*/ | |||
class PersonalMount extends MountPoint implements MoveableMount { | |||
/** @var UserStoragesService */ | |||
protected $storagesService; | |||
/** @var int */ | |||
protected $storageId; | |||
/** | |||
* @param UserStoragesService $storagesService | |||
* @param int $storageId | |||
* @param string|\OC\Files\Storage\Storage $storage | |||
* @param string $mountpoint | |||
* @param array $arguments (optional) configuration for the storage backend | |||
* @param \OCP\Files\Storage\IStorageFactory $loader | |||
* @param array $mountOptions mount specific options | |||
*/ | |||
public function __construct( | |||
UserStoragesService $storagesService, | |||
$storageId, | |||
$storage, | |||
$mountpoint, | |||
$arguments = null, | |||
$loader = null, | |||
$mountOptions = null | |||
) { | |||
parent::__construct($storage, $mountpoint, $arguments, $loader, $mountOptions); | |||
$this->storagesService = $storagesService; | |||
$this->storageId = $storageId; | |||
} | |||
/** | |||
* Move the mount point to $target | |||
* | |||
@@ -36,9 +66,13 @@ class PersonalMount extends MountPoint implements MoveableMount { | |||
* @return bool | |||
*/ | |||
public function moveMount($target) { | |||
$result = \OC_Mount_Config::movePersonalMountPoint($this->getMountPoint(), $target, \OC_Mount_Config::MOUNT_TYPE_USER); | |||
$storage = $this->storagesService->getStorage($this->storageId); | |||
// remove "/$user/files" prefix | |||
$targetParts = explode('/', trim($target, '/'), 3); | |||
$storage->setMountPoint($targetParts[2]); | |||
$this->storagesService->updateStorage($storage); | |||
$this->setMountPoint($target); | |||
return $result; | |||
return true; | |||
} | |||
/** | |||
@@ -47,8 +81,7 @@ class PersonalMount extends MountPoint implements MoveableMount { | |||
* @return bool | |||
*/ | |||
public function removeMount() { | |||
$user = \OCP\User::getUser(); | |||
$relativeMountPoint = substr($this->getMountPoint(), strlen('/' . $user . '/files/')); | |||
return \OC_Mount_Config::removeMountPoint($relativeMountPoint, \OC_Mount_Config::MOUNT_TYPE_USER, $user , true); | |||
$this->storagesService->removeStorage($this->storageId); | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk> | |||
* | |||
* @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\Lib; | |||
use \OCA\Files_External\Service\BackendService; | |||
/** | |||
* Trait to implement priority mechanics for a configuration class | |||
*/ | |||
trait PriorityTrait { | |||
/** @var int initial priority */ | |||
protected $priority = BackendService::PRIORITY_DEFAULT; | |||
/** | |||
* @return int | |||
*/ | |||
public function getPriority() { | |||
return $this->priority; | |||
} | |||
/** | |||
* @param int $priority | |||
* @return self | |||
*/ | |||
public function setPriority($priority) { | |||
$this->priority = $priority; | |||
return $this; | |||
} | |||
/** | |||
* @param PriorityTrait $a | |||
* @param PriorityTrait $b | |||
* @return int | |||
*/ | |||
public static function priorityCompare(PriorityTrait $a, PriorityTrait $b) { | |||
return ($a->getPriority() - $b->getPriority()); | |||
} | |||
} | |||
@@ -21,6 +21,8 @@ | |||
namespace OCA\Files_external\Lib; | |||
use \OCA\Files_External\Lib\Backend\Backend; | |||
/** | |||
* External storage configuration | |||
*/ | |||
@@ -34,11 +36,11 @@ class StorageConfig implements \JsonSerializable { | |||
private $id; | |||
/** | |||
* Backend class name | |||
* Backend | |||
* | |||
* @var string | |||
* @var Backend | |||
*/ | |||
private $backendClass; | |||
private $backend; | |||
/** | |||
* Backend options | |||
@@ -138,21 +140,17 @@ class StorageConfig implements \JsonSerializable { | |||
} | |||
/** | |||
* Returns the external storage backend class name | |||
* | |||
* @return string external storage backend class name | |||
* @return Backend | |||
*/ | |||
public function getBackendClass() { | |||
return $this->backendClass; | |||
public function getBackend() { | |||
return $this->backend; | |||
} | |||
/** | |||
* Sets the external storage backend class name | |||
* | |||
* @param string external storage backend class name | |||
* @param Backend | |||
*/ | |||
public function setBackendClass($backendClass) { | |||
$this->backendClass = $backendClass; | |||
public function setBackend(Backend $backend) { | |||
$this->backend= $backend; | |||
} | |||
/** | |||
@@ -173,6 +171,25 @@ class StorageConfig implements \JsonSerializable { | |||
$this->backendOptions = $backendOptions; | |||
} | |||
/** | |||
* @param string $key | |||
* @return mixed | |||
*/ | |||
public function getBackendOption($key) { | |||
if (isset($this->backendOptions[$key])) { | |||
return $this->backendOptions[$key]; | |||
} | |||
return null; | |||
} | |||
/** | |||
* @param string $key | |||
* @param mixed $value | |||
*/ | |||
public function setBackendOption($key, $value) { | |||
$this->backendOptions[$key] = $value; | |||
} | |||
/** | |||
* Returns the mount priority | |||
* | |||
@@ -283,7 +300,7 @@ class StorageConfig implements \JsonSerializable { | |||
$result['id'] = $this->id; | |||
} | |||
$result['mountPoint'] = $this->mountPoint; | |||
$result['backendClass'] = $this->backendClass; | |||
$result['backendClass'] = $this->backend->getClass(); | |||
$result['backendOptions'] = $this->backendOptions; | |||
if (!is_null($this->priority)) { | |||
$result['priority'] = $this->priority; |
@@ -0,0 +1,51 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@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\Lib; | |||
use \OCP\Files\Storage; | |||
use \OCA\Files_External\Lib\StorageConfig; | |||
/** | |||
* Trait for objects that can modify StorageConfigs and wrap Storages | |||
*/ | |||
trait StorageModifierTrait { | |||
/** | |||
* Modify a StorageConfig parameters | |||
* | |||
* @param StorageConfig $storage | |||
*/ | |||
public function manipulateStorageConfig(StorageConfig &$storage) { | |||
} | |||
/** | |||
* Wrap a Storage if necessary | |||
* | |||
* @param Storage $storage | |||
* @return Storage | |||
*/ | |||
public function wrapStorage(Storage $storage) { | |||
return $storage; | |||
} | |||
} | |||
@@ -0,0 +1,129 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk> | |||
* | |||
* @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\Lib; | |||
use \OCA\Files_External\Service\BackendService; | |||
/** | |||
* Trait to implement visibility mechanics for a configuration class | |||
*/ | |||
trait VisibilityTrait { | |||
/** @var int visibility */ | |||
protected $visibility = BackendService::VISIBILITY_DEFAULT; | |||
/** @var int allowed visibilities */ | |||
protected $allowedVisibility = BackendService::VISIBILITY_DEFAULT; | |||
/** | |||
* @return int | |||
*/ | |||
public function getVisibility() { | |||
return $this->visibility; | |||
} | |||
/** | |||
* Check if the backend is visible for a user type | |||
* | |||
* @param int $visibility | |||
* @return bool | |||
*/ | |||
public function isVisibleFor($visibility) { | |||
if ($this->visibility & $visibility) { | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* @param int $visibility | |||
* @return self | |||
*/ | |||
public function setVisibility($visibility) { | |||
$this->visibility = $visibility; | |||
$this->allowedVisibility |= $visibility; | |||
return $this; | |||
} | |||
/** | |||
* @param int $visibility | |||
* @return self | |||
*/ | |||
public function addVisibility($visibility) { | |||
return $this->setVisibility($this->visibility | $visibility); | |||
} | |||
/** | |||
* @param int $visibility | |||
* @return self | |||
*/ | |||
public function removeVisibility($visibility) { | |||
return $this->setVisibility($this->visibility & ~$visibility); | |||
} | |||
/** | |||
* @return int | |||
*/ | |||
public function getAllowedVisibility() { | |||
return $this->allowedVisibility; | |||
} | |||
/** | |||
* Check if the backend is allowed to be visible for a user type | |||
* | |||
* @param int $allowedVisibility | |||
* @return bool | |||
*/ | |||
public function isAllowedVisibleFor($allowedVisibility) { | |||
if ($this->allowedVisibility & $allowedVisibility) { | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* @param int $allowedVisibility | |||
* @return self | |||
*/ | |||
public function setAllowedVisibility($allowedVisibility) { | |||
$this->allowedVisibility = $allowedVisibility; | |||
$this->visibility &= $allowedVisibility; | |||
return $this; | |||
} | |||
/** | |||
* @param int $allowedVisibility | |||
* @return self | |||
*/ | |||
public function addAllowedVisibility($allowedVisibility) { | |||
return $this->setAllowedVisibility($this->allowedVisibility | $allowedVisibility); | |||
} | |||
/** | |||
* @param int $allowedVisibility | |||
* @return self | |||
*/ | |||
public function removeAllowedVisibility($allowedVisibility) { | |||
return $this->setAllowedVisibility($this->allowedVisibility & ~$allowedVisibility); | |||
} | |||
} |
@@ -24,34 +24,20 @@ | |||
* | |||
*/ | |||
OCP\Util::addScript('files_external', 'settings'); | |||
OCP\Util::addStyle('files_external', 'settings'); | |||
$backends = OC_Mount_Config::getPersonalBackends(); | |||
use \OCA\Files_External\Service\BackendService; | |||
$mounts = OC_Mount_Config::getPersonalMountPoints(); | |||
$hasId = true; | |||
foreach ($mounts as $mount) { | |||
if (!isset($mount['id'])) { | |||
// some mount points are missing ids | |||
$hasId = false; | |||
break; | |||
} | |||
} | |||
$app = new \OCA\Files_external\Appinfo\Application(); | |||
$appContainer = $app->getContainer(); | |||
$backendService = $appContainer->query('OCA\Files_External\Service\BackendService'); | |||
$userStoragesService = $appContainer->query('OCA\Files_external\Service\UserStoragesService'); | |||
if (!$hasId) { | |||
$service = new \OCA\Files_external\Service\UserStoragesService(\OC::$server->getUserSession()); | |||
// this will trigger the new storage code which will automatically | |||
// generate storage config ids | |||
$service->getAllStorages(); | |||
// re-read updated config | |||
$mounts = OC_Mount_Config::getPersonalMountPoints(); | |||
// TODO: use the new storage config format in the template | |||
} | |||
OCP\Util::addScript('files_external', 'settings'); | |||
OCP\Util::addStyle('files_external', 'settings'); | |||
$tmpl = new OCP\Template('files_external', 'settings'); | |||
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled()); | |||
$tmpl->assign('isAdminPage', false); | |||
$tmpl->assign('mounts', $mounts); | |||
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies()); | |||
$tmpl->assign('backends', $backends); | |||
$tmpl->assign('storages', $userStoragesService->getAllStorages()); | |||
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); | |||
$tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL)); | |||
return $tmpl->fetchPage(); |
@@ -0,0 +1,170 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk> | |||
* | |||
* @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\IConfig; | |||
use \OCA\Files_External\Lib\Backend\Backend; | |||
/** | |||
* Service class to manage backend definitions | |||
*/ | |||
class BackendService { | |||
/** Visibility constants for VisibilityTrait */ | |||
const VISIBILITY_NONE = 0; | |||
const VISIBILITY_PERSONAL = 1; | |||
const VISIBILITY_ADMIN = 2; | |||
//const VISIBILITY_ALIENS = 4; | |||
const VISIBILITY_DEFAULT = 3; // PERSONAL | ADMIN | |||
/** Priority constants for PriorityTrait */ | |||
const PRIORITY_DEFAULT = 100; | |||
/** @var IConfig */ | |||
protected $config; | |||
/** @var bool */ | |||
private $userMountingAllowed = true; | |||
/** @var string[] */ | |||
private $userMountingBackends = []; | |||
/** @var Backend[] */ | |||
private $backends = []; | |||
/** | |||
* @param IConfig $config | |||
*/ | |||
public function __construct( | |||
IConfig $config | |||
) { | |||
$this->config = $config; | |||
// Load config values | |||
if ($this->config->getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') { | |||
$this->userMountingAllowed = false; | |||
} | |||
$this->userMountingBackends = explode(',', | |||
$this->config->getAppValue('files_external', 'user_mounting_backends', '') | |||
); | |||
} | |||
/** | |||
* Register a backend | |||
* | |||
* @param Backend $backend | |||
*/ | |||
public function registerBackend(Backend $backend) { | |||
if (!$this->isAllowedUserBackend($backend)) { | |||
$backend->removeVisibility(BackendService::VISIBILITY_PERSONAL); | |||
} | |||
$this->backends[$backend->getClass()] = $backend; | |||
} | |||
/** | |||
* @param Backend[] $backends | |||
*/ | |||
public function registerBackends(array $backends) { | |||
foreach ($backends as $backend) { | |||
$this->registerBackend($backend); | |||
} | |||
} | |||
/** | |||
* Get all backends | |||
* | |||
* @return Backend[] | |||
*/ | |||
public function getBackends() { | |||
return $this->backends; | |||
} | |||
/** | |||
* Get all available backends | |||
* | |||
* @return Backend[] | |||
*/ | |||
public function getAvailableBackends() { | |||
return array_filter($this->getBackends(), function($backend) { | |||
return empty($backend->checkDependencies()); | |||
}); | |||
} | |||
/** | |||
* Get backends visible for $visibleFor | |||
* | |||
* @param int $visibleFor | |||
* @return Backend[] | |||
*/ | |||
public function getBackendsVisibleFor($visibleFor) { | |||
return array_filter($this->getAvailableBackends(), function($backend) use ($visibleFor) { | |||
return $backend->isVisibleFor($visibleFor); | |||
}); | |||
} | |||
/** | |||
* Get backends allowed to be visible for $visibleFor | |||
* | |||
* @param int $visibleFor | |||
* @return Backend[] | |||
*/ | |||
public function getBackendsAllowedVisibleFor($visibleFor) { | |||
return array_filter($this->getAvailableBackends(), function($backend) use ($visibleFor) { | |||
return $backend->isAllowedVisibleFor($visibleFor); | |||
}); | |||
} | |||
/** | |||
* @param string $class Backend class name | |||
* @return Backend|null | |||
*/ | |||
public function getBackend($class) { | |||
if (isset($this->backends[$class])) { | |||
return $this->backends[$class]; | |||
} | |||
return null; | |||
} | |||
/** | |||
* @return bool | |||
*/ | |||
public function isUserMountingAllowed() { | |||
return $this->userMountingAllowed; | |||
} | |||
/** | |||
* Check a backend if a user is allowed to mount it | |||
* | |||
* @param Backend $backend | |||
* @return bool | |||
*/ | |||
protected function isAllowedUserBackend(Backend $backend) { | |||
if ($this->userMountingAllowed && | |||
in_array($backend->getClass(), $this->userMountingBackends) | |||
) { | |||
return true; | |||
} | |||
return false; | |||
} | |||
} |
@@ -28,12 +28,23 @@ use \OC\Files\Filesystem; | |||
use \OCA\Files_external\Lib\StorageConfig; | |||
use \OCA\Files_external\NotFoundException; | |||
use \OCA\Files_External\Service\BackendService; | |||
/** | |||
* Service class to manage external storages | |||
*/ | |||
abstract class StoragesService { | |||
/** @var BackendService */ | |||
protected $backendService; | |||
/** | |||
* @param BackendService $backendService | |||
*/ | |||
public function __construct(BackendService $backendService) { | |||
$this->backendService = $backendService; | |||
} | |||
/** | |||
* Read legacy config data | |||
* | |||
@@ -60,14 +71,17 @@ abstract class StoragesService { | |||
$applicable, | |||
$storageOptions | |||
) { | |||
$storageConfig->setBackendClass($storageOptions['class']); | |||
$backend = $this->backendService->getBackend($storageOptions['class']); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions($storageOptions['options']); | |||
if (isset($storageOptions['mountOptions'])) { | |||
$storageConfig->setMountOptions($storageOptions['mountOptions']); | |||
} | |||
if (isset($storageOptions['priority'])) { | |||
$storageConfig->setPriority($storageOptions['priority']); | |||
if (!isset($storageOptions['priority'])) { | |||
$storageOptions['priority'] = $backend->getPriority(); | |||
} | |||
$storageConfig->setPriority($storageOptions['priority']); | |||
if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) { | |||
$applicableUsers = $storageConfig->getApplicableUsers(); | |||
@@ -222,7 +236,7 @@ abstract class StoragesService { | |||
$options = [ | |||
'id' => $storageConfig->getId(), | |||
'class' => $storageConfig->getBackendClass(), | |||
'class' => $storageConfig->getBackend()->getClass(), | |||
'options' => $storageConfig->getBackendOptions(), | |||
]; | |||
@@ -296,6 +310,52 @@ abstract class StoragesService { | |||
return $newStorage; | |||
} | |||
/** | |||
* Create a storage from its parameters | |||
* | |||
* @param string $mountPoint storage mount point | |||
* @param string $backendClass backend class name | |||
* @param array $backendOptions backend-specific options | |||
* @param array|null $mountOptions mount-specific options | |||
* @param array|null $applicableUsers users for which to mount the storage | |||
* @param array|null $applicableGroups groups for which to mount the storage | |||
* @param int|null $priority priority | |||
* | |||
* @return StorageConfig | |||
*/ | |||
public function createStorage( | |||
$mountPoint, | |||
$backendClass, | |||
$backendOptions, | |||
$mountOptions = null, | |||
$applicableUsers = null, | |||
$applicableGroups = null, | |||
$priority = null | |||
) { | |||
$backend = $this->backendService->getBackend($backendClass); | |||
if (!$backend) { | |||
throw new \InvalidArgumentException('Unable to get backend for backend class '.$backendClass); | |||
} | |||
$newStorage = new StorageConfig(); | |||
$newStorage->setMountPoint($mountPoint); | |||
$newStorage->setBackend($backend); | |||
$newStorage->setBackendOptions($backendOptions); | |||
if (isset($mountOptions)) { | |||
$newStorage->setMountOptions($mountOptions); | |||
} | |||
if (isset($applicableUsers)) { | |||
$newStorage->setApplicableUsers($applicableUsers); | |||
} | |||
if (isset($applicableGroups)) { | |||
$newStorage->setApplicableGroups($applicableGroups); | |||
} | |||
if (isset($priority)) { | |||
$newStorage->setPriority($priority); | |||
} | |||
return $newStorage; | |||
} | |||
/** | |||
* Triggers the given hook signal for all the applicables given | |||
* |
@@ -26,6 +26,7 @@ use \OC\Files\Filesystem; | |||
use \OCA\Files_external\Lib\StorageConfig; | |||
use \OCA\Files_external\NotFoundException; | |||
use \OCA\Files_External\Service\BackendService; | |||
/** | |||
* Service class to manage user external storages | |||
@@ -43,12 +44,15 @@ class UserStoragesService extends StoragesService { | |||
/** | |||
* Create a user storages service | |||
* | |||
* @param BackendService $backendService | |||
* @param IUserSession $userSession user session | |||
*/ | |||
public function __construct( | |||
BackendService $backendService, | |||
IUserSession $userSession | |||
) { | |||
$this->userSession = $userSession; | |||
parent::__construct($backendService); | |||
} | |||
/** |
@@ -26,54 +26,27 @@ | |||
* | |||
*/ | |||
use \OCA\Files_External\Service\BackendService; | |||
OC_Util::checkAdminUser(); | |||
$app = new \OCA\Files_external\Appinfo\Application(); | |||
$appContainer = $app->getContainer(); | |||
$backendService = $appContainer->query('OCA\Files_External\Service\BackendService'); | |||
$globalStoragesService = $appContainer->query('OCA\Files_external\Service\GlobalStoragesService'); | |||
OCP\Util::addScript('files_external', 'settings'); | |||
OCP\Util::addStyle('files_external', 'settings'); | |||
\OC_Util::addVendorScript('select2/select2'); | |||
\OC_Util::addVendorStyle('select2/select2'); | |||
$backends = OC_Mount_Config::getBackends(); | |||
$personal_backends = array(); | |||
$enabled_backends = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', '')); | |||
foreach ($backends as $class => $backend) | |||
{ | |||
if ($class != '\OC\Files\Storage\Local') | |||
{ | |||
$personal_backends[$class] = array( | |||
'backend' => $backend['backend'], | |||
'enabled' => in_array($class, $enabled_backends), | |||
); | |||
} | |||
} | |||
$mounts = OC_Mount_Config::getSystemMountPoints(); | |||
$hasId = true; | |||
foreach ($mounts as $mount) { | |||
if (!isset($mount['id'])) { | |||
// some mount points are missing ids | |||
$hasId = false; | |||
break; | |||
} | |||
} | |||
if (!$hasId) { | |||
$service = new \OCA\Files_external\Service\GlobalStoragesService(); | |||
// this will trigger the new storage code which will automatically | |||
// generate storage config ids | |||
$service->getAllStorages(); | |||
// re-read updated config | |||
$mounts = OC_Mount_Config::getSystemMountPoints(); | |||
// TODO: use the new storage config format in the template | |||
} | |||
$tmpl = new OCP\Template('files_external', 'settings'); | |||
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled()); | |||
$tmpl->assign('isAdminPage', true); | |||
$tmpl->assign('mounts', $mounts); | |||
$tmpl->assign('backends', $backends); | |||
$tmpl->assign('personal_backends', $personal_backends); | |||
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies()); | |||
$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes')); | |||
$tmpl->assign('storages', $globalStoragesService->getAllStorages()); | |||
$tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN)); | |||
$tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL)); | |||
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); | |||
$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed()); | |||
return $tmpl->fetchPage(); |
@@ -1,3 +1,8 @@ | |||
<?php | |||
use \OCA\Files_External\Lib\Backend\Backend; | |||
use \OCA\Files_External\Lib\DefinitionParameter; | |||
use \OCA\Files_External\Service\BackendService; | |||
?> | |||
<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>"> | |||
<h2><?php p($l->t('External Storage')); ?></h2> | |||
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?> | |||
@@ -14,103 +19,149 @@ | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<?php $_['mounts'] = array_merge($_['mounts'], array('' => array('id' => ''))); ?> | |||
<?php foreach ($_['mounts'] as $mount): ?> | |||
<tr <?php print_unescaped(isset($mount['mountpoint']) ? 'class="'.OC_Util::sanitizeHTML($mount['class']).'"' : 'id="addMountPoint"'); ?> data-id="<?php p($mount['id']) ?>"> | |||
<?php foreach ($_['storages'] as $storage): ?> | |||
<tr class="<?php p($storage->getBackend()->getClass()); ?>" data-id="<?php p($storage->getId()); ?>"> | |||
<td class="status"> | |||
<span></span> | |||
</td> | |||
<td class="mountPoint"><input type="text" name="mountPoint" | |||
value="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>" | |||
data-mountpoint="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>" | |||
value="<?php p(ltrim($storage->getMountPoint(), '/')); ?>" | |||
data-mountpoint="<?php p(ltrim($storage->getMountPoint(), '/')); ?>" | |||
placeholder="<?php p($l->t('Folder name')); ?>" /> | |||
</td> | |||
<?php if (!isset($mount['mountpoint'])): ?> | |||
<td class="backend"> | |||
<select id="selectBackend" class="selectBackend" data-configurations='<?php p(json_encode($_['backends'])); ?>'> | |||
<option value="" disabled selected | |||
style="display:none;"><?php p($l->t('Add storage')); ?></option> | |||
<?php foreach ($_['backends'] as $class => $backend): ?> | |||
<option value="<?php p($class); ?>"><?php p($backend['backend']); ?></option> | |||
<?php endforeach; ?> | |||
</select> | |||
</td> | |||
<?php else: ?> | |||
<td class="backend" data-class="<?php p($mount['class']); ?>"><?php p($mount['backend']); ?> | |||
</td> | |||
<?php endif; ?> | |||
<td class ="configuration"> | |||
<?php if (isset($mount['options'])): ?> | |||
<?php foreach ($mount['options'] as $parameter => $value): ?> | |||
<?php if (isset($_['backends'][$mount['class']]['configuration'][$parameter])): ?> | |||
<td class="backend" data-class="<?php p($storage->getBackend()->getClass()); ?>"><?php p($storage->getBackend()->getText()); ?> | |||
</td> | |||
<td class="configuration"> | |||
<?php $options = $storage->getBackendOptions(); ?> | |||
<?php foreach ($storage->getBackend()->getParameters() as $parameter): ?> | |||
<?php | |||
$value = ''; | |||
if (isset($options[$parameter->getName()])) { | |||
$value = $options[$parameter->getName()]; | |||
} | |||
$placeholder = $parameter->getText(); | |||
$is_optional = $parameter->isFlagSet(DefinitionParameter::FLAG_OPTIONAL); | |||
switch ($parameter->getType()) { | |||
case DefinitionParameter::VALUE_PASSWORD: ?> | |||
<input type="password" | |||
<?php if ($is_optional): ?> class="optional"<?php endif; ?> | |||
data-parameter="<?php p($parameter->getName()); ?>" | |||
value="<?php p($value); ?>" | |||
placeholder="<?php p($placeholder); ?>" | |||
/> | |||
<?php | |||
$placeholder = $_['backends'][$mount['class']]['configuration'][$parameter]; | |||
$is_optional = FALSE; | |||
if (strpos($placeholder, '&') === 0) { | |||
$is_optional = TRUE; | |||
$placeholder = substr($placeholder, 1); | |||
} | |||
?> | |||
<?php if (strpos($placeholder, '*') === 0): ?> | |||
<input type="password" | |||
<?php if ($is_optional): ?> class="optional"<?php endif; ?> | |||
data-parameter="<?php p($parameter); ?>" | |||
value="<?php p($value); ?>" | |||
placeholder="<?php p(substr($placeholder, 1)); ?>" /> | |||
<?php elseif (strpos($placeholder, '!') === 0): ?> | |||
<label><input type="checkbox" | |||
data-parameter="<?php p($parameter); ?>" | |||
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?> | |||
/><?php p(substr($placeholder, 1)); ?></label> | |||
<?php elseif (strpos($placeholder, '#') === 0): ?> | |||
<input type="hidden" | |||
data-parameter="<?php p($parameter); ?>" | |||
value="<?php p($value); ?>" /> | |||
<?php else: ?> | |||
<input type="text" | |||
<?php if ($is_optional): ?> class="optional"<?php endif; ?> | |||
data-parameter="<?php p($parameter); ?>" | |||
value="<?php p($value); ?>" | |||
placeholder="<?php p($placeholder); ?>" /> | |||
<?php endif; ?> | |||
<?php endif; ?> | |||
<?php endforeach; ?> | |||
<?php if (isset($_['backends'][$mount['class']]['custom'])): ?> | |||
<?php OCP\Util::addScript('files_external', $_['backends'][$mount['class']]['custom']); ?> | |||
<?php endif; ?> | |||
<?php endif; ?> | |||
break; | |||
case DefinitionParameter::VALUE_BOOLEAN: ?> | |||
<label> | |||
<input type="checkbox" | |||
data-parameter="<?php p($parameter->getName()); ?>" | |||
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?> | |||
/> | |||
<?php p($placeholder); ?> | |||
</label> | |||
<?php | |||
break; | |||
case DefinitionParameter::VALUE_HIDDEN: ?> | |||
<input type="hidden" | |||
data-parameter="<?php p($parameter->getName()); ?>" | |||
value="<?php p($value); ?>" | |||
/> | |||
<?php | |||
break; | |||
default: ?> | |||
<input type="text" | |||
<?php if ($is_optional): ?> class="optional"<?php endif; ?> | |||
data-parameter="<?php p($parameter->getName()); ?>" | |||
value="<?php p($value); ?>" | |||
placeholder="<?php p($placeholder); ?>" | |||
/> | |||
<?php | |||
} | |||
?> | |||
<?php endforeach; ?> | |||
<?php | |||
$customJs = $storage->getBackend()->getCustomJs(); | |||
if (isset($customJs)) { | |||
\OCP\Util::addScript('files_external', $customJs); | |||
} | |||
?> | |||
</td> | |||
<?php if ($_['isAdminPage']): ?> | |||
<td class="applicable" | |||
align="right" | |||
data-applicable-groups='<?php if (isset($mount['applicable']['groups'])) | |||
print_unescaped(json_encode($mount['applicable']['groups'])); ?>' | |||
data-applicable-users='<?php if (isset($mount['applicable']['users'])) | |||
print_unescaped(json_encode($mount['applicable']['users'])); ?>'> | |||
<input type="hidden" class="applicableUsers" style="width:20em;" value=""/> | |||
</td> | |||
<td class="applicable" | |||
align="right" | |||
data-applicable-groups='<?php print_unescaped(json_encode($storage->getApplicableGroups())); ?>' | |||
data-applicable-users='<?php print_unescaped(json_encode($storage->getApplicableUsers())); ?>'> | |||
<input type="hidden" class="applicableUsers" style="width:20em;" value=""/> | |||
</td> | |||
<?php endif; ?> | |||
<td class="mountOptionsToggle <?php if (!isset($mount['mountpoint'])) { p('hidden'); } ?>" | |||
><img | |||
<td class="mountOptionsToggle"> | |||
<img | |||
class="svg action" | |||
title="<?php p($l->t('Advanced settings')); ?>" | |||
alt="<?php p($l->t('Advanced settings')); ?>" | |||
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>" /> | |||
<input type="hidden" class="mountOptions" value="<?php isset($mount['mountOptions']) ? p(json_encode($mount['mountOptions'])) : '' ?>" /> | |||
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>" | |||
/> | |||
<input type="hidden" class="mountOptions" value="<?php p(json_encode($storage->getMountOptions())); ?>" /> | |||
<?php if ($_['isAdminPage']): ?> | |||
<?php if (isset($mount['priority'])): ?> | |||
<input type="hidden" class="priority" value="<?php p($mount['priority']) ?>" /> | |||
<?php endif; ?> | |||
<input type="hidden" class="priority" value="<?php p($storage->getPriority()); ?>" /> | |||
<?php endif; ?> | |||
</td> | |||
<td <?php if (isset($mount['mountpoint'])): ?>class="remove" | |||
<?php else: ?>class="hidden" | |||
<?php endif ?>><img alt="<?php p($l->t('Delete')); ?>" | |||
title="<?php p($l->t('Delete')); ?>" | |||
class="svg action" | |||
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>" /></td> | |||
<td class="remove"> | |||
<img alt="<?php p($l->t('Delete')); ?>" | |||
title="<?php p($l->t('Delete')); ?>" | |||
class="svg action" | |||
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>" | |||
/> | |||
</td> | |||
</tr> | |||
<?php endforeach; ?> | |||
<tr id="addMountPoint"> | |||
<td class="status"> | |||
<span></span> | |||
</td> | |||
<td class="mountPoint"><input type="text" name="mountPoint" value="" | |||
placeholder="<?php p($l->t('Folder name')); ?>"> | |||
</td> | |||
<td class="backend"> | |||
<select id="selectBackend" class="selectBackend" data-configurations='<?php p(json_encode($_['backends'])); ?>'> | |||
<option value="" disabled selected | |||
style="display:none;"> | |||
<?php p($l->t('Add storage')); ?> | |||
</option> | |||
<?php | |||
$sortedBackends = $_['backends']; | |||
uasort($sortedBackends, function($a, $b) { | |||
return strcasecmp($a->getText(), $b->getText()); | |||
}); | |||
?> | |||
<?php foreach ($sortedBackends as $backend): ?> | |||
<option value="<?php p($backend->getClass()); ?>"><?php p($backend->getText()); ?></option> | |||
<?php endforeach; ?> | |||
</select> | |||
</td> | |||
<td class="configuration"</td> | |||
<?php if ($_['isAdminPage']): ?> | |||
<td class="applicable" align="right"> | |||
<input type="hidden" class="applicableUsers" style="width:20em;" value="" /> | |||
</td> | |||
<?php endif; ?> | |||
<td class="mountOptionsToggle hidden"> | |||
<img class="svg action" | |||
title="<?php p($l->t('Advanced settings')); ?>" | |||
alt="<?php p($l->t('Advanced settings')); ?>" | |||
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>" | |||
/> | |||
<input type="hidden" class="mountOptions" value="" /> | |||
</td> | |||
<td class="hidden"> | |||
<img class="svg action" | |||
alt="<?php p($l->t('Delete')); ?>" | |||
title="<?php p($l->t('Delete')); ?>" | |||
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>" | |||
/> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<br /> | |||
@@ -123,9 +174,9 @@ | |||
<p id="userMountingBackends"<?php if ($_['allowUserMounting'] != 'yes'): ?> class="hidden"<?php endif; ?>> | |||
<?php p($l->t('Allow users to mount the following external storage')); ?><br /> | |||
<?php $i = 0; foreach ($_['personal_backends'] as $class => $backend): ?> | |||
<input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($class); ?>" <?php if ($backend['enabled']) print_unescaped(' checked="checked"'); ?> /> | |||
<label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend['backend']); ?></label> <br /> | |||
<?php $i = 0; foreach ($_['userBackends'] as $backend): ?> | |||
<input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($backend->getClass()); ?>" <?php if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) print_unescaped(' checked="checked"'); ?> /> | |||
<label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend->getText()); ?></label> <br /> | |||
<?php $i++; ?> | |||
<?php endforeach; ?> | |||
</p> |
@@ -28,7 +28,9 @@ use \OCA\Files_external\NotFoundException; | |||
class GlobalStoragesControllerTest extends StoragesControllerTest { | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->service = $this->getMock('\OCA\Files_external\Service\GlobalStoragesService'); | |||
$this->service = $this->getMockBuilder('\OCA\Files_external\Service\GlobalStoragesService') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->controller = new GlobalStoragesController( | |||
'files_external', |
@@ -47,10 +47,32 @@ abstract class StoragesControllerTest extends \Test\TestCase { | |||
\OC_Mount_Config::$skipTest = false; | |||
} | |||
protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') { | |||
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$backend->method('getStorageClass') | |||
->willReturn($storageClass); | |||
$backend->method('getClass') | |||
->willReturn($storageClass); | |||
return $backend; | |||
} | |||
public function testAddStorage() { | |||
$backend = $this->getBackendMock(); | |||
$backend->method('validateStorage') | |||
->willReturn(true); | |||
$backend->method('isVisibleFor') | |||
->willReturn(true); | |||
$storageConfig = new StorageConfig(1); | |||
$storageConfig->setMountPoint('mount'); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions([]); | |||
$this->service->expects($this->once()) | |||
->method('createStorage') | |||
->will($this->returnValue($storageConfig)); | |||
$this->service->expects($this->once()) | |||
->method('addStorage') | |||
->will($this->returnValue($storageConfig)); | |||
@@ -71,9 +93,20 @@ abstract class StoragesControllerTest extends \Test\TestCase { | |||
} | |||
public function testUpdateStorage() { | |||
$backend = $this->getBackendMock(); | |||
$backend->method('validateStorage') | |||
->willReturn(true); | |||
$backend->method('isVisibleFor') | |||
->willReturn(true); | |||
$storageConfig = new StorageConfig(1); | |||
$storageConfig->setMountPoint('mount'); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions([]); | |||
$this->service->expects($this->once()) | |||
->method('createStorage') | |||
->will($this->returnValue($storageConfig)); | |||
$this->service->expects($this->once()) | |||
->method('updateStorage') | |||
->will($this->returnValue($storageConfig)); | |||
@@ -106,6 +139,14 @@ abstract class StoragesControllerTest extends \Test\TestCase { | |||
* @dataProvider mountPointNamesProvider | |||
*/ | |||
public function testAddOrUpdateStorageInvalidMountPoint($mountPoint) { | |||
$storageConfig = new StorageConfig(1); | |||
$storageConfig->setMountPoint($mountPoint); | |||
$storageConfig->setBackend($this->getBackendMock()); | |||
$storageConfig->setBackendOptions([]); | |||
$this->service->expects($this->exactly(2)) | |||
->method('createStorage') | |||
->will($this->returnValue($storageConfig)); | |||
$this->service->expects($this->never()) | |||
->method('addStorage'); | |||
$this->service->expects($this->never()) | |||
@@ -138,6 +179,9 @@ abstract class StoragesControllerTest extends \Test\TestCase { | |||
} | |||
public function testAddOrUpdateStorageInvalidBackend() { | |||
$this->service->expects($this->exactly(2)) | |||
->method('createStorage') | |||
->will($this->throwException(new \InvalidArgumentException())); | |||
$this->service->expects($this->never()) | |||
->method('addStorage'); | |||
$this->service->expects($this->never()) | |||
@@ -170,6 +214,20 @@ abstract class StoragesControllerTest extends \Test\TestCase { | |||
} | |||
public function testUpdateStorageNonExisting() { | |||
$backend = $this->getBackendMock(); | |||
$backend->method('validateStorage') | |||
->willReturn(true); | |||
$backend->method('isVisibleFor') | |||
->willReturn(true); | |||
$storageConfig = new StorageConfig(255); | |||
$storageConfig->setMountPoint('mount'); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions([]); | |||
$this->service->expects($this->once()) | |||
->method('createStorage') | |||
->will($this->returnValue($storageConfig)); | |||
$this->service->expects($this->once()) | |||
->method('updateStorage') | |||
->will($this->throwException(new NotFoundException())); | |||
@@ -206,9 +264,10 @@ abstract class StoragesControllerTest extends \Test\TestCase { | |||
} | |||
public function testGetStorage() { | |||
$backend = $this->getBackendMock(); | |||
$storageConfig = new StorageConfig(1); | |||
$storageConfig->setMountPoint('test'); | |||
$storageConfig->setBackendClass('\OC\Files\Storage\SMB'); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']); | |||
$storageConfig->setMountOptions(['priority' => false]); | |||
@@ -24,6 +24,8 @@ use \OCA\Files_external\Controller\UserStoragesController; | |||
use \OCA\Files_external\Service\UserStoragesService; | |||
use \OCP\AppFramework\Http; | |||
use \OCA\Files_external\NotFoundException; | |||
use \OCA\Files_External\Lib\StorageConfig; | |||
use \OCA\Files_External\Service\BackendService; | |||
class UserStoragesControllerTest extends StoragesControllerTest { | |||
@@ -44,41 +46,22 @@ class UserStoragesControllerTest extends StoragesControllerTest { | |||
$this->getMock('\OCP\IL10N'), | |||
$this->service | |||
); | |||
$config = \OC::$server->getConfig(); | |||
$this->oldAllowedBackends = $config->getAppValue( | |||
'files_external', | |||
'user_mounting_backends', | |||
'' | |||
); | |||
$config->setAppValue( | |||
'files_external', | |||
'user_mounting_backends', | |||
'\OC\Files\Storage\SMB' | |||
); | |||
} | |||
public function tearDown() { | |||
$config = \OC::$server->getConfig(); | |||
$config->setAppValue( | |||
'files_external', | |||
'user_mounting_backends', | |||
$this->oldAllowedBackends | |||
); | |||
parent::tearDown(); | |||
} | |||
public function testAddOrUpdateStorageDisallowedBackend() { | |||
$backend = $this->getBackendMock(); | |||
$backend->method('isVisibleFor') | |||
->with(BackendService::VISIBILITY_PERSONAL) | |||
->willReturn(false); | |||
function disallowedBackendClassProvider() { | |||
return array( | |||
array('\OC\Files\Storage\Local'), | |||
array('\OC\Files\Storage\FTP'), | |||
); | |||
} | |||
/** | |||
* @dataProvider disallowedBackendClassProvider | |||
*/ | |||
public function testAddOrUpdateStorageDisallowedBackend($backendClass) { | |||
$storageConfig = new StorageConfig(1); | |||
$storageConfig->setMountPoint('mount'); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions([]); | |||
$this->service->expects($this->exactly(2)) | |||
->method('createStorage') | |||
->will($this->returnValue($storageConfig)); | |||
$this->service->expects($this->never()) | |||
->method('addStorage'); | |||
$this->service->expects($this->never()) | |||
@@ -86,7 +69,7 @@ class UserStoragesControllerTest extends StoragesControllerTest { | |||
$response = $this->controller->create( | |||
'mount', | |||
$backendClass, | |||
'\OC\Files\Storage\SMB', | |||
array(), | |||
[], | |||
[], | |||
@@ -99,7 +82,7 @@ class UserStoragesControllerTest extends StoragesControllerTest { | |||
$response = $this->controller->update( | |||
1, | |||
'mount', | |||
$backendClass, | |||
'\OC\Files\Storage\SMB', | |||
array(), | |||
[], | |||
[], |
@@ -1,104 +0,0 @@ | |||
<?php | |||
/** | |||
* @author Joas Schilling <nickvergessen@owncloud.com> | |||
* @author Morris Jobke <hey@morrisjobke.de> | |||
* @author Thomas Müller <thomas.mueller@tmit.eu> | |||
* | |||
* @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/> | |||
* | |||
*/ | |||
require_once __DIR__ . '/../../../lib/base.php'; | |||
/** | |||
* Class Test_Mount_Config_Dummy_Backend | |||
*/ | |||
class Test_Mount_Config_Dummy_Backend { | |||
public static $checkDependencies = true; | |||
public static function checkDependencies() { | |||
return self::$checkDependencies; | |||
} | |||
} | |||
/** | |||
* Class Test_Dynamic_Mount_Config | |||
*/ | |||
class Test_Dynamic_Mount_Config extends \Test\TestCase { | |||
private $backup; | |||
public function testRegistration() { | |||
// second registration shall return false | |||
$result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array( | |||
'backend' => 'Test Dummy', | |||
'configuration' => array(), | |||
'has_dependencies' => true)); | |||
$this->assertTrue($result); | |||
} | |||
public function testDependencyGetBackend() { | |||
// is the backend listed? | |||
Test_Mount_Config_Dummy_Backend::$checkDependencies = true; | |||
$backEnds = OC_Mount_Config::getBackends(); | |||
$this->assertArrayHasKey('Test_Mount_Config_Dummy_Backend', $backEnds); | |||
// backend shall not be listed | |||
Test_Mount_Config_Dummy_Backend::$checkDependencies = false; | |||
$backEnds = OC_Mount_Config::getBackends(); | |||
$this->assertArrayNotHasKey('Test_Mount_Config_Dummy_Backend', $backEnds); | |||
} | |||
public function testCheckDependencies() { | |||
Test_Mount_Config_Dummy_Backend::$checkDependencies = true; | |||
$message = OC_Mount_Config::checkDependencies(); | |||
$this->assertEmpty($message); | |||
// backend shall not be listed | |||
Test_Mount_Config_Dummy_Backend::$checkDependencies = array('dummy'); | |||
$message = OC_Mount_Config::checkDependencies(); | |||
$this->assertEquals('<br /><b>Note:</b> "dummy" is not installed. Mounting of <i>Test Dummy</i> is not possible. Please ask your system administrator to install it.', | |||
$message); | |||
} | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->backup = OC_Mount_Config::setUp(); | |||
// register dummy backend | |||
$result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array( | |||
'backend' => 'Test Dummy', | |||
'configuration' => array(), | |||
'has_dependencies' => true)); | |||
$this->assertTrue($result); | |||
} | |||
protected function tearDown() | |||
{ | |||
OC_Mount_Config::setUp($this->backup); | |||
parent::tearDown(); | |||
} | |||
} |
@@ -29,7 +29,7 @@ use \OCA\Files_external\Lib\StorageConfig; | |||
class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->service = new GlobalStoragesService(); | |||
$this->service = new GlobalStoragesService($this->backendService); | |||
} | |||
public function tearDown() { | |||
@@ -59,7 +59,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
return [ | |||
// all users | |||
[ | |||
$this->makeStorageConfig([ | |||
[ | |||
'mountPoint' => 'mountpoint', | |||
'backendClass' => '\OC\Files\Storage\SMB', | |||
'backendOptions' => [ | |||
@@ -70,11 +70,11 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
'applicableUsers' => [], | |||
'applicableGroups' => [], | |||
'priority' => 15, | |||
]), | |||
], | |||
], | |||
// some users | |||
[ | |||
$this->makeStorageConfig([ | |||
[ | |||
'mountPoint' => 'mountpoint', | |||
'backendClass' => '\OC\Files\Storage\SMB', | |||
'backendOptions' => [ | |||
@@ -85,11 +85,11 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
'applicableUsers' => ['user1', 'user2'], | |||
'applicableGroups' => [], | |||
'priority' => 15, | |||
]), | |||
], | |||
], | |||
// some groups | |||
[ | |||
$this->makeStorageConfig([ | |||
[ | |||
'mountPoint' => 'mountpoint', | |||
'backendClass' => '\OC\Files\Storage\SMB', | |||
'backendOptions' => [ | |||
@@ -100,11 +100,11 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
'applicableUsers' => [], | |||
'applicableGroups' => ['group1', 'group2'], | |||
'priority' => 15, | |||
]), | |||
], | |||
], | |||
// both users and groups | |||
[ | |||
$this->makeStorageConfig([ | |||
[ | |||
'mountPoint' => 'mountpoint', | |||
'backendClass' => '\OC\Files\Storage\SMB', | |||
'backendOptions' => [ | |||
@@ -115,7 +115,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
'applicableUsers' => ['user1', 'user2'], | |||
'applicableGroups' => ['group1', 'group2'], | |||
'priority' => 15, | |||
]), | |||
], | |||
], | |||
]; | |||
} | |||
@@ -123,7 +123,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
/** | |||
* @dataProvider storageDataProvider | |||
*/ | |||
public function testAddStorage($storage) { | |||
public function testAddStorage($storageParams) { | |||
$storage = $this->makeStorageConfig($storageParams); | |||
$newStorage = $this->service->addStorage($storage); | |||
$this->assertEquals(1, $newStorage->getId()); | |||
@@ -132,7 +133,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
$newStorage = $this->service->getStorage(1); | |||
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); | |||
$this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass()); | |||
$this->assertEquals($storage->getBackend(), $newStorage->getBackend()); | |||
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); | |||
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers()); | |||
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups()); | |||
@@ -148,7 +149,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest { | |||
/** | |||
* @dataProvider storageDataProvider | |||
*/ | |||
public function testUpdateStorage($updatedStorage) { | |||
public function testUpdateStorage($updatedStorageParams) { | |||
$updatedStorage = $this->makeStorageConfig($updatedStorageParams); | |||
$storage = $this->makeStorageConfig([ | |||
'mountPoint' => 'mountpoint', | |||
'backendClass' => '\OC\Files\Storage\SMB', |
@@ -24,6 +24,7 @@ use \OC\Files\Filesystem; | |||
use \OCA\Files_external\NotFoundException; | |||
use \OCA\Files_external\Lib\StorageConfig; | |||
use \OCA\Files_External\Lib\BackendService; | |||
abstract class StoragesServiceTest extends \Test\TestCase { | |||
@@ -32,6 +33,9 @@ abstract class StoragesServiceTest extends \Test\TestCase { | |||
*/ | |||
protected $service; | |||
/** @var BackendService */ | |||
protected $backendService; | |||
/** | |||
* Data directory | |||
* | |||
@@ -55,6 +59,25 @@ abstract class StoragesServiceTest extends \Test\TestCase { | |||
); | |||
\OC_Mount_Config::$skipTest = true; | |||
$this->backendService = | |||
$this->getMockBuilder('\OCA\Files_External\Service\BackendService') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$backends = [ | |||
'\OC\Files\Storage\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OC\Files\Storage\SMB'), | |||
'\OC\Files\Storage\SFTP' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SFTP', '\OC\Files\Storage\SFTP'), | |||
]; | |||
$this->backendService->method('getBackend') | |||
->will($this->returnCallback(function($backendClass) use ($backends) { | |||
if (isset($backends[$backendClass])) { | |||
return $backends[$backendClass]; | |||
} | |||
return null; | |||
})); | |||
$this->backendService->method('getBackends') | |||
->will($this->returnValue($backends)); | |||
\OCP\Util::connectHook( | |||
Filesystem::CLASSNAME, | |||
Filesystem::signal_create_mount, | |||
@@ -71,6 +94,17 @@ abstract class StoragesServiceTest extends \Test\TestCase { | |||
self::$hookCalls = array(); | |||
} | |||
protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') { | |||
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$backend->method('getStorageClass') | |||
->willReturn($storageClass); | |||
$backend->method('getClass') | |||
->willReturn($storageClass); | |||
return $backend; | |||
} | |||
/** | |||
* Creates a StorageConfig instance based on array data | |||
* | |||
@@ -84,7 +118,12 @@ abstract class StoragesServiceTest extends \Test\TestCase { | |||
$storage->setId($data['id']); | |||
} | |||
$storage->setMountPoint($data['mountPoint']); | |||
$storage->setBackendClass($data['backendClass']); | |||
if (!isset($data['backend'])) { | |||
// data providers are run before $this->backendService is initialised | |||
// so $data['backend'] can be specified directly | |||
$data['backend'] = $this->backendService->getBackend($data['backendClass']); | |||
} | |||
$storage->setBackend($data['backend']); | |||
$storage->setBackendOptions($data['backendOptions']); | |||
if (isset($data['applicableUsers'])) { | |||
$storage->setApplicableUsers($data['applicableUsers']); | |||
@@ -106,16 +145,18 @@ abstract class StoragesServiceTest extends \Test\TestCase { | |||
* @expectedException \OCA\Files_external\NotFoundException | |||
*/ | |||
public function testNonExistingStorage() { | |||
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB'); | |||
$storage = new StorageConfig(255); | |||
$storage->setMountPoint('mountpoint'); | |||
$storage->setBackendClass('\OC\Files\Storage\SMB'); | |||
$storage->setBackend($backend); | |||
$this->service->updateStorage($storage); | |||
} | |||
public function testDeleteStorage() { | |||
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB'); | |||
$storage = new StorageConfig(255); | |||
$storage->setMountPoint('mountpoint'); | |||
$storage->setBackendClass('\OC\Files\Storage\SMB'); | |||
$storage->setBackend($backend); | |||
$storage->setBackendOptions(['password' => 'testPassword']); | |||
$newStorage = $this->service->addStorage($storage); |
@@ -40,7 +40,7 @@ class UserStoragesServiceTest extends StoragesServiceTest { | |||
->method('getUser') | |||
->will($this->returnValue($this->user)); | |||
$this->service = new UserStoragesService($userSession); | |||
$this->service = new UserStoragesService($this->backendService, $userSession); | |||
// create home folder | |||
mkdir($this->dataDir . '/' . $this->userId . '/'); | |||
@@ -76,7 +76,7 @@ class UserStoragesServiceTest extends StoragesServiceTest { | |||
$newStorage = $this->service->getStorage(1); | |||
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); | |||
$this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass()); | |||
$this->assertEquals($storage->getBackend(), $newStorage->getBackend()); | |||
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); | |||
$this->assertEquals(1, $newStorage->getId()); | |||
$this->assertEquals(0, $newStorage->getStatus()); |
@@ -26,9 +26,15 @@ use \OCA\Files_external\Lib\StorageConfig; | |||
class StorageConfigTest extends \Test\TestCase { | |||
public function testJsonSerialization() { | |||
$backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$backend->method('getClass') | |||
->willReturn('\OC\Files\Storage\SMB'); | |||
$storageConfig = new StorageConfig(1); | |||
$storageConfig->setMountPoint('test'); | |||
$storageConfig->setBackendClass('\OC\Files\Storage\SMB'); | |||
$storageConfig->setBackend($backend); | |||
$storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']); | |||
$storageConfig->setPriority(128); | |||
$storageConfig->setApplicableUsers(['user1', 'user2']); |