aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/lib/Listener
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2024-03-12 18:47:14 +0100
committerLouis Chemineau <louis@chmn.me>2024-03-14 10:55:44 +0100
commit2de9880d79adeeab0e0a01ce3992de404a0c274d (patch)
tree1665d95b3fe23d64a2cd111acd64c90cc4e2658e /apps/files/lib/Listener
parentd9e09d5883e6cca4c61c874e1518dc92dd0a1bde (diff)
downloadnextcloud-server-2de9880d79adeeab0e0a01ce3992de404a0c274d.tar.gz
nextcloud-server-2de9880d79adeeab0e0a01ce3992de404a0c274d.zip
fix(files): Do not require files_trashbin in live photo sync listener
Fix https://github.com/nextcloud/server/issues/43299 Signed-off-by: Louis Chemineau <louis@chmn.me>
Diffstat (limited to 'apps/files/lib/Listener')
-rw-r--r--apps/files/lib/Listener/SyncLivePhotosListener.php148
1 files changed, 17 insertions, 131 deletions
diff --git a/apps/files/lib/Listener/SyncLivePhotosListener.php b/apps/files/lib/Listener/SyncLivePhotosListener.php
index 8f8234428d6..37a0eadc5ac 100644
--- a/apps/files/lib/Listener/SyncLivePhotosListener.php
+++ b/apps/files/lib/Listener/SyncLivePhotosListener.php
@@ -24,9 +24,7 @@ declare(strict_types=1);
namespace OCA\Files\Listener;
-use OCA\Files_Trashbin\Events\BeforeNodeRestoredEvent;
-use OCA\Files_Trashbin\Trash\ITrashItem;
-use OCA\Files_Trashbin\Trash\ITrashManager;
+use OCA\Files\Service\LivePhotosService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Exceptions\AbortedEventException;
@@ -39,10 +37,7 @@ use OCP\Files\Events\Node\NodeCopiedEvent;
use OCP\Files\Folder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
-use OCP\Files\NotPermittedException;
-use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
use OCP\FilesMetadata\IFilesMetadataManager;
-use OCP\IUserSession;
/**
* @template-implements IEventListener<Event>
@@ -52,37 +47,40 @@ class SyncLivePhotosListener implements IEventListener {
private array $pendingRenames = [];
/** @var Array<int, bool> */
private array $pendingDeletion = [];
- /** @var Array<int, bool> */
- private array $pendingRestores = [];
public function __construct(
private ?Folder $userFolder,
- private ?IUserSession $userSession,
- private ITrashManager $trashManager,
private IFilesMetadataManager $filesMetadataManager,
+ private LivePhotosService $livePhotosService,
) {
}
public function handle(Event $event): void {
- if ($this->userFolder === null || $this->userSession === null) {
+ if ($this->userFolder === null) {
return;
}
- $peerFile = null;
+ $peerFileId = null;
+
if ($event instanceof BeforeNodeRenamedEvent) {
- $peerFile = $this->getLivePhotoPeer($event->getSource()->getId());
- } elseif ($event instanceof BeforeNodeRestoredEvent) {
- $peerFile = $this->getLivePhotoPeer($event->getSource()->getId());
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getSource()->getId());
} elseif ($event instanceof BeforeNodeDeletedEvent) {
- $peerFile = $this->getLivePhotoPeer($event->getNode()->getId());
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getNode()->getId());
} elseif ($event instanceof CacheEntryRemovedEvent) {
- $peerFile = $this->getLivePhotoPeer($event->getFileId());
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getFileId());
} elseif ($event instanceof BeforeNodeCopiedEvent || $event instanceof NodeCopiedEvent) {
- $peerFile = $this->getLivePhotoPeer($event->getSource()->getId());
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getSource()->getId());
+ }
+
+ if ($peerFileId === null) {
+ return; // Not a live photo.
}
+ // Check the user's folder.
+ $peerFile = $this->userFolder->getFirstNodeById($peerFileId);
+
if ($peerFile === null) {
- return; // not a Live Photo
+ return; // Peer file not found.
}
if ($event instanceof BeforeNodeRenamedEvent) {
@@ -91,8 +89,6 @@ class SyncLivePhotosListener implements IEventListener {
$this->handleDeletion($event, $peerFile);
} elseif ($event instanceof CacheEntryRemovedEvent) {
$peerFile->delete();
- } elseif ($event instanceof BeforeNodeRestoredEvent) {
- $this->handleRestore($event, $peerFile);
} elseif ($event instanceof BeforeNodeCopiedEvent) {
$this->handleMove($event, $peerFile, true);
} elseif ($event instanceof NodeCopiedEvent) {
@@ -208,114 +204,4 @@ class SyncLivePhotosListener implements IEventListener {
}
return;
}
-
- /**
- * During restore event, we trigger another recursive restore on the peer file.
- * Restore operations on the .mov file directly are currently blocked.
- * The event listener being singleton, we can store the current state
- * of pending restores inside the 'pendingRestores' property,
- * to prevent infinite recursivity.
- */
- private function handleRestore(BeforeNodeRestoredEvent $event, Node $peerFile): void {
- $sourceFile = $event->getSource();
-
- if ($sourceFile->getMimetype() === 'video/quicktime') {
- if (isset($this->pendingRestores[$peerFile->getId()])) {
- unset($this->pendingRestores[$peerFile->getId()]);
- return;
- } else {
- $event->abortOperation(new NotPermittedException("Cannot restore the video part of a live photo"));
- }
- } else {
- $user = $this->userSession->getUser();
- if ($user === null) {
- return;
- }
-
- $peerTrashItem = $this->trashManager->getTrashNodeById($user, $peerFile->getId());
- // Peer file is not in the bin, no need to restore it.
- if ($peerTrashItem === null) {
- return;
- }
-
- $trashRoot = $this->trashManager->listTrashRoot($user);
- $trashItem = $this->getTrashItem($trashRoot, $peerFile->getInternalPath());
-
- if ($trashItem === null) {
- $event->abortOperation(new NotFoundException("Couldn't find peer file in trashbin"));
- }
-
- $this->pendingRestores[$sourceFile->getId()] = true;
- try {
- $this->trashManager->restoreItem($trashItem);
- } catch (\Throwable $ex) {
- $event->abortOperation($ex);
- }
- }
- }
-
- /**
- * Helper method to get the associated live photo file.
- * We first look for it in the user folder, and if we
- * cannot find it here, we look for it in the user's trashbin.
- */
- private function getLivePhotoPeer(int $nodeId): ?Node {
- if ($this->userFolder === null || $this->userSession === null) {
- return null;
- }
-
- try {
- $metadata = $this->filesMetadataManager->getMetadata($nodeId);
- } catch (FilesMetadataNotFoundException $ex) {
- return null;
- }
-
- if (!$metadata->hasKey('files-live-photo')) {
- return null;
- }
-
- $peerFileId = (int)$metadata->getString('files-live-photo');
-
- // Check the user's folder.
- $node = $this->userFolder->getFirstNodeById($peerFileId);
- if ($node) {
- return $node;
- }
-
- // Check the user's trashbin.
- $user = $this->userSession->getUser();
- if ($user !== null) {
- $peerFile = $this->trashManager->getTrashNodeById($user, $peerFileId);
- if ($peerFile !== null) {
- return $peerFile;
- }
- }
-
- $metadata->unset('files-live-photo');
- return null;
- }
-
- /**
- * There is currently no method to restore a file based on its fileId or path.
- * So we have to manually find a ITrashItem from the trash item list.
- * TODO: This should be replaced by a proper method in the TrashManager.
- */
- private function getTrashItem(array $trashFolder, string $path): ?ITrashItem {
- foreach($trashFolder as $trashItem) {
- if (str_starts_with($path, "files_trashbin/files".$trashItem->getTrashPath())) {
- if ($path === "files_trashbin/files".$trashItem->getTrashPath()) {
- return $trashItem;
- }
-
- if ($trashItem instanceof Folder) {
- $node = $this->getTrashItem($trashItem->getDirectoryListing(), $path);
- if ($node !== null) {
- return $node;
- }
- }
- }
- }
-
- return null;
- }
}