|
|
|
|
@ -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'); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|