diff options
author | Robin McCorkell <rmccorkell@owncloud.com> | 2015-08-11 18:45:07 +0100 |
---|---|---|
committer | Robin McCorkell <rmccorkell@owncloud.com> | 2015-08-19 10:05:11 +0100 |
commit | 37beb58c6f395523d8e2934870c5f52a8c6f6df0 (patch) | |
tree | b14325a790ddaf7236c3f8c1939ce9ef10df58bb /apps/files_external/lib | |
parent | 74237a9c44192fb98944ea7f3c14fa6f22c0814b (diff) | |
download | nextcloud-server-37beb58c6f395523d8e2934870c5f52a8c6f6df0.tar.gz nextcloud-server-37beb58c6f395523d8e2934870c5f52a8c6f6df0.zip |
Introduce BackendService for managing external storage backends
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).
Diffstat (limited to 'apps/files_external/lib')
-rw-r--r-- | apps/files_external/lib/backend/backend.php | 94 | ||||
-rw-r--r-- | apps/files_external/lib/config.php | 255 | ||||
-rw-r--r-- | apps/files_external/lib/config/configadapter.php | 14 | ||||
-rw-r--r-- | apps/files_external/lib/definitionparameter.php | 179 | ||||
-rw-r--r-- | apps/files_external/lib/dependencytrait.php | 86 | ||||
-rw-r--r-- | apps/files_external/lib/frontenddefinitiontrait.php | 147 | ||||
-rw-r--r-- | apps/files_external/lib/missingdependency.php | 64 | ||||
-rw-r--r-- | apps/files_external/lib/personalmount.php | 45 | ||||
-rw-r--r-- | apps/files_external/lib/prioritytrait.php | 60 | ||||
-rw-r--r-- | apps/files_external/lib/storageconfig.php | 45 | ||||
-rw-r--r-- | apps/files_external/lib/storagemodifiertrait.php | 51 | ||||
-rw-r--r-- | apps/files_external/lib/visibilitytrait.php | 129 |
12 files changed, 958 insertions, 211 deletions
diff --git a/apps/files_external/lib/backend/backend.php b/apps/files_external/lib/backend/backend.php new file mode 100644 index 00000000000..e7cd27a1d6c --- /dev/null +++ b/apps/files_external/lib/backend/backend.php @@ -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); + } + +} + diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 8fcf39cc767..11dec94621a 100644 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -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; } /** diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php index b5c2ba4fc92..6956de1e748 100644 --- a/apps/files_external/lib/config/configadapter.php +++ b/apps/files_external/lib/config/configadapter.php @@ -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); } diff --git a/apps/files_external/lib/definitionparameter.php b/apps/files_external/lib/definitionparameter.php new file mode 100644 index 00000000000..4b560908b69 --- /dev/null +++ b/apps/files_external/lib/definitionparameter.php @@ -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; + } +} diff --git a/apps/files_external/lib/dependencytrait.php b/apps/files_external/lib/dependencytrait.php new file mode 100644 index 00000000000..116421eab14 --- /dev/null +++ b/apps/files_external/lib/dependencytrait.php @@ -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; + } + +} + diff --git a/apps/files_external/lib/frontenddefinitiontrait.php b/apps/files_external/lib/frontenddefinitiontrait.php new file mode 100644 index 00000000000..4b826372d2f --- /dev/null +++ b/apps/files_external/lib/frontenddefinitiontrait.php @@ -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; + } + +} diff --git a/apps/files_external/lib/missingdependency.php b/apps/files_external/lib/missingdependency.php new file mode 100644 index 00000000000..9b25aeacc9b --- /dev/null +++ b/apps/files_external/lib/missingdependency.php @@ -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; + } +} diff --git a/apps/files_external/lib/personalmount.php b/apps/files_external/lib/personalmount.php index bbffc958641..d177f1a1ad0 100644 --- a/apps/files_external/lib/personalmount.php +++ b/apps/files_external/lib/personalmount.php @@ -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; } } diff --git a/apps/files_external/lib/prioritytrait.php b/apps/files_external/lib/prioritytrait.php new file mode 100644 index 00000000000..22f9fe275d8 --- /dev/null +++ b/apps/files_external/lib/prioritytrait.php @@ -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()); + } + +} + diff --git a/apps/files_external/lib/storageconfig.php b/apps/files_external/lib/storageconfig.php index 92c27701d80..cf8271ff4eb 100644 --- a/apps/files_external/lib/storageconfig.php +++ b/apps/files_external/lib/storageconfig.php @@ -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; } /** @@ -174,6 +172,25 @@ class StorageConfig implements \JsonSerializable { } /** + * @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 * * @return int 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; diff --git a/apps/files_external/lib/storagemodifiertrait.php b/apps/files_external/lib/storagemodifiertrait.php new file mode 100644 index 00000000000..f78116103db --- /dev/null +++ b/apps/files_external/lib/storagemodifiertrait.php @@ -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; + } + +} + diff --git a/apps/files_external/lib/visibilitytrait.php b/apps/files_external/lib/visibilitytrait.php new file mode 100644 index 00000000000..06c95dd70c9 --- /dev/null +++ b/apps/files_external/lib/visibilitytrait.php @@ -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); + } + +} |