diff options
Diffstat (limited to 'apps/files_external/lib/Service/BackendService.php')
-rw-r--r-- | apps/files_external/lib/Service/BackendService.php | 161 |
1 files changed, 110 insertions, 51 deletions
diff --git a/apps/files_external/lib/Service/BackendService.php b/apps/files_external/lib/Service/BackendService.php index 49af01f5bf9..3a688ee66e6 100644 --- a/apps/files_external/lib/Service/BackendService.php +++ b/apps/files_external/lib/Service/BackendService.php @@ -1,34 +1,23 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @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/> - * + * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\Files_External\Service; -use \OCP\IConfig; - -use \OCA\Files_External\Lib\Backend\Backend; -use \OCA\Files_External\Lib\Auth\AuthMechanism; -use \OCA\Files_External\Lib\Config\IBackendProvider; -use \OCA\Files_External\Lib\Config\IAuthMechanismProvider; +use OCA\Files_External\Config\IConfigHandler; +use OCA\Files_External\ConfigLexicon; +use OCA\Files_External\Lib\Auth\AuthMechanism; +use OCA\Files_External\Lib\Backend\Backend; +use OCA\Files_External\Lib\Config\IAuthMechanismProvider; +use OCA\Files_External\Lib\Config\IBackendProvider; +use OCA\Files_External\Lib\MissingDependency; +use OCP\EventDispatcher\GenericEvent; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IAppConfig; +use OCP\Server; /** * Service class to manage backend definitions @@ -36,18 +25,15 @@ use \OCA\Files_External\Lib\Config\IAuthMechanismProvider; class BackendService { /** Visibility constants for VisibilityTrait */ - const VISIBILITY_NONE = 0; - const VISIBILITY_PERSONAL = 1; - const VISIBILITY_ADMIN = 2; + public const VISIBILITY_NONE = 0; + public const VISIBILITY_PERSONAL = 1; + public const VISIBILITY_ADMIN = 2; //const VISIBILITY_ALIENS = 4; - const VISIBILITY_DEFAULT = 3; // PERSONAL | ADMIN + public const VISIBILITY_DEFAULT = 3; // PERSONAL | ADMIN /** Priority constants for PriorityTrait */ - const PRIORITY_DEFAULT = 100; - - /** @var IConfig */ - protected $config; + public const PRIORITY_DEFAULT = 100; /** @var bool */ private $userMountingAllowed = true; @@ -67,21 +53,17 @@ class BackendService { /** @var IAuthMechanismProvider[] */ private $authMechanismProviders = []; - /** - * @param IConfig $config - */ + /** @var callable[] */ + private $configHandlerLoaders = []; + + private $configHandlers = []; + public function __construct( - IConfig $config + protected IAppConfig $appConfig, ) { - $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', '') - ); + $this->userMountingAllowed = $appConfig->getValueBool('files_external', ConfigLexicon::ALLOW_USER_MOUNTING); + $this->userMountingBackends = explode(',', $appConfig->getValueString('files_external', ConfigLexicon::USER_MOUNTING_BACKENDS)); // if no backend is in the list an empty string is in the array and user mounting is disabled if ($this->userMountingBackends === ['']) { @@ -99,7 +81,19 @@ class BackendService { $this->backendProviders[] = $provider; } + private function callForRegistrations() { + static $eventSent = false; + if (!$eventSent) { + Server::get(IEventDispatcher::class)->dispatch( + 'OCA\\Files_External::loadAdditionalBackends', + new GenericEvent() + ); + $eventSent = true; + } + } + private function loadBackendProviders() { + $this->callForRegistrations(); foreach ($this->backendProviders as $provider) { $this->registerBackends($provider->getBackends()); } @@ -117,6 +111,7 @@ class BackendService { } private function loadAuthMechanismProviders() { + $this->callForRegistrations(); foreach ($this->authMechanismProviders as $provider) { $this->registerAuthMechanisms($provider->getAuthMechanisms()); } @@ -193,8 +188,9 @@ class BackendService { * @return Backend[] */ public function getAvailableBackends() { - return array_filter($this->getBackends(), function($backend) { - return !($backend->checkDependencies()); + return array_filter($this->getBackends(), function ($backend) { + $missing = array_filter($backend->checkDependencies(), fn (MissingDependency $dependency) => !$dependency->isOptional()); + return count($missing) === 0; }); } @@ -232,7 +228,7 @@ class BackendService { * @return AuthMechanism[] */ public function getAuthMechanismsByScheme(array $schemes) { - return array_filter($this->getAuthMechanisms(), function($authMech) use ($schemes) { + return array_filter($this->getAuthMechanisms(), function ($authMech) use ($schemes) { return in_array($authMech->getScheme(), $schemes, true); }); } @@ -263,8 +259,8 @@ class BackendService { * @return bool */ protected function isAllowedUserBackend(Backend $backend) { - if ($this->userMountingAllowed && - array_intersect($backend->getIdentifierAliases(), $this->userMountingBackends) + if ($this->userMountingAllowed + && array_intersect($backend->getIdentifierAliases(), $this->userMountingBackends) ) { return true; } @@ -280,4 +276,67 @@ class BackendService { protected function isAllowedAuthMechanism(AuthMechanism $authMechanism) { return true; // not implemented } + + /** + * registers a configuration handler + * + * The function of the provided $placeholder is mostly to act a sorting + * criteria, so longer placeholders are replaced first. This avoids + * "$user" overwriting parts of "$userMail" and "$userLang", for example. + * The provided value should not contain the $ prefix, only a-z0-9 are + * allowed. Upper case letters are lower cased, the replacement is case- + * insensitive. + * + * The configHandlerLoader should just instantiate the handler on demand. + * For now all handlers are instantiated when a mount is loaded, independent + * of whether the placeholder is present or not. This may change in future. + * + * @since 16.0.0 + */ + public function registerConfigHandler(string $placeholder, callable $configHandlerLoader) { + $placeholder = trim(strtolower($placeholder)); + if (!(bool)\preg_match('/^[a-z0-9]*$/', $placeholder)) { + throw new \RuntimeException(sprintf( + 'Invalid placeholder %s, only [a-z0-9] are allowed', $placeholder + )); + } + if ($placeholder === '') { + throw new \RuntimeException('Invalid empty placeholder'); + } + if (isset($this->configHandlerLoaders[$placeholder]) || isset($this->configHandlers[$placeholder])) { + throw new \RuntimeException(sprintf('A handler is already registered for %s', $placeholder)); + } + $this->configHandlerLoaders[$placeholder] = $configHandlerLoader; + } + + protected function loadConfigHandlers():void { + $this->callForRegistrations(); + $newLoaded = false; + foreach ($this->configHandlerLoaders as $placeholder => $loader) { + $handler = $loader(); + if (!$handler instanceof IConfigHandler) { + throw new \RuntimeException(sprintf( + 'Handler for %s is not an instance of IConfigHandler', $placeholder + )); + } + $this->configHandlers[$placeholder] = $handler; + $newLoaded = true; + } + $this->configHandlerLoaders = []; + if ($newLoaded) { + // ensure those with longest placeholders come first, + // to avoid substring matches + uksort($this->configHandlers, function ($phA, $phB) { + return strlen($phB) <=> strlen($phA); + }); + } + } + + /** + * @since 16.0.0 + */ + public function getConfigHandlers() { + $this->loadConfigHandlers(); + return $this->configHandlers; + } } |