diff --git a/apps/files_versions/lib/Versions/IVersionBackend.php b/apps/files_versions/lib/Versions/IVersionBackend.php index 616d535f7f..913745c985 100644 --- a/apps/files_versions/lib/Versions/IVersionBackend.php +++ b/apps/files_versions/lib/Versions/IVersionBackend.php @@ -25,12 +25,24 @@ use OCP\Files\File; use OCP\Files\FileInfo; use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; +use OCP\Files\Storage\IStorage; use OCP\IUser; /** * @since 15.0.0 */ interface IVersionBackend { + /** + * Whether or not this version backend should be used for a storage + * + * If false is returned then the next applicable backend will be used + * + * @param IStorage $storage + * @return bool + * @since 17.0.0 + */ + public function useBackendForStorage(IStorage $storage): bool; + /** * Get all versions for a file * diff --git a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php index 99424f5456..aceddef29d 100644 --- a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php +++ b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php @@ -29,6 +29,7 @@ use OCP\Files\FileInfo; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; +use OCP\Files\Storage\IStorage; use OCP\IUser; use OCP\IUserManager; @@ -43,6 +44,10 @@ class LegacyVersionsBackend implements IVersionBackend { $this->userManager = $userManager; } + public function useBackendForStorage(IStorage $storage): bool { + return true; + } + public function getVersionsForFile(IUser $user, FileInfo $file): array { $storage = $file->getStorage(); if ($storage->instanceOfStorage(SharedStorage::class)) { diff --git a/apps/files_versions/lib/Versions/VersionManager.php b/apps/files_versions/lib/Versions/VersionManager.php index 757b600271..99fa9f62bc 100644 --- a/apps/files_versions/lib/Versions/VersionManager.php +++ b/apps/files_versions/lib/Versions/VersionManager.php @@ -27,15 +27,18 @@ use OCP\Files\Storage\IStorage; use OCP\IUser; class VersionManager implements IVersionManager { - /** @var IVersionBackend[] */ + /** @var (IVersionBackend[])[] */ private $backends = []; public function registerBackend(string $storageType, IVersionBackend $backend) { - $this->backends[$storageType] = $backend; + if (!isset($this->backends[$storageType])) { + $this->backends[$storageType] = []; + } + $this->backends[$storageType][] = $backend; } /** - * @return IVersionBackend[] + * @return (IVersionBackend[])[] */ private function getBackends(): array { return $this->backends; @@ -49,20 +52,29 @@ class VersionManager implements IVersionManager { public function getBackendForStorage(IStorage $storage): IVersionBackend { $fullType = get_class($storage); $backends = $this->getBackends(); - $foundType = array_reduce(array_keys($backends), function ($type, $registeredType) use ($storage) { + + $foundType = ''; + $foundBackend = null; + + foreach ($backends as $type => $backendsForType) { if ( - $storage->instanceOfStorage($registeredType) && - ($type === '' || is_subclass_of($registeredType, $type)) + $storage->instanceOfStorage($type) && + ($foundType === '' || is_subclass_of($type, $foundType)) ) { - return $registeredType; - } else { - return $type; + foreach ($backendsForType as $backend) { + /** @var IVersionBackend $backend */ + if ($backend->useBackendForStorage($storage)) { + $foundBackend = $backend; + $foundType = $type; + } + } } - }, ''); - if ($foundType === '') { + } + + if ($foundType === '' || $foundBackend === null) { throw new BackendNotFoundException("Version backend for $fullType not found"); } else { - return $backends[$foundType]; + return $foundBackend; } } @@ -90,4 +102,8 @@ class VersionManager implements IVersionManager { $backend = $this->getBackendForStorage($sourceFile->getStorage()); return $backend->getVersionFile($user, $sourceFile, $revision); } + + public function useBackendForStorage(IStorage $storage): bool { + return false; + } } diff --git a/apps/files_versions/tests/Versions/VersionManagerTest.php b/apps/files_versions/tests/Versions/VersionManagerTest.php new file mode 100644 index 0000000000..25afa7f53e --- /dev/null +++ b/apps/files_versions/tests/Versions/VersionManagerTest.php @@ -0,0 +1,84 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\files_versions\tests\Versions; + +use OC\Files\Storage\Local; +use OCA\Files_Versions\Versions\IVersionBackend; +use OCA\Files_Versions\Versions\VersionManager; +use OCP\Files\Storage\IStorage; +use Test\TestCase; + +class VersionManagerTest extends TestCase { + private function getBackend(bool $shouldUse = true): IVersionBackend { + $backend = $this->createMock(IVersionBackend::class); + $backend->method('useBackendForStorage') + ->willReturn($shouldUse); + return $backend; + } + + private function getStorage(string $class): IStorage { + return $this->getMockBuilder($class) + ->disableOriginalConstructor() + ->setMethodsExcept(['instanceOfStorage']) + ->getMock(); + } + + public function testGetBackendSingle() { + $manager = new VersionManager(); + $backend = $this->getBackend(); + $manager->registerBackend(IStorage::class, $backend); + + $this->assertEquals($backend, $manager->getBackendForStorage($this->getStorage(Local::class))); + } + + public function testGetBackendMoreSpecific() { + $manager = new VersionManager(); + $backend1 = $this->getBackend(); + $backend2 = $this->getBackend(); + $manager->registerBackend(IStorage::class, $backend1); + $manager->registerBackend(Local::class, $backend2); + + $this->assertEquals($backend2, $manager->getBackendForStorage($this->getStorage(Local::class))); + } + + public function testGetBackendNoUse() { + $manager = new VersionManager(); + $backend1 = $this->getBackend(); + $backend2 = $this->getBackend(false); + $manager->registerBackend(IStorage::class, $backend1); + $manager->registerBackend(Local::class, $backend2); + + $this->assertEquals($backend1, $manager->getBackendForStorage($this->getStorage(Local::class))); + } + + public function testGetBackendMultiple() { + $manager = new VersionManager(); + $backend1 = $this->getBackend(); + $backend2 = $this->getBackend(false); + $backend3 = $this->getBackend(); + $manager->registerBackend(IStorage::class, $backend1); + $manager->registerBackend(Local::class, $backend2); + $manager->registerBackend(Local::class, $backend3); + + $this->assertEquals($backend3, $manager->getBackendForStorage($this->getStorage(Local::class))); + } +}