From 899256779b42767907fb9d84d971a044b53dce34 Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Mon, 20 Mar 2023 19:37:14 +0100 Subject: [PATCH] Wrap-up changes for updated subfolders When a subfolder is updated, the changes were not saved. Changed folders are now tracked and changes metadata update are done for the all the changed folders instead of the top one. Signed-off-by: Louis Chemineau --- lib/Controller/LockingController.php | 9 ++++++-- lib/Controller/MetaDataController.php | 4 ++-- lib/FileService.php | 2 +- lib/IMetaDataStorage.php | 20 +++++++++++++++- lib/MetaDataStorage.php | 33 ++++++++++++++++++++++++++- lib/RollbackService.php | 2 ++ 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/lib/Controller/LockingController.php b/lib/Controller/LockingController.php index a0640930..2dfd1459 100644 --- a/lib/Controller/LockingController.php +++ b/lib/Controller/LockingController.php @@ -151,9 +151,14 @@ public function unlockFolder(int $id, ?string $shareToken = null): DataResponse throw new OCSForbiddenException($this->l10n->t('You are not allowed to remove the lock')); } - $this->fileService->finalizeChanges($nodes[0]); + $touchFoldersIds = $this->metaDataStorage->getTouchedFolders($token); + foreach ($touchFoldersIds as $folderId) { + $this->fileService->finalizeChanges($userFolder->getById($folderId)[0]); - $this->metaDataStorage->saveIntermediateFile($ownerId, $id); + $this->metaDataStorage->saveIntermediateFile($ownerId, $folderId); + } + + $this->metaDataStorage->clearTouchedFolders($token); try { $this->lockManager->unlockFile($id, $token); diff --git a/lib/Controller/MetaDataController.php b/lib/Controller/MetaDataController.php index f772de7d..2c839c3b 100644 --- a/lib/Controller/MetaDataController.php +++ b/lib/Controller/MetaDataController.php @@ -136,7 +136,7 @@ public function updateMetaData(int $id, string $metaData): DataResponse { } try { - $this->metaDataStorage->updateMetaDataIntoIntermediateFile($this->userId, $id, $metaData); + $this->metaDataStorage->updateMetaDataIntoIntermediateFile($this->userId, $id, $metaData, $e2eToken); } catch (MissingMetaDataException $e) { throw new OCSNotFoundException($this->l10n->t('Metadata-file does not exist')); } catch (NotFoundException $e) { @@ -201,7 +201,7 @@ public function addMetadataFileDrop(int $id, string $fileDrop, ?string $shareTok $decodedMetadata['filedrop'] = array_merge($decodedMetadata['filedrop'] ?? [], $decodedFileDrop); $encodedMetadata = json_encode($decodedMetadata); - $this->metaDataStorage->updateMetaDataIntoIntermediateFile($ownerId, $id, $encodedMetadata); + $this->metaDataStorage->updateMetaDataIntoIntermediateFile($ownerId, $id, $encodedMetadata, $e2eToken); } catch (MissingMetaDataException $e) { throw new OCSNotFoundException($this->l10n->t('Metadata-file does not exist')); } catch (NotFoundException $e) { diff --git a/lib/FileService.php b/lib/FileService.php index ea21df26..266a9980 100644 --- a/lib/FileService.php +++ b/lib/FileService.php @@ -56,7 +56,7 @@ public function revertChanges(Folder $folder): bool { } /** - * @return bool Whether this operation changed any files + * @return bool Move and delete temporary files suffixed by .e2e-to-save and .e2e-to-delete */ public function finalizeChanges(Folder $folder): bool { $intermediateFiles = $this->getIntermediateFiles($folder); diff --git a/lib/IMetaDataStorage.php b/lib/IMetaDataStorage.php index 348c8c81..a20e9043 100644 --- a/lib/IMetaDataStorage.php +++ b/lib/IMetaDataStorage.php @@ -58,7 +58,7 @@ public function setMetaDataIntoIntermediateFile(string $userId, int $id, string * @throws NotFoundException * @throws MissingMetaDataException */ - public function updateMetaDataIntoIntermediateFile(string $userId, int $id, string $fileKey): void; + public function updateMetaDataIntoIntermediateFile(string $userId, int $id, string $fileKey, string $token = null): void; /** * Moves intermediate metadata file to final file @@ -84,4 +84,22 @@ public function deleteIntermediateFile(string $userId, int $id): void; * @throws NotFoundException */ public function deleteMetaData(string $userId, int $id): void; + + /** + * Return the list of folders marked as touched. + * + * @return int[] + * + * @throws NotPermittedException + * @throws NotFoundException + */ + public function getTouchedFolders(string $token): array; + + /** + * Clear the list of touched folder for a token. + * + * @throws NotPermittedException + * @throws NotFoundException + */ + public function clearTouchedFolders(?string $token): void; } diff --git a/lib/MetaDataStorage.php b/lib/MetaDataStorage.php index 4958f339..c09a2f7f 100644 --- a/lib/MetaDataStorage.php +++ b/lib/MetaDataStorage.php @@ -106,7 +106,7 @@ public function setMetaDataIntoIntermediateFile(string $userId, int $id, string /** * @inheritDoc */ - public function updateMetaDataIntoIntermediateFile(string $userId, int $id, string $fileKey): void { + public function updateMetaDataIntoIntermediateFile(string $userId, int $id, string $fileKey, string $token = null): void { // ToDo check signature for race condition $this->verifyFolderStructure(); $this->verifyOwner($userId, $id); @@ -136,6 +136,18 @@ public function updateMetaDataIntoIntermediateFile(string $userId, int $id, stri $intermediateMetaDataFile ->putContent($fileKey); + + // To ease the wrap-up process during unlocking, + // we keep track of every folder for which metadata was updated. + // For that we create a file named /tokens/$token/$folderId. + if ($token !== null) { + try { + $tokenFolder = $this->appData->getFolder("/tokens/$token"); + } catch (NotFoundException $ex) { + $tokenFolder = $this->appData->newFolder("/tokens/$token"); + } + $tokenFolder->newFile("$id", ''); + } } /** @@ -308,4 +320,23 @@ protected function getLegacyOwnerPath(string $userId, int $id):string { return $ownerNodes[0]->getPath(); } + + /** + * @inheritDoc + */ + public function getTouchedFolders(string $token): array { + return array_map( + fn (ISimpleFile $file) => (int)$file->getName(), + $this->appData->getFolder("/tokens")->getFolder($token)->getDirectoryListing() + ); + } + + /** + * @inheritDoc + */ + public function clearTouchedFolders(?string $token): void { + if ($token !== null) { + $this->appData->getFolder("/tokens/$token")->delete(); + } + } } diff --git a/lib/RollbackService.php b/lib/RollbackService.php index 4a154e34..9cc1f1d1 100644 --- a/lib/RollbackService.php +++ b/lib/RollbackService.php @@ -117,6 +117,8 @@ public function rollbackOlderThan(int $olderThanTimestamp, ?int $limit = null): continue; } + $this->metaDataStorage->clearTouchedFolders($lock->getToken()); + $this->lockMapper->delete($lock); } }