aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/lib
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-07-16 12:39:29 +0200
committerFerdinand Thiessen <opensource@fthiessen.de>2024-07-17 16:17:14 +0200
commit0936af996013ab07fe845fb852b80b3ab1d536f0 (patch)
tree35af0615e55836c53c149b2884e2cde10d8409b5 /apps/files/lib
parent19ba872e9aae98686ad61acd543f9945d8577797 (diff)
downloadnextcloud-server-0936af996013ab07fe845fb852b80b3ab1d536f0.tar.gz
nextcloud-server-0936af996013ab07fe845fb852b80b3ab1d536f0.zip
feat(files): Allow to configure Windows filename compatibility in the settings
This adds an admin setting to toggle Windows filename compatibility. Co-authored-by: Ferdinand Thiessen <opensource@fthiessen.de> Co-authored-by: Louis <louis@chmn.me> Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/files/lib')
-rw-r--r--apps/files/lib/AppInfo/Application.php9
-rw-r--r--apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php39
-rw-r--r--apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php50
-rw-r--r--apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php40
-rw-r--r--apps/files/lib/Service/SettingsService.php63
-rw-r--r--apps/files/lib/Settings/PersonalSettings.php1
6 files changed, 202 insertions, 0 deletions
diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php
index 5f57b2e2f34..b4fd04c9fbc 100644
--- a/apps/files/lib/AppInfo/Application.php
+++ b/apps/files/lib/AppInfo/Application.php
@@ -17,6 +17,9 @@ use OCA\Files\Controller\ApiController;
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\ISearch;
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 @@ class Application extends App implements IBootstrap {
$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 00000000000..b1d0ee3a395
--- /dev/null
+++ b/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Files\Listener;
+
+use OCA\Files\AppInfo\Application;
+use OCA\Files\Service\SettingsService;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
+
+/** @template-implements IEventListener<DeclarativeSettingsGetValueEvent> */
+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 00000000000..51832e89ecb
--- /dev/null
+++ b/apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Files\Listener;
+
+use OCA\Files\AppInfo\Application;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IL10N;
+use OCP\Settings\DeclarativeSettingsTypes;
+use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
+
+/** @template-implements IEventListener<DeclarativeSettingsRegisterFormEvent> */
+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 00000000000..43d01563c26
--- /dev/null
+++ b/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Files\Listener;
+
+use OCA\Files\AppInfo\Application;
+use OCA\Files\Service\SettingsService;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
+
+/** @template-implements IEventListener<DeclarativeSettingsSetValueEvent> */
+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 00000000000..d07e907a5f6
--- /dev/null
+++ b/apps/files/lib/Service/SettingsService.php
@@ -0,0 +1,63 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Files\Service;
+
+use OC\Files\FilenameValidator;
+use OCP\IConfig;
+use Psr\Log\LoggerInterface;
+
+class SettingsService {
+
+ protected const WINDOWS_EXTENSION = [
+ ' ',
+ '.',
+ ];
+
+ protected const WINDOWS_BASENAMES = [
+ 'con', 'prn', 'aux', 'nul', 'com0', 'com1', 'com2', 'com3', 'com4', 'com5',
+ 'com6', 'com7', 'com8', 'com9', 'com¹', 'com²', 'com³', 'lpt0', 'lpt1', 'lpt2',
+ 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9', 'lpt¹', 'lpt²', 'lpt³',
+ ];
+
+ protected const WINDOWS_CHARACTERS = [
+ '<', '>', ':',
+ '"', '|', '?',
+ '*',
+ ];
+
+ 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 c70a7171c94..484e4bde2b8 100644
--- a/apps/files/lib/Settings/PersonalSettings.php
+++ b/apps/files/lib/Settings/PersonalSettings.php
@@ -14,6 +14,7 @@ use OCP\Settings\ISettings;
class PersonalSettings implements ISettings {
public function getForm(): TemplateResponse {
+ \OCP\Util::addScript(Application::APP_ID, 'settings-personal');
return new TemplateResponse(Application::APP_ID, 'settings-personal');
}