Skip to content

Commit

Permalink
feat(files): Allow to configure Windows filename compatibility in the…
Browse files Browse the repository at this point in the history
… settings

This adds an admin setting to toggle Windows filename compatibility.

Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Jul 17, 2024
1 parent e4368f6 commit 74aac75
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 7 deletions.
8 changes: 4 additions & 4 deletions apps/files/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
<command>OCA\Files\Command\Object\Put</command>
</commands>

<settings>
<personal>OCA\Files\Settings\PersonalSettings</personal>
</settings>

<activity>
<settings>
<setting>OCA\Files\Activity\Settings\FavoriteAction</setting>
Expand All @@ -77,8 +81,4 @@
</navigation>
</navigations>

<settings>
<personal>OCA\Files\Settings\PersonalSettings</personal>
</settings>

</info>
4 changes: 4 additions & 0 deletions apps/files/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down
4 changes: 4 additions & 0 deletions apps/files/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down
9 changes: 9 additions & 0 deletions apps/files/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?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\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(),
}
);
}
}
Original file line number Diff line number Diff line change
@@ -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,
],
],
]);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
63 changes: 63 additions & 0 deletions apps/files/lib/Service/SettingsService.php
Original file line number Diff line number Diff line change
@@ -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);
}
}
1 change: 1 addition & 0 deletions apps/files/lib/Settings/PersonalSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}

Expand Down
3 changes: 0 additions & 3 deletions apps/files/templates/settings-personal.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');

?>
<div id="files-personal-settings" class="section">
</div>

0 comments on commit 74aac75

Please sign in to comment.