From 6e69881512ad072508f13983ad9c145b48855ce7 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 14 Sep 2017 13:59:09 +0200 Subject: [PATCH] allow apps to control the trash bin Signed-off-by: Bjoern Schiessle --- .../lib/Events/MoveToTrashEvent.php | 73 +++++++++++++++++++ apps/files_trashbin/lib/Storage.php | 46 +++++++++++- apps/files_trashbin/tests/StorageTest.php | 52 ++++++++++--- 3 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 apps/files_trashbin/lib/Events/MoveToTrashEvent.php diff --git a/apps/files_trashbin/lib/Events/MoveToTrashEvent.php b/apps/files_trashbin/lib/Events/MoveToTrashEvent.php new file mode 100644 index 0000000000..185f39f63c --- /dev/null +++ b/apps/files_trashbin/lib/Events/MoveToTrashEvent.php @@ -0,0 +1,73 @@ + + * + * @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_Trashbin\Events; + + +use OCP\Files\Node; +use Symfony\Component\EventDispatcher\Event; + +/** + * Class MoveToTrashEvent + * + * Event to allow other apps to disable the trash bin for specific files + * + * @package OCA\Files_Trashbin\Events + */ +class MoveToTrashEvent extends Event { + + /** @var bool */ + private $moveToTrashBin; + + /** @var Node */ + private $node; + + public function __construct(Node $node) { + $this->moveToTrashBin = true; + $this->node = $node; + } + + /** + * get Node which will be deleted + * + * @return Node + */ + public function getNode() { + return $this->node; + } + + /** + * disable trash bin for this operation + */ + public function disableTrashBin() { + $this->moveToTrashBin = false; + } + + /** + * should the file be moved to the trash bin? + * + * @return bool + */ + public function shouldMoveToTrashBin() { + return $this->moveToTrashBin; + } +} diff --git a/apps/files_trashbin/lib/Storage.php b/apps/files_trashbin/lib/Storage.php index fdc7081b13..cb36b4604c 100644 --- a/apps/files_trashbin/lib/Storage.php +++ b/apps/files_trashbin/lib/Storage.php @@ -28,9 +28,13 @@ namespace OCA\Files_Trashbin; use OC\Files\Filesystem; use OC\Files\Storage\Wrapper\Wrapper; use OC\Files\View; +use OCA\Files_Trashbin\Events\MoveToTrashEvent; use OCP\Encryption\Exceptions\GenericEncryptionException; +use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\ILogger; use OCP\IUserManager; +use Symfony\Component\EventDispatcher\EventDispatcher; class Storage extends Wrapper { @@ -60,18 +64,31 @@ class Storage extends Wrapper { /** @var ILogger */ private $logger; + /** @var EventDispatcher */ + private $eventDispatcher; + + /** @var IRootFolder */ + private $rootFolder; + /** * Storage constructor. * * @param array $parameters * @param IUserManager|null $userManager + * @param ILogger|null $logger + * @param EventDispatcher|null $eventDispatcher + * @param IRootFolder|null $rootFolder */ public function __construct($parameters, IUserManager $userManager = null, - ILogger $logger = null) { + ILogger $logger = null, + EventDispatcher $eventDispatcher = null, + IRootFolder $rootFolder = null) { $this->mountPoint = $parameters['mountPoint']; $this->userManager = $userManager; $this->logger = $logger; + $this->eventDispatcher = $eventDispatcher; + $this->rootFolder = $rootFolder; parent::__construct($parameters); } @@ -200,6 +217,18 @@ class Storage extends Wrapper { * @return bool */ protected function shouldMoveToTrash($path){ + + // check if there is a app which want to disable the trash bin for this file + $fileId = $this->storage->getCache()->getId($path); + $nodes = $this->rootFolder->getById($fileId); + foreach ($nodes as $node) { + $event = $this->createMoveToTrashEvent($node); + $this->eventDispatcher->dispatch('OCA\Files_Trashbin::moveToTrash', $event); + if ($event->shouldMoveToTrashBin() === false) { + return false; + } + } + $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path); $parts = explode('/', $normalized); if (count($parts) < 4) { @@ -213,6 +242,17 @@ class Storage extends Wrapper { return false; } + /** + * get move to trash event + * + * @param Node $node + * @return MoveToTrashEvent + */ + protected function createMoveToTrashEvent(Node $node) { + $event = new MoveToTrashEvent($node); + return $event; + } + /** * Run the delete operation with the given method * @@ -269,7 +309,9 @@ class Storage extends Wrapper { return new \OCA\Files_Trashbin\Storage( array('storage' => $storage, 'mountPoint' => $mountPoint), \OC::$server->getUserManager(), - \OC::$server->getLogger() + \OC::$server->getLogger(), + \OC::$server->getEventDispatcher(), + \OC::$server->getLazyRootFolder() ); }, 1); } diff --git a/apps/files_trashbin/tests/StorageTest.php b/apps/files_trashbin/tests/StorageTest.php index 52d5f05614..2e3ddf2e6b 100644 --- a/apps/files_trashbin/tests/StorageTest.php +++ b/apps/files_trashbin/tests/StorageTest.php @@ -31,7 +31,13 @@ namespace OCA\Files_Trashbin\Tests; use OC\Files\Storage\Temporary; use OC\Files\Filesystem; +use OCA\Files_Trashbin\Events\MoveToTrashEvent; +use OCA\Files_Trashbin\Storage; +use OCP\Files\Cache\ICache; +use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\ILogger; +use Symfony\Component\EventDispatcher\EventDispatcher; /** * Class Storage @@ -522,19 +528,40 @@ class StorageTest extends \Test\TestCase { /** * @dataProvider dataTestShouldMoveToTrash */ - public function testShouldMoveToTrash($mountPoint, $path, $userExists, $expected) { + public function testShouldMoveToTrash($mountPoint, $path, $userExists, $appDisablesTrash, $expected) { + $fileID = 1; + $cache = $this->getMock(ICache::class); + $cache->expects($this->any())->method('getId')->willReturn($fileID); $tmpStorage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor()->getMock($cache); + $tmpStorage->expects($this->any())->method('getCache')->willReturn($cache); $userManager = $this->getMockBuilder('OCP\IUserManager') ->disableOriginalConstructor()->getMock(); $userManager->expects($this->any()) ->method('userExists')->willReturn($userExists); $logger = $this->getMockBuilder(ILogger::class)->getMock(); - $storage = new \OCA\Files_Trashbin\Storage( - ['mountPoint' => $mountPoint, 'storage' => $tmpStorage], - $userManager, - $logger - ); + $eventDispatcher = $this->getMockBuilder(EventDispatcher::class) + ->disableOriginalConstructor()->getMock(); + $rootFolder = $this->getMock(IRootFolder::class); + $node = $this->getMockBuilder(Node::class)->disableOriginalConstructor()->getMock(); + $event = $this->getMockBuilder(MoveToTrashEvent::class)->disableOriginalConstructor()->getMock(); + $event->expects($this->any())->method('shouldMoveToTrashBin')->willReturn(!$appDisablesTrash); + + $rootFolder->expects($this->any())->method('getById')->with($fileID)->willReturn([$node]); + + $storage = $this->getMockBuilder(Storage::class) + ->setConstructorArgs( + [ + ['mountPoint' => $mountPoint, 'storage' => $tmpStorage], + $userManager, + $logger, + $eventDispatcher, + $rootFolder + ] + )->setMethods(['createMoveToTrashEvent'])->getMock(); + + $storage->expects($this->any())->method('createMoveToTrashEvent')->with($node) + ->willReturn($event); $this->assertSame($expected, $this->invokePrivate($storage, 'shouldMoveToTrash', [$path]) @@ -544,10 +571,13 @@ class StorageTest extends \Test\TestCase { public function dataTestShouldMoveToTrash() { return [ - ['/schiesbn/', '/files/test.txt', true, true], - ['/schiesbn/', '/files/test.txt', false, false], - ['/schiesbn/', '/test.txt', true, false], - ['/schiesbn/', '/test.txt', false, false], + ['/schiesbn/', '/files/test.txt', true, false, true], + ['/schiesbn/', '/files/test.txt', false, false, false], + ['/schiesbn/', '/test.txt', true, false, false], + ['/schiesbn/', '/test.txt', false, false, false], + // other apps disables the trashbin + ['/schiesbn/', '/files/test.txt', true, true, false], + ['/schiesbn/', '/files/test.txt', false, true, false], ]; }