Merge pull request #15659 from nextcloud/version-backend-use

add way for version backends to programmatically specify if they should be used
This commit is contained in:
Morris Jobke 2019-05-21 21:00:15 +02:00 committed by GitHub
commit 553543e85c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 129 additions and 12 deletions

View File

@ -25,12 +25,24 @@ use OCP\Files\File;
use OCP\Files\FileInfo; use OCP\Files\FileInfo;
use OCP\Files\NotFoundException; use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\Storage\IStorage;
use OCP\IUser; use OCP\IUser;
/** /**
* @since 15.0.0 * @since 15.0.0
*/ */
interface IVersionBackend { 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 * Get all versions for a file
* *

View File

@ -29,6 +29,7 @@ use OCP\Files\FileInfo;
use OCP\Files\Folder; use OCP\Files\Folder;
use OCP\Files\IRootFolder; use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException; use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
use OCP\IUser; use OCP\IUser;
use OCP\IUserManager; use OCP\IUserManager;
@ -43,6 +44,10 @@ class LegacyVersionsBackend implements IVersionBackend {
$this->userManager = $userManager; $this->userManager = $userManager;
} }
public function useBackendForStorage(IStorage $storage): bool {
return true;
}
public function getVersionsForFile(IUser $user, FileInfo $file): array { public function getVersionsForFile(IUser $user, FileInfo $file): array {
$storage = $file->getStorage(); $storage = $file->getStorage();
if ($storage->instanceOfStorage(SharedStorage::class)) { if ($storage->instanceOfStorage(SharedStorage::class)) {

View File

@ -27,15 +27,18 @@ use OCP\Files\Storage\IStorage;
use OCP\IUser; use OCP\IUser;
class VersionManager implements IVersionManager { class VersionManager implements IVersionManager {
/** @var IVersionBackend[] */ /** @var (IVersionBackend[])[] */
private $backends = []; private $backends = [];
public function registerBackend(string $storageType, IVersionBackend $backend) { 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 { private function getBackends(): array {
return $this->backends; return $this->backends;
@ -49,20 +52,29 @@ class VersionManager implements IVersionManager {
public function getBackendForStorage(IStorage $storage): IVersionBackend { public function getBackendForStorage(IStorage $storage): IVersionBackend {
$fullType = get_class($storage); $fullType = get_class($storage);
$backends = $this->getBackends(); $backends = $this->getBackends();
$foundType = array_reduce(array_keys($backends), function ($type, $registeredType) use ($storage) {
$foundType = '';
$foundBackend = null;
foreach ($backends as $type => $backendsForType) {
if ( if (
$storage->instanceOfStorage($registeredType) && $storage->instanceOfStorage($type) &&
($type === '' || is_subclass_of($registeredType, $type)) ($foundType === '' || is_subclass_of($type, $foundType))
) { ) {
return $registeredType; foreach ($backendsForType as $backend) {
} else { /** @var IVersionBackend $backend */
return $type; if ($backend->useBackendForStorage($storage)) {
$foundBackend = $backend;
$foundType = $type;
} }
}, ''); }
if ($foundType === '') { }
}
if ($foundType === '' || $foundBackend === null) {
throw new BackendNotFoundException("Version backend for $fullType not found"); throw new BackendNotFoundException("Version backend for $fullType not found");
} else { } else {
return $backends[$foundType]; return $foundBackend;
} }
} }
@ -90,4 +102,8 @@ class VersionManager implements IVersionManager {
$backend = $this->getBackendForStorage($sourceFile->getStorage()); $backend = $this->getBackendForStorage($sourceFile->getStorage());
return $backend->getVersionFile($user, $sourceFile, $revision); return $backend->getVersionFile($user, $sourceFile, $revision);
} }
public function useBackendForStorage(IStorage $storage): bool {
return false;
}
} }

View File

@ -0,0 +1,84 @@
<?php declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 Robin Appelman <robin@icewind.nl>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
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)));
}
}