Skip to content

Commit 4e816f7

Browse files
susnuxbackportbot[bot]
authored andcommitted
feat(files_versions): allow to block version creation using WFE
This allows users to create workflows to block the versions creation for some files, based on tags or other conditions using the workflow engine. The usecase would be compliance to allow configure some rules to prevent versioning. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 8a960ca commit 4e816f7

8 files changed

Lines changed: 196 additions & 1 deletion

File tree

apps/files_versions/composer/composer/autoload_classmap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
'OCA\\Files_Versions\\Events\\VersionCreatedEvent' => $baseDir . '/../lib/Events/VersionCreatedEvent.php',
2121
'OCA\\Files_Versions\\Events\\VersionRestoredEvent' => $baseDir . '/../lib/Events/VersionRestoredEvent.php',
2222
'OCA\\Files_Versions\\Expiration' => $baseDir . '/../lib/Expiration.php',
23+
'OCA\\Files_Versions\\Listener\\CreateVersionListenerForWorkflow' => $baseDir . '/../lib/Listener/CreateVersionListenerForWorkflow.php',
2324
'OCA\\Files_Versions\\Listener\\FileEventsListener' => $baseDir . '/../lib/Listener/FileEventsListener.php',
2425
'OCA\\Files_Versions\\Listener\\LegacyRollbackListener' => $baseDir . '/../lib/Listener/LegacyRollbackListener.php',
2526
'OCA\\Files_Versions\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php',
2627
'OCA\\Files_Versions\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php',
28+
'OCA\\Files_Versions\\Listener\\RegisterWorkflowIntegrationListener' => $baseDir . '/../lib/Listener/RegisterWorkflowIntegrationListener.php',
2729
'OCA\\Files_Versions\\Listener\\VersionAuthorListener' => $baseDir . '/../lib/Listener/VersionAuthorListener.php',
2830
'OCA\\Files_Versions\\Listener\\VersionStorageMoveListener' => $baseDir . '/../lib/Listener/VersionStorageMoveListener.php',
2931
'OCA\\Files_Versions\\Migration\\Version1020Date20221114144058' => $baseDir . '/../lib/Migration/Version1020Date20221114144058.php',
32+
'OCA\\Files_Versions\\Operation' => $baseDir . '/../lib/Operation.php',
3033
'OCA\\Files_Versions\\Sabre\\Plugin' => $baseDir . '/../lib/Sabre/Plugin.php',
3134
'OCA\\Files_Versions\\Sabre\\RestoreFolder' => $baseDir . '/../lib/Sabre/RestoreFolder.php',
3235
'OCA\\Files_Versions\\Sabre\\RootCollection' => $baseDir . '/../lib/Sabre/RootCollection.php',

apps/files_versions/composer/composer/autoload_static.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ class ComposerStaticInitFiles_Versions
3535
'OCA\\Files_Versions\\Events\\VersionCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/VersionCreatedEvent.php',
3636
'OCA\\Files_Versions\\Events\\VersionRestoredEvent' => __DIR__ . '/..' . '/../lib/Events/VersionRestoredEvent.php',
3737
'OCA\\Files_Versions\\Expiration' => __DIR__ . '/..' . '/../lib/Expiration.php',
38+
'OCA\\Files_Versions\\Listener\\CreateVersionListenerForWorkflow' => __DIR__ . '/..' . '/../lib/Listener/CreateVersionListenerForWorkflow.php',
3839
'OCA\\Files_Versions\\Listener\\FileEventsListener' => __DIR__ . '/..' . '/../lib/Listener/FileEventsListener.php',
3940
'OCA\\Files_Versions\\Listener\\LegacyRollbackListener' => __DIR__ . '/..' . '/../lib/Listener/LegacyRollbackListener.php',
4041
'OCA\\Files_Versions\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php',
4142
'OCA\\Files_Versions\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php',
43+
'OCA\\Files_Versions\\Listener\\RegisterWorkflowIntegrationListener' => __DIR__ . '/..' . '/../lib/Listener/RegisterWorkflowIntegrationListener.php',
4244
'OCA\\Files_Versions\\Listener\\VersionAuthorListener' => __DIR__ . '/..' . '/../lib/Listener/VersionAuthorListener.php',
4345
'OCA\\Files_Versions\\Listener\\VersionStorageMoveListener' => __DIR__ . '/..' . '/../lib/Listener/VersionStorageMoveListener.php',
4446
'OCA\\Files_Versions\\Migration\\Version1020Date20221114144058' => __DIR__ . '/..' . '/../lib/Migration/Version1020Date20221114144058.php',
47+
'OCA\\Files_Versions\\Operation' => __DIR__ . '/..' . '/../lib/Operation.php',
4548
'OCA\\Files_Versions\\Sabre\\Plugin' => __DIR__ . '/..' . '/../lib/Sabre/Plugin.php',
4649
'OCA\\Files_Versions\\Sabre\\RestoreFolder' => __DIR__ . '/..' . '/../lib/Sabre/RestoreFolder.php',
4750
'OCA\\Files_Versions\\Sabre\\RootCollection' => __DIR__ . '/..' . '/../lib/Sabre/RootCollection.php',

