diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index a222973fc3..a0448f7a6a 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -51,6 +51,8 @@ OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file'); OCP\Util::addScript('files_sharing', 'share'); OCP\Util::addScript('files_sharing', 'external'); +\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob'); + \OC::$server->getActivityManager()->registerExtension(function() { return new \OCA\Files_Sharing\Activity( \OC::$server->query('L10NFactory'), diff --git a/apps/files_sharing/lib/deleteorphanedsharesjob.php b/apps/files_sharing/lib/deleteorphanedsharesjob.php new file mode 100644 index 0000000000..f39078b778 --- /dev/null +++ b/apps/files_sharing/lib/deleteorphanedsharesjob.php @@ -0,0 +1,59 @@ + + * @author Vincent Petry + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_sharing\Lib; + +use Doctrine\DBAL\Platforms\SqlitePlatform; +use OCP\IDBConnection; +use OC\BackgroundJob\TimedJob; + +/** + * Delete all share entries that have no matching entries in the file cache table. + */ +class DeleteOrphanedSharesJob extends TimedJob { + + /** + * Default interval in minutes + * + * @var int $defaultIntervalMin + **/ + protected $defaultIntervalMin = 15; + + /** + * Makes the background job do its work + * + * @param array $argument unused argument + */ + public function run($argument) { + $connection = \OC::$server->getDatabaseConnection(); + $logger = \OC::$server->getLogger(); + + $sql = + 'DELETE FROM `*PREFIX*share` ' . + 'WHERE `item_type` in (\'file\', \'folder\') ' . + 'AND NOT EXISTS (SELECT `fileid` FROM `*PREFIX*filecache` WHERE `file_source` = `fileid`)'; + + $deletedEntries = $connection->executeUpdate($sql); + $logger->info("$deletedEntries orphaned share(s) deleted", ['app' => 'DeleteOrphanedSharesJob']); + } + +} diff --git a/apps/files_sharing/tests/deleteorphanedsharesjobtest.php b/apps/files_sharing/tests/deleteorphanedsharesjobtest.php new file mode 100644 index 0000000000..ec9d5f089b --- /dev/null +++ b/apps/files_sharing/tests/deleteorphanedsharesjobtest.php @@ -0,0 +1,142 @@ + + * @author Vincent Petry + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +namespace Test\BackgroundJob; + +use OCA\Files_sharing\Lib\DeleteOrphanedSharesJob; + +class DeleteOrphanedSharesJobTest extends \Test\TestCase { + + /** + * @var DeleteOrphanedSharesJob + */ + private $job; + + /** + * @var \OCP\IDBConnection + */ + private $connection; + + /** + * @var string + */ + private $user1; + + /** + * @var string + */ + private $user2; + + protected function setup() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + + $this->user1 = $this->getUniqueID('user1_'); + $this->user2 = $this->getUniqueID('user2_'); + + $userManager = \OC::$server->getUserManager(); + $userManager->createUser($this->user1, 'pass'); + $userManager->createUser($this->user2, 'pass'); + + \OC::registerShareHooks(); + + $this->job = new DeleteOrphanedSharesJob(); + } + + protected function tearDown() { + $this->connection->executeUpdate('DELETE FROM `*PREFIX*share` WHERE `item_type` in (\'file\', \'folder\')'); + + $userManager = \OC::$server->getUserManager(); + $user1 = $userManager->get($this->user1); + if($user1) { + $user1->delete(); + } + $user2 = $userManager->get($this->user2); + if($user2) { + $user2->delete(); + } + + $this->logout(); + + parent::tearDown(); + } + + private function getShares() { + $shares = []; + $result = $this->connection->executeQuery('SELECT * FROM `*PREFIX*share`'); + while ($row = $result->fetch()) { + $shares[] = $row; + } + $result->closeCursor(); + return $shares; + } + + /** + * Test clearing orphaned shares + */ + public function testClearShares() { + $this->loginAsUser($this->user1); + + $view = new \OC\Files\View('/' . $this->user1 . '/'); + $view->mkdir('files/test'); + $view->mkdir('files/test/sub'); + + $fileInfo = $view->getFileInfo('files/test/sub'); + $fileId = $fileInfo->getId(); + + $this->assertTrue( + \OCP\Share::shareItem('folder', $fileId, \OCP\Share::SHARE_TYPE_USER, $this->user2, \OCP\Constants::PERMISSION_READ), + 'Failed asserting that user 1 successfully shared "test/sub" with user 2.' + ); + + $this->assertCount(1, $this->getShares()); + + $this->job->run([]); + + $this->assertCount(1, $this->getShares(), 'Linked shares not deleted'); + + $view->unlink('files/test'); + + $this->job->run([]); + + $this->assertCount(0, $this->getShares(), 'Orphaned shares deleted'); + } + + public function testKeepNonFileShares() { + $this->loginAsUser($this->user1); + + \OCP\Share::registerBackend('test', 'Test_Share_Backend'); + + $this->assertTrue( + \OCP\Share::shareItem('test', 'test.txt', \OCP\Share::SHARE_TYPE_USER, $this->user2, \OCP\Constants::PERMISSION_READ), + 'Failed asserting that user 1 successfully shared something with user 2.' + ); + + $this->assertCount(1, $this->getShares()); + + $this->job->run([]); + + $this->assertCount(1, $this->getShares(), 'Non-file shares kept'); + } +} +