Skip to content

Commit ddd844a

Browse files
committed
feat(files_trashbin): Allow preventing trash to be deleted permanently
Signed-off-by: provokateurin <kate@provokateurin.de>
1 parent 17e8948 commit ddd844a

File tree

8 files changed

+70
-4
lines changed

8 files changed

+70
-4
lines changed

apps/files/src/actions/deleteAction.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import TrashCanSvg from '@mdi/svg/svg/trash-can.svg?raw'
1313

1414
import logger from '../logger.ts'
1515
import { askConfirmation, canDisconnectOnly, canUnshareOnly, deleteNode, displayName, isTrashbinEnabled } from './deleteUtils'
16+
import { loadState } from '@nextcloud/initial-state'
17+
import type { FilesTrashbinConfigState } from '../../../files_trashbin/src/fileListActions/emptyTrashAction.ts'
1618

1719
const queue = new PQueue({ concurrency: 5 })
1820

@@ -34,6 +36,11 @@ export const action = new FileAction({
3436
},
3537

3638
enabled(nodes: Node[]) {
39+
const config = loadState<FilesTrashbinConfigState>('files_trashbin', 'config')
40+
if (!config.allow_delete) {
41+
return false
42+
}
43+
3744
return nodes.length > 0 && nodes
3845
.map(node => node.permissions)
3946
.every(permission => (permission & Permission.DELETE) !== 0)

apps/files_trashbin/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
'OCA\\Files_Trashbin\\Sabre\\TrashHome' => $baseDir . '/../lib/Sabre/TrashHome.php',
4141
'OCA\\Files_Trashbin\\Sabre\\TrashRoot' => $baseDir . '/../lib/Sabre/TrashRoot.php',
4242
'OCA\\Files_Trashbin\\Sabre\\TrashbinPlugin' => $baseDir . '/../lib/Sabre/TrashbinPlugin.php',
43+
'OCA\\Files_Trashbin\\Service\\ConfigService' => $baseDir . '/../lib/Service/ConfigService.php',
4344
'OCA\\Files_Trashbin\\Storage' => $baseDir . '/../lib/Storage.php',
4445
'OCA\\Files_Trashbin\\Trash\\BackendNotFoundException' => $baseDir . '/../lib/Trash/BackendNotFoundException.php',
4546
'OCA\\Files_Trashbin\\Trash\\ITrashBackend' => $baseDir . '/../lib/Trash/ITrashBackend.php',

apps/files_trashbin/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class ComposerStaticInitFiles_Trashbin
5555
'OCA\\Files_Trashbin\\Sabre\\TrashHome' => __DIR__ . '/..' . '/../lib/Sabre/TrashHome.php',
5656
'OCA\\Files_Trashbin\\Sabre\\TrashRoot' => __DIR__ . '/..' . '/../lib/Sabre/TrashRoot.php',
5757
'OCA\\Files_Trashbin\\Sabre\\TrashbinPlugin' => __DIR__ . '/..' . '/../lib/Sabre/TrashbinPlugin.php',
58+
'OCA\\Files_Trashbin\\Service\\ConfigService' => __DIR__ . '/..' . '/../lib/Service/ConfigService.php',
5859
'OCA\\Files_Trashbin\\Storage' => __DIR__ . '/..' . '/../lib/Storage.php',
5960
'OCA\\Files_Trashbin\\Trash\\BackendNotFoundException' => __DIR__ . '/..' . '/../lib/Trash/BackendNotFoundException.php',
6061
'OCA\\Files_Trashbin\\Trash\\ITrashBackend' => __DIR__ . '/..' . '/../lib/Trash/ITrashBackend.php',

apps/files_trashbin/lib/Capabilities.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
namespace OCA\Files_Trashbin;
88

9+
use OCA\Files_Trashbin\Service\ConfigService;
910
use OCP\Capabilities\ICapability;
1011

1112
/**
@@ -18,12 +19,18 @@ class Capabilities implements ICapability {
1819
/**
1920
* Return this classes capabilities
2021
*
21-
* @return array{files: array{undelete: bool}}
22+
* @return array{
23+
* files: array{
24+
* undelete: bool,
25+
* delete_from_trash: bool
26+
* }
27+
* }
2228
*/
2329
public function getCapabilities() {
2430
return [
2531
'files' => [
26-
'undelete' => true
32+
'undelete' => true,
33+
'delete_from_trash' => ConfigService::getDeleteFromTrashEnabled(),
2734
]
2835
];
2936
}

apps/files_trashbin/lib/Listeners/LoadAdditionalScripts.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,30 @@
1010

1111
use OCA\Files\Event\LoadAdditionalScriptsEvent;
1212
use OCA\Files_Trashbin\AppInfo\Application;
13+
use OCA\Files_Trashbin\Service\ConfigService;
14+
use OCP\AppFramework\Services\IInitialState;
1315
use OCP\EventDispatcher\Event;
1416
use OCP\EventDispatcher\IEventListener;
1517
use OCP\Util;
1618

1719
/** @template-implements IEventListener<LoadAdditionalScriptsEvent> */
1820
class LoadAdditionalScripts implements IEventListener {
21+
public function __construct(
22+
private IInitialState $initialState,
23+
) {
24+
}
25+
1926
public function handle(Event $event): void {
2027
if (!($event instanceof LoadAdditionalScriptsEvent)) {
2128
return;
2229
}
2330

2431
Util::addInitScript(Application::APP_ID, 'init');
32+
33+
$this->initialState->provideLazyInitialState('config', function () {
34+
return [
35+
'allow_delete' => ConfigService::getDeleteFromTrashEnabled(),
36+
];
37+
});
2538
}
2639
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OCA\Files_Trashbin\Service;
6+
7+
use OCP\IConfig;
8+
use OCP\Server;
9+
10+
/**
11+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
12+
* SPDX-License-Identifier: AGPL-3.0-or-later
13+
*/
14+
class ConfigService {
15+
public static function getDeleteFromTrashEnabled(): bool {
16+
return Server::get(IConfig::class)->getSystemValueBool('files.trash.delete', true);
17+
}
18+
}

apps/files_trashbin/src/fileListActions/emptyTrashAction.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ import { logger } from '../logger.ts'
1919
import { generateRemoteUrl } from '@nextcloud/router'
2020
import { getCurrentUser } from '@nextcloud/auth'
2121
import { emit } from '@nextcloud/event-bus'
22+
import { loadState } from '@nextcloud/initial-state'
23+
24+
export type FilesTrashbinConfigState = {
25+
allow_delete: boolean;
26+
}
2227

2328
const emptyTrash = async (): Promise<boolean> => {
2429
try {
@@ -42,6 +47,12 @@ export const emptyTrashAction = new FileListAction({
4247
if (view.id !== 'trashbin') {
4348
return false
4449
}
50+
51+
const config = loadState<FilesTrashbinConfigState>('files_trashbin', 'config')
52+
if (!config.allow_delete) {
53+
return false
54+
}
55+
4556
return nodes.length > 0 && folder.path === '/'
4657
},
4758

config/config.sample.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@
369369
/**
370370
* Enable or disable the automatic logout after session_lifetime, even if session
371371
* keepalive is enabled. This will make sure that an inactive browser will log itself out
372-
* even if requests to the server might extend the session lifetime. Note: the logout is
372+
* even if requests to the server might extend the session lifetime. Note: the logout is
373373
* handled on the client side. This is not a way to limit the duration of potentially
374374
* compromised sessions.
375375
*
@@ -688,7 +688,7 @@
688688
* are generated within Nextcloud using any kind of command line tools (cron or
689689
* occ). The value should contain the full base URL:
690690
* ``https://www.example.com/nextcloud``
691-
* Please make sure to set the value to the URL that your users mainly use to access this Nextcloud.
691+
* Please make sure to set the value to the URL that your users mainly use to access this Nextcloud.
692692
* Otherwise there might be problems with the URL generation via cron.
693693
*
694694
* Defaults to ``''`` (empty string)
@@ -2597,4 +2597,12 @@
25972597
* Defaults to 5.
25982598
*/
25992599
'files.chunked_upload.max_parallel_count' => 5,
2600+
2601+
/**
2602+
* Allow users to manually delete files from their trashbin.
2603+
* Automated deletions are not affected and will continue to work in cases like low remaining quota for example.
2604+
*
2605+
* Defaults to true.
2606+
*/
2607+
'files.trash.delete' => true,
26002608
];

0 commit comments

Comments
 (0)