diff options
author | Vincent Petry <vincent@nextcloud.com> | 2022-04-06 15:32:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-06 15:32:39 +0200 |
commit | b88dc5ff2e32952e03d88d421627ed0d60486aa6 (patch) | |
tree | 4f4c9a7d46ca726ca7ca09601246816a38be815a /apps/files_trashbin | |
parent | ef9890fb7857282f13a8c72def13475de1e1909e (diff) | |
parent | 90cfa31533337cbb7d45aafe1e0e56c083ab8c67 (diff) | |
download | nextcloud-server-b88dc5ff2e32952e03d88d421627ed0d60486aa6.tar.gz nextcloud-server-b88dc5ff2e32952e03d88d421627ed0d60486aa6.zip |
Merge pull request #28935 from cahogan/trashbin-restore
Add trashbin:restore occ command
Diffstat (limited to 'apps/files_trashbin')
5 files changed, 166 insertions, 2 deletions
diff --git a/apps/files_trashbin/appinfo/info.xml b/apps/files_trashbin/appinfo/info.xml index 91f89672b11..e5308a2e3fd 100644 --- a/apps/files_trashbin/appinfo/info.xml +++ b/apps/files_trashbin/appinfo/info.xml @@ -35,6 +35,7 @@ To prevent a user from running out of disk space, the Deleted files app will not <command>OCA\Files_Trashbin\Command\CleanUp</command> <command>OCA\Files_Trashbin\Command\ExpireTrash</command> <command>OCA\Files_Trashbin\Command\Size</command> + <command>OCA\Files_Trashbin\Command\RestoreAllFiles</command> </commands> <sabre> diff --git a/apps/files_trashbin/composer/composer/autoload_classmap.php b/apps/files_trashbin/composer/composer/autoload_classmap.php index 7ce7e565c83..760044d4f87 100644 --- a/apps/files_trashbin/composer/composer/autoload_classmap.php +++ b/apps/files_trashbin/composer/composer/autoload_classmap.php @@ -13,6 +13,7 @@ return array( 'OCA\\Files_Trashbin\\Command\\CleanUp' => $baseDir . '/../lib/Command/CleanUp.php', 'OCA\\Files_Trashbin\\Command\\Expire' => $baseDir . '/../lib/Command/Expire.php', 'OCA\\Files_Trashbin\\Command\\ExpireTrash' => $baseDir . '/../lib/Command/ExpireTrash.php', + 'OCA\\Files_Trashbin\\Command\\RestoreAllFiles' => $baseDir . '/../lib/Command/RestoreAllFiles.php', 'OCA\\Files_Trashbin\\Command\\Size' => $baseDir . '/../lib/Command/Size.php', 'OCA\\Files_Trashbin\\Controller\\PreviewController' => $baseDir . '/../lib/Controller/PreviewController.php', 'OCA\\Files_Trashbin\\Events\\MoveToTrashEvent' => $baseDir . '/../lib/Events/MoveToTrashEvent.php', diff --git a/apps/files_trashbin/composer/composer/autoload_static.php b/apps/files_trashbin/composer/composer/autoload_static.php index 2f6d1936a28..ef52ac0e1e7 100644 --- a/apps/files_trashbin/composer/composer/autoload_static.php +++ b/apps/files_trashbin/composer/composer/autoload_static.php @@ -28,6 +28,7 @@ class ComposerStaticInitFiles_Trashbin 'OCA\\Files_Trashbin\\Command\\CleanUp' => __DIR__ . '/..' . '/../lib/Command/CleanUp.php', 'OCA\\Files_Trashbin\\Command\\Expire' => __DIR__ . '/..' . '/../lib/Command/Expire.php', 'OCA\\Files_Trashbin\\Command\\ExpireTrash' => __DIR__ . '/..' . '/../lib/Command/ExpireTrash.php', + 'OCA\\Files_Trashbin\\Command\\RestoreAllFiles' => __DIR__ . '/..' . '/../lib/Command/RestoreAllFiles.php', 'OCA\\Files_Trashbin\\Command\\Size' => __DIR__ . '/..' . '/../lib/Command/Size.php', 'OCA\\Files_Trashbin\\Controller\\PreviewController' => __DIR__ . '/..' . '/../lib/Controller/PreviewController.php', 'OCA\\Files_Trashbin\\Events\\MoveToTrashEvent' => __DIR__ . '/..' . '/../lib/Events/MoveToTrashEvent.php', diff --git a/apps/files_trashbin/composer/composer/installed.php b/apps/files_trashbin/composer/composer/installed.php index 5440719fa40..914fa1a857f 100644 --- a/apps/files_trashbin/composer/composer/installed.php +++ b/apps/files_trashbin/composer/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => 'c6429e6cd19c57582364338362e543580821cf99', + 'reference' => 'ff67123569a861301d14f83f7b2310e9a518c46d', 'name' => '__root__', 'dev' => false, ), @@ -16,7 +16,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => 'c6429e6cd19c57582364338362e543580821cf99', + 'reference' => 'ff67123569a861301d14f83f7b2310e9a518c46d', 'dev_requirement' => false, ), ), diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php new file mode 100644 index 00000000000..43e9363327b --- /dev/null +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -0,0 +1,161 @@ +<?php +/** + * @copyright Copyright (c) 2021, Caitlin Hogan (cahogan16@gmail.com) + * @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 <http://www.gnu.org/licenses/> + * + */ +namespace OCA\Files_Trashbin\Command; + +use OC\Core\Command\Base; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\IL10N; +use OCP\IUserBackend; +use OCA\Files_Trashbin\Trashbin; +use OCA\Files_Trashbin\Helper; +use OCP\IUserManager; +use OCP\L10N\IFactory; +use Symfony\Component\Console\Exception\InvalidOptionException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class RestoreAllFiles extends Base { + + /** @var IUserManager */ + protected $userManager; + + /** @var IRootFolder */ + protected $rootFolder; + + /** @var \OCP\IDBConnection */ + protected $dbConnection; + + /** @var IL10N */ + protected $l10n; + + /** + * @param IRootFolder $rootFolder + * @param IUserManager $userManager + * @param IDBConnection $dbConnection + */ + public function __construct(IRootFolder $rootFolder, IUserManager $userManager, IDBConnection $dbConnection, IFactory $l10nFactory) { + parent::__construct(); + $this->userManager = $userManager; + $this->rootFolder = $rootFolder; + $this->dbConnection = $dbConnection; + $this->l10n = $l10nFactory->get('files_trashbin'); + } + + protected function configure(): void { + parent::configure(); + $this + ->setName('trashbin:restore') + ->setDescription('Restore all deleted files') + ->addArgument( + 'user_id', + InputArgument::OPTIONAL | InputArgument::IS_ARRAY, + 'restore all deleted files of the given user(s)' + ) + ->addOption( + 'all-users', + null, + InputOption::VALUE_NONE, + 'run action on all users' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + /** @var string[] $users */ + $users = $input->getArgument('user_id'); + if ((!empty($users)) and ($input->getOption('all-users'))) { + throw new InvalidOptionException('Either specify a user_id or --all-users'); + } elseif (!empty($users)) { + foreach ($users as $user) { + if ($this->userManager->userExists($user)) { + $output->writeln("Restoring deleted files for user <info>$user</info>"); + $this->restoreDeletedFiles($user, $output); + } else { + $output->writeln("<error>Unknown user $user</error>"); + return 1; + } + } + } elseif ($input->getOption('all-users')) { + $output->writeln('Restoring deleted files for all users'); + foreach ($this->userManager->getBackends() as $backend) { + $name = get_class($backend); + if ($backend instanceof IUserBackend) { + $name = $backend->getBackendName(); + } + $output->writeln("Restoring deleted files for users on backend <info>$name</info>"); + $limit = 500; + $offset = 0; + do { + $users = $backend->getUsers('', $limit, $offset); + foreach ($users as $user) { + $output->writeln("<info>$user</info>"); + $this->restoreDeletedFiles($user, $output); + } + $offset += $limit; + } while (count($users) >= $limit); + } + } else { + throw new InvalidOptionException('Either specify a user_id or --all-users'); + } + return 0; + } + + /** + * Restore deleted files for the given user + * + * @param string $uid + * @param OutputInterface $output + */ + protected function restoreDeletedFiles(string $uid, OutputInterface $output): void { + \OC_Util::tearDownFS(); + \OC_Util::setupFS($uid); + \OC_User::setUserId($uid); + + $filesInTrash = Helper::getTrashFiles('/', $uid, 'mtime'); + $trashCount = count($filesInTrash); + if ($trashCount == 0) { + $output->writeln("User has no deleted files in the trashbin"); + return; + } + $output->writeln("Preparing to restore <info>$trashCount</info> files..."); + $count = 0; + foreach ($filesInTrash as $trashFile) { + $filename = $trashFile->getName(); + $timestamp = $trashFile->getMtime(); + $humanTime = $this->l10n->l('datetime', $timestamp); + $output->write("File <info>$filename</info> originally deleted at <info>$humanTime</info> "); + $file = $filename . '.d' . $timestamp; + $location = Trashbin::getLocation($uid, $filename, (string) $timestamp); + if ($location === '.') { + $location = ''; + } + $output->write("restoring to <info>/$location</info>:"); + if (Trashbin::restore($file, $filename, $timestamp)) { + $count = $count + 1; + $output->writeln(" <info>success</info>"); + } else { + $output->writeln(" <error>failed</error>"); + } + } + + $output->writeln("Successfully restored <info>$count</info> out of <info>$trashCount</info> files."); + } +} |