aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2024-11-19 13:04:50 +0100
committerLouis Chemineau <louis@chmn.me>2024-12-05 10:47:57 +0100
commit62163890f7daadbbbc461ce2df438390cb965f02 (patch)
tree1eaadc131032c44e1f27dd0650af599c33795cc3 /apps
parent9ff3ba7ce02cfb76bd1cdb1df97ac7d7e4fda0a6 (diff)
downloadnextcloud-server-62163890f7daadbbbc461ce2df438390cb965f02.tar.gz
nextcloud-server-62163890f7daadbbbc461ce2df438390cb965f02.zip
fix: Handle copy of folders containing live photos
We need to recursively look for live photos in the folder, and then handle them as usual. Signed-off-by: Louis Chemineau <louis@chmn.me>
Diffstat (limited to 'apps')
-rw-r--r--apps/files/lib/Listener/SyncLivePhotosListener.php154
1 files changed, 98 insertions, 56 deletions
diff --git a/apps/files/lib/Listener/SyncLivePhotosListener.php b/apps/files/lib/Listener/SyncLivePhotosListener.php
index 02cf85f9917..2e682cd2575 100644
--- a/apps/files/lib/Listener/SyncLivePhotosListener.php
+++ b/apps/files/lib/Listener/SyncLivePhotosListener.php
@@ -8,6 +8,10 @@ declare(strict_types=1);
namespace OCA\Files\Listener;
+use Exception;
+use OC\Files\Node\NonExistingFile;
+use OC\Files\Node\NonExistingFolder;
+use OC\Files\View;
use OC\FilesMetadata\Model\FilesMetadata;
use OCA\Files\Service\LivePhotosService;
use OCP\EventDispatcher\Event;
@@ -19,7 +23,9 @@ use OCP\Files\Events\Node\BeforeNodeCopiedEvent;
use OCP\Files\Events\Node\BeforeNodeDeletedEvent;
use OCP\Files\Events\Node\BeforeNodeRenamedEvent;
use OCP\Files\Events\Node\NodeCopiedEvent;
+use OCP\Files\File;
use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\FilesMetadata\IFilesMetadataManager;
@@ -37,6 +43,8 @@ class SyncLivePhotosListener implements IEventListener {
private ?Folder $userFolder,
private IFilesMetadataManager $filesMetadataManager,
private LivePhotosService $livePhotosService,
+ private IRootFolder $rootFolder,
+ private View $view,
) {
}
@@ -45,39 +53,37 @@ class SyncLivePhotosListener implements IEventListener {
return;
}
- $peerFileId = null;
-
- if ($event instanceof BeforeNodeRenamedEvent) {
- $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getSource()->getId());
- } elseif ($event instanceof BeforeNodeDeletedEvent) {
- $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getNode()->getId());
- } elseif ($event instanceof CacheEntryRemovedEvent) {
- $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getFileId());
- } elseif ($event instanceof BeforeNodeCopiedEvent || $event instanceof NodeCopiedEvent) {
- $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getSource()->getId());
- }
+ if ($event instanceof BeforeNodeCopiedEvent || $event instanceof NodeCopiedEvent) {
+ $this->handleCopyRecursive($event, $event->getSource(), $event->getTarget());
+ } else {
+ $peerFileId = null;
+
+ if ($event instanceof BeforeNodeRenamedEvent) {
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getSource()->getId());
+ } elseif ($event instanceof BeforeNodeDeletedEvent) {
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getNode()->getId());
+ } elseif ($event instanceof CacheEntryRemovedEvent) {
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($event->getFileId());
+ }
- if ($peerFileId === null) {
- return; // Not a live photo.
- }
+ if ($peerFileId === null) {
+ return; // Not a live photo.
+ }
- // Check the user's folder.
- $peerFile = $this->userFolder->getFirstNodeById($peerFileId);
+ // Check the user's folder.
+ $peerFile = $this->userFolder->getFirstNodeById($peerFileId);
- if ($peerFile === null) {
- return; // Peer file not found.
- }
+ if ($peerFile === null) {
+ return; // Peer file not found.
+ }
- if ($event instanceof BeforeNodeRenamedEvent) {
- $this->handleMove($event, $peerFile, false);
- } elseif ($event instanceof BeforeNodeDeletedEvent) {
- $this->handleDeletion($event, $peerFile);
- } elseif ($event instanceof CacheEntryRemovedEvent) {
- $peerFile->delete();
- } elseif ($event instanceof BeforeNodeCopiedEvent) {
- $this->handleMove($event, $peerFile, true);
- } elseif ($event instanceof NodeCopiedEvent) {
- $this->handleCopy($event, $peerFile);
+ if ($event instanceof BeforeNodeRenamedEvent) {
+ $this->handleMove($event->getSource(), $event->getTarget(), $peerFile, false);
+ } elseif ($event instanceof BeforeNodeDeletedEvent) {
+ $this->handleDeletion($event, $peerFile);
+ } elseif ($event instanceof CacheEntryRemovedEvent) {
+ $peerFile->delete();
+ }
}
}
@@ -88,14 +94,7 @@ class SyncLivePhotosListener implements IEventListener {
* of pending renames inside the 'pendingRenames' property,
* to prevent infinite recursive.
*/
- private function handleMove(AbstractNodesEvent $event, Node $peerFile, bool $prepForCopyOnly = false): void {
- if (!($event instanceof BeforeNodeCopiedEvent) &&
- !($event instanceof BeforeNodeRenamedEvent)) {
- return;
- }
-
- $sourceFile = $event->getSource();
- $targetFile = $event->getTarget();
+ private function handleMove(Node $sourceFile, Node $targetFile, Node $peerFile, bool $prepForCopyOnly = false): void {
$targetParent = $targetFile->getParent();
$sourceExtension = $sourceFile->getExtension();
$peerFileExtension = $peerFile->getExtension();
@@ -112,10 +111,12 @@ class SyncLivePhotosListener implements IEventListener {
}
$peerTargetName = substr($targetName, 0, -strlen($sourceExtension)) . $peerFileExtension;
- try {
- $targetParent->get($peerTargetName);
- throw new AbortedEventException('A file already exist at destination path of the Live Photo');
- } catch (NotFoundException) {
+ if (!($targetParent instanceof NonExistingFolder)) {
+ try {
+ $targetParent->get($peerTargetName);
+ throw new AbortedEventException('A file already exist at destination path of the Live Photo');
+ } catch (NotFoundException) {
+ }
}
// in case the rename was initiated from this listener, we stop right now
@@ -136,33 +137,31 @@ class SyncLivePhotosListener implements IEventListener {
/**
* handle copy, we already know if it is doable from BeforeNodeCopiedEvent, so we just copy the linked file
- *
- * @param NodeCopiedEvent $event
- * @param Node $peerFile
*/
- private function handleCopy(NodeCopiedEvent $event, Node $peerFile): void {
- $sourceFile = $event->getSource();
+ private function handleCopy(File $sourceFile, File $targetFile, File $peerFile): void {
$sourceExtension = $sourceFile->getExtension();
$peerFileExtension = $peerFile->getExtension();
- $targetFile = $event->getTarget();
$targetParent = $targetFile->getParent();
$targetName = $targetFile->getName();
$peerTargetName = substr($targetName, 0, -strlen($sourceExtension)) . $peerFileExtension;
- /**
- * let's use freshly set variable.
- * we copy the file and get its id. We already have the id of the current copy
- * We have everything to update metadata and keep the link between the 2 copies.
- */
- $newPeerFile = $peerFile->copy($targetParent->getPath() . '/' . $peerTargetName);
+
+ if ($targetParent->nodeExists($peerTargetName)) {
+ // If the copy was a folder copy, then the peer file already exists.
+ $targetPeerFile = $targetParent->get($peerTargetName);
+ } else {
+ // If the copy was a file copy, then we need to create the peer file.
+ $targetPeerFile = $peerFile->copy($targetParent->getPath() . '/' . $peerTargetName);
+ }
+
/** @var FilesMetadata $targetMetadata */
$targetMetadata = $this->filesMetadataManager->getMetadata($targetFile->getId(), true);
$targetMetadata->setStorageId($targetFile->getStorage()->getCache()->getNumericStorageId());
- $targetMetadata->setString('files-live-photo', (string)$newPeerFile->getId());
+ $targetMetadata->setString('files-live-photo', (string)$targetPeerFile->getId());
$this->filesMetadataManager->saveMetadata($targetMetadata);
/** @var FilesMetadata $peerMetadata */
- $peerMetadata = $this->filesMetadataManager->getMetadata($newPeerFile->getId(), true);
- $peerMetadata->setStorageId($newPeerFile->getStorage()->getCache()->getNumericStorageId());
+ $peerMetadata = $this->filesMetadataManager->getMetadata($targetPeerFile->getId(), true);
+ $peerMetadata->setStorageId($targetPeerFile->getStorage()->getCache()->getNumericStorageId());
$peerMetadata->setString('files-live-photo', (string)$targetFile->getId());
$this->filesMetadataManager->saveMetadata($peerMetadata);
}
@@ -193,4 +192,47 @@ class SyncLivePhotosListener implements IEventListener {
}
return;
}
+
+ /*
+ * Recursively get all the peer ids of a live photo.
+ * Needed when coping a folder.
+ *
+ * @param BeforeNodeCopiedEvent|NodeCopiedEvent $event
+ */
+ private function handleCopyRecursive(Event $event, Node $sourceNode, Node $targetNode): void {
+ if ($sourceNode instanceof Folder && $targetNode instanceof Folder) {
+ foreach ($sourceNode->getDirectoryListing() as $sourceChild) {
+ if ($event instanceof BeforeNodeCopiedEvent) {
+ if ($sourceChild instanceof Folder) {
+ $targetChild = new NonExistingFolder($this->rootFolder, $this->view, $targetNode->getPath() . '/' . $sourceChild->getName(), null, $targetNode);
+ } else {
+ $targetChild = new NonExistingFile($this->rootFolder, $this->view, $targetNode->getPath() . '/' . $sourceChild->getName(), null, $targetNode);
+ }
+ } elseif ($event instanceof NodeCopiedEvent) {
+ $targetChild = $targetNode->get($sourceChild->getName());
+ } else {
+ throw new Exception('Event is type is not supported');
+ }
+
+ $this->handleCopyRecursive($event, $sourceChild, $targetChild);
+ }
+ } elseif ($sourceNode instanceof File && $targetNode instanceof File) {
+ $peerFileId = $this->livePhotosService->getLivePhotoPeerId($sourceNode->getId());
+ if ($peerFileId === null) {
+ return;
+ }
+ $peerFile = $this->userFolder->getFirstNodeById($peerFileId);
+ if ($peerFile === null) {
+ return;
+ }
+
+ if ($event instanceof BeforeNodeCopiedEvent) {
+ $this->handleMove($sourceNode, $targetNode, $peerFile, true);
+ } elseif ($event instanceof NodeCopiedEvent) {
+ $this->handleCopy($sourceNode, $targetNode, $peerFile);
+ }
+ } else {
+ throw new Exception('Source and target type are not matching');
+ }
+ }
}