apps/files_versions/lib/AppInfo/Application.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
use OCA\Files\Event\LoadAdditionalScriptsEvent;
1212
use OCA\Files\Event\LoadSidebar;
1313
use OCA\Files_Versions\Capabilities;
14+
use OCA\Files_Versions\Events\CreateVersionEvent;
1415
use OCA\Files_Versions\Events\VersionRestoredEvent;
16+
use OCA\Files_Versions\Listener\CreateVersionListenerForWorkflow;
1517
use OCA\Files_Versions\Listener\FileEventsListener;
1618
use OCA\Files_Versions\Listener\LegacyRollbackListener;
1719
use OCA\Files_Versions\Listener\LoadAdditionalListener;
1820
use OCA\Files_Versions\Listener\LoadSidebarListener;
21+
use OCA\Files_Versions\Listener\RegisterWorkflowIntegrationListener;
1922
use OCA\Files_Versions\Listener\VersionAuthorListener;
2023
use OCA\Files_Versions\Listener\VersionStorageMoveListener;
2124
use OCA\Files_Versions\Versions\IVersionManager;
@@ -36,6 +39,8 @@
3639
use OCP\Files\Events\Node\NodeRenamedEvent;
3740
use OCP\Files\Events\Node\NodeTouchedEvent;
3841
use OCP\Files\Events\Node\NodeWrittenEvent;
42+
use OCP\WorkflowEngine\Events\LoadSettingsScriptsEvent;
43+
use OCP\WorkflowEngine\Events\RegisterOperationsEvent;
3944
use Psr\Container\ContainerInterface;
4045
use Psr\Log\LoggerInterface;
4146

@@ -85,8 +90,12 @@ public function register(IRegistrationContext $context): void {
8590

8691
// we add the version author listener with lower priority to make sure new versions already are created by FileEventsListener
8792
$context->registerEventListener(NodeWrittenEvent::class, VersionAuthorListener::class, -1);
88-
8993
$context->registerEventListener(VersionRestoredEvent::class, LegacyRollbackListener::class);
94+
95+
// WFE integration
96+
$context->registerEventListener(RegisterOperationsEvent::class, RegisterWorkflowIntegrationListener::class);
97+
$context->registerEventListener(LoadSettingsScriptsEvent::class, RegisterWorkflowIntegrationListener::class);
98+
$context->registerEventListener(CreateVersionEvent::class, CreateVersionListenerForWorkflow::class);
9099
}
91100

92101
#[\Override]
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*!
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OCA\Files_Versions;
10+
11+
use OCA\Files_Versions\Events\CreateVersionEvent;
12+
use OCA\WorkflowEngine\Entity\File as FileEntity;
13+
use OCP\EventDispatcher\Event;
14+
use OCP\Files\Folder;
15+
use OCP\IL10N;
16+
use OCP\IURLGenerator;
17+
use OCP\WorkflowEngine\IComplexOperation;
18+
use OCP\WorkflowEngine\IManager;
19+
use OCP\WorkflowEngine\IRuleMatcher;
20+
use OCP\WorkflowEngine\ISpecificOperation;
21+
use Psr\Log\LoggerInterface;
22+
23+
class BlockVersioningOperation implements ISpecificOperation, IComplexOperation {
24+
25+
public function __construct(
26+
private readonly IL10N $l10n,
27+
private readonly FileEntity $fileEntity,
28+
private readonly LoggerInterface $logger,
29+
private readonly IURLGenerator $urlGenerator,
30+
) {
31+
}
32+
33+
#[\Override]
34+
public function getEntityId(): string {
35+
return FileEntity::class;
36+
}
37+
38+
#[\Override]
39+
public function getDisplayName(): string {
40+
return $this->l10n->t('Block file versioning');
41+
}
42+
43+
#[\Override]
44+
public function getDescription(): string {
45+
return $this->l10n->t('Automatic tag based blocking of file version creation.');
46+
}
47+
48+
#[\Override]
49+
public function getIcon(): string {
50+
return $this->urlGenerator->imagePath('files_versions', 'app.svg');
51+
}
52+
53+
#[\Override]
54+
public function isAvailableForScope(int $scope): bool {
55+
return $scope === IManager::SCOPE_ADMIN;
56+
}
57+
58+
#[\Override]
59+
public function validateOperation(string $name, array $checks, string $operation): void {
60+
if (empty($checks)) {
61+
throw new \UnexpectedValueException($this->l10n->t('No rule given'));
62+
}
63+
}
64+
65+
#[\Override]
66+
public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatcher): void {
67+
if ($eventName !== CreateVersionEvent::class || !($event instanceof CreateVersionEvent)) {
68+
return;
69+
}
70+
71+
$node = $event->getNode();
72+
$path = $node->getInternalPath();
73+
74+
$ruleMatcher->setFileInfo(
75+
$node->getStorage(),
76+
$path,
77+
$node instanceof Folder,
78+
);
79+
$ruleMatcher->setEntitySubject($this->fileEntity, $node);
80+
$ruleMatcher->setOperation($this);
81+
$flows = $ruleMatcher->getFlows();
82+
83+
if ($flows !== []) {
84+
$this->logger->debug('Blocking version creation due to matching workflow rules', [
85+
'path' => $path,
86+
]);
87+
$event->disableVersions();
88+
}
89+
}
90+
91+
#[\Override]
92+
public function getTriggerHint(): string {
93+
return $this->l10n->t('A new version is created'); // TRANSLATORS: This will be shown as "When: " "A new version is created"
94+
}
95+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*!
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OCA\Files_Versions\Listener;
10+
11+
use OCA\Files_Versions\BlockVersioningOperation;
12+
use OCA\Files_Versions\Events\CreateVersionEvent;
13+
use OCP\EventDispatcher\Event;
14+
use OCP\EventDispatcher\IEventListener;
15+
use OCP\WorkflowEngine\IManager;
16+
17+
/** @template-implements IEventListener<CreateVersionEvent> */
18+
class CreateVersionListenerForWorkflow implements IEventListener {
19+
20+
public function __construct(
21+
private IManager $manager,
22+
private BlockVersioningOperation $operation,
23+
) {
24+
}
25+
26+
#[\Override]
27+
public function handle(Event $event): void {
28+
if (!($event instanceof CreateVersionEvent)) {
29+
return;
30+
}
31+
32+
$this->operation->onEvent(
33+
$event::class,
34+
$event,
35+
$this->manager->getRuleMatcher(),
36+
);
37+
}
38+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*!
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OCA\Files_Versions\Listener;
10+
11+
use OCA\Files_Versions\BlockVersioningOperation;
12+
use OCP\EventDispatcher\Event;
13+
use OCP\EventDispatcher\IEventListener;
14+
use OCP\Util;
15+
use OCP\WorkflowEngine\Events\LoadSettingsScriptsEvent;
16+
use OCP\WorkflowEngine\Events\RegisterOperationsEvent;
17+
18+
/** @template-implements IEventListener<RegisterOperationsEvent|LoadSettingsScriptsEvent> */
19+
class RegisterWorkflowIntegrationListener implements IEventListener {
20+
21+
public function __construct(
22+
private readonly BlockVersioningOperation $operation,
23+
) {
24+
}
25+
26+
#[\Override]
27+
public function handle(Event $event): void {
28+
if ($event instanceof RegisterOperationsEvent) {
29+
$event->registerOperation($this->operation);
30+
} elseif ($event instanceof LoadSettingsScriptsEvent) {
31+
Util::addScript('files_versions', 'workflow', 'workflowengine');
32+
}
33+
}
34+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
window.addEventListener('DOMContentLoaded', () => {
7+
globalThis.OCA.WorkflowEngine.registerOperator({
8+
id: 'OCA\\Files_Versions\\BlockVersioningOperation',
9+
color: '#ff5900',
10+
operation: 'deny',
11+
})
12+
})

build/frontend/vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const modules = {
4848
},
4949
files_versions: {
5050
'sidebar-tab': resolve(import.meta.dirname, 'apps/files_versions/src', 'sidebar_tab.ts'),
51+
workflow: resolve(import.meta.dirname, 'apps/files_versions/src', 'workflow.ts'),
5152
},
5253
oauth2: {
5354
'settings-admin': resolve(import.meta.dirname, 'apps/oauth2/src', 'settings-admin.ts'),

0 commit comments

Comments
 (0)