mirror of
https://github.com/nextcloud/server.git
synced 2026-04-25 08:08:33 -04:00
Merge pull request #14644 from owncloud/trash-expire-command
Expire files from the trash in the background
This commit is contained in:
commit
bbaf97ca43
5 changed files with 167 additions and 32 deletions
56
apps/files_trashbin/command/expire.php
Normal file
56
apps/files_trashbin/command/expire.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud - trash bin
|
||||
*
|
||||
* @author Robin Appelman
|
||||
* @copyright 2015 Robin Appelman icewind@owncloud.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Trashbin\Command;
|
||||
|
||||
use OC\Command\FileAccess;
|
||||
use OCA\Files_Trashbin\Trashbin;
|
||||
use OCP\Command\ICommand;
|
||||
|
||||
class Expire implements ICommand {
|
||||
use FileAccess;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $trashBinSize;
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @param int $trashBinSize
|
||||
*/
|
||||
function __construct($user, $trashBinSize) {
|
||||
$this->user = $user;
|
||||
$this->trashBinSize = $trashBinSize;
|
||||
}
|
||||
|
||||
public function handle() {
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_Util::setupFS($this->user);
|
||||
Trashbin::expire($this->trashBinSize, $this->user);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
namespace OCA\Files_Trashbin;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OCA\Files_Trashbin\Command\Expire;
|
||||
|
||||
class Trashbin {
|
||||
// how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
|
||||
|
|
@ -211,13 +212,13 @@ class Trashbin {
|
|||
}
|
||||
|
||||
$userTrashSize += $size;
|
||||
$userTrashSize -= self::expire($userTrashSize, $user);
|
||||
self::scheduleExpire($userTrashSize, $user);
|
||||
|
||||
// if owner !== user we also need to update the owners trash size
|
||||
if ($owner !== $user) {
|
||||
$ownerTrashSize = self::getTrashbinSize($owner);
|
||||
$ownerTrashSize += $size;
|
||||
$ownerTrashSize -= self::expire($ownerTrashSize, $owner);
|
||||
self::scheduleExpire($ownerTrashSize, $owner);
|
||||
}
|
||||
|
||||
return ($sizeOfAddedFiles === false) ? false : true;
|
||||
|
|
@ -429,7 +430,7 @@ class Trashbin {
|
|||
|
||||
if ($view->is_dir('/files_trashbin/versions/' . $file)) {
|
||||
$rootView->rename(\OC\Files\Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
|
||||
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp)) {
|
||||
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
|
||||
foreach ($versions as $v) {
|
||||
if ($timestamp) {
|
||||
$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
|
||||
|
|
@ -533,8 +534,8 @@ class Trashbin {
|
|||
$file = $filename;
|
||||
}
|
||||
|
||||
$size += self::deleteVersions($view, $file, $filename, $timestamp);
|
||||
$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp);
|
||||
$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
|
||||
$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp, $user);
|
||||
|
||||
if ($view->is_dir('/files_trashbin/files/' . $file)) {
|
||||
$size += self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin/files/' . $file));
|
||||
|
|
@ -555,14 +556,13 @@ class Trashbin {
|
|||
* @param $timestamp
|
||||
* @return int
|
||||
*/
|
||||
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp) {
|
||||
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
|
||||
$size = 0;
|
||||
if (\OCP\App::isEnabled('files_versions')) {
|
||||
$user = \OCP\User::getUser();
|
||||
if ($view->is_dir('files_trashbin/versions/' . $file)) {
|
||||
$size += self::calculateSize(new \OC\Files\view('/' . $user . '/files_trashbin/versions/' . $file));
|
||||
$view->unlink('files_trashbin/versions/' . $file);
|
||||
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp)) {
|
||||
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
|
||||
foreach ($versions as $v) {
|
||||
if ($timestamp) {
|
||||
$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
|
||||
|
|
@ -584,10 +584,9 @@ class Trashbin {
|
|||
* @param $timestamp
|
||||
* @return int
|
||||
*/
|
||||
private static function deleteEncryptionKeys(\OC\Files\View $view, $file, $filename, $timestamp) {
|
||||
private static function deleteEncryptionKeys(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
|
||||
$size = 0;
|
||||
if (\OCP\App::isEnabled('files_encryption')) {
|
||||
$user = \OCP\User::getUser();
|
||||
|
||||
$keyfiles = \OC\Files\Filesystem::normalizePath('files_trashbin/keys/' . $filename);
|
||||
|
||||
|
|
@ -689,26 +688,18 @@ class Trashbin {
|
|||
$freeSpace = self::calculateFreeSpace($size, $user);
|
||||
|
||||
if ($freeSpace < 0) {
|
||||
self::expire($size, $user);
|
||||
self::scheduleExpire($size, $user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up the trash bin
|
||||
*
|
||||
* @param int $trashbinSize current size of the trash bin
|
||||
* @param int $trashBinSize current size of the trash bin
|
||||
* @param string $user
|
||||
* @return int size of expired files
|
||||
*/
|
||||
private static function expire($trashbinSize, $user) {
|
||||
|
||||
// let the admin disable auto expire
|
||||
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
|
||||
if ($autoExpire === false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$availableSpace = self::calculateFreeSpace($trashbinSize, $user);
|
||||
public static function expire($trashBinSize, $user) {
|
||||
$availableSpace = self::calculateFreeSpace($trashBinSize, $user);
|
||||
$size = 0;
|
||||
|
||||
$retention_obligation = \OC_Config::getValue('trashbin_retention_obligation', self::DEFAULT_RETENTION_OBLIGATION);
|
||||
|
|
@ -725,8 +716,18 @@ class Trashbin {
|
|||
|
||||
// delete files from trash until we meet the trash bin size limit again
|
||||
$size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
|
||||
}
|
||||
|
||||
return $size;
|
||||
/**@param int $trashBinSize current size of the trash bin
|
||||
* @param string $user
|
||||
*/
|
||||
private static function scheduleExpire($trashBinSize, $user) {
|
||||
// let the admin disable auto expire
|
||||
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
|
||||
if ($autoExpire === false) {
|
||||
return;
|
||||
}
|
||||
\OC::$server->getCommandBus()->push(new Expire($user, $trashBinSize));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -827,8 +828,8 @@ class Trashbin {
|
|||
* @param int $timestamp timestamp when the file was deleted
|
||||
* @return array
|
||||
*/
|
||||
private static function getVersionsFromTrash($filename, $timestamp) {
|
||||
$view = new \OC\Files\View('/' . \OCP\User::getUser() . '/files_trashbin/versions');
|
||||
private static function getVersionsFromTrash($filename, $timestamp, $user) {
|
||||
$view = new \OC\Files\View('/' . $user . '/files_trashbin/versions');
|
||||
$versions = array();
|
||||
|
||||
//force rescan of versions, local storage may not have updated the cache
|
||||
|
|
|
|||
|
|
@ -210,6 +210,8 @@ class Test_Trashbin extends \Test\TestCase {
|
|||
|
||||
\OC\Files\Filesystem::unlink($folder . 'user1-4.txt');
|
||||
|
||||
$this->runCommands();
|
||||
|
||||
$filesInTrashUser2AfterDelete = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER2);
|
||||
|
||||
// user2-1.txt should have been expired
|
||||
|
|
|
|||
53
lib/private/command/queuebus.php
Normal file
53
lib/private/command/queuebus.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OC\Command;
|
||||
|
||||
use OCP\Command\IBus;
|
||||
use OCP\Command\ICommand;
|
||||
|
||||
class QueueBus implements IBus {
|
||||
/**
|
||||
* @var (ICommand|callable)[]
|
||||
*/
|
||||
private $queue;
|
||||
|
||||
/**
|
||||
* Schedule a command to be fired
|
||||
*
|
||||
* @param \OCP\Command\ICommand | callable $command
|
||||
*/
|
||||
public function push($command) {
|
||||
$this->queue[] = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require all commands using a trait to be run synchronous
|
||||
*
|
||||
* @param string $trait
|
||||
*/
|
||||
public function requireSync($trait) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \OCP\Command\ICommand | callable $command
|
||||
*/
|
||||
private function runCommand($command) {
|
||||
if ($command instanceof ICommand) {
|
||||
$command->handle();
|
||||
} else {
|
||||
$command();
|
||||
}
|
||||
}
|
||||
|
||||
public function run() {
|
||||
while ($command = array_shift($this->queue)) {
|
||||
$this->runCommand($command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,9 +22,23 @@
|
|||
|
||||
namespace Test;
|
||||
|
||||
use OC\Command\QueueBus;
|
||||
use OCP\Security\ISecureRandom;
|
||||
|
||||
abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \OC\Command\QueueBus
|
||||
*/
|
||||
private $commandBus;
|
||||
|
||||
protected function setUp() {
|
||||
// overwrite the command bus with one we can run ourselves
|
||||
$this->commandBus = new QueueBus();
|
||||
\OC::$server->registerService('AsyncCommandBus', function(){
|
||||
return $this->commandBus;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique identifier as uniqid() is not reliable sometimes
|
||||
*
|
||||
|
|
@ -55,6 +69,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
/**
|
||||
* Remove all entries from the files map table
|
||||
*
|
||||
* @param string $dataDir
|
||||
*/
|
||||
static protected function tearDownAfterClassCleanFileMapper($dataDir) {
|
||||
|
|
@ -66,6 +81,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
/**
|
||||
* Remove all entries from the storages table
|
||||
*
|
||||
* @throws \OC\DatabaseException
|
||||
*/
|
||||
static protected function tearDownAfterClassCleanStorages() {
|
||||
|
|
@ -76,6 +92,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
/**
|
||||
* Remove all entries from the filecache table
|
||||
*
|
||||
* @throws \OC\DatabaseException
|
||||
*/
|
||||
static protected function tearDownAfterClassCleanFileCache() {
|
||||
|
|
@ -91,11 +108,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
|||
*/
|
||||
static protected function tearDownAfterClassCleanStrayDataFiles($dataDir) {
|
||||
$knownEntries = array(
|
||||
'owncloud.log' => true,
|
||||
'owncloud.db' => true,
|
||||
'.ocdata' => true,
|
||||
'..' => true,
|
||||
'.' => true,
|
||||
'owncloud.log' => true,
|
||||
'owncloud.db' => true,
|
||||
'.ocdata' => true,
|
||||
'..' => true,
|
||||
'.' => true,
|
||||
);
|
||||
|
||||
if ($dh = opendir($dataDir)) {
|
||||
|
|
@ -122,8 +139,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
|||
$path = $dir . '/' . $file;
|
||||
if (is_dir($path)) {
|
||||
self::tearDownAfterClassCleanStrayDataUnlinkDir($path);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
@unlink($path);
|
||||
}
|
||||
}
|
||||
|
|
@ -169,4 +185,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
|
|||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all commands pushed to the bus
|
||||
*/
|
||||
protected function runCommands() {
|
||||
$this->commandBus->run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue