From 74aac75fc53040f4c9bee2ef3cf0ac1c5df747ea Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 16 Jul 2024 12:39:29 +0200 Subject: [PATCH] feat(files): Allow to configure Windows filename compatibility in the settings This adds an admin setting to toggle Windows filename compatibility. Signed-off-by: Ferdinand Thiessen --- apps/files/appinfo/info.xml | 8 +-- .../composer/composer/autoload_classmap.php | 4 ++ .../composer/composer/autoload_static.php | 4 ++ apps/files/lib/AppInfo/Application.php | 9 +++ ...clarativeSettingsGetValueEventListener.php | 39 ++++++++++++ ...ativeSettingsRegisterFormEventListener.php | 50 +++++++++++++++ ...clarativeSettingsSetValueEventListener.php | 40 ++++++++++++ apps/files/lib/Service/SettingsService.php | 63 +++++++++++++++++++ apps/files/lib/Settings/PersonalSettings.php | 1 + apps/files/templates/settings-personal.php | 3 - 10 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php create mode 100644 apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php create mode 100644 apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php create mode 100644 apps/files/lib/Service/SettingsService.php diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml index 4a920b499cea1..f3da2057f6523 100644 --- a/apps/files/appinfo/info.xml +++ b/apps/files/appinfo/info.xml @@ -51,6 +51,10 @@ OCA\Files\Command\Object\Put + + OCA\Files\Settings\PersonalSettings + + OCA\Files\Activity\Settings\FavoriteAction @@ -77,8 +81,4 @@ - - OCA\Files\Settings\PersonalSettings - - diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index f7880847ac0f7..68cdabb3dcdab 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -58,6 +58,9 @@ 'OCA\\Files\\Event\\LoadSidebar' => $baseDir . '/../lib/Event/LoadSidebar.php', 'OCA\\Files\\Exception\\TransferOwnershipException' => $baseDir . '/../lib/Exception/TransferOwnershipException.php', 'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php', + 'OCA\\Files\\Listener\\DeclarativeSettingsGetValueEventListener' => $baseDir . '/../lib/Listener/DeclarativeSettingsGetValueEventListener.php', + 'OCA\\Files\\Listener\\DeclarativeSettingsRegisterFormEventListener' => $baseDir . '/../lib/Listener/DeclarativeSettingsRegisterFormEventListener.php', + 'OCA\\Files\\Listener\\DeclarativeSettingsSetValueEventListener' => $baseDir . '/../lib/Listener/DeclarativeSettingsSetValueEventListener.php', 'OCA\\Files\\Listener\\LoadSearchPluginsListener' => $baseDir . '/../lib/Listener/LoadSearchPluginsListener.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', 'OCA\\Files\\Listener\\RenderReferenceEventListener' => $baseDir . '/../lib/Listener/RenderReferenceEventListener.php', @@ -70,6 +73,7 @@ 'OCA\\Files\\Service\\DirectEditingService' => $baseDir . '/../lib/Service/DirectEditingService.php', 'OCA\\Files\\Service\\LivePhotosService' => $baseDir . '/../lib/Service/LivePhotosService.php', 'OCA\\Files\\Service\\OwnershipTransferService' => $baseDir . '/../lib/Service/OwnershipTransferService.php', + 'OCA\\Files\\Service\\SettingsService' => $baseDir . '/../lib/Service/SettingsService.php', 'OCA\\Files\\Service\\TagService' => $baseDir . '/../lib/Service/TagService.php', 'OCA\\Files\\Service\\UserConfig' => $baseDir . '/../lib/Service/UserConfig.php', 'OCA\\Files\\Service\\ViewConfig' => $baseDir . '/../lib/Service/ViewConfig.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 9ba311f277652..ca88e773e4aa5 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -73,6 +73,9 @@ class ComposerStaticInitFiles 'OCA\\Files\\Event\\LoadSidebar' => __DIR__ . '/..' . '/../lib/Event/LoadSidebar.php', 'OCA\\Files\\Exception\\TransferOwnershipException' => __DIR__ . '/..' . '/../lib/Exception/TransferOwnershipException.php', 'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php', + 'OCA\\Files\\Listener\\DeclarativeSettingsGetValueEventListener' => __DIR__ . '/..' . '/../lib/Listener/DeclarativeSettingsGetValueEventListener.php', + 'OCA\\Files\\Listener\\DeclarativeSettingsRegisterFormEventListener' => __DIR__ . '/..' . '/../lib/Listener/DeclarativeSettingsRegisterFormEventListener.php', + 'OCA\\Files\\Listener\\DeclarativeSettingsSetValueEventListener' => __DIR__ . '/..' . '/../lib/Listener/DeclarativeSettingsSetValueEventListener.php', 'OCA\\Files\\Listener\\LoadSearchPluginsListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSearchPluginsListener.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', 'OCA\\Files\\Listener\\RenderReferenceEventListener' => __DIR__ . '/..' . '/../lib/Listener/RenderReferenceEventListener.php', @@ -85,6 +88,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\Service\\DirectEditingService' => __DIR__ . '/..' . '/../lib/Service/DirectEditingService.php', 'OCA\\Files\\Service\\LivePhotosService' => __DIR__ . '/..' . '/../lib/Service/LivePhotosService.php', 'OCA\\Files\\Service\\OwnershipTransferService' => __DIR__ . '/..' . '/../lib/Service/OwnershipTransferService.php', + 'OCA\\Files\\Service\\SettingsService' => __DIR__ . '/..' . '/../lib/Service/SettingsService.php', 'OCA\\Files\\Service\\TagService' => __DIR__ . '/..' . '/../lib/Service/TagService.php', 'OCA\\Files\\Service\\UserConfig' => __DIR__ . '/..' . '/../lib/Service/UserConfig.php', 'OCA\\Files\\Service\\ViewConfig' => __DIR__ . '/..' . '/../lib/Service/ViewConfig.php', diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 5f57b2e2f34ba..b4fd04c9fbc7f 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -17,6 +17,9 @@ use OCA\Files\DirectEditingCapabilities; use OCA\Files\Event\LoadSearchPlugins; use OCA\Files\Event\LoadSidebar; +use OCA\Files\Listener\DeclarativeSettingsGetValueEventListener; +use OCA\Files\Listener\DeclarativeSettingsRegisterFormEventListener; +use OCA\Files\Listener\DeclarativeSettingsSetValueEventListener; use OCA\Files\Listener\LoadSearchPluginsListener; use OCA\Files\Listener\LoadSidebarListener; use OCA\Files\Listener\RenderReferenceEventListener; @@ -46,6 +49,9 @@ use OCP\IServerContainer; use OCP\ITagManager; use OCP\IUserSession; +use OCP\Settings\Events\DeclarativeSettingsGetValueEvent; +use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent; +use OCP\Settings\Events\DeclarativeSettingsSetValueEvent; use OCP\Share\IManager as IShareManager; use OCP\Util; use Psr\Container\ContainerInterface; @@ -109,6 +115,9 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(BeforeNodeCopiedEvent::class, SyncLivePhotosListener::class); $context->registerEventListener(NodeCopiedEvent::class, SyncLivePhotosListener::class); $context->registerEventListener(LoadSearchPlugins::class, LoadSearchPluginsListener::class); + $context->registerEventListener(DeclarativeSettingsRegisterFormEvent::class, DeclarativeSettingsRegisterFormEventListener::class); + $context->registerEventListener(DeclarativeSettingsGetValueEvent::class, DeclarativeSettingsGetValueEventListener::class); + $context->registerEventListener(DeclarativeSettingsSetValueEvent::class, DeclarativeSettingsSetValueEventListener::class); $context->registerSearchProvider(FilesSearchProvider::class); diff --git a/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php b/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php new file mode 100644 index 0000000000000..1af360e078adf --- /dev/null +++ b/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php @@ -0,0 +1,39 @@ + */ +class DeclarativeSettingsGetValueEventListener implements IEventListener { + + public function __construct( + private SettingsService $service, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof DeclarativeSettingsGetValueEvent)) { + return; + } + + if ($event->getApp() !== Application::APP_ID) { + return; + } + + $event->setValue( + match($event->getFieldId()) { + 'windows_support' => $this->service->hasFilesWindowsSupport(), + } + ); + } +} diff --git a/apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php b/apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php new file mode 100644 index 0000000000000..51832e89ecbfe --- /dev/null +++ b/apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php @@ -0,0 +1,50 @@ + */ +class DeclarativeSettingsRegisterFormEventListener implements IEventListener { + + public function __construct( + private IL10N $l, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof DeclarativeSettingsRegisterFormEvent)) { + return; + } + + $event->registerSchema(Application::APP_ID, [ + 'id' => 'files-filename-support', + 'priority' => 10, + 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN, + 'section_id' => 'server', + 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL, + 'title' => $this->l->t('Files compatibility'), + 'description' => $this->l->t('Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed.'), + + 'fields' => [ + [ + 'id' => 'windows_support', + 'title' => $this->l->t('Enforce Windows compatibility'), + 'description' => $this->l->t('This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity.'), + 'type' => DeclarativeSettingsTypes::CHECKBOX, + 'default' => false, + ], + ], + ]); + } +} diff --git a/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php b/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php new file mode 100644 index 0000000000000..43d01563c265f --- /dev/null +++ b/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php @@ -0,0 +1,40 @@ + */ +class DeclarativeSettingsSetValueEventListener implements IEventListener { + + public function __construct( + private SettingsService $service, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof DeclarativeSettingsSetValueEvent)) { + return; + } + + if ($event->getApp() !== Application::APP_ID) { + return; + } + + switch ($event->getFieldId()) { + case 'windows_support': + $this->service->setFilesWindowsSupport((bool) $event->getValue()); + $event->stopPropagation(); + break; + } + } +} diff --git a/apps/files/lib/Service/SettingsService.php b/apps/files/lib/Service/SettingsService.php new file mode 100644 index 0000000000000..d07e907a5f690 --- /dev/null +++ b/apps/files/lib/Service/SettingsService.php @@ -0,0 +1,63 @@ +', ':', + '"', '|', '?', + '*', + ]; + + public function __construct( + private IConfig $config, + private FilenameValidator $filenameValidator, + private LoggerInterface $logger, + ) { + } + + public function hasFilesWindowsSupport(): bool { + return empty(array_diff(self::WINDOWS_BASENAMES, $this->filenameValidator->getForbiddenBasenames())) + && empty(array_diff(self::WINDOWS_CHARACTERS, $this->filenameValidator->getForbiddenCharacters())) + && empty(array_diff(self::WINDOWS_EXTENSION, $this->filenameValidator->getForbiddenExtensions())); + } + + public function setFilesWindowsSupport(bool $enabled = true): void { + if ($enabled) { + $basenames = array_unique(array_merge(self::WINDOWS_BASENAMES, $this->filenameValidator->getForbiddenBasenames())); + $characters = array_unique(array_merge(self::WINDOWS_CHARACTERS, $this->filenameValidator->getForbiddenCharacters())); + $extensions = array_unique(array_merge(self::WINDOWS_EXTENSION, $this->filenameValidator->getForbiddenExtensions())); + } else { + $basenames = array_unique(array_values(array_diff($this->filenameValidator->getForbiddenBasenames(), self::WINDOWS_BASENAMES))); + $characters = array_unique(array_values(array_diff($this->filenameValidator->getForbiddenCharacters(), self::WINDOWS_CHARACTERS))); + $extensions = array_unique(array_values(array_diff($this->filenameValidator->getForbiddenExtensions(), self::WINDOWS_EXTENSION))); + } + $values = [ + 'forbidden_filename_basenames' => empty($basenames) ? null : $basenames, + 'forbidden_filename_characters' => empty($characters) ? null : $characters, + 'forbidden_filename_extensions' => empty($extensions) ? null : $extensions, + ]; + $this->config->setSystemValues($values); + } +} diff --git a/apps/files/lib/Settings/PersonalSettings.php b/apps/files/lib/Settings/PersonalSettings.php index c70a7171c9415..484e4bde2b821 100644 --- a/apps/files/lib/Settings/PersonalSettings.php +++ b/apps/files/lib/Settings/PersonalSettings.php @@ -14,6 +14,7 @@ class PersonalSettings implements ISettings { public function getForm(): TemplateResponse { + \OCP\Util::addScript(Application::APP_ID, 'settings-personal'); return new TemplateResponse(Application::APP_ID, 'settings-personal'); } diff --git a/apps/files/templates/settings-personal.php b/apps/files/templates/settings-personal.php index 06ea218f3b00d..0ca3846d699c2 100644 --- a/apps/files/templates/settings-personal.php +++ b/apps/files/templates/settings-personal.php @@ -4,9 +4,6 @@ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ - -script(\OCA\Files\AppInfo\Application::APP_ID, 'personal-settings'); - ?>