aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarl Schwan <carl.schwan@nextclound.com>2025-08-06 13:40:37 +0200
committerCarl Schwan <carl.schwan@nextclound.com>2025-08-06 16:01:16 +0200
commit299859f85dcfb26657ed6ba0ac1e3b9a0ce5558b (patch)
treed0004cb1f9c9c4457f26301b6ac06f673af2354c
parent2211390ca5c0972b45584948e14dbcee00f4ad89 (diff)
downloadnextcloud-server-cleanup-legacy-trash.tar.gz
nextcloud-server-cleanup-legacy-trash.zip
refactor(trash): Port deletion code of Trashbin to node based APIcleanup-legacy-trash
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>
-rw-r--r--apps/admin_audit/lib/Actions/Trashbin.php11
-rw-r--r--apps/admin_audit/lib/AppInfo/Application.php22
-rw-r--r--apps/files_trashbin/composer/composer/autoload_classmap.php4
-rw-r--r--apps/files_trashbin/composer/composer/autoload_static.php4
-rw-r--r--apps/files_trashbin/lib/Events/BeforeDeleteAllEvent.php31
-rw-r--r--apps/files_trashbin/lib/Events/BeforeNodeDeletedEvent.php25
-rw-r--r--apps/files_trashbin/lib/Events/DeleteAllEvent.php31
-rw-r--r--apps/files_trashbin/lib/Events/NodeDeletedEvent.php25
-rw-r--r--apps/files_trashbin/lib/Sabre/TrashRoot.php3
-rw-r--r--apps/files_trashbin/lib/Trashbin.php188
-rw-r--r--build/psalm-baseline.xml3
-rw-r--r--lib/public/Files/Cache/CacheEntriesRemovedEvent.php31
12 files changed, 257 insertions, 121 deletions
diff --git a/apps/admin_audit/lib/Actions/Trashbin.php b/apps/admin_audit/lib/Actions/Trashbin.php
index c1e994da3a5..0a73b1d5235 100644
--- a/apps/admin_audit/lib/Actions/Trashbin.php
+++ b/apps/admin_audit/lib/Actions/Trashbin.php
@@ -7,16 +7,19 @@ declare(strict_types=1);
*/
namespace OCA\AdminAudit\Actions;
+use OCA\Files_Trashbin\Events\BeforeNodeDeletedEvent;
+use OCA\Files_Trashbin\Events\NodeRestoredEvent;
+
class Trashbin extends Action {
- public function delete(array $params): void {
+ public function delete(BeforeNodeDeletedEvent $beforeNodeDeletedEvent): void {
$this->log('File "%s" deleted from trash bin.',
- ['path' => $params['path']], ['path']
+ ['path' => $beforeNodeDeletedEvent->getSource()->getPath()], ['path']
);
}
- public function restore(array $params): void {
+ public function restore(NodeRestoredEvent $nodeRestoredEvent): void {
$this->log('File "%s" restored from trash bin.',
- ['path' => $params['filePath']], ['path']
+ ['path' => $nodeRestoredEvent->getTarget()], ['path']
);
}
}
diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php
index 63a1d065bc8..1371debf03f 100644
--- a/apps/admin_audit/lib/AppInfo/Application.php
+++ b/apps/admin_audit/lib/AppInfo/Application.php
@@ -27,6 +27,8 @@ use OCA\AdminAudit\Listener\GroupManagementEventListener;
use OCA\AdminAudit\Listener\SecurityEventListener;
use OCA\AdminAudit\Listener\SharingEventListener;
use OCA\AdminAudit\Listener\UserManagementEventListener;
+use OCA\Files_Trashbin\Events\NodeRestoredEvent;
+use OCA\Files_Trashbin\Events\BeforeNodeDeletedEvent as TrashbinBeforeNodeDeletedEvent;
use OCA\Files_Versions\Events\VersionRestoredEvent;
use OCP\App\Events\AppDisableEvent;
use OCP\App\Events\AppEnableEvent;
@@ -44,6 +46,7 @@ use OCP\Files\Events\Node\BeforeNodeDeletedEvent;
use OCP\Files\Events\Node\BeforeNodeReadEvent;
use OCP\Files\Events\Node\NodeCopiedEvent;
use OCP\Files\Events\Node\NodeCreatedEvent;
+use OCP\Files\Events\Node\NodeDeletedEvent;
use OCP\Files\Events\Node\NodeRenamedEvent;
use OCP\Files\Events\Node\NodeWrittenEvent;
use OCP\Group\Events\GroupCreatedEvent;
@@ -144,7 +147,7 @@ class Application extends App implements IBootstrap {
$eventDispatcher = $serverContainer->get(IEventDispatcher::class);
$this->sharingLegacyHooks($logger);
$this->fileHooks($logger, $eventDispatcher);
- $this->trashbinHooks($logger);
+ $this->trashbinHooks($logger, $eventDispatcher);
$this->versionsHooks($logger);
$this->tagHooks($logger, $eventDispatcher);
}
@@ -217,9 +220,20 @@ class Application extends App implements IBootstrap {
Util::connectHook('\OCP\Versions', 'delete', $versionsActions, 'delete');
}
- private function trashbinHooks(IAuditLogger $logger): void {
+ private function trashbinHooks(IAuditLogger $logger, IEventDispatcher $eventDispatcher): void {
$trashActions = new Trashbin($logger);
- Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete');
- Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore');
+
+ $eventDispatcher->addListener(TrashbinBeforeNodeDeletedEvent::class,
+ function (TrashbinBeforeNodeDeletedEvent $event) use ($trashActions): void {
+ $trashActions->delete($event);
+ }
+ );
+
+ $eventDispatcher->addListener(
+ NodeRestoredEvent::class,
+ function (NodeRestoredEvent $event) use ($trashActions): void {
+ $trashActions->restore($event);
+ }
+ );
}
}
diff --git a/apps/files_trashbin/composer/composer/autoload_classmap.php b/apps/files_trashbin/composer/composer/autoload_classmap.php
index 23e2e7baff6..be2ec71eaf2 100644
--- a/apps/files_trashbin/composer/composer/autoload_classmap.php
+++ b/apps/files_trashbin/composer/composer/autoload_classmap.php
@@ -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',
diff --git a/apps/files_trashbin/composer/composer/autoload_static.php b/apps/files_trashbin/composer/composer/autoload_static.php
index fc604299261..0606643c4fe 100644
--- a/apps/files_trashbin/composer/composer/autoload_static.php
+++ b/apps/files_trashbin/composer/composer/autoload_static.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',
diff --git a/apps/files_trashbin/lib/Events/BeforeDeleteAllEvent.php b/apps/files_trashbin/lib/Events/BeforeDeleteAllEvent.php
new file mode 100644
index 00000000000..1cd519b8255
--- /dev/null
+++ b/apps/files_trashbin/lib/Events/BeforeDeleteAllEvent.php
@@ -0,0 +1,31 @@
+<?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) {
+ }
+
+ /** @return Node[] */
+ public function getDeletedNodes(): array {
+ return $this->deletedNodes;
+ }
+}
diff --git a/apps/files_trashbin/lib/Events/BeforeNodeDeletedEvent.php b/apps/files_trashbin/lib/Events/BeforeNodeDeletedEvent.php
new file mode 100644
index 00000000000..7f1249a5a0c
--- /dev/null
+++ b/apps/files_trashbin/lib/Events/BeforeNodeDeletedEvent.php
@@ -0,0 +1,25 @@
+<?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) {
+ }
+
+ public function getSource(): Node {
+ return $this->source;
+ }
+}
diff --git a/apps/files_trashbin/lib/Events/DeleteAllEvent.php b/apps/files_trashbin/lib/Events/DeleteAllEvent.php
new file mode 100644
index 00000000000..5c19b1575be
--- /dev/null
+++ b/apps/files_trashbin/lib/Events/DeleteAllEvent.php
@@ -0,0 +1,31 @@
+<?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) {
+ }
+
+ /** @return Node[] */
+ public function getDeletedNodes(): array {
+ return $this->deletedNodes;
+ }
+}
diff --git a/apps/files_trashbin/lib/Events/NodeDeletedEvent.php b/apps/files_trashbin/lib/Events/NodeDeletedEvent.php
new file mode 100644
index 00000000000..f493c10c7f1
--- /dev/null
+++ b/apps/files_trashbin/lib/Events/NodeDeletedEvent.php
@@ -0,0 +1,25 @@
+<?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(private Node $source) {
+ }
+
+ public function getSource(): Node {
+ return $this->source;
+ }
+}
diff --git a/apps/files_trashbin/lib/Sabre/TrashRoot.php b/apps/files_trashbin/lib/Sabre/TrashRoot.php
index dd89583d9a1..7e806cd7ca1 100644
--- a/apps/files_trashbin/lib/Sabre/TrashRoot.php
+++ b/apps/files_trashbin/lib/Sabre/TrashRoot.php
@@ -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);
}
diff --git a/apps/files_trashbin/lib/Trashbin.php b/apps/files_trashbin/lib/Trashbin.php
index 667066c2fca..7142ab07b9d 100644
--- a/apps/files_trashbin/lib/Trashbin.php
+++ b/apps/files_trashbin/lib/Trashbin.php
@@ -19,7 +19,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;
@@ -43,6 +45,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;
@@ -514,7 +517,6 @@ class Trashbin implements IEventListener {
$view->chroot('/' . $user . '/files');
$view->touch('/' . $location . '/' . $uniqueFilename, $mtime);
$view->chroot($fakeRoot);
- Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => $targetPath, 'trashPath' => $sourcePath]);
$sourceNode = self::getNodeForPath($sourcePath);
$targetNode = self::getNodeForPath($targetPath);
@@ -587,49 +589,54 @@ 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);
}
+ unset($trashNodes); // save memory
+
$trash = $userRoot->newFolder('files_trashbin');
$trash->newFolder('files');
@@ -637,39 +644,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)))
@@ -681,48 +680,52 @@ class Trashbin implements IEventListener {
$file = $filename;
}
- $size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
+ if ($appManager->isEnabledForUser('files_versions')) {
+ 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;
@@ -1076,37 +1079,6 @@ class Trashbin implements IEventListener {
}
/**
- * 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
*
* @param string $user user who owns the trash bin
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 73dfeab49e4..5bf36ae6485 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -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>
@@ -1857,7 +1855,6 @@
<DeprecatedMethod>
<code><![CDATA[Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', ['filePath' => Filesystem::normalizePath($file_path),
'trashPath' => Filesystem::normalizePath(static::getTrashFilename($filename, $timestamp))])]]></code>
- <code><![CDATA[Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => $targetPath, 'trashPath' => $sourcePath])]]></code>
<code><![CDATA[getAppValue]]></code>
<code><![CDATA[getUserFolder]]></code>
<code><![CDATA[getUserFolder]]></code>
diff --git a/lib/public/Files/Cache/CacheEntriesRemovedEvent.php b/lib/public/Files/Cache/CacheEntriesRemovedEvent.php
new file mode 100644
index 00000000000..277b7ee4ba6
--- /dev/null
+++ b/lib/public/Files/Cache/CacheEntriesRemovedEvent.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Files\Cache;
+
+use OCP\EventDispatcher\Event;
+
+/**
+ * Meta-event wrapping multiple CacheEntryRemovedEvent for when an existing
+ * entry in the cache gets removed.
+ *
+ * @since 32.0.0
+ */
+class CacheEntriesRemovedEvent extends Event {
+ /**
+ * @param CacheEntryRemovedEvent[] $cacheEntryRemovedEvents
+ */
+ public function __construct(private readonly array $cacheEntryRemovedEvents) {}
+
+ /**
+ * @return CacheEntryRemovedEvent[]
+ */
+ public function getCacheEntryRemovedEvents(): array {
+ return $this->cacheEntryRemovedEvents;
+ }
+}