diff --git a/apps/files_versions/composer/composer/autoload_classmap.php b/apps/files_versions/composer/composer/autoload_classmap.php index 27e68decdcc52..c66020648df81 100644 --- a/apps/files_versions/composer/composer/autoload_classmap.php +++ b/apps/files_versions/composer/composer/autoload_classmap.php @@ -9,6 +9,7 @@ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'OCA\\Files_Versions\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php', 'OCA\\Files_Versions\\BackgroundJob\\ExpireVersions' => $baseDir . '/../lib/BackgroundJob/ExpireVersions.php', + 'OCA\\Files_Versions\\BlockVersioningOperation' => $baseDir . '/../lib/BlockVersioningOperation.php', 'OCA\\Files_Versions\\Capabilities' => $baseDir . '/../lib/Capabilities.php', 'OCA\\Files_Versions\\Command\\CleanUp' => $baseDir . '/../lib/Command/CleanUp.php', 'OCA\\Files_Versions\\Command\\Expire' => $baseDir . '/../lib/Command/Expire.php', @@ -20,10 +21,12 @@ 'OCA\\Files_Versions\\Events\\VersionCreatedEvent' => $baseDir . '/../lib/Events/VersionCreatedEvent.php', 'OCA\\Files_Versions\\Events\\VersionRestoredEvent' => $baseDir . '/../lib/Events/VersionRestoredEvent.php', 'OCA\\Files_Versions\\Expiration' => $baseDir . '/../lib/Expiration.php', + 'OCA\\Files_Versions\\Listener\\CreateVersionListenerForWorkflow' => $baseDir . '/../lib/Listener/CreateVersionListenerForWorkflow.php', 'OCA\\Files_Versions\\Listener\\FileEventsListener' => $baseDir . '/../lib/Listener/FileEventsListener.php', 'OCA\\Files_Versions\\Listener\\LegacyRollbackListener' => $baseDir . '/../lib/Listener/LegacyRollbackListener.php', 'OCA\\Files_Versions\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php', 'OCA\\Files_Versions\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files_Versions\\Listener\\RegisterWorkflowIntegrationListener' => $baseDir . '/../lib/Listener/RegisterWorkflowIntegrationListener.php', 'OCA\\Files_Versions\\Listener\\VersionAuthorListener' => $baseDir . '/../lib/Listener/VersionAuthorListener.php', 'OCA\\Files_Versions\\Listener\\VersionStorageMoveListener' => $baseDir . '/../lib/Listener/VersionStorageMoveListener.php', 'OCA\\Files_Versions\\Migration\\Version1020Date20221114144058' => $baseDir . '/../lib/Migration/Version1020Date20221114144058.php', diff --git a/apps/files_versions/composer/composer/autoload_static.php b/apps/files_versions/composer/composer/autoload_static.php index 060c062c9f6cc..0d2673c4fcf8d 100644 --- a/apps/files_versions/composer/composer/autoload_static.php +++ b/apps/files_versions/composer/composer/autoload_static.php @@ -24,6 +24,7 @@ class ComposerStaticInitFiles_Versions 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'OCA\\Files_Versions\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php', 'OCA\\Files_Versions\\BackgroundJob\\ExpireVersions' => __DIR__ . '/..' . '/../lib/BackgroundJob/ExpireVersions.php', + 'OCA\\Files_Versions\\BlockVersioningOperation' => __DIR__ . '/..' . '/../lib/BlockVersioningOperation.php', 'OCA\\Files_Versions\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php', 'OCA\\Files_Versions\\Command\\CleanUp' => __DIR__ . '/..' . '/../lib/Command/CleanUp.php', 'OCA\\Files_Versions\\Command\\Expire' => __DIR__ . '/..' . '/../lib/Command/Expire.php', @@ -35,10 +36,12 @@ class ComposerStaticInitFiles_Versions 'OCA\\Files_Versions\\Events\\VersionCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/VersionCreatedEvent.php', 'OCA\\Files_Versions\\Events\\VersionRestoredEvent' => __DIR__ . '/..' . '/../lib/Events/VersionRestoredEvent.php', 'OCA\\Files_Versions\\Expiration' => __DIR__ . '/..' . '/../lib/Expiration.php', + 'OCA\\Files_Versions\\Listener\\CreateVersionListenerForWorkflow' => __DIR__ . '/..' . '/../lib/Listener/CreateVersionListenerForWorkflow.php', 'OCA\\Files_Versions\\Listener\\FileEventsListener' => __DIR__ . '/..' . '/../lib/Listener/FileEventsListener.php', 'OCA\\Files_Versions\\Listener\\LegacyRollbackListener' => __DIR__ . '/..' . '/../lib/Listener/LegacyRollbackListener.php', 'OCA\\Files_Versions\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php', 'OCA\\Files_Versions\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files_Versions\\Listener\\RegisterWorkflowIntegrationListener' => __DIR__ . '/..' . '/../lib/Listener/RegisterWorkflowIntegrationListener.php', 'OCA\\Files_Versions\\Listener\\VersionAuthorListener' => __DIR__ . '/..' . '/../lib/Listener/VersionAuthorListener.php', 'OCA\\Files_Versions\\Listener\\VersionStorageMoveListener' => __DIR__ . '/..' . '/../lib/Listener/VersionStorageMoveListener.php', 'OCA\\Files_Versions\\Migration\\Version1020Date20221114144058' => __DIR__ . '/..' . '/../lib/Migration/Version1020Date20221114144058.php', diff --git a/apps/files_versions/lib/AppInfo/Application.php b/apps/files_versions/lib/AppInfo/Application.php index 6d1aa6c21baf3..3f76d27ae5644 100644 --- a/apps/files_versions/lib/AppInfo/Application.php +++ b/apps/files_versions/lib/AppInfo/Application.php @@ -11,11 +11,14 @@ use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSidebar; use OCA\Files_Versions\Capabilities; +use OCA\Files_Versions\Events\CreateVersionEvent; use OCA\Files_Versions\Events\VersionRestoredEvent; +use OCA\Files_Versions\Listener\CreateVersionListenerForWorkflow; use OCA\Files_Versions\Listener\FileEventsListener; use OCA\Files_Versions\Listener\LegacyRollbackListener; use OCA\Files_Versions\Listener\LoadAdditionalListener; use OCA\Files_Versions\Listener\LoadSidebarListener; +use OCA\Files_Versions\Listener\RegisterWorkflowIntegrationListener; use OCA\Files_Versions\Listener\VersionAuthorListener; use OCA\Files_Versions\Listener\VersionStorageMoveListener; use OCA\Files_Versions\Versions\IVersionManager; @@ -36,6 +39,8 @@ use OCP\Files\Events\Node\NodeRenamedEvent; use OCP\Files\Events\Node\NodeTouchedEvent; use OCP\Files\Events\Node\NodeWrittenEvent; +use OCP\WorkflowEngine\Events\LoadSettingsScriptsEvent; +use OCP\WorkflowEngine\Events\RegisterOperationsEvent; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -85,8 +90,12 @@ public function register(IRegistrationContext $context): void { // we add the version author listener with lower priority to make sure new versions already are created by FileEventsListener $context->registerEventListener(NodeWrittenEvent::class, VersionAuthorListener::class, -1); - $context->registerEventListener(VersionRestoredEvent::class, LegacyRollbackListener::class); + + // WFE integration + $context->registerEventListener(RegisterOperationsEvent::class, RegisterWorkflowIntegrationListener::class); + $context->registerEventListener(LoadSettingsScriptsEvent::class, RegisterWorkflowIntegrationListener::class); + $context->registerEventListener(CreateVersionEvent::class, CreateVersionListenerForWorkflow::class); } #[\Override] diff --git a/apps/files_versions/lib/BlockVersioningOperation.php b/apps/files_versions/lib/BlockVersioningOperation.php new file mode 100644 index 0000000000000..42016403eb2ea --- /dev/null +++ b/apps/files_versions/lib/BlockVersioningOperation.php @@ -0,0 +1,95 @@ +l10n->t('Block versioning'); + } + + #[\Override] + public function getDescription(): string { + return $this->l10n->t('Automatic tag based blocking of files version creation.'); + } + + #[\Override] + public function getIcon(): string { + return $this->urlGenerator->imagePath('files_versions', 'app.svg'); + } + + #[\Override] + public function isAvailableForScope(int $scope): bool { + return $scope === IManager::SCOPE_ADMIN; + } + + #[\Override] + public function validateOperation(string $name, array $checks, string $operation): void { + if (empty($checks)) { + throw new \UnexpectedValueException($this->l10n->t('No rule given')); + } + } + + #[\Override] + public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatcher): void { + if ($eventName !== CreateVersionEvent::class || !($event instanceof CreateVersionEvent)) { + return; + } + + $node = $event->getNode(); + $path = $node->getInternalPath(); + + $ruleMatcher->setFileInfo( + $node->getStorage(), + $path, + $node instanceof Folder, + ); + $ruleMatcher->setEntitySubject($this->fileEntity, $node); + $ruleMatcher->setOperation($this); + $flows = $ruleMatcher->getFlows(); + + if ($flows !== []) { + $this->logger->debug('Blocking version creation due to matching workflow rules', [ + 'path' => $path, + ]); + $event->disableVersions(); + } + } + + #[\Override] + public function getTriggerHint(): string { + return $this->l10n->t('A new version is created'); // TRANSLATORS: This will be shown as "When: " "A new version is created" + } +} diff --git a/apps/files_versions/lib/Listener/CreateVersionListenerForWorkflow.php b/apps/files_versions/lib/Listener/CreateVersionListenerForWorkflow.php new file mode 100644 index 0000000000000..66a4105ecac5a --- /dev/null +++ b/apps/files_versions/lib/Listener/CreateVersionListenerForWorkflow.php @@ -0,0 +1,37 @@ + */ +class CreateVersionListenerForWorkflow implements IEventListener { + + public function __construct( + private IManager $manager, + private BlockVersioningOperation $operation, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof CreateVersionEvent)) { + return; + } + + $this->operation->onEvent( + $event::class, + $event, + $this->manager->getRuleMatcher(), + ); + } +} diff --git a/apps/files_versions/lib/Listener/RegisterWorkflowIntegrationListener.php b/apps/files_versions/lib/Listener/RegisterWorkflowIntegrationListener.php new file mode 100644 index 0000000000000..8da2b2e05c228 --- /dev/null +++ b/apps/files_versions/lib/Listener/RegisterWorkflowIntegrationListener.php @@ -0,0 +1,33 @@ + */ +class RegisterWorkflowIntegrationListener implements IEventListener { + + public function __construct( + private readonly BlockVersioningOperation $operation, + ) { + } + + public function handle(Event $event): void { + if ($event instanceof RegisterOperationsEvent) { + $event->registerOperation($this->operation); + } elseif ($event instanceof LoadSettingsScriptsEvent) { + Util::addScript('files_versions', 'workflow', 'workflowengine'); + } + } +} diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php index fe9f91534fa01..eaa242e98e138 100644 --- a/apps/files_versions/lib/Storage.php +++ b/apps/files_versions/lib/Storage.php @@ -205,6 +205,7 @@ public static function store($filename) { } $event = new CreateVersionEvent($file); + $eventDispatcher->dispatchTyped($event); $eventDispatcher->dispatch('OCA\Files_Versions::createVersion', $event); if ($event->shouldCreateVersion() === false) { return false; diff --git a/apps/files_versions/src/workflow.ts b/apps/files_versions/src/workflow.ts new file mode 100644 index 0000000000000..f3ffe6b6c8c08 --- /dev/null +++ b/apps/files_versions/src/workflow.ts @@ -0,0 +1,12 @@ +/*! + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +window.addEventListener('DOMContentLoaded', () => { + globalThis.OCA.WorkflowEngine.registerOperator({ + id: 'OCA\\Files_Versions\\BlockVersioningOperation', + color: '#ff5900', + operation: 'deny', + }) +}) diff --git a/build/frontend/vite.config.ts b/build/frontend/vite.config.ts index 0e0a924b8a231..c07ff0359b7c1 100644 --- a/build/frontend/vite.config.ts +++ b/build/frontend/vite.config.ts @@ -48,6 +48,7 @@ const modules = { }, files_versions: { 'sidebar-tab': resolve(import.meta.dirname, 'apps/files_versions/src', 'sidebar_tab.ts'), + workflow: resolve(import.meta.dirname, 'apps/files_versions/src', 'workflow.ts'), }, oauth2: { 'settings-admin': resolve(import.meta.dirname, 'apps/oauth2/src', 'settings-admin.ts'),