From cabedbf9c384ddf1f75bd32d3efa0f1d4aa2a3b8 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 12 Dec 2024 14:28:09 +0100 Subject: [PATCH] Revert "[stable30] fix: Handle copy of folders containing live photos" --- apps/dav/lib/Connector/Sabre/Directory.php | 8 +- .../lib/Listener/SyncLivePhotosListener.php | 184 +++++++----------- .../Listener/VersionStorageMoveListener.php | 3 +- cypress/e2e/files/FilesUtils.ts | 2 +- cypress/e2e/files/LivePhotosUtils.ts | 107 ---------- cypress/e2e/files/live_photos.cy.ts | 120 +++++++----- lib/private/Files/Node/HookConnector.php | 6 +- 7 files changed, 141 insertions(+), 289 deletions(-) delete mode 100644 cypress/e2e/files/LivePhotosUtils.ts diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index 8f63745540373..d56f56890cc7f 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -445,13 +445,7 @@ public function copyInto($targetName, $sourcePath, INode $sourceNode) { throw new InvalidPath($ex->getMessage()); } - $copyOkay = $this->fileView->copy($sourcePath, $destinationPath); - - if (!$copyOkay) { - throw new \Sabre\DAV\Exception\Forbidden('Copy did not proceed'); - } - - return true; + return $this->fileView->copy($sourcePath, $destinationPath); } catch (StorageNotAvailableException $e) { throw new ServiceUnavailable($e->getMessage(), $e->getCode(), $e); } catch (ForbiddenException $ex) { diff --git a/apps/files/lib/Listener/SyncLivePhotosListener.php b/apps/files/lib/Listener/SyncLivePhotosListener.php index 6df9b8d6e95a4..02cf85f991708 100644 --- a/apps/files/lib/Listener/SyncLivePhotosListener.php +++ b/apps/files/lib/Listener/SyncLivePhotosListener.php @@ -8,23 +8,18 @@ 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; use OCP\EventDispatcher\IEventListener; use OCP\Exceptions\AbortedEventException; use OCP\Files\Cache\CacheEntryRemovedEvent; +use OCP\Files\Events\Node\AbstractNodesEvent; 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; @@ -42,8 +37,6 @@ public function __construct( private ?Folder $userFolder, private IFilesMetadataManager $filesMetadataManager, private LivePhotosService $livePhotosService, - private IRootFolder $rootFolder, - private View $view, ) { } @@ -52,47 +45,61 @@ public function handle(Event $event): void { return; } - 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()); - } + $peerFileId = null; - if ($peerFileId === null) { - return; // Not a live photo. - } + 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()); + } - // Check the user's folder. - $peerFile = $this->userFolder->getFirstNodeById($peerFileId); + if ($peerFileId === null) { + return; // Not a live photo. + } - if ($peerFile === null) { - return; // Peer file not found. - } + // Check the user's folder. + $peerFile = $this->userFolder->getFirstNodeById($peerFileId); - if ($event instanceof BeforeNodeRenamedEvent) { - $this->runMoveOrCopyChecks($event->getSource(), $event->getTarget(), $peerFile); - $this->handleMove($event->getSource(), $event->getTarget(), $peerFile); - } elseif ($event instanceof BeforeNodeDeletedEvent) { - $this->handleDeletion($event, $peerFile); - } elseif ($event instanceof CacheEntryRemovedEvent) { - $peerFile->delete(); - } + 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); } } - private function runMoveOrCopyChecks(Node $sourceFile, Node $targetFile, Node $peerFile): void { + /** + * During rename events, which also include move operations, + * we rename the peer file using the same name. + * The event listener being singleton, we can store the current state + * 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(); $targetParent = $targetFile->getParent(); $sourceExtension = $sourceFile->getExtension(); $peerFileExtension = $peerFile->getExtension(); $targetName = $targetFile->getName(); - $peerTargetName = substr($targetName, 0, -strlen($sourceExtension)) . $peerFileExtension; if (!str_ends_with($targetName, "." . $sourceExtension)) { throw new AbortedEventException('Cannot change the extension of a Live Photo'); @@ -104,31 +111,15 @@ private function runMoveOrCopyChecks(Node $sourceFile, Node $targetFile, Node $p } 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) { - } - } - } - - /** - * During rename events, which also include move operations, - * we rename the peer file using the same name. - * The event listener being singleton, we can store the current state - * of pending renames inside the 'pendingRenames' property, - * to prevent infinite recursive. - */ - private function handleMove(Node $sourceFile, Node $targetFile, Node $peerFile): void { - $targetParent = $targetFile->getParent(); - $sourceExtension = $sourceFile->getExtension(); - $peerFileExtension = $peerFile->getExtension(); - $targetName = $targetFile->getName(); $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) { + } // in case the rename was initiated from this listener, we stop right now - if (in_array($peerFile->getId(), $this->pendingRenames)) { + if ($prepForCopyOnly || in_array($peerFile->getId(), $this->pendingRenames)) { return; } @@ -139,37 +130,39 @@ private function handleMove(Node $sourceFile, Node $targetFile, Node $peerFile): throw new AbortedEventException($ex->getMessage()); } - $this->pendingRenames = array_diff($this->pendingRenames, [$sourceFile->getId()]); + array_diff($this->pendingRenames, [$sourceFile->getId()]); } /** * 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(File $sourceFile, File $targetFile, File $peerFile): void { + private function handleCopy(NodeCopiedEvent $event, Node $peerFile): void { + $sourceFile = $event->getSource(); $sourceExtension = $sourceFile->getExtension(); $peerFileExtension = $peerFile->getExtension(); + $targetFile = $event->getTarget(); $targetParent = $targetFile->getParent(); $targetName = $targetFile->getName(); $peerTargetName = substr($targetName, 0, -strlen($sourceExtension)) . $peerFileExtension; - - 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); - } - + /** + * 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); /** @var FilesMetadata $targetMetadata */ $targetMetadata = $this->filesMetadataManager->getMetadata($targetFile->getId(), true); $targetMetadata->setStorageId($targetFile->getStorage()->getCache()->getNumericStorageId()); - $targetMetadata->setString('files-live-photo', (string)$targetPeerFile->getId()); + $targetMetadata->setString('files-live-photo', (string)$newPeerFile->getId()); $this->filesMetadataManager->saveMetadata($targetMetadata); /** @var FilesMetadata $peerMetadata */ - $peerMetadata = $this->filesMetadataManager->getMetadata($targetPeerFile->getId(), true); - $peerMetadata->setStorageId($targetPeerFile->getStorage()->getCache()->getNumericStorageId()); + $peerMetadata = $this->filesMetadataManager->getMetadata($newPeerFile->getId(), true); + $peerMetadata->setStorageId($newPeerFile->getStorage()->getCache()->getNumericStorageId()); $peerMetadata->setString('files-live-photo', (string)$targetFile->getId()); $this->filesMetadataManager->saveMetadata($peerMetadata); } @@ -200,47 +193,4 @@ private function handleDeletion(BeforeNodeDeletedEvent $event, Node $peerFile): } 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->runMoveOrCopyChecks($sourceNode, $targetNode, $peerFile); - } elseif ($event instanceof NodeCopiedEvent) { - $this->handleCopy($sourceNode, $targetNode, $peerFile); - } - } else { - throw new Exception('Source and target type are not matching'); - } - } } diff --git a/apps/files_versions/lib/Listener/VersionStorageMoveListener.php b/apps/files_versions/lib/Listener/VersionStorageMoveListener.php index 8bf1d4dce7bfa..b4b00108e43d8 100644 --- a/apps/files_versions/lib/Listener/VersionStorageMoveListener.php +++ b/apps/files_versions/lib/Listener/VersionStorageMoveListener.php @@ -11,7 +11,6 @@ use Exception; use OC\Files\Node\NonExistingFile; -use OC\Files\Node\NonExistingFolder; use OCA\Files_Versions\Versions\IVersionBackend; use OCA\Files_Versions\Versions\IVersionManager; use OCA\Files_Versions\Versions\IVersionsImporterBackend; @@ -131,7 +130,7 @@ private function handleMoveOrCopy(Event $event, IUser $user, File $source, File } private function getNodeStorage(Node $node): IStorage { - if ($node instanceof NonExistingFile || $node instanceof NonExistingFolder) { + if ($node instanceof NonExistingFile) { return $node->getParent()->getStorage(); } else { return $node->getStorage(); diff --git a/cypress/e2e/files/FilesUtils.ts b/cypress/e2e/files/FilesUtils.ts index 4fba37fbc5905..7372d7366af4f 100644 --- a/cypress/e2e/files/FilesUtils.ts +++ b/cypress/e2e/files/FilesUtils.ts @@ -151,7 +151,7 @@ export const createFolder = (folderName: string) => { // TODO: replace by proper data-cy selectors cy.get('[data-cy-upload-picker] .action-item__menutoggle').first().click() - cy.get('[data-cy-upload-picker-menu-entry="newFolder"] button').click() + cy.contains('.upload-picker__menu-entry button', 'New folder').click() cy.get('[data-cy-files-new-node-dialog]').should('be.visible') cy.get('[data-cy-files-new-node-dialog-input]').type(`{selectall}${folderName}`) cy.get('[data-cy-files-new-node-dialog-submit]').click() diff --git a/cypress/e2e/files/LivePhotosUtils.ts b/cypress/e2e/files/LivePhotosUtils.ts deleted file mode 100644 index 6b0015affce38..0000000000000 --- a/cypress/e2e/files/LivePhotosUtils.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -import type { User } from '@nextcloud/cypress' - -type SetupInfo = { - snapshot: string - jpgFileId: number - movFileId: number - fileName: string - user: User -} - -/** - * - * @param user - * @param fileName - * @param domain - * @param requesttoken - * @param metadata - */ -function setMetadata(user: User, fileName: string, requesttoken: string, metadata: object) { - cy.url().then(url => { - const hostname = new URL(url).hostname - cy.request({ - method: 'PROPPATCH', - url: `http://${hostname}/remote.php/dav/files/${user.userId}/${fileName}`, - auth: { user: user.userId, pass: user.password }, - headers: { - requesttoken, - }, - body: ` - - - - ${Object.entries(metadata).map(([key, value]) => `<${key}>${value}`).join('\n')} - - - `, - }) - }) - -} - -/** - * - * @param enable - */ -export function setShowHiddenFiles(enable: boolean) { - cy.get('[data-cy-files-navigation-settings-button]').click() - // Force:true because the checkbox is hidden by the pretty UI. - if (enable) { - cy.get('[data-cy-files-settings-setting="show_hidden"] input').check({ force: true }) - } else { - cy.get('[data-cy-files-settings-setting="show_hidden"] input').uncheck({ force: true }) - } - cy.get('[data-cy-files-navigation-settings]').type('{esc}') -} - -/** - * - */ -export function setupLivePhotos(): Cypress.Chainable { - return cy.task('getVariable', { key: 'live-photos-data' }) - .then((_setupInfo) => { - const setupInfo = _setupInfo as SetupInfo || {} - if (setupInfo.snapshot) { - cy.restoreState(setupInfo.snapshot) - } else { - let requesttoken: string - - setupInfo.fileName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10) - - cy.createRandomUser().then(_user => { setupInfo.user = _user }) - - cy.then(() => { - cy.uploadContent(setupInfo.user, new Blob(['jpg file'], { type: 'image/jpg' }), 'image/jpg', `/${setupInfo.fileName}.jpg`) - .then(response => { setupInfo.jpgFileId = parseInt(response.headers['oc-fileid']) }) - cy.uploadContent(setupInfo.user, new Blob(['mov file'], { type: 'video/mov' }), 'video/mov', `/${setupInfo.fileName}.mov`) - .then(response => { setupInfo.movFileId = parseInt(response.headers['oc-fileid']) }) - - cy.login(setupInfo.user) - }) - - cy.visit('/apps/files') - - cy.get('head').invoke('attr', 'data-requesttoken').then(_requesttoken => { requesttoken = _requesttoken as string }) - - cy.then(() => { - setMetadata(setupInfo.user, `${setupInfo.fileName}.jpg`, requesttoken, { 'nc:metadata-files-live-photo': setupInfo.movFileId }) - setMetadata(setupInfo.user, `${setupInfo.fileName}.mov`, requesttoken, { 'nc:metadata-files-live-photo': setupInfo.jpgFileId }) - }) - - cy.then(() => { - cy.saveState().then((value) => { setupInfo.snapshot = value }) - cy.task('setVariable', { key: 'live-photos-data', value: setupInfo }) - }) - } - return cy.then(() => { - cy.login(setupInfo.user) - cy.visit('/apps/files') - return cy.wrap(setupInfo) - }) - }) -} diff --git a/cypress/e2e/files/live_photos.cy.ts b/cypress/e2e/files/live_photos.cy.ts index 8eb4efaaec0e7..659cdc544ed97 100644 --- a/cypress/e2e/files/live_photos.cy.ts +++ b/cypress/e2e/files/live_photos.cy.ts @@ -4,34 +4,75 @@ */ import type { User } from '@nextcloud/cypress' -import { - clickOnBreadcrumbs, - copyFile, - createFolder, - getRowForFile, - getRowForFileId, - moveFile, - navigateToFolder, - renameFile, - triggerActionForFile, - triggerInlineActionForFileId, -} from './FilesUtils' -import { setShowHiddenFiles, setupLivePhotos } from './LivePhotosUtils' +import { clickOnBreadcrumbs, closeSidebar, copyFile, getRowForFile, getRowForFileId, renameFile, triggerActionForFile, triggerInlineActionForFileId } from './FilesUtils' + +/** + * + * @param user + * @param fileName + * @param domain + * @param requesttoken + * @param metadata + */ +function setMetadata(user: User, fileName: string, domain: string, requesttoken: string, metadata: object) { + cy.request({ + method: 'PROPPATCH', + url: `http://${domain}/remote.php/dav/files/${user.userId}/${fileName}`, + auth: { user: user.userId, pass: user.password }, + headers: { + requesttoken, + }, + body: ` + + + + ${Object.entries(metadata).map(([key, value]) => `<${key}>${value}`).join('\n')} + + + `, + }) +} describe('Files: Live photos', { testIsolation: true }, () => { - let user: User + let currentUser: User let randomFileName: string let jpgFileId: number let movFileId: number + let hostname: string + let requesttoken: string + + before(() => { + cy.createRandomUser().then((user) => { + currentUser = user + cy.login(currentUser) + cy.visit('/apps/files') + }) + + cy.url().then(url => { hostname = new URL(url).hostname }) + }) beforeEach(() => { - setupLivePhotos() - .then((setupInfo) => { - user = setupInfo.user - randomFileName = setupInfo.fileName - jpgFileId = setupInfo.jpgFileId - movFileId = setupInfo.movFileId - }) + randomFileName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10) + + cy.uploadContent(currentUser, new Blob(['jpg file'], { type: 'image/jpg' }), 'image/jpg', `/${randomFileName}.jpg`) + .then(response => { jpgFileId = parseInt(response.headers['oc-fileid']) }) + cy.uploadContent(currentUser, new Blob(['mov file'], { type: 'video/mov' }), 'video/mov', `/${randomFileName}.mov`) + .then(response => { movFileId = parseInt(response.headers['oc-fileid']) }) + + cy.login(currentUser) + cy.visit('/apps/files') + + cy.get('head').invoke('attr', 'data-requesttoken').then(_requesttoken => { requesttoken = _requesttoken as string }) + + cy.then(() => { + setMetadata(currentUser, `${randomFileName}.jpg`, hostname, requesttoken, { 'nc:metadata-files-live-photo': movFileId }) + setMetadata(currentUser, `${randomFileName}.mov`, hostname, requesttoken, { 'nc:metadata-files-live-photo': jpgFileId }) + }) + + cy.then(() => { + cy.visit(`/apps/files/files/${jpgFileId}`) // Refresh and scroll to the .jpg file. + closeSidebar() + }) }) it('Only renders the .jpg file', () => { @@ -40,8 +81,12 @@ describe('Files: Live photos', { testIsolation: true }, () => { }) context("'Show hidden files' is enabled", () => { - beforeEach(() => { - setShowHiddenFiles(true) + before(() => { + cy.login(currentUser) + cy.visit('/apps/files') + cy.get('[data-cy-files-navigation-settings-button]').click() + // Force:true because the checkbox is hidden by the pretty UI. + cy.get('[data-cy-files-settings-setting="show_hidden"] input').check({ force: true }) }) it("Shows both files when 'Show hidden files' is enabled", () => { @@ -68,35 +113,6 @@ describe('Files: Live photos', { testIsolation: true }, () => { getRowForFile(`${randomFileName} (copy).mov`).should('have.length', 1) }) - it('Keeps live photo link when copying folder', () => { - createFolder('folder') - moveFile(`${randomFileName}.jpg`, 'folder') - copyFile('folder', '.') - navigateToFolder('folder (copy)') - - getRowForFile(`${randomFileName}.jpg`).should('have.length', 1) - getRowForFile(`${randomFileName}.mov`).should('have.length', 1) - - setShowHiddenFiles(false) - - getRowForFile(`${randomFileName}.jpg`).should('have.length', 1) - getRowForFile(`${randomFileName}.mov`).should('have.length', 0) - }) - - it('Block copying live photo in a folder containing a mov file with the same name', () => { - createFolder('folder') - cy.uploadContent(user, new Blob(['mov file'], { type: 'video/mov' }), 'video/mov', `/folder/${randomFileName}.mov`) - cy.login(user) - cy.visit('/apps/files') - copyFile(`${randomFileName}.jpg`, 'folder') - navigateToFolder('folder') - - cy.get('[data-cy-files-list-row-fileid]').should('have.length', 1) - getRowForFile(`${randomFileName}.mov`).should('have.length', 1) - getRowForFile(`${randomFileName}.jpg`).should('have.length', 0) - getRowForFile(`${randomFileName} (copy).jpg`).should('have.length', 0) - }) - it('Moves files when moving the .jpg', () => { renameFile(`${randomFileName}.jpg`, `${randomFileName}_moved.jpg`) clickOnBreadcrumbs('All files') diff --git a/lib/private/Files/Node/HookConnector.php b/lib/private/Files/Node/HookConnector.php index 48ca61d4033a8..8fd2ffa33695c 100644 --- a/lib/private/Files/Node/HookConnector.php +++ b/lib/private/Files/Node/HookConnector.php @@ -171,7 +171,7 @@ public function postRename($arguments) { public function copy($arguments) { $source = $this->getNodeForPath($arguments['oldpath']); - $target = $this->getNodeForPath($arguments['newpath'], $source instanceof Folder); + $target = $this->getNodeForPath($arguments['newpath']); $this->root->emit('\OC\Files', 'preCopy', [$source, $target]); $this->dispatcher->dispatch('\OCP\Files::preCopy', new GenericEvent([$source, $target])); @@ -203,7 +203,7 @@ public function read($arguments) { $this->dispatcher->dispatchTyped($event); } - private function getNodeForPath(string $path, bool $isDir = false): Node { + private function getNodeForPath(string $path): Node { $info = Filesystem::getView()->getFileInfo($path); if (!$info) { $fullPath = Filesystem::getView()->getAbsolutePath($path); @@ -212,7 +212,7 @@ private function getNodeForPath(string $path, bool $isDir = false): Node { } else { $info = null; } - if ($isDir || Filesystem::is_dir($path)) { + if (Filesystem::is_dir($path)) { return new NonExistingFolder($this->root, $this->view, $fullPath, $info); } else { return new NonExistingFile($this->root, $this->view, $fullPath, $info);