mirror of
https://github.com/nextcloud/server.git
synced 2026-06-14 19:20:35 -04:00
refactor(trash): Port deletion code of Trashbin to node based API
Instead of using a mix of View and Node based file system manipulation, use the 'new' node based API everywhere. Replace the hooks used in the admin_audit related to the deletion to new typed event that expose the deleted nodes. And remove old calculateSize to get the size of the deleted folder and instead rely on the Node::getSize information. Signed-off-by: Carl Schwan <carl.schwan@nextclound.com> Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
This commit is contained in:
parent
057c0dcc98
commit
ac029d1839
14 changed files with 255 additions and 150 deletions
|
|
@ -11,7 +11,6 @@ return array(
|
|||
'OCA\\AdminAudit\\Actions\\Files' => $baseDir . '/../lib/Actions/Files.php',
|
||||
'OCA\\AdminAudit\\Actions\\Sharing' => $baseDir . '/../lib/Actions/Sharing.php',
|
||||
'OCA\\AdminAudit\\Actions\\TagManagement' => $baseDir . '/../lib/Actions/TagManagement.php',
|
||||
'OCA\\AdminAudit\\Actions\\Trashbin' => $baseDir . '/../lib/Actions/Trashbin.php',
|
||||
'OCA\\AdminAudit\\Actions\\Versions' => $baseDir . '/../lib/Actions/Versions.php',
|
||||
'OCA\\AdminAudit\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
|
||||
'OCA\\AdminAudit\\AuditLogger' => $baseDir . '/../lib/AuditLogger.php',
|
||||
|
|
@ -25,5 +24,6 @@ return array(
|
|||
'OCA\\AdminAudit\\Listener\\GroupManagementEventListener' => $baseDir . '/../lib/Listener/GroupManagementEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\SecurityEventListener' => $baseDir . '/../lib/Listener/SecurityEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\SharingEventListener' => $baseDir . '/../lib/Listener/SharingEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\TrashbinEventListener' => $baseDir . '/../lib/Listener/TrashbinEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\UserManagementEventListener' => $baseDir . '/../lib/Listener/UserManagementEventListener.php',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ class ComposerStaticInitAdminAudit
|
|||
'OCA\\AdminAudit\\Actions\\Files' => __DIR__ . '/..' . '/../lib/Actions/Files.php',
|
||||
'OCA\\AdminAudit\\Actions\\Sharing' => __DIR__ . '/..' . '/../lib/Actions/Sharing.php',
|
||||
'OCA\\AdminAudit\\Actions\\TagManagement' => __DIR__ . '/..' . '/../lib/Actions/TagManagement.php',
|
||||
'OCA\\AdminAudit\\Actions\\Trashbin' => __DIR__ . '/..' . '/../lib/Actions/Trashbin.php',
|
||||
'OCA\\AdminAudit\\Actions\\Versions' => __DIR__ . '/..' . '/../lib/Actions/Versions.php',
|
||||
'OCA\\AdminAudit\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
|
||||
'OCA\\AdminAudit\\AuditLogger' => __DIR__ . '/..' . '/../lib/AuditLogger.php',
|
||||
|
|
@ -40,6 +39,7 @@ class ComposerStaticInitAdminAudit
|
|||
'OCA\\AdminAudit\\Listener\\GroupManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/GroupManagementEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\SecurityEventListener' => __DIR__ . '/..' . '/../lib/Listener/SecurityEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\SharingEventListener' => __DIR__ . '/..' . '/../lib/Listener/SharingEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\TrashbinEventListener' => __DIR__ . '/..' . '/../lib/Listener/TrashbinEventListener.php',
|
||||
'OCA\\AdminAudit\\Listener\\UserManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/UserManagementEventListener.php',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCA\AdminAudit\Actions;
|
||||
|
||||
class Trashbin extends Action {
|
||||
public function delete(array $params): void {
|
||||
$this->log('File "%s" deleted from trash bin.',
|
||||
['path' => $params['path']], ['path']
|
||||
);
|
||||
}
|
||||
|
||||
public function restore(array $params): void {
|
||||
$this->log('File "%s" restored from trash bin.',
|
||||
['path' => $params['filePath']], ['path']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,10 @@ use OCA\AdminAudit\Listener\FileEventListener;
|
|||
use OCA\AdminAudit\Listener\GroupManagementEventListener;
|
||||
use OCA\AdminAudit\Listener\SecurityEventListener;
|
||||
use OCA\AdminAudit\Listener\SharingEventListener;
|
||||
use OCA\AdminAudit\Listener\TrashbinEventListener;
|
||||
use OCA\AdminAudit\Listener\UserManagementEventListener;
|
||||
use OCA\Files_Trashbin\Events\BeforeNodeDeletedEvent as TrashbinBeforeNodeDeletedEvent;
|
||||
use OCA\Files_Trashbin\Events\NodeRestoredEvent;
|
||||
use OCA\Files_Versions\Events\VersionRestoredEvent;
|
||||
use OCP\App\Events\AppDisableEvent;
|
||||
use OCP\App\Events\AppEnableEvent;
|
||||
|
|
@ -123,6 +126,10 @@ class Application extends App implements IBootstrap {
|
|||
|
||||
// Console events
|
||||
$context->registerEventListener(ConsoleEvent::class, ConsoleEventListener::class);
|
||||
|
||||
// Trashbin events
|
||||
$context->registerEventListener(TrashbinBeforeNodeDeletedEvent::class, TrashbinEventListener::class);
|
||||
$context->registerEventListener(NodeRestoredEvent::class, TrashbinEventListener::class);
|
||||
}
|
||||
|
||||
public function boot(IBootContext $context): void {
|
||||
|
|
@ -144,7 +151,6 @@ class Application extends App implements IBootstrap {
|
|||
$eventDispatcher = $serverContainer->get(IEventDispatcher::class);
|
||||
$this->sharingLegacyHooks($logger);
|
||||
$this->fileHooks($logger, $eventDispatcher);
|
||||
$this->trashbinHooks($logger);
|
||||
$this->versionsHooks($logger);
|
||||
$this->tagHooks($logger, $eventDispatcher);
|
||||
}
|
||||
|
|
@ -216,10 +222,4 @@ class Application extends App implements IBootstrap {
|
|||
$versionsActions = new Versions($logger);
|
||||
Util::connectHook('\OCP\Versions', 'delete', $versionsActions, 'delete');
|
||||
}
|
||||
|
||||
private function trashbinHooks(IAuditLogger $logger): void {
|
||||
$trashActions = new Trashbin($logger);
|
||||
Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete');
|
||||
Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
apps/admin_audit/lib/Listener/TrashbinEventListener.php
Normal file
34
apps/admin_audit/lib/Listener/TrashbinEventListener.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\AdminAudit\Listener;
|
||||
|
||||
use OCA\AdminAudit\Actions\Action;
|
||||
use OCA\Files_Trashbin\Events\BeforeNodeDeletedEvent;
|
||||
use OCA\Files_Trashbin\Events\NodeRestoredEvent;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
|
||||
/**
|
||||
* @template-implements IEventListener<BeforeNodeDeletedEvent|NodeRestoredEvent>
|
||||
*/
|
||||
class TrashbinEventListener extends Action implements IEventListener {
|
||||
|
||||
public function handle(Event $event): void {
|
||||
if ($event instanceof BeforeNodeDeletedEvent) {
|
||||
$this->log('File "%s" deleted from trash bin.',
|
||||
['path' => $event->getSource()->getPath()], ['path']
|
||||
);
|
||||
} elseif ($event instanceof NodeRestoredEvent) {
|
||||
$this->log('File "%s" restored from trash bin.',
|
||||
['path' => $event->getTarget()->getPath()], ['path']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,12 @@ return array(
|
|||
'OCA\\Files_Trashbin\\Command\\RestoreAllFiles' => $baseDir . '/../lib/Command/RestoreAllFiles.php',
|
||||
'OCA\\Files_Trashbin\\Command\\Size' => $baseDir . '/../lib/Command/Size.php',
|
||||
'OCA\\Files_Trashbin\\Controller\\PreviewController' => $baseDir . '/../lib/Controller/PreviewController.php',
|
||||
'OCA\\Files_Trashbin\\Events\\BeforeDeleteAllEvent' => $baseDir . '/../lib/Events/BeforeDeleteAllEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\BeforeNodeDeletedEvent' => $baseDir . '/../lib/Events/BeforeNodeDeletedEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\BeforeNodeRestoredEvent' => $baseDir . '/../lib/Events/BeforeNodeRestoredEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\DeleteAllEvent' => $baseDir . '/../lib/Events/DeleteAllEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\MoveToTrashEvent' => $baseDir . '/../lib/Events/MoveToTrashEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\NodeDeletedEvent' => $baseDir . '/../lib/Events/NodeDeletedEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\NodeRestoredEvent' => $baseDir . '/../lib/Events/NodeRestoredEvent.php',
|
||||
'OCA\\Files_Trashbin\\Exceptions\\CopyRecursiveException' => $baseDir . '/../lib/Exceptions/CopyRecursiveException.php',
|
||||
'OCA\\Files_Trashbin\\Expiration' => $baseDir . '/../lib/Expiration.php',
|
||||
|
|
|
|||
|
|
@ -31,8 +31,12 @@ class ComposerStaticInitFiles_Trashbin
|
|||
'OCA\\Files_Trashbin\\Command\\RestoreAllFiles' => __DIR__ . '/..' . '/../lib/Command/RestoreAllFiles.php',
|
||||
'OCA\\Files_Trashbin\\Command\\Size' => __DIR__ . '/..' . '/../lib/Command/Size.php',
|
||||
'OCA\\Files_Trashbin\\Controller\\PreviewController' => __DIR__ . '/..' . '/../lib/Controller/PreviewController.php',
|
||||
'OCA\\Files_Trashbin\\Events\\BeforeDeleteAllEvent' => __DIR__ . '/..' . '/../lib/Events/BeforeDeleteAllEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\BeforeNodeDeletedEvent' => __DIR__ . '/..' . '/../lib/Events/BeforeNodeDeletedEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\BeforeNodeRestoredEvent' => __DIR__ . '/..' . '/../lib/Events/BeforeNodeRestoredEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\DeleteAllEvent' => __DIR__ . '/..' . '/../lib/Events/DeleteAllEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\MoveToTrashEvent' => __DIR__ . '/..' . '/../lib/Events/MoveToTrashEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\NodeDeletedEvent' => __DIR__ . '/..' . '/../lib/Events/NodeDeletedEvent.php',
|
||||
'OCA\\Files_Trashbin\\Events\\NodeRestoredEvent' => __DIR__ . '/..' . '/../lib/Events/NodeRestoredEvent.php',
|
||||
'OCA\\Files_Trashbin\\Exceptions\\CopyRecursiveException' => __DIR__ . '/..' . '/../lib/Exceptions/CopyRecursiveException.php',
|
||||
'OCA\\Files_Trashbin\\Expiration' => __DIR__ . '/..' . '/../lib/Expiration.php',
|
||||
|
|
|
|||
34
apps/files_trashbin/lib/Events/BeforeDeleteAllEvent.php
Normal file
34
apps/files_trashbin/lib/Events/BeforeDeleteAllEvent.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Trashbin\Events;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\Files\Node;
|
||||
|
||||
/**
|
||||
* Event send before emptying the trash.
|
||||
* @since 32.0.0
|
||||
*/
|
||||
class BeforeDeleteAllEvent extends Event {
|
||||
|
||||
/**
|
||||
* @param Node[] $deletedNodes
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $deletedNodes,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/** @return Node[] */
|
||||
public function getDeletedNodes(): array {
|
||||
return $this->deletedNodes;
|
||||
}
|
||||
}
|
||||
28
apps/files_trashbin/lib/Events/BeforeNodeDeletedEvent.php
Normal file
28
apps/files_trashbin/lib/Events/BeforeNodeDeletedEvent.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCA\Files_Trashbin\Events;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\Files\Node;
|
||||
|
||||
/**
|
||||
* Event send before a node is deleted definitively.
|
||||
* @since 32.0.0
|
||||
*/
|
||||
class BeforeNodeDeletedEvent extends Event {
|
||||
public function __construct(
|
||||
private readonly Node $source,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function getSource(): Node {
|
||||
return $this->source;
|
||||
}
|
||||
}
|
||||
34
apps/files_trashbin/lib/Events/DeleteAllEvent.php
Normal file
34
apps/files_trashbin/lib/Events/DeleteAllEvent.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Trashbin\Events;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\Files\Node;
|
||||
|
||||
/**
|
||||
* Event send before emptying the trash.
|
||||
* @since 32.0.0
|
||||
*/
|
||||
class DeleteAllEvent extends Event {
|
||||
|
||||
/**
|
||||
* @param Node[] $deletedNodes
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $deletedNodes,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/** @return Node[] */
|
||||
public function getDeletedNodes(): array {
|
||||
return $this->deletedNodes;
|
||||
}
|
||||
}
|
||||
28
apps/files_trashbin/lib/Events/NodeDeletedEvent.php
Normal file
28
apps/files_trashbin/lib/Events/NodeDeletedEvent.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCA\Files_Trashbin\Events;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\Files\Node;
|
||||
|
||||
/**
|
||||
* Event send before a node is deleted definitively.
|
||||
* @since 32.0.0
|
||||
*/
|
||||
class NodeDeletedEvent extends Event {
|
||||
public function __construct(
|
||||
readonly private Node $source,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function getSource(): Node {
|
||||
return $this->source;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ use Sabre\DAV\Exception\NotFound;
|
|||
use Sabre\DAV\ICollection;
|
||||
|
||||
class TrashRoot implements ICollection {
|
||||
|
||||
public function __construct(
|
||||
private IUser $user,
|
||||
private ITrashManager $trashManager,
|
||||
|
|
@ -31,7 +30,7 @@ class TrashRoot implements ICollection {
|
|||
throw new Forbidden('Not allowed to delete items from the trash bin');
|
||||
}
|
||||
|
||||
Trashbin::deleteAll();
|
||||
Trashbin::deleteAll($this->user);
|
||||
foreach ($this->trashManager->listTrashRoot($this->user) as $trashItem) {
|
||||
$this->trashManager->removeItem($trashItem);
|
||||
}
|
||||
|
|
@ -67,6 +66,7 @@ class TrashRoot implements ICollection {
|
|||
}
|
||||
|
||||
public function getChild($name): ITrash {
|
||||
/** @var list<ITrash&ICollection> $entries */
|
||||
$entries = $this->getChildren();
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ use OC\User\NoUserException;
|
|||
use OC_User;
|
||||
use OCA\Files_Trashbin\AppInfo\Application;
|
||||
use OCA\Files_Trashbin\Command\Expire;
|
||||
use OCA\Files_Trashbin\Events\BeforeDeleteAllEvent;
|
||||
use OCA\Files_Trashbin\Events\BeforeNodeRestoredEvent;
|
||||
use OCA\Files_Trashbin\Events\DeleteAllEvent;
|
||||
use OCA\Files_Trashbin\Events\NodeRestoredEvent;
|
||||
use OCA\Files_Trashbin\Exceptions\CopyRecursiveException;
|
||||
use OCA\Files_Versions\Storage;
|
||||
|
|
@ -42,6 +44,7 @@ use OCP\FilesMetadata\IFilesMetadataManager;
|
|||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Lock\ILockingProvider;
|
||||
use OCP\Lock\LockedException;
|
||||
|
|
@ -590,47 +593,50 @@ class Trashbin implements IEventListener {
|
|||
/**
|
||||
* delete all files from the trash
|
||||
*/
|
||||
public static function deleteAll() {
|
||||
$user = OC_User::getUser();
|
||||
$userRoot = \OC::$server->getUserFolder($user)->getParent();
|
||||
$view = new View('/' . $user);
|
||||
$fileInfos = $view->getDirectoryContent('files_trashbin/files');
|
||||
public static function deleteAll(IUser $user) {
|
||||
$rootFolder = Server::get(IRootFolder::class);
|
||||
$dispatcher = Server::get(IEventDispatcher::class);
|
||||
$dbConnection = Server::get(IDBConnection::class);
|
||||
|
||||
$userRoot = $rootFolder->getUserFolder($user->getUID())->getParent();
|
||||
|
||||
try {
|
||||
$trash = $userRoot->get('files_trashbin');
|
||||
} catch (NotFoundException $e) {
|
||||
/** @var Folder $trashRoot */
|
||||
$trashRoot = $userRoot->get('files_trashbin');
|
||||
/** @var Folder $trashFilesRoot */
|
||||
$trashFilesRoot = $trashRoot->get('files');
|
||||
} catch (NotFoundException) {
|
||||
return false;
|
||||
} catch (NotPermittedException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Array to store the relative path in (after the file is deleted, the view won't be able to relativise the path anymore)
|
||||
$filePaths = [];
|
||||
foreach ($fileInfos as $fileInfo) {
|
||||
$filePaths[] = $view->getRelativePath($fileInfo->getPath());
|
||||
}
|
||||
unset($fileInfos); // save memory
|
||||
|
||||
// Bulk PreDelete-Hook
|
||||
\OC_Hook::emit('\OCP\Trashbin', 'preDeleteAll', ['paths' => $filePaths]);
|
||||
$trashNodes = $trashFilesRoot->getDirectoryListing();
|
||||
$beforeDeleteAllEvent = new BeforeDeleteAllEvent($trashNodes);
|
||||
$dispatcher->dispatchTyped($beforeDeleteAllEvent);
|
||||
|
||||
// Single-File Hooks
|
||||
foreach ($filePaths as $path) {
|
||||
self::emitTrashbinPreDelete($path);
|
||||
foreach ($trashNodes as $trashNode) {
|
||||
$event = new Events\BeforeNodeDeletedEvent($trashNode);
|
||||
$dispatcher->dispatchTyped($event);
|
||||
}
|
||||
|
||||
// actual file deletion
|
||||
$trash->delete();
|
||||
$trashRoot->delete();
|
||||
|
||||
$query = Server::get(IDBConnection::class)->getQueryBuilder();
|
||||
$query = $dbConnection->getQueryBuilder();
|
||||
$query->delete('files_trash')
|
||||
->where($query->expr()->eq('user', $query->createNamedParameter($user)));
|
||||
->where($query->expr()->eq('user', $query->createNamedParameter($user->getUID())));
|
||||
$query->executeStatement();
|
||||
|
||||
// Bulk PostDelete-Hook
|
||||
\OC_Hook::emit('\OCP\Trashbin', 'deleteAll', ['paths' => $filePaths]);
|
||||
$deleteAllEvent = new DeleteAllEvent($trashNodes);
|
||||
$dispatcher->dispatchTyped($deleteAllEvent);
|
||||
|
||||
// Single-File Hooks
|
||||
foreach ($filePaths as $path) {
|
||||
self::emitTrashbinPostDelete($path);
|
||||
foreach ($trashNodes as $trashNode) {
|
||||
$event = new Events\NodeDeletedEvent($trashNode);
|
||||
$dispatcher->dispatchTyped($event);
|
||||
}
|
||||
|
||||
$trash = $userRoot->newFolder('files_trashbin');
|
||||
|
|
@ -640,39 +646,31 @@ class Trashbin implements IEventListener {
|
|||
}
|
||||
|
||||
/**
|
||||
* wrapper function to emit the 'preDelete' hook of \OCP\Trashbin before a file is deleted
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
protected static function emitTrashbinPreDelete($path) {
|
||||
\OC_Hook::emit('\OCP\Trashbin', 'preDelete', ['path' => $path]);
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper function to emit the 'delete' hook of \OCP\Trashbin after a file has been deleted
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
protected static function emitTrashbinPostDelete($path) {
|
||||
\OC_Hook::emit('\OCP\Trashbin', 'delete', ['path' => $path]);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete file from trash bin permanently
|
||||
* Delete file from trash bin permanently
|
||||
*
|
||||
* @param string $filename path to the file
|
||||
* @param string $user
|
||||
* @param int $timestamp of deletion time
|
||||
*
|
||||
* @param ?int $timestamp of deletion time
|
||||
* @return int|float size of deleted files
|
||||
*/
|
||||
public static function delete($filename, $user, $timestamp = null) {
|
||||
$userRoot = \OC::$server->getUserFolder($user)->getParent();
|
||||
$view = new View('/' . $user);
|
||||
public static function delete(string $filename, string $user, ?int $timestamp = null): int|float {
|
||||
$rootFolder = Server::get(IRootFolder::class);
|
||||
$appManager = Server::get(IAppManager::class);
|
||||
$dispatcher = Server::get(IEventDispatcher::class);
|
||||
$dbConnection = Server::get(IDBConnection::class);
|
||||
|
||||
$userRoot = $rootFolder->getUserFolder($user)->getParent();
|
||||
|
||||
try {
|
||||
/** @var Folder $trashRoot */
|
||||
$trashRoot = $userRoot->get('files_trashbin');
|
||||
} catch (NotFoundException|NotPermittedException) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$size = 0;
|
||||
|
||||
if ($timestamp) {
|
||||
$query = Server::get(IDBConnection::class)->getQueryBuilder();
|
||||
$query = $dbConnection->getQueryBuilder();
|
||||
$query->delete('files_trash')
|
||||
->where($query->expr()->eq('user', $query->createNamedParameter($user)))
|
||||
->andWhere($query->expr()->eq('id', $query->createNamedParameter($filename)))
|
||||
|
|
@ -684,48 +682,52 @@ class Trashbin implements IEventListener {
|
|||
$file = $filename;
|
||||
}
|
||||
|
||||
$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
|
||||
if ($appManager->isEnabledForUser('files_versions')) {
|
||||
size += Trashbin::deleteVersions($trashRoot, $file, $filename, $timestamp, $user);
|
||||
}
|
||||
|
||||
try {
|
||||
$node = $userRoot->get('/files_trashbin/files/' . $file);
|
||||
} catch (NotFoundException $e) {
|
||||
} catch (NotFoundException) {
|
||||
return $size;
|
||||
}
|
||||
|
||||
if ($node instanceof Folder) {
|
||||
$size += self::calculateSize(new View('/' . $user . '/files_trashbin/files/' . $file));
|
||||
} elseif ($node instanceof File) {
|
||||
$size += $view->filesize('/files_trashbin/files/' . $file);
|
||||
}
|
||||
$size += $node->getSize();
|
||||
|
||||
$event = new Events\BeforeNodeDeletedEvent($node);
|
||||
$dispatcher->dispatchTyped($event);
|
||||
|
||||
self::emitTrashbinPreDelete('/files_trashbin/files/' . $file);
|
||||
$node->delete();
|
||||
self::emitTrashbinPostDelete('/files_trashbin/files/' . $file);
|
||||
|
||||
$event = new Events\NodeDeletedEvent($node);
|
||||
$dispatcher->dispatchTyped($event);
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $filename
|
||||
* @param ?int $timestamp
|
||||
* Delete version files corresponding to a given file from trash bin permanently.
|
||||
*/
|
||||
private static function deleteVersions(View $view, $file, $filename, $timestamp, string $user): int|float {
|
||||
private static function deleteVersions(Folder $trashRoot, string $file, string $filename, ?int $timestamp, string $user): int|float {
|
||||
$size = 0;
|
||||
if (Server::get(IAppManager::class)->isEnabledForUser('files_versions')) {
|
||||
if ($view->is_dir('files_trashbin/versions/' . $file)) {
|
||||
$size += self::calculateSize(new View('/' . $user . '/files_trashbin/versions/' . $file));
|
||||
$view->unlink('files_trashbin/versions/' . $file);
|
||||
} elseif ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
|
||||
foreach ($versions as $v) {
|
||||
if ($timestamp) {
|
||||
$size += $view->filesize('/files_trashbin/versions/' . static::getTrashFilename($filename . '.v' . $v, $timestamp));
|
||||
$view->unlink('/files_trashbin/versions/' . static::getTrashFilename($filename . '.v' . $v, $timestamp));
|
||||
} else {
|
||||
$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v);
|
||||
$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v);
|
||||
}
|
||||
try {
|
||||
$fileVersion = $trashRoot->get('versions/' . $file);
|
||||
} catch (NotFoundException) {
|
||||
}
|
||||
|
||||
if ($fileVersion) {
|
||||
$size += $fileVersion->getSize();
|
||||
$fileVersion->delete();
|
||||
} elseif ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
|
||||
foreach ($versions as $v) {
|
||||
if ($timestamp) {
|
||||
$node = $trashRoot->get('/files_trashbin/versions/' . static::getTrashFilename($filename . '.v' . $v, $timestamp));
|
||||
} else {
|
||||
$node = $trashRoot->get('/files_trashbin/versions/' . $filename . '.v' . $v);
|
||||
}
|
||||
|
||||
$size += $node->getSize();
|
||||
$node->delete();
|
||||
}
|
||||
}
|
||||
return $size;
|
||||
|
|
@ -1078,37 +1080,6 @@ class Trashbin implements IEventListener {
|
|||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the size from a given root folder
|
||||
*
|
||||
* @param View $view file view on the root folder
|
||||
* @return int|float size of the folder
|
||||
*/
|
||||
private static function calculateSize(View $view): int|float {
|
||||
$root = Server::get(IConfig::class)->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . $view->getAbsolutePath('');
|
||||
if (!file_exists($root)) {
|
||||
return 0;
|
||||
}
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($root), \RecursiveIteratorIterator::CHILD_FIRST);
|
||||
$size = 0;
|
||||
|
||||
/**
|
||||
* RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
|
||||
* This bug is fixed in PHP 5.5.9 or before
|
||||
* See #8376
|
||||
*/
|
||||
$iterator->rewind();
|
||||
while ($iterator->valid()) {
|
||||
$path = $iterator->current();
|
||||
$relpath = substr($path, strlen($root) - 1);
|
||||
if (!$view->is_dir($relpath)) {
|
||||
$size += $view->filesize($relpath);
|
||||
}
|
||||
$iterator->next();
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current size of trash bin from a given user
|
||||
*
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
<code><![CDATA[ManagerEvent::EVENT_CREATE]]></code>
|
||||
</DeprecatedConstant>
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore')]]></code>
|
||||
<code><![CDATA[Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete')]]></code>
|
||||
<code><![CDATA[Util::connectHook('\OCP\Versions', 'delete', $versionsActions, 'delete')]]></code>
|
||||
<code><![CDATA[Util::connectHook(Share::class, 'post_set_expiration_date', $shareActions, 'updateExpirationDate')]]></code>
|
||||
<code><![CDATA[Util::connectHook(Share::class, 'post_update_password', $shareActions, 'updatePassword')]]></code>
|
||||
|
|
@ -1644,14 +1642,6 @@
|
|||
<code><![CDATA[INode]]></code>
|
||||
</MismatchingDocblockReturnType>
|
||||
</file>
|
||||
<file src="apps/files_trashbin/lib/Sabre/TrashRoot.php">
|
||||
<InvalidReturnStatement>
|
||||
<code><![CDATA[$entry]]></code>
|
||||
</InvalidReturnStatement>
|
||||
<InvalidReturnType>
|
||||
<code><![CDATA[ITrash]]></code>
|
||||
</InvalidReturnType>
|
||||
</file>
|
||||
<file src="apps/files_trashbin/lib/Storage.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[dispatch]]></code>
|
||||
|
|
|
|||
Loading…
Reference in a new issue