feat(files_external): support lexicon

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
pull/52621/head
Maxence Lange 2025-05-05 17:05:10 +07:00
parent 2a1e63be14
commit 6bd5f6af83
7 changed files with 74 additions and 33 deletions

@ -22,6 +22,7 @@ return array(
'OCA\\Files_External\\Command\\Scan' => $baseDir . '/../lib/Command/Scan.php', 'OCA\\Files_External\\Command\\Scan' => $baseDir . '/../lib/Command/Scan.php',
'OCA\\Files_External\\Command\\StorageAuthBase' => $baseDir . '/../lib/Command/StorageAuthBase.php', 'OCA\\Files_External\\Command\\StorageAuthBase' => $baseDir . '/../lib/Command/StorageAuthBase.php',
'OCA\\Files_External\\Command\\Verify' => $baseDir . '/../lib/Command/Verify.php', 'OCA\\Files_External\\Command\\Verify' => $baseDir . '/../lib/Command/Verify.php',
'OCA\\Files_External\\ConfigLexicon' => $baseDir . '/../lib/ConfigLexicon.php',
'OCA\\Files_External\\Config\\ConfigAdapter' => $baseDir . '/../lib/Config/ConfigAdapter.php', 'OCA\\Files_External\\Config\\ConfigAdapter' => $baseDir . '/../lib/Config/ConfigAdapter.php',
'OCA\\Files_External\\Config\\ExternalMountPoint' => $baseDir . '/../lib/Config/ExternalMountPoint.php', 'OCA\\Files_External\\Config\\ExternalMountPoint' => $baseDir . '/../lib/Config/ExternalMountPoint.php',
'OCA\\Files_External\\Config\\IConfigHandler' => $baseDir . '/../lib/Config/IConfigHandler.php', 'OCA\\Files_External\\Config\\IConfigHandler' => $baseDir . '/../lib/Config/IConfigHandler.php',

@ -37,6 +37,7 @@ class ComposerStaticInitFiles_External
'OCA\\Files_External\\Command\\Scan' => __DIR__ . '/..' . '/../lib/Command/Scan.php', 'OCA\\Files_External\\Command\\Scan' => __DIR__ . '/..' . '/../lib/Command/Scan.php',
'OCA\\Files_External\\Command\\StorageAuthBase' => __DIR__ . '/..' . '/../lib/Command/StorageAuthBase.php', 'OCA\\Files_External\\Command\\StorageAuthBase' => __DIR__ . '/..' . '/../lib/Command/StorageAuthBase.php',
'OCA\\Files_External\\Command\\Verify' => __DIR__ . '/..' . '/../lib/Command/Verify.php', 'OCA\\Files_External\\Command\\Verify' => __DIR__ . '/..' . '/../lib/Command/Verify.php',
'OCA\\Files_External\\ConfigLexicon' => __DIR__ . '/..' . '/../lib/ConfigLexicon.php',
'OCA\\Files_External\\Config\\ConfigAdapter' => __DIR__ . '/..' . '/../lib/Config/ConfigAdapter.php', 'OCA\\Files_External\\Config\\ConfigAdapter' => __DIR__ . '/..' . '/../lib/Config/ConfigAdapter.php',
'OCA\\Files_External\\Config\\ExternalMountPoint' => __DIR__ . '/..' . '/../lib/Config/ExternalMountPoint.php', 'OCA\\Files_External\\Config\\ExternalMountPoint' => __DIR__ . '/..' . '/../lib/Config/ExternalMountPoint.php',
'OCA\\Files_External\\Config\\IConfigHandler' => __DIR__ . '/..' . '/../lib/Config/IConfigHandler.php', 'OCA\\Files_External\\Config\\IConfigHandler' => __DIR__ . '/..' . '/../lib/Config/IConfigHandler.php',

@ -9,6 +9,7 @@ namespace OCA\Files_External\AppInfo;
use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files_External\Config\ConfigAdapter; use OCA\Files_External\Config\ConfigAdapter;
use OCA\Files_External\Config\UserPlaceholderHandler; use OCA\Files_External\Config\UserPlaceholderHandler;
use OCA\Files_External\ConfigLexicon;
use OCA\Files_External\Lib\Auth\AmazonS3\AccessKey; use OCA\Files_External\Lib\Auth\AmazonS3\AccessKey;
use OCA\Files_External\Lib\Auth\Builtin; use OCA\Files_External\Lib\Auth\Builtin;
use OCA\Files_External\Lib\Auth\NullMechanism; use OCA\Files_External\Lib\Auth\NullMechanism;
@ -73,6 +74,7 @@ class Application extends App implements IBackendProvider, IAuthMechanismProvide
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class); $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
$context->registerEventListener(GroupDeletedEvent::class, GroupDeletedListener::class); $context->registerEventListener(GroupDeletedEvent::class, GroupDeletedListener::class);
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class); $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
$context->registerConfigLexicon(ConfigLexicon::class);
} }
public function boot(IBootContext $context): void { public function boot(IBootContext $context): void {

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Files_External;
use NCU\Config\Lexicon\ConfigLexiconEntry;
use NCU\Config\Lexicon\ConfigLexiconStrictness;
use NCU\Config\Lexicon\IConfigLexicon;
use NCU\Config\ValueType;
/**
* Config Lexicon for files_sharing.
*
* Please Add & Manage your Config Keys in that file and keep the Lexicon up to date!
*
* {@see IConfigLexicon}
*/
class ConfigLexicon implements IConfigLexicon {
public const ALLOW_USER_MOUNTING = 'allow_user_mounting';
public const USER_MOUNTING_BACKENDS = 'user_mounting_backends';
public function getStrictness(): ConfigLexiconStrictness {
return ConfigLexiconStrictness::NOTICE;
}
public function getAppConfigs(): array {
return [
new ConfigLexiconEntry(self::ALLOW_USER_MOUNTING, ValueType::BOOL, false, 'allow users to mount their own external filesystems', true),
new ConfigLexiconEntry(self::USER_MOUNTING_BACKENDS, ValueType::STRING, '', 'list of mounting backends available for users', true),
];
}
public function getUserConfigs(): array {
return [];
}
}

@ -10,10 +10,11 @@ namespace OCA\Files_External\Listener;
use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files_External\AppInfo\Application; use OCA\Files_External\AppInfo\Application;
use OCA\Files_External\ConfigLexicon;
use OCP\AppFramework\Services\IInitialState; use OCP\AppFramework\Services\IInitialState;
use OCP\EventDispatcher\Event; use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener; use OCP\EventDispatcher\IEventListener;
use OCP\IConfig; use OCP\IAppConfig;
use OCP\Util; use OCP\Util;
/** /**
@ -22,7 +23,7 @@ use OCP\Util;
class LoadAdditionalListener implements IEventListener { class LoadAdditionalListener implements IEventListener {
public function __construct( public function __construct(
private IConfig $config, private readonly IAppConfig $appConfig,
private IInitialState $initialState, private IInitialState $initialState,
) { ) {
} }
@ -32,7 +33,7 @@ class LoadAdditionalListener implements IEventListener {
return; return;
} }
$allowUserMounting = $this->config->getAppValue('files_external', 'allow_user_mounting', 'no') === 'yes'; $allowUserMounting = $this->appConfig->getValueBool('files_external', ConfigLexicon::ALLOW_USER_MOUNTING);
$this->initialState->provideInitialState('allowUserMounting', $allowUserMounting); $this->initialState->provideInitialState('allowUserMounting', $allowUserMounting);
Util::addInitScript(Application::APP_ID, 'init'); Util::addInitScript(Application::APP_ID, 'init');

@ -7,14 +7,14 @@
namespace OCA\Files_External\Service; namespace OCA\Files_External\Service;
use OCA\Files_External\Config\IConfigHandler; use OCA\Files_External\Config\IConfigHandler;
use OCA\Files_External\ConfigLexicon;
use OCA\Files_External\Lib\Auth\AuthMechanism; use OCA\Files_External\Lib\Auth\AuthMechanism;
use OCA\Files_External\Lib\Backend\Backend; use OCA\Files_External\Lib\Backend\Backend;
use OCA\Files_External\Lib\Config\IAuthMechanismProvider; use OCA\Files_External\Lib\Config\IAuthMechanismProvider;
use OCA\Files_External\Lib\Config\IBackendProvider; use OCA\Files_External\Lib\Config\IBackendProvider;
use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\GenericEvent;
use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig; use OCP\IAppConfig;
use OCP\Server; use OCP\Server;
/** /**
@ -56,19 +56,12 @@ class BackendService {
private $configHandlers = []; private $configHandlers = [];
/**
* @param IConfig $config
*/
public function __construct( public function __construct(
protected IConfig $config, protected IAppConfig $appConfig,
) { ) {
// Load config values // Load config values
if ($this->config->getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') { $this->userMountingAllowed = $appConfig->getValueBool('files_external', ConfigLexicon::ALLOW_USER_MOUNTING);
$this->userMountingAllowed = false; $this->userMountingBackends = explode(',', $appConfig->getValueString('files_external', ConfigLexicon::USER_MOUNTING_BACKENDS));
}
$this->userMountingBackends = explode(',',
$this->config->getAppValue('files_external', 'user_mounting_backends', '')
);
// if no backend is in the list an empty string is in the array and user mounting is disabled // if no backend is in the list an empty string is in the array and user mounting is disabled
if ($this->userMountingBackends === ['']) { if ($this->userMountingBackends === ['']) {

@ -12,15 +12,15 @@ use OCA\Files_External\Lib\Backend\Backend;
use OCA\Files_External\Lib\Config\IAuthMechanismProvider; use OCA\Files_External\Lib\Config\IAuthMechanismProvider;
use OCA\Files_External\Lib\Config\IBackendProvider; use OCA\Files_External\Lib\Config\IBackendProvider;
use OCA\Files_External\Service\BackendService; use OCA\Files_External\Service\BackendService;
use OCP\IConfig; use OCP\IAppConfig;
class BackendServiceTest extends \Test\TestCase { class BackendServiceTest extends \Test\TestCase {
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ /** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */
protected $config; protected $appConfig;
protected function setUp(): void { protected function setUp(): void {
$this->config = $this->createMock(IConfig::class); $this->appConfig = $this->createMock(IAppConfig::class);
} }
/** /**
@ -52,7 +52,7 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testRegisterBackend(): void { public function testRegisterBackend(): void {
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$backend = $this->getBackendMock('\Foo\Bar'); $backend = $this->getBackendMock('\Foo\Bar');
@ -80,7 +80,7 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testBackendProvider(): void { public function testBackendProvider(): void {
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$backend1 = $this->getBackendMock('\Foo\Bar'); $backend1 = $this->getBackendMock('\Foo\Bar');
$backend2 = $this->getBackendMock('\Bar\Foo'); $backend2 = $this->getBackendMock('\Bar\Foo');
@ -99,7 +99,7 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testAuthMechanismProvider(): void { public function testAuthMechanismProvider(): void {
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$backend1 = $this->getAuthMechanismMock('\Foo\Bar'); $backend1 = $this->getAuthMechanismMock('\Foo\Bar');
$backend2 = $this->getAuthMechanismMock('\Bar\Foo'); $backend2 = $this->getAuthMechanismMock('\Bar\Foo');
@ -118,7 +118,7 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testMultipleBackendProviders(): void { public function testMultipleBackendProviders(): void {
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$backend1a = $this->getBackendMock('\Foo\Bar'); $backend1a = $this->getBackendMock('\Foo\Bar');
$backend1b = $this->getBackendMock('\Bar\Foo'); $backend1b = $this->getBackendMock('\Bar\Foo');
@ -146,14 +146,16 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testUserMountingBackends(): void { public function testUserMountingBackends(): void {
$this->config->expects($this->exactly(2)) $this->appConfig->expects($this->once())
->method('getAppValue') ->method('getValueString')
->willReturnMap([ ->with('files_external', 'user_mounting_backends')
['files_external', 'allow_user_mounting', 'yes', 'yes'], ->willReturn('identifier:\User\Mount\Allowed,identifier_alias');
['files_external', 'user_mounting_backends', '', 'identifier:\User\Mount\Allowed,identifier_alias'] $this->appConfig->expects($this->once())
]); ->method('getValueBool')
->with('files_external', 'allow_user_mounting')
->willReturn(true);
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$backendAllowed = $this->getBackendMock('\User\Mount\Allowed'); $backendAllowed = $this->getBackendMock('\User\Mount\Allowed');
$backendAllowed->expects($this->never()) $backendAllowed->expects($this->never())
@ -177,7 +179,7 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testGetAvailableBackends(): void { public function testGetAvailableBackends(): void {
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$backendAvailable = $this->getBackendMock('\Backend\Available'); $backendAvailable = $this->getBackendMock('\Backend\Available');
$backendAvailable->expects($this->once()) $backendAvailable->expects($this->once())
@ -220,7 +222,7 @@ class BackendServiceTest extends \Test\TestCase {
public function testRegisterConfigHandlerInvalid(array $placeholders): void { public function testRegisterConfigHandlerInvalid(array $placeholders): void {
$this->expectException(\RuntimeException::class); $this->expectException(\RuntimeException::class);
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$mock = $this->createMock(IConfigHandler::class); $mock = $this->createMock(IConfigHandler::class);
$cb = function () use ($mock) { $cb = function () use ($mock) {
return $mock; return $mock;
@ -231,7 +233,7 @@ class BackendServiceTest extends \Test\TestCase {
} }
public function testConfigHandlers(): void { public function testConfigHandlers(): void {
$service = new BackendService($this->config); $service = new BackendService($this->appConfig);
$mock = $this->createMock(IConfigHandler::class); $mock = $this->createMock(IConfigHandler::class);
$mock->expects($this->exactly(3)) $mock->expects($this->exactly(3))
->method('handle'); ->method('handle');